Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Replace the sqlite3_memdb_ptr() interface with the more general sqlite3_serialize() interface. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | memdb |
Files: | files | file ages | folders |
SHA3-256: |
8cf2ed4eff6d2e0958656e23384b05ea |
User & Date: | drh 2018-01-03 16:49:52.676 |
Context
2018-01-03
| ||
19:03 | Replace sqlite3_memdb_config() with sqlite3_deserialize(). Remove the "db memdb" command from the TCL interface, replacing it with "db serialize" and "db deserialize". (check-in: 2f6e9df9f0 user: drh tags: memdb) | |
16:49 | Replace the sqlite3_memdb_ptr() interface with the more general sqlite3_serialize() interface. (check-in: 8cf2ed4eff user: drh tags: memdb) | |
13:20 | Simplify the "sqlite3" command in the TCL interface. The filename is now optional. There is a new --memdb option with an argument that is the blob to which the database content should be initialized. (check-in: 47398ae772 user: drh tags: memdb) | |
Changes
Changes to src/memdb.c.
︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 | void *zBuf, int iAmt, sqlite_int64 iOfst ){ MemFile *p = (MemFile *)pFile; if( iOfst+iAmt>p->sz ){ memset(zBuf, 0, iAmt); return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, p->aData+iOfst, iAmt); return SQLITE_OK; } /* | > | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | void *zBuf, int iAmt, sqlite_int64 iOfst ){ MemFile *p = (MemFile *)pFile; if( iOfst+iAmt>p->sz ){ memset(zBuf, 0, iAmt); if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, p->aData+iOfst, iAmt); return SQLITE_OK; } /* |
︙ | ︙ | |||
445 446 447 448 449 450 451 | MemFile *p = 0; int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); if( rc ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0; return p; } | < < < < < < < < < < < < < < | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | MemFile *p = 0; int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); if( rc ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0; return p; } /* ** Reconfigure a memdb database. */ int sqlite3_memdb_config( sqlite3 *db, const char *zSchema, void *aData, |
︙ | ︙ | |||
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | rc = SQLITE_OK; } if( rc!=SQLITE_OK && (mFlags & SQLITE_MEMDB_FREEONCLOSE)!=0 ){ sqlite3_free(aData); } return SQLITE_OK; } /* ** This routine is called when the extension is loaded. ** Register the new VFS. */ int sqlite3MemdbInit(void){ memdb_vfs.pAppData = sqlite3_vfs_find(0); memdb_vfs.szOsFile = sizeof(MemFile); return sqlite3_vfs_register(&memdb_vfs, 0); } #endif /* SQLITE_ENABLE_MEMDB */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | rc = SQLITE_OK; } if( rc!=SQLITE_OK && (mFlags & SQLITE_MEMDB_FREEONCLOSE)!=0 ){ sqlite3_free(aData); } return SQLITE_OK; } /* ** Return the serialization of a database */ unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which database within the connection */ sqlite3_int64 *piSize, /* Write size here, if not NULL */ unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */ ){ MemFile *p = memdbFromDbSchema(db, zSchema); int iDb = sqlite3FindDbName(db, zSchema); Btree *pBt; sqlite3_int64 sz; int szPage = 0; sqlite3_stmt *pStmt = 0; unsigned char *pOut; char *zSql; int rc; if( piSize ) *piSize = -1; if( iDb<0 ) return 0; if( p ){ if( piSize ) *piSize = p->sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = p->aData; }else{ pOut = sqlite3_malloc64( p->sz ); if( pOut ) memcpy(pOut, p->aData, p->sz); } return pOut; } pBt = db->aDb[iDb].pBt; if( pBt==0 ) return 0; szPage = sqlite3BtreeGetPageSize(pBt); zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM; sqlite3_free(zSql); if( rc ) return 0; sqlite3_step(pStmt); sz = sqlite3_column_int64(pStmt, 0)*szPage; if( piSize ) *piSize = sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = 0; }else{ pOut = sqlite3_malloc64( sz ); if( pOut ){ int nPage = sqlite3_column_int(pStmt, 0); Pager *pPager = sqlite3BtreePager(pBt); int pgno; for(pgno=1; pgno<=nPage; pgno++){ DbPage *pPage = 0; unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0); if( rc==SQLITE_OK ){ memcpy(pTo, sqlite3PagerGetData(pPage), szPage); }else{ memset(pTo, 0, szPage); } sqlite3PagerUnref(pPage); } } } sqlite3_finalize(pStmt); return pOut; } /* ** This routine is called when the extension is loaded. ** Register the new VFS. */ int sqlite3MemdbInit(void){ memdb_vfs.pAppData = sqlite3_vfs_find(0); memdb_vfs.szOsFile = sizeof(MemFile); return sqlite3_vfs_register(&memdb_vfs, 0); } #endif /* SQLITE_ENABLE_MEMDB */ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
8754 8755 8756 8757 8758 8759 8760 | ** transaction open on the database, or if the database is not a wal mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); | < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 | ** transaction open on the database, or if the database is not a wal mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Set the current MEMDB buffer ** EXPERIMENTAL ** ** This interface is only available when SQLite is compiled ** with SQLITE_ENABLE_MEMDB. ** ** The sqlite3_memdb_config(D,S,P,N,M,F) interface initializes a MEMDB database. ** The database identified by D and S must not be in active use when this ** interface is called, or [SQLITE_BUSY] is returned. */ int sqlite3_memdb_config(sqlite3*,const char*,void*,sqlite3_int64,sqlite3_int64,unsigned); /* ** CAPI3REF: Flags for configuring MEMDB databases ** EXPERIMENTAL ** ** The following are allowed values for the 6th argument (the "flags" ** argument) of the [sqlite3_memdb_config()] interface. */ #define SQLITE_MEMDB_FREEONCLOSE 0x001 /* Free the memory buffer on close */ #define SQLITE_MEMDB_RESIZEABLE 0x002 /* Resize using sqlite3_realloc64() */ /* ** CAPI3REF: Serialize a database ** EXPERIMENTAL ** ** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory ** that is a serialization of the S database on [database connection] D. ** If P is not a NULL pointer, then the size of the database in bytes ** is written into *P. ** ** For an ordinary on-disk database file, the serialization is just a ** copy of the disk file. For an in-memory database or a "TEMP" database, ** the serialization is the same sequence of bytes which would be written ** to disk if that database where backed up to disk. ** ** The usual case is that sqlite3_serialize() copies the serialization of ** the database into memory obtained from [sqlite3_malloc64()] and returns ** a pointer to that memory. The caller is responsible for freeing the ** returned value to avoid a memory leak. However, if the F argument ** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations ** are made, and the sqlite3_serialize() function will return a pointer ** to the contiguous memory representation of the database that SQLite ** is currently using for that database, or NULL if the no such contiguous ** memory representation of the database exists. A contigous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the ** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. */ unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ ); /* ** CAPI3REF: Flags for sqlite3_serialize ** EXPERIMENTAL */ #define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */ /* ** CAPI3REF: Set the current MEMDB buffer ** EXPERIMENTAL ** ** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the ** [database connection] D to disconnection from database S and then ** reopen S as an in-memory database based on the serialization contained ** in P. The serialized database P is N bytes in size. M is the size of ** the buffer P, which might be larger than N. If M is larger than N, and ** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is ** permitted to add content to the in-memory database as long as the total ** size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. */ int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ sqlite3_int64 szDb, /* Number bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ); /* ** CAPI3REF: Flags for sqlite3_deserialize() ** EXPERIMENTAL ** ** The following are allowed values for the 6th argument (the "flags" or "F" ** argument) of the [sqlite3_deserialize()] interface. */ #define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */ #define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ #define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
1842 1843 1844 1845 1846 1847 1848 | int objc, Tcl_Obj *const*objv ){ SqliteDb *pDb = (SqliteDb*)cd; int choice; int rc = TCL_OK; static const char *DB_strs[] = { | | | | | | | | | | > | | | | | | | | | | | | | | > | | | | 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 | int objc, Tcl_Obj *const*objv ){ SqliteDb *pDb = (SqliteDb*)cd; int choice; int rc = TCL_OK; static const char *DB_strs[] = { "authorizer", "backup", "busy", "cache", "changes", "close", "collate", "collation_needed", "commit_hook", "complete", "copy", "deserialize", "enable_load_extension", "errorcode", "eval", "exists", "function", "incrblob", "interrupt", "last_insert_rowid", "memdb", "nullvalue", "onecolumn", "preupdate", "profile", "progress", "rekey", "restore", "rollback_hook", "serialize", "status", "timeout", "total_changes", "trace", "trace_v2", "transaction", "unlock_notify", "update_hook", "version", "wal_hook", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BACKUP, DB_BUSY, DB_CACHE, DB_CHANGES, DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE, DB_EVAL, DB_EXISTS, DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_MEMDB, DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK }; /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } |
︙ | ︙ | |||
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 | sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); Tcl_AppendResult(interp,", failed while processing line: ",zLineNum, (char*)0); rc = TCL_ERROR; } break; } /* ** $db enable_load_extension BOOLEAN ** ** Turn the extension loading feature on or off. It if off by ** default. */ | > > > > > > > > > > | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 | sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); Tcl_AppendResult(interp,", failed while processing line: ",zLineNum, (char*)0); rc = TCL_ERROR; } break; } /* ** $db deserialize ?DATABASE? VALUE ** ** Reopen DATABASE (default "main") using the content in $VALUE */ case DB_DESERIALIZE: { rc = TCL_ERROR; /* TBD */ break; } /* ** $db enable_load_extension BOOLEAN ** ** Turn the extension loading feature on or off. It if off by ** default. */ |
︙ | ︙ | |||
2675 2676 2677 2678 2679 2680 2681 | case DB_MEMDB: { #ifndef SQLITE_ENABLE_MEMDB Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; #else const char *zSchema = Tcl_GetString(objv[2]); | < | < < < < < < < < | 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 | case DB_MEMDB: { #ifndef SQLITE_ENABLE_MEMDB Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; #else const char *zSchema = Tcl_GetString(objv[2]); unsigned char *pData; if( objc==4 ){ int len = 0, xrc; unsigned char *pBA = Tcl_GetByteArrayFromObj(objv[3], &len); pData = sqlite3_malloc64( len ); if( pData==0 ){ Tcl_AppendResult(interp, "out of memory", (char*)0); rc = TCL_ERROR; }else{ |
︙ | ︙ | |||
2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 | Tcl_AppendResult(interp, "restore failed: ", sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_close(pSrc); break; } /* ** $db status (step|sort|autoindex|vmstep) ** ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or ** SQLITE_STMTSTATUS_SORT for the most recent eval. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 | Tcl_AppendResult(interp, "restore failed: ", sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_close(pSrc); break; } /* ** $db serialize ?DATABASE? ** ** Return a serialization of a database. */ case DB_SERIALIZE: { #ifndef SQLITE_ENABLE_MEMDB Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; #else const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main"; sqlite3_int64 sz = 0; unsigned char *pData; if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE?"); rc = TCL_ERROR; }else{ int needFree; pData = sqlite3_serialize(pDb->db, zSchema, &sz, SQLITE_SERIALIZE_NOCOPY); if( pData ){ needFree = 0; }else{ pData = sqlite3_serialize(pDb->db, zSchema, &sz, 0); needFree = 1; } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz)); if( needFree ) sqlite3_free(pData); } #endif break; } /* ** $db status (step|sort|autoindex|vmstep) ** ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or ** SQLITE_STMTSTATUS_SORT for the most recent eval. */ |
︙ | ︙ |
Changes to test/memdb1.test.
︙ | ︙ | |||
23 24 25 26 27 28 29 | } # Create a MEMDB and populate it with some dummy data. # Then extract the database into the $::db1 variable. # Verify that the size of $::db1 is the same as the size of # the database. # | < < | > > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | } # Create a MEMDB and populate it with some dummy data. # Then extract the database into the $::db1 variable. # Verify that the size of $::db1 is the same as the size of # the database. # unset -nocomplain db1 unset -nocomplain sz1 unset -nocomplain pgsz do_test 100 { db eval { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); } set ::pgsz [db one {PRAGMA page_size}] set ::sz1 [expr {$::pgsz*[db one {PRAGMA page_count}]}] set ::db1 [db serialize] expr {[string length $::db1]==$::sz1} } 1 set fd [open db1.db wb] puts -nonewline $fd $db1 close $fd # Create a new MEMDB and initialize it to the content of $::db1 # Verify that the content is the same. # db close sqlite3 db -memdb $db1 do_execsql_test 110 { |
︙ | ︙ |
Changes to tool/mkopts.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/usr/bin/tclsh # # This script is used to generate the array of strings and the enum # that appear at the beginning of the C code implementation of a # a TCL command and that define the available subcommands for that # TCL command. set prefix {} while {![eof stdin]} { set line [gets stdin] if {$line==""} continue regsub -all "\[ \t\n,\]+" [string trim $line] { } line foreach token [split $line { }] { | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #!/usr/bin/tclsh # # This script is used to generate the array of strings and the enum # that appear at the beginning of the C code implementation of a # a TCL command and that define the available subcommands for that # TCL command. set prefix {} while {![eof stdin]} { set line [gets stdin] if {$line==""} continue regsub -all "\[ \t\n,\]+" [string trim $line] { } line foreach token [split $line { }] { if {![regexp {(([a-zA-Z]+)_)?([_a-zA-Z0-9]+)} $token all px p2 name]} continue lappend namelist [string tolower $name] if {$px!=""} {set prefix $p2} } } puts " static const char *${prefix}_strs\[\] = \173" set col 0 proc put_item x { global col if {$col==0} {puts -nonewline " "} if {$col<2} { puts -nonewline [format " %-25s" $x] incr col } else { puts $x set col 0 } } proc finalize {} { |
︙ | ︙ |