monetdb 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![Linux](https://github.com/MonetDB/monetdb-nodejs/workflows/Linux/badge.svg)
4
4
  ![macOS](https://github.com/MonetDB/monetdb-nodejs/workflows/macos/badge.svg)
5
- ![MonetDB-dev-builds](https://github.com/MonetDB/monetdb-nodejs/workflows/monetdb-dev-builds/badge.svg)
5
+ ![MonetDB-dev-builds](https://github.com/MonetDB/monetdb-nodejs/workflows/devbuilds/badge.svg)
6
6
  ![npm version](https://img.shields.io/npm/v/monetdb)
7
7
 
8
8
  Node.js connector for MonetDB.
@@ -14,6 +14,7 @@ declare class Connection extends EventEmitter {
14
14
  close(): Promise<boolean>;
15
15
  commit(): Promise<void>;
16
16
  private command;
17
+ destroy(): void;
17
18
  execute(sql: string, stream?: boolean): Promise<any>;
18
19
  prepare(sql: string): Promise<PrepareStatement>;
19
20
  setAutocommit(v: boolean): Promise<boolean>;
@@ -58,6 +58,9 @@ class Connection extends events_1.EventEmitter {
58
58
  command(str) {
59
59
  return this.mapi.request(str);
60
60
  }
61
+ destroy() {
62
+ return this.mapi.destroy();
63
+ }
61
64
  execute(sql, stream = false) {
62
65
  const query = `s${sql};\n`;
63
66
  if (stream && this.replySize !== -1)
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
package/dist/mapi.d.ts CHANGED
@@ -77,24 +77,24 @@ interface ResponseOpt {
77
77
  fileHandler?: any;
78
78
  }
79
79
  declare class Response {
80
+ chunks: Buffer[];
80
81
  buff: Buffer;
81
82
  offset: number;
82
83
  parseOffset: number;
83
84
  stream: boolean;
84
85
  settled: boolean;
85
86
  headerEmitted: boolean;
86
- segments: Segment[];
87
87
  result?: QueryResult;
88
88
  callbacks: ResponseCallbacks;
89
89
  queryStream?: QueryStream;
90
90
  headers?: ResponseHeaders;
91
91
  fileHandler: any;
92
+ last: boolean;
93
+ leftOver: number;
94
+ private _str;
92
95
  constructor(opt?: ResponseOpt);
93
96
  append(data: Buffer): number;
94
97
  complete(): boolean;
95
- private seekOffset;
96
- private expand;
97
- private firstCharacter;
98
98
  errorMessage(): string;
99
99
  isFileTransfer(): boolean;
100
100
  isPrompt(): boolean;
@@ -104,14 +104,7 @@ declare class Response {
104
104
  toString(start?: number): string;
105
105
  settle(res?: Promise<any>): void;
106
106
  parseQueryResponse(data: string, res: any[]): number;
107
- }
108
- declare class Segment {
109
- offset: number;
110
- bytes: number;
111
- bytesOffset: number;
112
- last: boolean;
113
- constructor(bytes: number, last: boolean, offset: number, bytesOffset: number);
114
- isFull(): boolean;
107
+ streamResult(): void;
115
108
  }
116
109
  declare class MapiConnection extends EventEmitter {
117
110
  state: MAPI_STATE;
@@ -131,7 +124,8 @@ declare class MapiConnection extends EventEmitter {
131
124
  private createSocket;
132
125
  connect(handShakeOptions?: HandShakeOption[]): Promise<any[]>;
133
126
  ready(): boolean;
134
- disconnect(): Promise<boolean>;
127
+ disconnect(): Promise<true>;
128
+ destroy(): void;
135
129
  private login;
136
130
  /**
137
131
  * Raise exception on server by sending bad packet
package/dist/mapi.js CHANGED
@@ -272,15 +272,18 @@ function parseTupleLine(line, types) {
272
272
  }
273
273
  class Response {
274
274
  constructor(opt = {}) {
275
- this.buff = buffer_1.Buffer.allocUnsafe(MAPI_BLOCK_SIZE).fill(0);
275
+ this.chunks = [];
276
+ //this.buff = Buffer.allocUnsafe(MAPI_BLOCK_SIZE).fill(0);
276
277
  this.offset = 0;
277
278
  this.parseOffset = 0;
278
- this.segments = [];
279
279
  this.settled = false;
280
+ this.last = false;
280
281
  this.headerEmitted = false;
281
282
  this.stream = opt.stream;
282
283
  this.callbacks = opt.callbacks;
283
284
  this.fileHandler = opt.fileHandler;
285
+ this.leftOver = 0;
286
+ this._str = "";
284
287
  if (opt.stream) {
285
288
  this.queryStream = new QueryStream();
286
289
  if (opt.callbacks && opt.callbacks.resolve)
@@ -288,106 +291,89 @@ class Response {
288
291
  }
289
292
  }
290
293
  append(data) {
291
- let srcStartIndx = 0;
292
- let srcEndIndx = srcStartIndx + data.length;
293
- const l = this.segments.length;
294
- let segment = (l > 0 && this.segments[l - 1]) || undefined;
295
- let bytesCopied = 0;
294
+ //let srcStartIndx = 0;
295
+ //let srcEndIndx = srcStartIndx + data.length;
296
296
  let bytesProcessed = 0;
297
- if (!this.complete()) {
298
- // check if out of space
299
- if (this.buff.length - this.offset < data.length) {
300
- const bytes = this.expand(MAPI_BLOCK_SIZE);
301
- console.log(`expanding by ${bytes} bytes!`);
302
- }
303
- if (segment === undefined || (segment && segment.isFull())) {
304
- const hdr = data.readUInt16LE(0);
305
- const last = (hdr & 1) === 1;
306
- const bytes = hdr >> 1;
307
- srcStartIndx = MAPI_HEADER_SIZE;
308
- srcEndIndx = srcStartIndx + Math.min(bytes, data.length);
309
- bytesCopied = data.copy(this.buff, this.offset, srcStartIndx, srcEndIndx);
310
- segment = new Segment(bytes, last, this.offset, bytesCopied);
311
- this.segments.push(segment);
312
- this.offset += bytesCopied;
313
- bytesProcessed = MAPI_HEADER_SIZE + bytesCopied;
314
- }
315
- else {
316
- const byteCntToRead = segment.bytes - segment.bytesOffset;
317
- srcEndIndx = srcStartIndx + byteCntToRead;
318
- bytesCopied = data.copy(this.buff, this.offset, srcStartIndx, srcEndIndx);
319
- this.offset += bytesCopied;
320
- segment.bytesOffset += bytesCopied;
321
- // console.log(`segment is full ${segment.bytesOffset === segment.bytes}`);
322
- bytesProcessed = bytesCopied;
323
- }
324
- if (this.isQueryResponse()) {
325
- const tuples = [];
326
- // const firstPackage = this.parseOffset === 0;
327
- this.parseOffset += this.parseQueryResponse(this.toString(this.parseOffset), tuples);
328
- if (tuples.length > 0) {
329
- if (this.queryStream) {
330
- // emit header once
331
- if (this.headerEmitted === false &&
332
- this.result &&
333
- this.result.columns) {
334
- this.queryStream.emit("header", this.result.columns);
335
- this.headerEmitted = true;
336
- }
337
- // emit tuples
338
- this.queryStream.emit("data", tuples);
339
- }
340
- else {
341
- this.result.data = this.result.data || [];
342
- for (let t of tuples) {
343
- this.result.data.push(t);
344
- }
345
- }
346
- }
347
- }
297
+ if (this.leftOver == 0) {
298
+ // new mapi blk, read header
299
+ const hdr = data.readUInt16LE(0);
300
+ this.last = (hdr & 1) === 1;
301
+ this.leftOver = hdr >> 1;
302
+ data = data.subarray(MAPI_HEADER_SIZE);
303
+ bytesProcessed += MAPI_HEADER_SIZE;
304
+ //bytesCopied = data.copy(
305
+ // this.buff,
306
+ // this.offset,
307
+ // srcStartIndx,
308
+ // srcEndIndx
309
+ //);
310
+ //segment = new Segment(bytes, last, this.offset, bytesCopied);
311
+ //this.segments.push(segment);
312
+ //this.offset += bytesCopied;
313
+ //bytesProcessed = MAPI_HEADER_SIZE + bytesCopied;
348
314
  }
315
+ //else {
316
+ // const byteCntToRead = segment.bytes - segment.bytesOffset;
317
+ // srcEndIndx = srcStartIndx + byteCntToRead;
318
+ // bytesCopied = data.copy(
319
+ // this.buff,
320
+ // this.offset,
321
+ // srcStartIndx,
322
+ // srcEndIndx
323
+ // );
324
+ // this.offset += bytesCopied;
325
+ // segment.bytesOffset += bytesCopied;
326
+ // // console.log(`segment is full ${segment.bytesOffset === segment.bytes}`);
327
+ // bytesProcessed = bytesCopied;
328
+ //}
329
+ const bytesToRead = Math.min(data.length, this.leftOver);
330
+ //console.log(`bytesToRead ${bytesToRead}`);
331
+ if (bytesToRead > 0) {
332
+ const chunk = data.subarray(0, bytesToRead);
333
+ this.chunks.push(chunk);
334
+ this.leftOver -= bytesToRead;
335
+ bytesProcessed += bytesToRead;
336
+ }
337
+ //if (this.isQueryResponse()) {
338
+ // const tuples = [];
339
+ // // const firstPackage = this.parseOffset === 0;
340
+ // this.parseOffset += this.parseQueryResponse(
341
+ // this.toString(this.parseOffset),
342
+ // tuples
343
+ // );
344
+ // console.log("tuples");
345
+ // console.log(tuples);
346
+ // if (tuples.length > 0) {
347
+ // if (this.queryStream) {
348
+ // // emit header once
349
+ // if (
350
+ // this.headerEmitted === false &&
351
+ // this.result &&
352
+ // this.result.columns
353
+ // ) {
354
+ // this.queryStream.emit("header", this.result.columns);
355
+ // this.headerEmitted = true;
356
+ // }
357
+ // // emit tuples
358
+ // this.queryStream.emit("data", tuples);
359
+ // } else {
360
+ // this.result.data = this.result.data || [];
361
+ // for (let t of tuples) {
362
+ // this.result.data.push(t);
363
+ // }
364
+ // }
365
+ // }
366
+ //}
367
+ //console.log(`bytesProcessed ${bytesToRead}`);
349
368
  return bytesProcessed;
350
369
  }
351
370
  complete() {
352
- const l = this.segments.length;
353
- if (l > 0) {
354
- const segment = this.segments[l - 1];
355
- return segment.last && segment.isFull();
356
- }
357
- return false;
358
- }
359
- seekOffset() {
360
- const len = this.segments.length;
361
- if (len) {
362
- const last = this.segments[len - 1];
363
- if (last.isFull())
364
- return last.offset + last.bytes;
365
- return last.offset;
366
- }
367
- return 0;
368
- }
369
- expand(byteCount) {
370
- if (this.buff.length + byteCount > MAX_BUFF_SIZE &&
371
- this.fileHandler instanceof file_transfer_1.FileDownloader) {
372
- const offset = this.seekOffset();
373
- if (offset) {
374
- this.fileHandler.writeChunk(this.buff.subarray(0, offset));
375
- this.buff = this.buff.subarray(offset);
376
- this.offset -= offset;
377
- }
378
- }
379
- const buff = buffer_1.Buffer.allocUnsafe(this.buff.length + byteCount).fill(0);
380
- const bytesCopied = this.buff.copy(buff);
381
- this.buff = buff;
382
- // should be byteCount
383
- return this.buff.length - bytesCopied;
384
- }
385
- firstCharacter() {
386
- return this.buff.toString("utf8", 0, 1);
371
+ return this.last && (this.leftOver == 0);
387
372
  }
388
373
  errorMessage() {
389
- if (this.firstCharacter() === MSG_ERROR) {
390
- return this.buff.toString("utf8", 1);
374
+ const msg = this.toString();
375
+ if (msg.startsWith(MSG_ERROR)) {
376
+ return msg;
391
377
  }
392
378
  return "";
393
379
  }
@@ -395,27 +381,32 @@ class Response {
395
381
  return this.toString().startsWith(MSG_FILETRANS);
396
382
  }
397
383
  isPrompt() {
398
- // perhaps use toString
399
- return this.complete() && this.firstCharacter() === "\x00";
384
+ return this.complete() && this.toString() == MSG_PROMPT;
400
385
  }
401
386
  isRedirect() {
402
- return this.firstCharacter() === MSG_REDIRECT;
387
+ return this.toString().startsWith(MSG_REDIRECT);
403
388
  }
404
389
  isQueryResponse() {
405
390
  if (this.result && this.result.type) {
406
391
  return this.result.type.startsWith(MSG_Q);
407
392
  }
408
- return this.firstCharacter() === MSG_Q;
393
+ return this.toString().startsWith(MSG_Q);
409
394
  }
410
395
  isMsgMore() {
411
396
  // server wants more ?
412
397
  return this.toString().startsWith(MSG_MORE);
413
398
  }
414
399
  toString(start) {
415
- const res = this.buff.toString("utf8", 0, this.offset);
400
+ if (this.complete() && !this.queryStream && this._str) {
401
+ if (start)
402
+ return this._str.substring(start);
403
+ return this._str;
404
+ }
405
+ const buff = buffer_1.Buffer.concat(this.chunks);
406
+ this._str = buff.toString("utf8");
416
407
  if (start)
417
- return res.substring(start);
418
- return res;
408
+ return this._str.substring(start);
409
+ return this._str;
419
410
  }
420
411
  settle(res) {
421
412
  if (this.settled === false && this.complete()) {
@@ -443,6 +434,8 @@ class Response {
443
434
  }
444
435
  }
445
436
  this.settled = true;
437
+ this._str = "";
438
+ this.chunks = [];
446
439
  }
447
440
  }
448
441
  parseQueryResponse(data, res) {
@@ -532,16 +525,22 @@ class Response {
532
525
  }
533
526
  return offset;
534
527
  }
535
- }
536
- class Segment {
537
- constructor(bytes, last, offset, bytesOffset) {
538
- this.bytes = bytes;
539
- this.last = last;
540
- this.offset = offset;
541
- this.bytesOffset = bytesOffset;
542
- }
543
- isFull() {
544
- return this.bytes === this.bytesOffset;
528
+ streamResult() {
529
+ if (this.queryStream && this.isQueryResponse()) {
530
+ const tuples = [];
531
+ this.parseOffset += this.parseQueryResponse(this.toString(this.parseOffset), tuples);
532
+ if (tuples.length > 0) {
533
+ // emit header once
534
+ if (this.headerEmitted === false &&
535
+ this.result &&
536
+ this.result.columns) {
537
+ this.queryStream.emit("header", this.result.columns);
538
+ this.headerEmitted = true;
539
+ }
540
+ // emit tuples
541
+ this.queryStream.emit("data", tuples);
542
+ }
543
+ }
545
544
  }
546
545
  }
547
546
  class MapiConnection extends events_1.EventEmitter {
@@ -554,23 +553,12 @@ class MapiConnection extends events_1.EventEmitter {
554
553
  socket.addListener("data", this.recv.bind(this));
555
554
  socket.addListener("error", this.handleSocketError.bind(this));
556
555
  socket.addListener("timeout", this.handleTimeout.bind(this));
557
- socket.addListener("close", () => {
558
- console.log("socket close event");
559
- this.emit("end");
556
+ socket.once("end", () => {
557
+ console.log("Server has ended the connection");
560
558
  });
561
559
  return socket;
562
560
  };
563
561
  this.state = MAPI_STATE.INIT;
564
- this.socket = this.createSocket(config.timeout);
565
- // this.socket = new Socket();
566
- // if (config.timeout) this.socket.setTimeout(config.timeout);
567
- // this.socket.addListener("data", this.recv.bind(this));
568
- // this.socket.addListener("error", this.handleSocketError.bind(this));
569
- // this.socket.addListener("timeout", this.handleTimeout.bind(this));
570
- // this.socket.addListener("close", () => {
571
- // console.log("socket close event");
572
- // this.emit("end");
573
- // });
574
562
  this.redirects = 0;
575
563
  this.queue = [];
576
564
  this.database = config.database;
@@ -601,18 +589,46 @@ class MapiConnection extends events_1.EventEmitter {
601
589
  return (0, events_1.once)(this, "ready");
602
590
  }
603
591
  ready() {
604
- return this.state === MAPI_STATE.READY;
592
+ return this.socket && this.socket.writable && this.state === MAPI_STATE.READY;
605
593
  }
606
594
  disconnect() {
607
595
  return new Promise((resolve, reject) => {
608
- this.socket.end(() => {
609
- this.redirects = 0;
596
+ if (!this.socket || this.socket.destroyed) {
597
+ this.socket = null;
610
598
  this.state = MAPI_STATE.INIT;
611
- this.socket.destroy();
612
- resolve(this.state === MAPI_STATE.INIT);
613
- });
599
+ return resolve(true);
600
+ }
601
+ const onClose = () => {
602
+ cleanup();
603
+ this.socket = null;
604
+ this.state = MAPI_STATE.INIT;
605
+ resolve(true);
606
+ };
607
+ const onError = (err) => {
608
+ var _a;
609
+ console.error(err);
610
+ cleanup();
611
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.destroy(); // force cleanup
612
+ this.socket = null;
613
+ this.state = MAPI_STATE.INIT;
614
+ reject(err);
615
+ };
616
+ const cleanup = () => {
617
+ var _a, _b;
618
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.removeListener("close", onClose);
619
+ (_b = this.socket) === null || _b === void 0 ? void 0 : _b.removeListener("error", onError);
620
+ };
621
+ this.socket.once("close", onClose);
622
+ this.socket.once("error", onError);
623
+ // Initiate graceful shutdown
624
+ this.socket.end();
614
625
  });
615
626
  }
627
+ destroy() {
628
+ if (this.socket && !this.socket.destroyed)
629
+ this.socket.destroy();
630
+ this.socket = null;
631
+ }
616
632
  login(challenge) {
617
633
  const challengeParts = challenge.split(":");
618
634
  const [salt, identity, protocol, hashes, endian, algo, opt_level] = challengeParts;
@@ -711,7 +727,8 @@ class MapiConnection extends events_1.EventEmitter {
711
727
  this.emit("error", new Error("Timeout"));
712
728
  }
713
729
  handleSocketError(err) {
714
- console.error(err);
730
+ console.error('Socket error: ', err);
731
+ this.destroy();
715
732
  }
716
733
  request(sql, stream = false) {
717
734
  return __awaiter(this, void 0, void 0, function* () {
@@ -744,8 +761,9 @@ class MapiConnection extends events_1.EventEmitter {
744
761
  recv(data) {
745
762
  let bytesLeftOver;
746
763
  let resp;
747
- // process queue left to right, find 1st uncomplete response
748
- // remove responses that are completed
764
+ // process queue left to right,
765
+ // find 1st uncomplete response
766
+ // remove complete responses
749
767
  while (this.queue.length) {
750
768
  const next = this.queue[0];
751
769
  if (next.complete() || next.settled) {
@@ -759,17 +777,23 @@ class MapiConnection extends events_1.EventEmitter {
759
777
  if (resp === undefined && this.queue.length === 0) {
760
778
  // challenge message
761
779
  // or direct call to send has being made
762
- // e.g. request api appends Response to the queue
780
+ // request api appends Response to the queue
763
781
  resp = new Response();
764
782
  this.queue.push(resp);
765
783
  }
766
- const offset = resp.append(data);
784
+ let offset = 0;
785
+ let end = data.length;
786
+ do {
787
+ offset += resp.append(data.subarray(offset, end));
788
+ } while ((offset < end) && !resp.complete());
789
+ if (resp.queryStream)
790
+ resp.streamResult();
767
791
  if (resp.complete())
768
792
  this.handleResponse(resp);
769
793
  bytesLeftOver = data.length - offset;
770
794
  if (bytesLeftOver) {
771
- const msg = `some ${bytesLeftOver} bytes left over!`;
772
- console.warn(msg);
795
+ //const msg = `some ${bytesLeftOver} bytes left over!`;
796
+ //console.warn(msg);
773
797
  this.recv(data.subarray(offset));
774
798
  }
775
799
  }
@@ -787,7 +811,7 @@ class MapiConnection extends events_1.EventEmitter {
787
811
  return;
788
812
  }
789
813
  if (resp.isPrompt()) {
790
- console.log("login OK");
814
+ //console.log("login OK");
791
815
  this.state = MAPI_STATE.READY;
792
816
  this.emit("ready", this.state);
793
817
  return;
@@ -795,7 +819,7 @@ class MapiConnection extends events_1.EventEmitter {
795
819
  return this.login(resp.toString());
796
820
  }
797
821
  if (resp.isFileTransfer()) {
798
- console.log("file transfer");
822
+ //console.log("file transfer");
799
823
  let fhandler;
800
824
  const msg = resp.toString(MSG_FILETRANS.length).trim();
801
825
  let mode, offset, file;
@@ -832,11 +856,17 @@ class MapiConnection extends events_1.EventEmitter {
832
856
  resp.fileHandler.ready()) {
833
857
  // end of download
834
858
  const fileHandler = resp.fileHandler;
835
- fileHandler.writeChunk(resp.buff);
859
+ const buff = buffer_1.Buffer.concat(resp.chunks);
860
+ fileHandler.writeChunk(buff);
836
861
  // we do expect a final response from server
837
862
  this.queue.push(new Response({ fileHandler }));
838
863
  return resp.settle(fileHandler.close());
839
864
  }
865
+ if (resp.isQueryResponse()) {
866
+ const data = [];
867
+ resp.parseQueryResponse(resp.toString(), data);
868
+ resp.result.data = data;
869
+ }
840
870
  resp.settle();
841
871
  }
842
872
  }