]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Implemented Stmt.get() and friends for WASM OO #1 wrapper. Added basic tests for...
authorstephan <stephan@noemail.net>
Sun, 22 May 2022 19:09:59 +0000 (19:09 +0000)
committerstephan <stephan@noemail.net>
Sun, 22 May 2022 19:09:59 +0000 (19:09 +0000)
FossilOrigin-Name: 601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec

ext/fiddle/EXPORTED_FUNCTIONS.sqlite3
ext/fiddle/sqlite3-api.js
ext/fiddle/testing-common.js
ext/fiddle/testing1.js
manifest
manifest.uuid

index e6b57420c2ae0fd7eec726a88eae0f61a582d35a..ae34ccdb19ad7a5a7f0eb18f3218908c0a2da5ee 100644 (file)
@@ -14,6 +14,8 @@ _sqlite3_column_bytes
 _sqlite3_column_count
 _sqlite3_column_count
 _sqlite3_column_double
+_sqlite3_column_int
+_sqlite3_column_int64
 _sqlite3_column_name
 _sqlite3_column_text
 _sqlite3_column_type
index 0c24085784e93ee5895832e6092562d06d90242b..d4423a2175dd3169c5dd6f961182d279823fed7e 100644 (file)
   Note that this file is not named sqlite3.js because that file gets
   generated by emscripten as the JS-glue counterpart of sqlite3.wasm.
 
-  The API gets installed as self.sqlite3, where self is expected to be
-  either the global window or Worker object. In addition, a higher-level
-  OO API is installed as self.SQLite3.
-
-  Potential TODO: instead of exporting 2 symbols, export only SQLite3
-  as {api: sqlite3, oo1: SQLite3}. The way we export this module is
-  not _really_ modern-JS-friendly because it exports global symbols
-  (which is admittedly poor form). Exporting it "cleanly" requires
-  using a module loader in all client code. As there are several
-  different approaches, none of which this developer is currently
-  truly familiar with, the current approach will have to do for the
-  time being.
+  This code installs an object named self.sqlite3, where self is
+  expected to be either the global window or Worker object:
+
+  self.sqlite3 = {
+      api: core WASM bindings of sqlite3 APIs,
+      SQLite3: high-level OO API wrapper
+  };
+
+  The way we export this module is not _really_ modern-JS-friendly
+  because it exports a global symbol (which is admittedly not
+  ideal). Exporting it "cleanly," without introducing any global-scope
+  symbols, requires using a module loader in all client code. As there
+  are several different approaches, none of which this developer is
+  currently truly familiar with, the current approach will have to do
+  for the time being.
 
   Because using the low-level API properly requires some degree of
   WASM-related magic, it is not recommended that that API be used
   as-is in client-level code. Rather, client code should use the
-  higher-level OO API or write such a wrapper on top of the
+  higher-level OO API or write a custom wrapper on top of the
   lower-level API.
 
   This file installs namespace.sqlite3, where namespace is `self`,
         ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]],
         ["sqlite3_bind_double","number",["number", "number", "number"]],
         ["sqlite3_bind_int","number",["number", "number", "number"]],
-        ["sqlite3_bind_int64","number",["number", "number", "number"]],
+        [/*Noting that wasm does not currently support 64-bit integers:*/
+         "sqlite3_bind_int64","number",["number", "number", "number"]],
         ["sqlite3_bind_null","void",["number"]],
         ["sqlite3_bind_parameter_count", "number", ["number"]],
         ["sqlite3_bind_parameter_index","number",["number", "string"]],
         ["sqlite3_column_count", "number", ["number"]],
         ["sqlite3_column_count","number",["number"]],
         ["sqlite3_column_double","number",["number", "number"]],
+        ["sqlite3_column_int","number",["number", "number"]],
+        [/*Noting that wasm does not currently support 64-bit integers:*/
+         "sqlite3_column_int64","number",["number", "number"]],
         ["sqlite3_column_name","string",["number", "number"]],
         ["sqlite3_column_text","string",["number", "number"]],
         ["sqlite3_column_type","number",["number", "number"]],
        and the sqlite3 API is in a worker. */
     /* memory for use in some pointer-passing routines */
     const pPtrArg = stackAlloc(4);
+    /** Throws a new error, concatenating all args with a space between
+        each. */
     const toss = function(){
         throw new Error(Array.prototype.join.call(arguments, ' '));
     };
             toss("TODO: support blob image of db here.");
         }
         this.checkRc(S.sqlite3_open(name, pPtrArg));
-        this.pDb = getValue(pPtrArg, "i32");
+        this._pDb = getValue(pPtrArg, "i32");
         this.filename = name;
         this._statements = {/*map of open Stmt _pointers_*/};
     };
             toss("Do not call the Stmt constructor directly. Use DB.prepare().");
         }
         this.db = arguments[0];
-        this.pStmt = arguments[1];
-        this.columnCount = S.sqlite3_column_count(this.pStmt);
-        this.parameterCount = S.sqlite3_bind_parameter_count(this.pStmt);
+        this._pStmt = arguments[1];
+        this.columnCount = S.sqlite3_column_count(this._pStmt);
+        this.parameterCount = S.sqlite3_bind_parameter_count(this._pStmt);
         this._allocs = [/*list of alloc'd memory blocks for bind() values*/]
     };
 
     /** Throws if the given DB has been closed, else it is returned. */
     const affirmDbOpen = function(db){
-        if(!db.pDb) toss("DB has been closed.");
+        if(!db._pDb) toss("DB has been closed.");
         return db;
     };
 
         */
         checkRc: function(sqliteResultCode){
             if(!sqliteResultCode) return this;
-            toss(S.sqlite3_errmsg(this.pDb) || "Unknown db error.");
+            toss(S.sqlite3_errmsg(this._pDb) || "Unknown db error.");
         },
         /**
            Finalizes all open statements and closes this database
            closed.
         */
         close: function(){
-            if(this.pDb){
+            if(this._pDb){
                 let s;
                 const that = this;
                 Object.keys(this._statements).forEach(function(k,s){
                     delete that._statements[k];
-                    if(s && s.pStmt) s.finalize();
+                    if(s && s._pStmt) s.finalize();
                 });
-                S.sqlite3_close_v2(this.pDb);
-                delete this.pDb;
+                S.sqlite3_close_v2(this._pDb);
+                delete this._pDb;
             }
         },
         /**
            a name of `main`.
         */
         fileName: function(dbName){
-            return S.sqlite3_db_filename(affirmDbOpen(this).pDb, dbName||"main");
+            return S.sqlite3_db_filename(affirmDbOpen(this)._pDb, dbName||"main");
         },
         /**
            Compiles the given SQL and returns a prepared Stmt. This is
         prepare: function(sql){
             affirmDbOpen(this);
             setValue(pPtrArg,0,"i32");
-            this.checkRc(S.sqlite3_prepare_v2(this.pDb, sql, -1, pPtrArg, null));
+            this.checkRc(S.sqlite3_prepare_v2(this._pDb, sql, -1, pPtrArg, null));
             const pStmt = getValue(pPtrArg, "i32");
             if(!pStmt) toss("Empty SQL is not permitted.");
             const stmt = new Stmt(this, pStmt, BindTypes);
         returns a falsy value. */
     const isSupportedBindType = function(v){
         let t = BindTypes[null===v ? 'null' : typeof v];
-        if(t) return t;
-        // TODO: handle buffer/blob types.
-        return undefined;
+        switch(t){
+            case BindTypes.boolean:
+            case BindTypes.null:
+            case BindTypes.number:
+            case BindTypes.string:
+                return t;
+            default:
+                if(v instanceof Uint8Array) return BindTypes.blob;
+                toss("Unhandled isSupportedBindType()",t);
+        }
     }
 
     /**
        function returns that value, else it throws.
     */
     const affirmSupportedBindType = function(v){
-        const t = isSupportedBindType(v);
-        if(t) return t;
-        toss("Unsupport bind() argument type.");
+        return isSupportedBindType(v) || toss("Unsupport bind() argument type.");
     };
 
     /**
 
        Else it throws.
     */
-    const indexOfParam = function(stmt,key){
+    const affirmParamIndex = function(stmt,key){
         const n = ('number'===typeof key)
-              ? key : S.sqlite3_bind_parameter_index(stmt.pStmt, key);
+              ? key : S.sqlite3_bind_parameter_index(stmt._pStmt, key);
         if(0===n || (n===key && (n!==(n|0)/*floating point*/))){
             toss("Invalid bind() parameter name: "+key);
         }
         return n;
     };
 
+    /** Throws if ndx is not an integer or if it is out of range
+        for stmt.columnCount, else returns stmt. */
+    const affirmColIndex = function(stmt,ndx){
+        if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){
+            toss("Column index",ndx,"is out of range.");
+        }
+        return stmt;
+    };
+
+    /** If stmt._mayGet, returns stmt, else throws. */
+    const affirmMayGet = function(stmt){
+        if(!affirmStmtOpen(stmt)._mayGet){
+            toss("Statement.step() has not (recently) returned true.");
+        }
+        return stmt;
+    };
+    
     /**
        Binds a single bound parameter value on the given stmt at the
        given index (numeric or named) using the given bindType (see
        the BindTypes enum) and value. Throws on error. Returns stmt on
        success.
     */
-    const bindOne = function(stmt,ndx,bindType,val){
+    const bindOne = function f(stmt,ndx,bindType,val){
+        if(!f._){
+            f._ = {
+                string: function(stmt, ndx, val, asBlob){
+                    const bytes = intArrayFromString(val,true);
+                    const pStr = allocate(bytes, ALLOC_NORMAL);
+                    stmt._allocs.push(pStr);
+                    const func =  asBlob ? S.sqlite3_bind_blob : S.sqlite3_bind_text;
+                    return func(stmt._pStmt, ndx, pStr, bytes.length, 0);
+                }
+            };
+        }
         affirmSupportedBindType(val);
-        ndx = indexOfParam(stmt,ndx);
+        ndx = affirmParamIndex(stmt,ndx);
         let rc = 0;
-        switch(bindType){
+        switch((null===val || undefined===val) ? BindTypes.null : bindType){
             case BindType.null:
-                rc = S.sqlite3_bind_null(stmt.pStmt, ndx);
+                rc = S.sqlite3_bind_null(stmt._pStmt, ndx);
                 break;
             case BindType.string:{
-                const bytes = intArrayFromString(string,false);
-                const pStr = allocate(bytes, ALLOC_NORMAL);
-                stmt._allocs.push(pStr);
-                rc = S.sqlite3_bind_text(stmt.pStmt, ndx, pStr,
-                                         bytes.length, 0);
+                rc = f._.string(stmt, ndx, val, false);
                 break;
             }
             case BindType.number: {
                 const m = ((val === (val|0))
-                           ? (val>0xefffffff
+                           ? ((val & 0x00000000/*>32 bits*/)
                               ? S.sqlite3_bind_int64
                               : S.sqlite3_bind_int)
                            : S.sqlite3_bind_double);
-                rc = m(stmt.pStmt, ndx, val);
+                rc = m(stmt._pStmt, ndx, val);
                 break;
             }
             case BindType.boolean:
-                rc = S.sqlite3_bind_int(stmt.pStmt, ndx, val ? 1 : 0);
+                rc = S.sqlite3_bind_int(stmt._pStmt, ndx, val ? 1 : 0);
                 break;
-            case BindType.blob:
+            case BindType.blob: {
+                if('string'===typeof val){
+                    rc = f._.string(stmt, ndx, val, true);
+                }else{
+                    const len = val.length;
+                    if(undefined===len){
+                        toss("Binding a value as a blob requires",
+                             "that it have a length member.");
+                    }
+                    const pBlob = allocate(val, ALLOC_NORMAL);
+                    stmt._allocs.push(pBlob);
+                    rc = S.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0);
+                }
+            }
             default: toss("Unsupported bind() argument type.");
         }
         if(rc) stmt.db.checkRc(rc);
     /** Throws if the given Stmt has been finalized, else
         it is returned. */
     const affirmStmtOpen = function(stmt){
-        if(!stmt.pStmt) toss("Stmt has been closed.");
+        if(!stmt._pStmt) toss("Stmt has been closed.");
         return stmt;
     };
 
            after this is.
         */
         finalize: function(){
-            if(this.pStmt){
+            if(this._pStmt){
                 freeBindMemory(this);
-                delete this.db._statements[this.pStmt];
-                S.sqlite3_finalize(this.pStmt);
-                delete this.pStmt;
+                delete this.db._statements[this._pStmt];
+                S.sqlite3_finalize(this._pStmt);
+                delete this.columnCount;
+                delete this.parameterCount;
+                delete this._pStmt;
                 delete this.db;
             }
         },
             Throws if this statement has been finalized. */
         clearBindings: function(){
             freeBindMemory(affirmStmtOpen(this));
-            S.sqlite3_clear_bindings(this.pStmt);
+            S.sqlite3_clear_bindings(this._pStmt);
+            this._mayGet = false;
             return this;
         },
         /**
         */
         reset: function(alsoClearBinds){
             if(alsoClearBinds) this.clearBindings();
-            S.sqlite3_reset(affirmStmtOpen(this).pStmt);
+            S.sqlite3_reset(affirmStmtOpen(this)._pStmt);
+            this._mayGet = false;
             return this;
         },
         /**
            - Strings are bound as strings (use bindAsBlob() to force
              blob binding).
 
-           - buffers (blobs) are currently TODO but will be bound as
-             blobs.
+           - Uint8Array instances are bound as blobs.
 
            If passed an array, each element of the array is bound at
            the parameter index equal to the array index plus 1
            - The statement has been finalized.
         */
         bind: function(/*[ndx,] value*/){
-            if(!this.parameterCount){
+            if(!affirmStmtOpen(this).parameterCount){
                 toss("This statement has no bindable parameters.");
             }
+            this._mayGet = false;
             let ndx, arg;
             switch(arguments.length){
                 case 1: ndx = 1; arg = arguments[0]; break;
                 case 2: ndx = arguments[0]; arg = arguments[1]; break;
                 default: toss("Invalid bind() arguments.");
             }
-            affirmStmtOpen(this);
             if(null===arg || undefined===arg){
                 /* bind NULL */
                 return bindOne(this, ndx, BindType.null, arg);
            using the BLOB binding mechanism instead of the default
            selected one for the value. The ndx may be a numbered
            or named bind index. The value must be of type string,
-           buffer, or null/undefined (both treated as null).
+           Uint8Array, or null/undefined (both treated as null).
 
-            If passed a single argument, a bind index of 1 is assumed.
+           If passed a single argument, a bind index of 1 is assumed.
         */
         bindAsBlob: function(ndx,arg){
-            affirmStmtOpen(this);
+            affirmStmtOpen(this)._mayGet = false;
             if(1===arguments.length){
                 ndx = 1;
                 arg = arguments[0];
                 toss("Invalid value type for bindAsBlob()");
             }
             return bindOne(this, ndx, BindType.blob, arg);
+        },
+        /**
+           Steps the statement one time. If the result indicates that
+           a row of data is available, true is returned.  If no row of
+           data is available, false is returned.  Throws on error.
+        */
+        step: function(){
+            const rc = S.sqlite3_step(affirmStmtOpen(this)._pStmt);
+            this._mayGet = false;
+            switch(rc){
+                case S.SQLITE_DONE: return false;
+                case S.SQLITE_ROW: return this._mayGet = true;
+                default: this.db.checkRc(rc);
+            };
+        },
+        /**
+           Fetches the value from the given 0-based column index of
+           the current data row, throwing if index is out of range. 
+
+           Requires that step() has just returned a truthy value, else
+           an exception is thrown.
+
+           By default it will determine the data type of the result
+           automatically. If passed a second arugment, it must be one
+           of the enumeration values for sqlite3 types, which are
+           defined as members of the sqlite3 module: SQLITE_INTEGER,
+           SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
+           except for undefined, will trigger an exception. Passing
+           undefined is the same as not passing a value. It is legal
+           to, e.g., fetch an integer value as a string, in which case
+           sqlite3 will convert the value to a string.
+
+           If ndx is an array, this function behaves a differently: it
+           assigns the indexes of the array, from 0 to the number of
+           result columns, to the values of the corresponding column,
+           and returns that array.
+
+           If ndx is a plain object, this function behaves even
+           differentlier: it assigns the properties of the object to
+           the values of their corresponding result columns.
+
+           Blobs are returned as Uint8Array instances.
+
+           Potential TODO: add type ID SQLITE_JSON, which fetches the
+           result as a string and passes it (if it's not null) to
+           JSON.parse(), returning the result of that. Until then,
+           getJSON() can be used for that.
+        */
+        get: function(ndx,asType){
+            affirmMayGet(this);
+            if(Array.isArray(ndx)){
+                let i = 0;
+                while(i<this.columnCount){
+                    ndx[i] = this.get(i++);
+                }
+                return ndx;
+            }else if(ndx && 'object'===typeof ndx){
+                let i = 0;
+                while(i<this.columnCount){
+                    ndx[S.sqlite3_column_name(this._pStmt,i)] = this.get(i++);
+                }
+                return ndx;
+            }
+            affirmColIndex(this, ndx);
+            switch(undefined===asType
+                   ? S.sqlite3_column_type(this._pStmt, ndx)
+                   : asType){
+                case S.SQLITE_INTEGER:
+                    return S.sqlite3_column_int64(this._pStmt, ndx);
+                case S.SQLITE_FLOAT:
+                    return S.sqlite3_column_double(this._pStmt, ndx);
+                case S.SQLITE_TEXT:
+                    return S.sqlite3_column_text(this._pStmt, ndx);
+                case S.SQLITE_BLOB: {
+                    const n = S.sqlite3_column_bytes(this._pStmt, ndx);
+                    const ptr = S.sqlite3_column_blob(this._pStmt, ndx);
+                    const rc = new Uint8Array(n);
+                    for(let i = 0; i < n; ++i) rc[i] = HEAP8[ptr + i];
+                    return rc;
+                }
+                default: toss("Don't know how to translate",
+                              "type of result column #"+ndx+".");
+            }
+            abort("Not reached.");
+        },
+        /** Equivalent to get(ndx) but coerces the result to an
+            integer. */
+        getInt: function(ndx){return this.get(ndx,S.SQLITE_INTEGER)},
+        /** Equivalent to get(ndx) but coerces the result to a
+            float. */
+        getFloat: function(ndx){return this.get(ndx,S.SQLITE_FLOAT)},
+        /** Equivalent to get(ndx) but coerces the result to a
+            string. */
+        getString: function(ndx){return this.get(ndx,S.SQLITE_TEXT)},
+        /** Equivalent to get(ndx) but coerces the result to a
+            Uint8Array. */
+        getBlob: function(ndx){return this.get(ndx,S.SQLITE_BLOB)},
+        /**
+           A convenience wrapper around get() which fetches the value
+           as a string and then, if it is not null, passes it to
+           JSON.parse(), returning that result. Throws if parsing
+           fails.
+        */
+        getJSON: function(ndx){
+            const s = this.get(ndx, S.SQLITE_STRING);
+            return null===s ? s : JSON.parse(s);
+        },
+        /**
+           Returns the result column name of the given index, or
+           throws if index is out of bounds or this statement has been
+           finalized.
+        */
+        getColumnName: function(ndx){
+            return S.sqlite3_column_name(affirmColIndex(this,ndx)._pStmt, ndx);
         }
     };
 
             if(!arguments.length){
                 if(!f._opt){
                     f._rx = /^([^=]+)=(.+)/;
-                    f._rxInt = /^-?\d+/;
+                    f._rxInt = /^-?\d+$/;
                     f._opt = function(opt, rv){
                         const m = f._rx.exec(opt);
                         rv[0] = (m ? m[1] : opt);
         }
     };
     
-    namespace.sqlite3 = sqlite3;
-    namespace.SQLite3 = SQLite3;
+    namespace.sqlite3 = {
+        api:sqlite3,
+        SQLite3
+    };
 })(self/*worker or window*/);
index 762ce58668fa4390155ea0a0f04073e632476007..79bb0ba9d90e200f863d83ecf5d4eb88f8db1c8f 100644 (file)
         return (arguments.length>1 ? arguments[0] : document)
             .querySelector(arguments[arguments.length-1]);
     };
-    
+
+    /* emscripten-related bits... */
     const statusElement = E('#module-status');
     const progressElement = E('#module-progress');
     const spinnerElement = E('#module-spinner');
     self.Module = {
-        /* ^^^ cannot declare that const because fiddle-module.js
-           (auto-generated) includes a decl for it and runs in this scope. */
+        /* ^^^ cannot declare that const because sqlite3.js
+           (auto-generated) includes a decl for it and runs in this
+           scope. */
         preRun: [],
         postRun: [],
         //onRuntimeInitialized: function(){},
             }
         }
     };
-
-    const _expr = function(expr){
-        return (expr instanceof Function) ? expr() : !!expr;
-    };
     
     /**
        Helpers for writing sqlite3-specific tests.
         /** Running total of the number of tests run via
             this API. */
         counter: 0,
+        /**
+           If expr is a function, it is called and its result
+           is returned, coerced to a bool, else expr, coerced to
+           a bool, is returned.
+        */
+        toBool: function(expr){
+            return (expr instanceof Function) ? !!expr() : !!expr;
+        },
         /** abort() if expr is false. If expr is a function, it
             is called and its result is evaluated.
         */
         assert: function(expr, msg){
             ++this.counter;
-            if(!_expr(expr)) abort(msg || "Assertion failed.");
+            if(!this.toBool(expr)) abort(msg || "Assertion failed.");
             return this;
         },
         /** Identical to assert() but throws instead of calling
             abort(). */
         affirm: function(expr, msg){
             ++this.counter;
-            if(!_expr(expr)) throw new Error(msg || "Affirmation failed.");
+            if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed.");
             return this;
         },
         /** Calls f() and squelches any exception it throws. If it
             returns truthy. */
         throwIf: function(expr, msg){
             ++this.counter;
-            if(_expr(expr)) throw new Error(msg || "throwIf() failed");
+            if(this.toBool(expr)) throw new Error(msg || "throwIf() failed");
             return this;
         },
         /** Throws if expr is falsy or expr is a function and expr()
             returns falsy. */
         throwUnless: function(expr, msg){
             ++this.counter;
-            if(!_expr(expr)) throw new Error(msg || "throwUnless() failed");
+            if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed");
             return this;
         }
     };
index 6e79be0257ade8dfaf03e81cd35662c8f84eacee..d667a480c53c30dcbc6b29d26995e0c27e96bb55 100644 (file)
 */
 
 const mainTest1 = function(namespace){
-    const S = namespace.sqlite3;
-    const oo = namespace.SQLite3;
+    const S = namespace.sqlite3.api;
+    const oo = namespace.sqlite3.SQLite3;
     const T = self.SqliteTester;
     console.log("Loaded module:",S.sqlite3_libversion(),
                 S.sqlite3_sourceid());
     const db = new oo.DB();
     const log = console.log.bind(console);
-    T.assert(db.pDb);
+    T.assert(db._pDb);
     log("DB:",db.filename);
     log("Build options:",oo.compileOptionUsed());
-
-    let st = db.prepare("select 1");
-    T.assert(st.pStmt);
+    let st = db.prepare("select 3 as a");
     log("statement =",st);
-    T.assert(st === db._statements[st.pStmt])
+    T.assert(st._pStmt)
+        .assert(!st._mayGet)
+        .assert('a' === st.getColumnName(0))
+        .assert(st === db._statements[st._pStmt])
         .assert(1===st.columnCount)
         .assert(0===st.parameterCount)
-        .mustThrow(()=>st.bind(1,null));
-
-    let pId = st.pStmt;
+        .mustThrow(()=>st.bind(1,null))
+        .assert(true===st.step())
+        .assert(3 === st.get(0))
+        .mustThrow(()=>st.get(1))
+        .mustThrow(()=>st.get(0,~S.SQLITE_INTEGER))
+        .assert(3 === st.get(0,S.SQLITE_INTEGER))
+        .assert(3 === st.getInt(0))
+        .assert('3' === st.get(0,S.SQLITE_TEXT))
+        .assert('3' === st.getString(0))
+        .assert(3.0 === st.get(0,S.SQLITE_FLOAT))
+        .assert(3.0 === st.getFloat(0))
+        .assert(st.get(0,S.SQLITE_BLOB) instanceof Uint8Array)
+        .assert(st.getBlob(0) instanceof Uint8Array)
+        .assert(3 === st.get([])[0])
+        .assert(3 === st.get({}).a)
+        .assert(3 === st.getJSON(0))
+        .assert(st._mayGet)
+        .assert(false===st.step())
+        .assert(!st._mayGet)
+    ;
+    let pId = st._pStmt;
     st.finalize();
-    T.assert(!st.pStmt)
+    T.assert(!st._pStmt)
         .assert(!db._statements[pId]);
     log("Test count:",T.counter);
 };
index 36dce9f18d7e2f2e55a1bd9aebbb84f7cae6ef5c..da28b2bacd3907799f29fde9451c16f67e8a3565 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C WASM:\sadded\sbindings\sfor\ssqlite3_compileoption_get/used(),\smoved\sOO\s#1\sinto\ssqlite3-api.js\ssince\sit\scan\sonly\sbe\sused\sfrom\sthe\ssame\sthread\sas\sthat\sAPI\sand\sseparating\sthem\scomplicates\sclient-side\suse.\sStarted\sadding\stest\sutilities\sand\stests\sfor\sthe\sOO1\sAPI.
-D 2022-05-22T16:25:43.076
+C Implemented\sStmt.get()\sand\sfriends\sfor\sWASM\sOO\s#1\swrapper.\sAdded\sbasic\stests\sfor\sprepare/step/get.\sRestructured\smodule\sinit\soutput\sto\sintroduce\sonly\s1\sglobal-scope\ssymbol\sinstead\sof\s2.
+D 2022-05-22T19:09:59.198
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -56,7 +56,7 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0
 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
 F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f
-F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 00553766051a038b1acd3992d04e50540d1284c3ea78bd11daa521383e57d653
+F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 bba07bb2b81ce667df7916d4c942f0bfe6de6c77f5fe769d479f01250f92ca01
 F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0
 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95
 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
@@ -64,10 +64,10 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4
 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c
 F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0
 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf
-F ext/fiddle/sqlite3-api.js ab7e7ded7b3079ee7de43e8290f1942e757d90ebb47ae4654cfe03c980cd0cad
-F ext/fiddle/testing-common.js 2b2826a1e7c8ca3e610dfa4255ff1077438b6570e08096cc139c226811e60dbb
+F ext/fiddle/sqlite3-api.js e205ccb758678bab7261f184e816d809a5031e1b4babd7738bed98de534787dd
+F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8
 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1
-F ext/fiddle/testing1.js 6a314a10efc954bcd854af89d53ab768f48a42d3dcb80773b297f4ba0ac0236d
+F ext/fiddle/testing1.js 8849eaee6d7b31a195b29f9532c16a87a03e1be780a48cbdec54760c39ebf66c
 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
 F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
 F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
@@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39
-R d3343607f5b0d8f2cee2f7485f266550
+P f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf
+R e0afacc1df156a218ff63194b2d94770
 U stephan
-Z 4ea03d4418e5522f96fc7a3cf30bf26a
+Z 8276de9ecbbfd692683c1010f2d924a3
 # Remove this line to create a well-formed Fossil manifest.
index 47aa878ffb6df9fa16cf2844ad902866691429d6..826df84f448f72f6ff5d081131555bf7fd961075 100644 (file)
@@ -1 +1 @@
-f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf
\ No newline at end of file
+601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec
\ No newline at end of file