SQLite

Check-in [6e79505d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add ability for the JS Worker1.exec() API to report the number of changes made to the caller, per request in forum post d0b19483642e20dd.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 6e79505df915612b60696e4eec5c9973175fe6ecf273eb3152b996e63ae54a07
User & Date: stephan 2023-05-25 16:49:06
Context
2023-05-27
19:34
Add extra tests for fts5, large rowids and "ORDER BY rowid DESC". No changes to code. (check-in: b5b5eaee user: dan tags: trunk)
00:03
CLI much closer to being callable. (fewer exit() calls) ^C interrupt response improved. Sync w/trunk. Some diagnostic code removed. Some refactoring for sake of FIDDLE build. Streamline main(), by moving code to more dedicated routines and otherwise. Make -quiet more useful. (check-in: bff3a9a8 user: larrybr tags: cli_extension)
2023-05-25
16:49
Add ability for the JS Worker1.exec() API to report the number of changes made to the caller, per request in forum post d0b19483642e20dd. (check-in: 6e79505d user: stephan tags: trunk)
2023-05-23
19:11
Minor cleanups in demo JS code, per forum feedback. (check-in: 80c7c036 user: stephan tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/wasm/api/sqlite3-api-worker1.js.

273
274
275
276
277
278
279













280
281
282
283
284
285
286
      input arguments, possibly modified. See below.
    }
  }
  ```

  The arguments are in the same form accepted by oo1.DB.exec(), with
  the exceptions noted below.














  A function-type args.callback property cannot cross
  the window/Worker boundary, so is not useful here. If
  args.callback is a string then it is assumed to be a
  message type key, in which case a callback function will be
  applied which posts each row result via:








>
>
>
>
>
>
>
>
>
>
>
>
>







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
      input arguments, possibly modified. See below.
    }
  }
  ```

  The arguments are in the same form accepted by oo1.DB.exec(), with
  the exceptions noted below.

  If the `countChanges` arguments property (added in version 3.43) is
  truthy then the `result` property contained by the returned object
  will have a `changeCount` property which holds the number of changes
  made by the provided SQL. Because the SQL may contain an arbitrary
  number of statements, the `changeCount` is calculated by calling
  `sqlite3_total_changes()` before and after the SQL is evaluated. If
  the value of `countChanges` is 64 then the `changeCount` property
  will be returned as a 64-bit integer in the form of a BigInt (noting
  that that will trigger an exception if used in a BigInt-incapable
  build).  In the latter case, the number of changes is calculated by
  calling `sqlite3_total_changes64()` before and after the SQL is
  evaluated.

  A function-type args.callback property cannot cross
  the window/Worker boundary, so is not useful here. If
  args.callback is a string then it is assumed to be a
  message type key, in which case a callback function will be
  applied which posts each row result via:

519
520
521
522
523
524
525



526



527
528
529
530
531
532
533
            columnNames: rc.columnNames,
            rowNumber: ++rowNumber,
            row: row
          }, wState.xfer);
        }
      }
      try {



        db.exec(rc);



        if(rc.callback instanceof Function){
          rc.callback = theCallback;
          /* Post a sentinel message to tell the client that the end
             of the result set has been reached (possibly with zero
             rows). */
          wState.post({
            type: theCallback,







>
>
>

>
>
>







532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
            columnNames: rc.columnNames,
            rowNumber: ++rowNumber,
            row: row
          }, wState.xfer);
        }
      }
      try {
        const changeCount = !!rc.countChanges
              ? db.changes(true,(64===rc.countChanges))
              : undefined;
        db.exec(rc);
        if(undefined !== changeCount){
          rc.changeCount = db.changes(true,64===rc.countChanges) - changeCount;
        }
        if(rc.callback instanceof Function){
          rc.callback = theCallback;
          /* Post a sentinel message to tell the client that the end
             of the result set has been reached (possibly with zero
             rows). */
          wState.post({
            type: theCallback,

Changes to ext/wasm/api/sqlite3-worker1-promiser.c-pp.js.

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
    catch(e){msgHandler.reject(e)}
  }/*worker.onmessage()*/;
  return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
    let msg;
    if(1===arguments.length){
      msg = arguments[0];
    }else if(2===arguments.length){
      msg = {
        type: arguments[0],
        args: arguments[1]
      };
    }else{
      toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
    }
    if(!msg.dbId) msg.dbId = dbId;
    msg.messageId = genMsgId(msg);
    msg.departureTime = performance.now();
    const proxy = Object.create(null);







|
|
|
<







192
193
194
195
196
197
198
199
200
201

202
203
204
205
206
207
208
    catch(e){msgHandler.reject(e)}
  }/*worker.onmessage()*/;
  return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
    let msg;
    if(1===arguments.length){
      msg = arguments[0];
    }else if(2===arguments.length){
      msg = Object.create(null);
      msg.type = arguments[0];
      msg.args = arguments[1];

    }else{
      toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
    }
    if(!msg.dbId) msg.dbId = dbId;
    msg.messageId = genMsgId(msg);
    msg.departureTime = performance.now();
    const proxy = Object.create(null);

Changes to ext/wasm/demo-worker1-promiser.js.

60
61
62
63
64
65
66

67

68
69
70

71
72
73
74
75
76
77
78
79
80
81
82
  delete self.sqlite3Worker1Promiser;

  const wtest = async function(msgType, msgArgs, callback){
    if(2===arguments.length && 'function'===typeof msgArgs){
      callback = msgArgs;
      msgArgs = undefined;
    }

    const p = workerPromise({type: msgType, args:msgArgs});

    return callback ? p.then(callback).finally(testCount) : p;
  };


  const runTests = async function(){
    const dbFilename = '/testing2.sqlite3';
    startTime = performance.now();

    let sqConfig;
    await wtest('config-get', (ev)=>{
      const r = ev.result;
      log('sqlite3.config subset:', r);
      T.assert('boolean' === typeof r.bigIntEnabled);
      sqConfig = r;
    });
    logHtml('',







>
|
>



>




<







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
  delete self.sqlite3Worker1Promiser;

  const wtest = async function(msgType, msgArgs, callback){
    if(2===arguments.length && 'function'===typeof msgArgs){
      callback = msgArgs;
      msgArgs = undefined;
    }
    const p = 1
          ? workerPromise({type: msgType, args:msgArgs})
          : workerPromise(msgType, msgArgs);
    return callback ? p.then(callback).finally(testCount) : p;
  };

  let sqConfig;
  const runTests = async function(){
    const dbFilename = '/testing2.sqlite3';
    startTime = performance.now();


    await wtest('config-get', (ev)=>{
      const r = ev.result;
      log('sqlite3.config subset:', r);
      T.assert('boolean' === typeof r.bigIntEnabled);
      sqConfig = r;
    });
    logHtml('',
98
99
100
101
102
103
104
105

106
107
108
109



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
  const runTests2 = async function(){
    const mustNotReach = ()=>toss("This is not supposed to be reached.");

    await wtest('exec',{
      sql: ["create table t(a,b)",
            "insert into t(a,b) values(1,2),(3,4),(5,6)"
           ].join(';'),
      resultRows: [], columnNames: []

    }, function(ev){
      ev = ev.result;
      T.assert(0===ev.resultRows.length)
        .assert(0===ev.columnNames.length);



    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0][0])
        .assert(6===ev.resultRows[2][1])
        .assert(2===ev.columnNames.length)
        .assert('b'===ev.columnNames[1]);
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
      rowMode: 'object'

    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0].a)
        .assert(6===ev.resultRows[2].b)

    });

    await wtest(
      'exec',
      {sql:'intentional_error'},
      mustNotReach
    ).catch((e)=>{
      warn("Intentional error:",e);
    });

    await wtest('exec',{
      sql:'select 1 union all select 3',
      resultRows: [],
    }, function(ev){
      ev = ev.result;
      T.assert(2 === ev.resultRows.length)
        .assert(1 === ev.resultRows[0][0])
        .assert(3 === ev.resultRows[1][0]);

    });

    const resultRowTest1 = function f(ev){
      if(undefined === f.counter) f.counter = 0;
      if(null === ev.rowNumber){
        /* End of result set. */
        T.assert(undefined === ev.row)







|
>



|
>
>
>

















|
>





>












|




|
>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  const runTests2 = async function(){
    const mustNotReach = ()=>toss("This is not supposed to be reached.");

    await wtest('exec',{
      sql: ["create table t(a,b)",
            "insert into t(a,b) values(1,2),(3,4),(5,6)"
           ].join(';'),
      resultRows: [], columnNames: [],
      countChanges: sqConfig.bigIntEnabled ? 64 : true
    }, function(ev){
      ev = ev.result;
      T.assert(0===ev.resultRows.length)
        .assert(0===ev.columnNames.length)
        .assert(sqConfig.bigIntEnabled
                ? (3n===ev.changeCount)
                : (3===ev.changeCount));
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0][0])
        .assert(6===ev.resultRows[2][1])
        .assert(2===ev.columnNames.length)
        .assert('b'===ev.columnNames[1]);
    });

    await wtest('exec',{
      sql: 'select a a, b b from t order by a',
      resultRows: [], columnNames: [],
      rowMode: 'object',
      countChanges: true
    }, function(ev){
      ev = ev.result;
      T.assert(3===ev.resultRows.length)
        .assert(1===ev.resultRows[0].a)
        .assert(6===ev.resultRows[2].b)
        .assert(0===ev.changeCount);
    });

    await wtest(
      'exec',
      {sql:'intentional_error'},
      mustNotReach
    ).catch((e)=>{
      warn("Intentional error:",e);
    });

    await wtest('exec',{
      sql:'select 1 union all select 3',
      resultRows: []
    }, function(ev){
      ev = ev.result;
      T.assert(2 === ev.resultRows.length)
        .assert(1 === ev.resultRows[0][0])
        .assert(3 === ev.resultRows[1][0])
        .assert(undefined === ev.changeCount);
    });

    const resultRowTest1 = function f(ev){
      if(undefined === f.counter) f.counter = 0;
      if(null === ev.rowNumber){
        /* End of result set. */
        T.assert(undefined === ev.row)