| | @@ -981,10 +981,11 @@ |
| 981 | 981 | |
| 982 | 982 | /* |
| 983 | 983 | ** We need several support functions from the SQLite core. |
| 984 | 984 | */ |
| 985 | 985 | |
| 986 | +/* #include "sqlite3.h" */ |
| 986 | 987 | |
| 987 | 988 | /* |
| 988 | 989 | ** We need several things from the ANSI and MSVCRT headers. |
| 989 | 990 | */ |
| 990 | 991 | |
| | @@ -1334,10 +1335,11 @@ |
| 1334 | 1335 | ** |
| 1335 | 1336 | ** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm |
| 1336 | 1337 | ** is used. If SIZE is included it must be one of the integers 224, 256, |
| 1337 | 1338 | ** 384, or 512, to determine SHA3 hash variant that is computed. |
| 1338 | 1339 | */ |
| 1340 | +/* #include "sqlite3ext.h" */ |
| 1339 | 1341 | SQLITE_EXTENSION_INIT1 |
| 1340 | 1342 | #include <assert.h> |
| 1341 | 1343 | #include <string.h> |
| 1342 | 1344 | #include <stdarg.h> |
| 1343 | 1345 | /* typedef sqlite3_uint64 u64; */ |
| | @@ -2097,10 +2099,11 @@ |
| 2097 | 2099 | ** If a non-NULL value is specified for the optional $dir parameter and |
| 2098 | 2100 | ** $path is a relative path, then $path is interpreted relative to $dir. |
| 2099 | 2101 | ** And the paths returned in the "name" column of the table are also |
| 2100 | 2102 | ** relative to directory $dir. |
| 2101 | 2103 | */ |
| 2104 | +/* #include "sqlite3ext.h" */ |
| 2102 | 2105 | SQLITE_EXTENSION_INIT1 |
| 2103 | 2106 | #include <stdio.h> |
| 2104 | 2107 | #include <string.h> |
| 2105 | 2108 | #include <assert.h> |
| 2106 | 2109 | |
| | @@ -2175,17 +2178,17 @@ |
| 2175 | 2178 | if( nIn>mxBlob ){ |
| 2176 | 2179 | sqlite3_result_error_code(ctx, SQLITE_TOOBIG); |
| 2177 | 2180 | fclose(in); |
| 2178 | 2181 | return; |
| 2179 | 2182 | } |
| 2180 | | - pBuf = sqlite3_malloc64( nIn ); |
| 2183 | + pBuf = sqlite3_malloc64( nIn ? nIn : 1 ); |
| 2181 | 2184 | if( pBuf==0 ){ |
| 2182 | 2185 | sqlite3_result_error_nomem(ctx); |
| 2183 | 2186 | fclose(in); |
| 2184 | 2187 | return; |
| 2185 | 2188 | } |
| 2186 | | - if( 1==fread(pBuf, nIn, 1, in) ){ |
| 2189 | + if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){ |
| 2187 | 2190 | sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free); |
| 2188 | 2191 | }else{ |
| 2189 | 2192 | sqlite3_result_error_code(ctx, SQLITE_IOERR); |
| 2190 | 2193 | sqlite3_free(pBuf); |
| 2191 | 2194 | } |
| | @@ -2316,19 +2319,19 @@ |
| 2316 | 2319 | |
| 2317 | 2320 | /* |
| 2318 | 2321 | ** Argument zFile is the name of a file that will be created and/or written |
| 2319 | 2322 | ** by SQL function writefile(). This function ensures that the directory |
| 2320 | 2323 | ** zFile will be written to exists, creating it if required. The permissions |
| 2321 | | -** for any path components created by this function are set to (mode&0777). |
| 2324 | +** for any path components created by this function are set in accordance |
| 2325 | +** with the current umask. |
| 2322 | 2326 | ** |
| 2323 | 2327 | ** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise, |
| 2324 | 2328 | ** SQLITE_OK is returned if the directory is successfully created, or |
| 2325 | 2329 | ** SQLITE_ERROR otherwise. |
| 2326 | 2330 | */ |
| 2327 | 2331 | static int makeDirectory( |
| 2328 | | - const char *zFile, |
| 2329 | | - mode_t mode |
| 2332 | + const char *zFile |
| 2330 | 2333 | ){ |
| 2331 | 2334 | char *zCopy = sqlite3_mprintf("%s", zFile); |
| 2332 | 2335 | int rc = SQLITE_OK; |
| 2333 | 2336 | |
| 2334 | 2337 | if( zCopy==0 ){ |
| | @@ -2345,11 +2348,11 @@ |
| 2345 | 2348 | if( i==nCopy ) break; |
| 2346 | 2349 | zCopy[i] = '\0'; |
| 2347 | 2350 | |
| 2348 | 2351 | rc2 = fileStat(zCopy, &sStat); |
| 2349 | 2352 | if( rc2!=0 ){ |
| 2350 | | - if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR; |
| 2353 | + if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR; |
| 2351 | 2354 | }else{ |
| 2352 | 2355 | if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR; |
| 2353 | 2356 | } |
| 2354 | 2357 | zCopy[i] = '/'; |
| 2355 | 2358 | i++; |
| | @@ -2503,11 +2506,11 @@ |
| 2503 | 2506 | mtime = sqlite3_value_int64(argv[3]); |
| 2504 | 2507 | } |
| 2505 | 2508 | |
| 2506 | 2509 | res = writeFile(context, zFile, argv[1], mode, mtime); |
| 2507 | 2510 | if( res==1 && errno==ENOENT ){ |
| 2508 | | - if( makeDirectory(zFile, mode)==SQLITE_OK ){ |
| 2511 | + if( makeDirectory(zFile)==SQLITE_OK ){ |
| 2509 | 2512 | res = writeFile(context, zFile, argv[1], mode, mtime); |
| 2510 | 2513 | } |
| 2511 | 2514 | } |
| 2512 | 2515 | |
| 2513 | 2516 | if( argc>2 && res!=0 ){ |
| | @@ -3054,10 +3057,11 @@ |
| 3054 | 3057 | ** This virtual table operates at the speed of human typing, and so there |
| 3055 | 3058 | ** is no attempt to make it fast. Even a slow implementation will be much |
| 3056 | 3059 | ** faster than any human can type. |
| 3057 | 3060 | ** |
| 3058 | 3061 | */ |
| 3062 | +/* #include "sqlite3ext.h" */ |
| 3059 | 3063 | SQLITE_EXTENSION_INIT1 |
| 3060 | 3064 | #include <assert.h> |
| 3061 | 3065 | #include <string.h> |
| 3062 | 3066 | #include <ctype.h> |
| 3063 | 3067 | |
| | @@ -3570,10 +3574,11 @@ |
| 3570 | 3574 | ** database in a separate file. |
| 3571 | 3575 | ** |
| 3572 | 3576 | ** If the file being opened is not an appended database, then this shim is |
| 3573 | 3577 | ** a pass-through into the default underlying VFS. |
| 3574 | 3578 | **/ |
| 3579 | +/* #include "sqlite3ext.h" */ |
| 3575 | 3580 | SQLITE_EXTENSION_INIT1 |
| 3576 | 3581 | #include <string.h> |
| 3577 | 3582 | #include <assert.h> |
| 3578 | 3583 | |
| 3579 | 3584 | /* The append mark at the end of the database is: |
| | @@ -4226,10 +4231,11 @@ |
| 4226 | 4231 | ** * No support for encryption |
| 4227 | 4232 | ** * No support for ZIP archives spanning multiple files |
| 4228 | 4233 | ** * No support for zip64 extensions |
| 4229 | 4234 | ** * Only the "inflate/deflate" (zlib) compression method is supported |
| 4230 | 4235 | */ |
| 4236 | +/* #include "sqlite3ext.h" */ |
| 4231 | 4237 | SQLITE_EXTENSION_INIT1 |
| 4232 | 4238 | #include <stdio.h> |
| 4233 | 4239 | #include <string.h> |
| 4234 | 4240 | #include <assert.h> |
| 4235 | 4241 | |
| | @@ -6396,10 +6402,11 @@ |
| 6396 | 6402 | ** |
| 6397 | 6403 | ** Utility functions sqlar_compress() and sqlar_uncompress(). Useful |
| 6398 | 6404 | ** for working with sqlar archives and used by the shell tool's built-in |
| 6399 | 6405 | ** sqlar support. |
| 6400 | 6406 | */ |
| 6407 | +/* #include "sqlite3ext.h" */ |
| 6401 | 6408 | SQLITE_EXTENSION_INIT1 |
| 6402 | 6409 | #include <zlib.h> |
| 6403 | 6410 | |
| 6404 | 6411 | /* |
| 6405 | 6412 | ** Implementation of the "sqlar_compress(X)" SQL function. |
| | @@ -6518,10 +6525,11 @@ |
| 6518 | 6525 | ** |
| 6519 | 6526 | ************************************************************************* |
| 6520 | 6527 | */ |
| 6521 | 6528 | |
| 6522 | 6529 | |
| 6530 | +/* #include "sqlite3.h" */ |
| 6523 | 6531 | |
| 6524 | 6532 | typedef struct sqlite3expert sqlite3expert; |
| 6525 | 6533 | |
| 6526 | 6534 | /* |
| 6527 | 6535 | ** Create a new sqlite3expert object. |
| | @@ -6686,10 +6694,11 @@ |
| 6686 | 6694 | ** May you find forgiveness for yourself and forgive others. |
| 6687 | 6695 | ** May you share freely, never taking more than you give. |
| 6688 | 6696 | ** |
| 6689 | 6697 | ************************************************************************* |
| 6690 | 6698 | */ |
| 6699 | +/* #include "sqlite3expert.h" */ |
| 6691 | 6700 | #include <assert.h> |
| 6692 | 6701 | #include <string.h> |
| 6693 | 6702 | #include <stdio.h> |
| 6694 | 6703 | |
| 6695 | 6704 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | @@ -8628,10 +8637,867 @@ |
| 8628 | 8637 | } |
| 8629 | 8638 | |
| 8630 | 8639 | #endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */ |
| 8631 | 8640 | |
| 8632 | 8641 | /************************* End ../ext/expert/sqlite3expert.c ********************/ |
| 8642 | + |
| 8643 | +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 8644 | +/************************* Begin ../ext/misc/dbdata.c ******************/ |
| 8645 | +/* |
| 8646 | +** 2019-04-17 |
| 8647 | +** |
| 8648 | +** The author disclaims copyright to this source code. In place of |
| 8649 | +** a legal notice, here is a blessing: |
| 8650 | +** |
| 8651 | +** May you do good and not evil. |
| 8652 | +** May you find forgiveness for yourself and forgive others. |
| 8653 | +** May you share freely, never taking more than you give. |
| 8654 | +** |
| 8655 | +****************************************************************************** |
| 8656 | +** |
| 8657 | +** This file contains an implementation of two eponymous virtual tables, |
| 8658 | +** "sqlite_dbdata" and "sqlite_dbptr". Both modules require that the |
| 8659 | +** "sqlite_dbpage" eponymous virtual table be available. |
| 8660 | +** |
| 8661 | +** SQLITE_DBDATA: |
| 8662 | +** sqlite_dbdata is used to extract data directly from a database b-tree |
| 8663 | +** page and its associated overflow pages, bypassing the b-tree layer. |
| 8664 | +** The table schema is equivalent to: |
| 8665 | +** |
| 8666 | +** CREATE TABLE sqlite_dbdata( |
| 8667 | +** pgno INTEGER, |
| 8668 | +** cell INTEGER, |
| 8669 | +** field INTEGER, |
| 8670 | +** value ANY, |
| 8671 | +** schema TEXT HIDDEN |
| 8672 | +** ); |
| 8673 | +** |
| 8674 | +** IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE |
| 8675 | +** FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND |
| 8676 | +** "schema". |
| 8677 | +** |
| 8678 | +** Each page of the database is inspected. If it cannot be interpreted as |
| 8679 | +** a b-tree page, or if it is a b-tree page containing 0 entries, the |
| 8680 | +** sqlite_dbdata table contains no rows for that page. Otherwise, the |
| 8681 | +** table contains one row for each field in the record associated with |
| 8682 | +** each cell on the page. For intkey b-trees, the key value is stored in |
| 8683 | +** field -1. |
| 8684 | +** |
| 8685 | +** For example, for the database: |
| 8686 | +** |
| 8687 | +** CREATE TABLE t1(a, b); -- root page is page 2 |
| 8688 | +** INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five'); |
| 8689 | +** INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten'); |
| 8690 | +** |
| 8691 | +** the sqlite_dbdata table contains, as well as from entries related to |
| 8692 | +** page 1, content equivalent to: |
| 8693 | +** |
| 8694 | +** INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES |
| 8695 | +** (2, 0, -1, 5 ), |
| 8696 | +** (2, 0, 0, 'v' ), |
| 8697 | +** (2, 0, 1, 'five'), |
| 8698 | +** (2, 1, -1, 10 ), |
| 8699 | +** (2, 1, 0, 'x' ), |
| 8700 | +** (2, 1, 1, 'ten' ); |
| 8701 | +** |
| 8702 | +** If database corruption is encountered, this module does not report an |
| 8703 | +** error. Instead, it attempts to extract as much data as possible and |
| 8704 | +** ignores the corruption. |
| 8705 | +** |
| 8706 | +** SQLITE_DBPTR: |
| 8707 | +** The sqlite_dbptr table has the following schema: |
| 8708 | +** |
| 8709 | +** CREATE TABLE sqlite_dbptr( |
| 8710 | +** pgno INTEGER, |
| 8711 | +** child INTEGER, |
| 8712 | +** schema TEXT HIDDEN |
| 8713 | +** ); |
| 8714 | +** |
| 8715 | +** It contains one entry for each b-tree pointer between a parent and |
| 8716 | +** child page in the database. |
| 8717 | +*/ |
| 8718 | +#if !defined(SQLITEINT_H) |
| 8719 | +/* #include "sqlite3ext.h" */ |
| 8720 | + |
| 8721 | +/* typedef unsigned char u8; */ |
| 8722 | + |
| 8723 | +#endif |
| 8724 | +SQLITE_EXTENSION_INIT1 |
| 8725 | +#include <string.h> |
| 8726 | +#include <assert.h> |
| 8727 | + |
| 8728 | +#define DBDATA_PADDING_BYTES 100 |
| 8729 | + |
| 8730 | +typedef struct DbdataTable DbdataTable; |
| 8731 | +typedef struct DbdataCursor DbdataCursor; |
| 8732 | + |
| 8733 | +/* Cursor object */ |
| 8734 | +struct DbdataCursor { |
| 8735 | + sqlite3_vtab_cursor base; /* Base class. Must be first */ |
| 8736 | + sqlite3_stmt *pStmt; /* For fetching database pages */ |
| 8737 | + |
| 8738 | + int iPgno; /* Current page number */ |
| 8739 | + u8 *aPage; /* Buffer containing page */ |
| 8740 | + int nPage; /* Size of aPage[] in bytes */ |
| 8741 | + int nCell; /* Number of cells on aPage[] */ |
| 8742 | + int iCell; /* Current cell number */ |
| 8743 | + int bOnePage; /* True to stop after one page */ |
| 8744 | + int szDb; |
| 8745 | + sqlite3_int64 iRowid; |
| 8746 | + |
| 8747 | + /* Only for the sqlite_dbdata table */ |
| 8748 | + u8 *pRec; /* Buffer containing current record */ |
| 8749 | + int nRec; /* Size of pRec[] in bytes */ |
| 8750 | + int nHdr; /* Size of header in bytes */ |
| 8751 | + int iField; /* Current field number */ |
| 8752 | + u8 *pHdrPtr; |
| 8753 | + u8 *pPtr; |
| 8754 | + |
| 8755 | + sqlite3_int64 iIntkey; /* Integer key value */ |
| 8756 | +}; |
| 8757 | + |
| 8758 | +/* Table object */ |
| 8759 | +struct DbdataTable { |
| 8760 | + sqlite3_vtab base; /* Base class. Must be first */ |
| 8761 | + sqlite3 *db; /* The database connection */ |
| 8762 | + sqlite3_stmt *pStmt; /* For fetching database pages */ |
| 8763 | + int bPtr; /* True for sqlite3_dbptr table */ |
| 8764 | +}; |
| 8765 | + |
| 8766 | +/* Column and schema definitions for sqlite_dbdata */ |
| 8767 | +#define DBDATA_COLUMN_PGNO 0 |
| 8768 | +#define DBDATA_COLUMN_CELL 1 |
| 8769 | +#define DBDATA_COLUMN_FIELD 2 |
| 8770 | +#define DBDATA_COLUMN_VALUE 3 |
| 8771 | +#define DBDATA_COLUMN_SCHEMA 4 |
| 8772 | +#define DBDATA_SCHEMA \ |
| 8773 | + "CREATE TABLE x(" \ |
| 8774 | + " pgno INTEGER," \ |
| 8775 | + " cell INTEGER," \ |
| 8776 | + " field INTEGER," \ |
| 8777 | + " value ANY," \ |
| 8778 | + " schema TEXT HIDDEN" \ |
| 8779 | + ")" |
| 8780 | + |
| 8781 | +/* Column and schema definitions for sqlite_dbptr */ |
| 8782 | +#define DBPTR_COLUMN_PGNO 0 |
| 8783 | +#define DBPTR_COLUMN_CHILD 1 |
| 8784 | +#define DBPTR_COLUMN_SCHEMA 2 |
| 8785 | +#define DBPTR_SCHEMA \ |
| 8786 | + "CREATE TABLE x(" \ |
| 8787 | + " pgno INTEGER," \ |
| 8788 | + " child INTEGER," \ |
| 8789 | + " schema TEXT HIDDEN" \ |
| 8790 | + ")" |
| 8791 | + |
| 8792 | +/* |
| 8793 | +** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual |
| 8794 | +** table. |
| 8795 | +*/ |
| 8796 | +static int dbdataConnect( |
| 8797 | + sqlite3 *db, |
| 8798 | + void *pAux, |
| 8799 | + int argc, const char *const*argv, |
| 8800 | + sqlite3_vtab **ppVtab, |
| 8801 | + char **pzErr |
| 8802 | +){ |
| 8803 | + DbdataTable *pTab = 0; |
| 8804 | + int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); |
| 8805 | + |
| 8806 | + if( rc==SQLITE_OK ){ |
| 8807 | + pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); |
| 8808 | + if( pTab==0 ){ |
| 8809 | + rc = SQLITE_NOMEM; |
| 8810 | + }else{ |
| 8811 | + memset(pTab, 0, sizeof(DbdataTable)); |
| 8812 | + pTab->db = db; |
| 8813 | + pTab->bPtr = (pAux!=0); |
| 8814 | + } |
| 8815 | + } |
| 8816 | + |
| 8817 | + *ppVtab = (sqlite3_vtab*)pTab; |
| 8818 | + return rc; |
| 8819 | +} |
| 8820 | + |
| 8821 | +/* |
| 8822 | +** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table. |
| 8823 | +*/ |
| 8824 | +static int dbdataDisconnect(sqlite3_vtab *pVtab){ |
| 8825 | + DbdataTable *pTab = (DbdataTable*)pVtab; |
| 8826 | + if( pTab ){ |
| 8827 | + sqlite3_finalize(pTab->pStmt); |
| 8828 | + sqlite3_free(pVtab); |
| 8829 | + } |
| 8830 | + return SQLITE_OK; |
| 8831 | +} |
| 8832 | + |
| 8833 | +/* |
| 8834 | +** This function interprets two types of constraints: |
| 8835 | +** |
| 8836 | +** schema=? |
| 8837 | +** pgno=? |
| 8838 | +** |
| 8839 | +** If neither are present, idxNum is set to 0. If schema=? is present, |
| 8840 | +** the 0x01 bit in idxNum is set. If pgno=? is present, the 0x02 bit |
| 8841 | +** in idxNum is set. |
| 8842 | +** |
| 8843 | +** If both parameters are present, schema is in position 0 and pgno in |
| 8844 | +** position 1. |
| 8845 | +*/ |
| 8846 | +static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){ |
| 8847 | + DbdataTable *pTab = (DbdataTable*)tab; |
| 8848 | + int i; |
| 8849 | + int iSchema = -1; |
| 8850 | + int iPgno = -1; |
| 8851 | + int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA); |
| 8852 | + |
| 8853 | + for(i=0; i<pIdx->nConstraint; i++){ |
| 8854 | + struct sqlite3_index_constraint *p = &pIdx->aConstraint[i]; |
| 8855 | + if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ |
| 8856 | + if( p->iColumn==colSchema ){ |
| 8857 | + if( p->usable==0 ) return SQLITE_CONSTRAINT; |
| 8858 | + iSchema = i; |
| 8859 | + } |
| 8860 | + if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){ |
| 8861 | + iPgno = i; |
| 8862 | + } |
| 8863 | + } |
| 8864 | + } |
| 8865 | + |
| 8866 | + if( iSchema>=0 ){ |
| 8867 | + pIdx->aConstraintUsage[iSchema].argvIndex = 1; |
| 8868 | + pIdx->aConstraintUsage[iSchema].omit = 1; |
| 8869 | + } |
| 8870 | + if( iPgno>=0 ){ |
| 8871 | + pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0); |
| 8872 | + pIdx->aConstraintUsage[iPgno].omit = 1; |
| 8873 | + pIdx->estimatedCost = 100; |
| 8874 | + pIdx->estimatedRows = 50; |
| 8875 | + |
| 8876 | + if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){ |
| 8877 | + int iCol = pIdx->aOrderBy[0].iColumn; |
| 8878 | + if( pIdx->nOrderBy==1 ){ |
| 8879 | + pIdx->orderByConsumed = (iCol==0 || iCol==1); |
| 8880 | + }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){ |
| 8881 | + pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1); |
| 8882 | + } |
| 8883 | + } |
| 8884 | + |
| 8885 | + }else{ |
| 8886 | + pIdx->estimatedCost = 100000000; |
| 8887 | + pIdx->estimatedRows = 1000000000; |
| 8888 | + } |
| 8889 | + pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00); |
| 8890 | + return SQLITE_OK; |
| 8891 | +} |
| 8892 | + |
| 8893 | +/* |
| 8894 | +** Open a new sqlite_dbdata or sqlite_dbptr cursor. |
| 8895 | +*/ |
| 8896 | +static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ |
| 8897 | + DbdataCursor *pCsr; |
| 8898 | + |
| 8899 | + pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor)); |
| 8900 | + if( pCsr==0 ){ |
| 8901 | + return SQLITE_NOMEM; |
| 8902 | + }else{ |
| 8903 | + memset(pCsr, 0, sizeof(DbdataCursor)); |
| 8904 | + pCsr->base.pVtab = pVTab; |
| 8905 | + } |
| 8906 | + |
| 8907 | + *ppCursor = (sqlite3_vtab_cursor *)pCsr; |
| 8908 | + return SQLITE_OK; |
| 8909 | +} |
| 8910 | + |
| 8911 | +/* |
| 8912 | +** Restore a cursor object to the state it was in when first allocated |
| 8913 | +** by dbdataOpen(). |
| 8914 | +*/ |
| 8915 | +static void dbdataResetCursor(DbdataCursor *pCsr){ |
| 8916 | + DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab); |
| 8917 | + if( pTab->pStmt==0 ){ |
| 8918 | + pTab->pStmt = pCsr->pStmt; |
| 8919 | + }else{ |
| 8920 | + sqlite3_finalize(pCsr->pStmt); |
| 8921 | + } |
| 8922 | + pCsr->pStmt = 0; |
| 8923 | + pCsr->iPgno = 1; |
| 8924 | + pCsr->iCell = 0; |
| 8925 | + pCsr->iField = 0; |
| 8926 | + pCsr->bOnePage = 0; |
| 8927 | + sqlite3_free(pCsr->aPage); |
| 8928 | + sqlite3_free(pCsr->pRec); |
| 8929 | + pCsr->pRec = 0; |
| 8930 | + pCsr->aPage = 0; |
| 8931 | +} |
| 8932 | + |
| 8933 | +/* |
| 8934 | +** Close an sqlite_dbdata or sqlite_dbptr cursor. |
| 8935 | +*/ |
| 8936 | +static int dbdataClose(sqlite3_vtab_cursor *pCursor){ |
| 8937 | + DbdataCursor *pCsr = (DbdataCursor*)pCursor; |
| 8938 | + dbdataResetCursor(pCsr); |
| 8939 | + sqlite3_free(pCsr); |
| 8940 | + return SQLITE_OK; |
| 8941 | +} |
| 8942 | + |
| 8943 | +/* |
| 8944 | +** Utility methods to decode 16 and 32-bit big-endian unsigned integers. |
| 8945 | +*/ |
| 8946 | +static unsigned int get_uint16(unsigned char *a){ |
| 8947 | + return (a[0]<<8)|a[1]; |
| 8948 | +} |
| 8949 | +static unsigned int get_uint32(unsigned char *a){ |
| 8950 | + return ((unsigned int)a[0]<<24) |
| 8951 | + | ((unsigned int)a[1]<<16) |
| 8952 | + | ((unsigned int)a[2]<<8) |
| 8953 | + | ((unsigned int)a[3]); |
| 8954 | +} |
| 8955 | + |
| 8956 | +/* |
| 8957 | +** Load page pgno from the database via the sqlite_dbpage virtual table. |
| 8958 | +** If successful, set (*ppPage) to point to a buffer containing the page |
| 8959 | +** data, (*pnPage) to the size of that buffer in bytes and return |
| 8960 | +** SQLITE_OK. In this case it is the responsibility of the caller to |
| 8961 | +** eventually free the buffer using sqlite3_free(). |
| 8962 | +** |
| 8963 | +** Or, if an error occurs, set both (*ppPage) and (*pnPage) to 0 and |
| 8964 | +** return an SQLite error code. |
| 8965 | +*/ |
| 8966 | +static int dbdataLoadPage( |
| 8967 | + DbdataCursor *pCsr, /* Cursor object */ |
| 8968 | + unsigned int pgno, /* Page number of page to load */ |
| 8969 | + u8 **ppPage, /* OUT: pointer to page buffer */ |
| 8970 | + int *pnPage /* OUT: Size of (*ppPage) in bytes */ |
| 8971 | +){ |
| 8972 | + int rc2; |
| 8973 | + int rc = SQLITE_OK; |
| 8974 | + sqlite3_stmt *pStmt = pCsr->pStmt; |
| 8975 | + |
| 8976 | + *ppPage = 0; |
| 8977 | + *pnPage = 0; |
| 8978 | + sqlite3_bind_int64(pStmt, 2, pgno); |
| 8979 | + if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 8980 | + int nCopy = sqlite3_column_bytes(pStmt, 0); |
| 8981 | + if( nCopy>0 ){ |
| 8982 | + u8 *pPage; |
| 8983 | + pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES); |
| 8984 | + if( pPage==0 ){ |
| 8985 | + rc = SQLITE_NOMEM; |
| 8986 | + }else{ |
| 8987 | + const u8 *pCopy = sqlite3_column_blob(pStmt, 0); |
| 8988 | + memcpy(pPage, pCopy, nCopy); |
| 8989 | + memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES); |
| 8990 | + } |
| 8991 | + *ppPage = pPage; |
| 8992 | + *pnPage = nCopy; |
| 8993 | + } |
| 8994 | + } |
| 8995 | + rc2 = sqlite3_reset(pStmt); |
| 8996 | + if( rc==SQLITE_OK ) rc = rc2; |
| 8997 | + |
| 8998 | + return rc; |
| 8999 | +} |
| 9000 | + |
| 9001 | +/* |
| 9002 | +** Read a varint. Put the value in *pVal and return the number of bytes. |
| 9003 | +*/ |
| 9004 | +static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){ |
| 9005 | + sqlite3_int64 v = 0; |
| 9006 | + int i; |
| 9007 | + for(i=0; i<8; i++){ |
| 9008 | + v = (v<<7) + (z[i]&0x7f); |
| 9009 | + if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } |
| 9010 | + } |
| 9011 | + v = (v<<8) + (z[i]&0xff); |
| 9012 | + *pVal = v; |
| 9013 | + return 9; |
| 9014 | +} |
| 9015 | + |
| 9016 | +/* |
| 9017 | +** Return the number of bytes of space used by an SQLite value of type |
| 9018 | +** eType. |
| 9019 | +*/ |
| 9020 | +static int dbdataValueBytes(int eType){ |
| 9021 | + switch( eType ){ |
| 9022 | + case 0: case 8: case 9: |
| 9023 | + case 10: case 11: |
| 9024 | + return 0; |
| 9025 | + case 1: |
| 9026 | + return 1; |
| 9027 | + case 2: |
| 9028 | + return 2; |
| 9029 | + case 3: |
| 9030 | + return 3; |
| 9031 | + case 4: |
| 9032 | + return 4; |
| 9033 | + case 5: |
| 9034 | + return 6; |
| 9035 | + case 6: |
| 9036 | + case 7: |
| 9037 | + return 8; |
| 9038 | + default: |
| 9039 | + if( eType>0 ){ |
| 9040 | + return ((eType-12) / 2); |
| 9041 | + } |
| 9042 | + return 0; |
| 9043 | + } |
| 9044 | +} |
| 9045 | + |
| 9046 | +/* |
| 9047 | +** Load a value of type eType from buffer pData and use it to set the |
| 9048 | +** result of context object pCtx. |
| 9049 | +*/ |
| 9050 | +static void dbdataValue( |
| 9051 | + sqlite3_context *pCtx, |
| 9052 | + int eType, |
| 9053 | + u8 *pData, |
| 9054 | + int nData |
| 9055 | +){ |
| 9056 | + if( eType>=0 && dbdataValueBytes(eType)<=nData ){ |
| 9057 | + switch( eType ){ |
| 9058 | + case 0: |
| 9059 | + case 10: |
| 9060 | + case 11: |
| 9061 | + sqlite3_result_null(pCtx); |
| 9062 | + break; |
| 9063 | + |
| 9064 | + case 8: |
| 9065 | + sqlite3_result_int(pCtx, 0); |
| 9066 | + break; |
| 9067 | + case 9: |
| 9068 | + sqlite3_result_int(pCtx, 1); |
| 9069 | + break; |
| 9070 | + |
| 9071 | + case 1: case 2: case 3: case 4: case 5: case 6: case 7: { |
| 9072 | + sqlite3_uint64 v = (signed char)pData[0]; |
| 9073 | + pData++; |
| 9074 | + switch( eType ){ |
| 9075 | + case 7: |
| 9076 | + case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; |
| 9077 | + case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; |
| 9078 | + case 4: v = (v<<8) + pData[0]; pData++; |
| 9079 | + case 3: v = (v<<8) + pData[0]; pData++; |
| 9080 | + case 2: v = (v<<8) + pData[0]; pData++; |
| 9081 | + } |
| 9082 | + |
| 9083 | + if( eType==7 ){ |
| 9084 | + double r; |
| 9085 | + memcpy(&r, &v, sizeof(r)); |
| 9086 | + sqlite3_result_double(pCtx, r); |
| 9087 | + }else{ |
| 9088 | + sqlite3_result_int64(pCtx, (sqlite3_int64)v); |
| 9089 | + } |
| 9090 | + break; |
| 9091 | + } |
| 9092 | + |
| 9093 | + default: { |
| 9094 | + int n = ((eType-12) / 2); |
| 9095 | + if( eType % 2 ){ |
| 9096 | + sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT); |
| 9097 | + }else{ |
| 9098 | + sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT); |
| 9099 | + } |
| 9100 | + } |
| 9101 | + } |
| 9102 | + } |
| 9103 | +} |
| 9104 | + |
| 9105 | +/* |
| 9106 | +** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry. |
| 9107 | +*/ |
| 9108 | +static int dbdataNext(sqlite3_vtab_cursor *pCursor){ |
| 9109 | + DbdataCursor *pCsr = (DbdataCursor*)pCursor; |
| 9110 | + DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; |
| 9111 | + |
| 9112 | + pCsr->iRowid++; |
| 9113 | + while( 1 ){ |
| 9114 | + int rc; |
| 9115 | + int iOff = (pCsr->iPgno==1 ? 100 : 0); |
| 9116 | + int bNextPage = 0; |
| 9117 | + |
| 9118 | + if( pCsr->aPage==0 ){ |
| 9119 | + while( 1 ){ |
| 9120 | + if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; |
| 9121 | + rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); |
| 9122 | + if( rc!=SQLITE_OK ) return rc; |
| 9123 | + if( pCsr->aPage ) break; |
| 9124 | + pCsr->iPgno++; |
| 9125 | + } |
| 9126 | + pCsr->iCell = pTab->bPtr ? -2 : 0; |
| 9127 | + pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); |
| 9128 | + } |
| 9129 | + |
| 9130 | + if( pTab->bPtr ){ |
| 9131 | + if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){ |
| 9132 | + pCsr->iCell = pCsr->nCell; |
| 9133 | + } |
| 9134 | + pCsr->iCell++; |
| 9135 | + if( pCsr->iCell>=pCsr->nCell ){ |
| 9136 | + sqlite3_free(pCsr->aPage); |
| 9137 | + pCsr->aPage = 0; |
| 9138 | + if( pCsr->bOnePage ) return SQLITE_OK; |
| 9139 | + pCsr->iPgno++; |
| 9140 | + }else{ |
| 9141 | + return SQLITE_OK; |
| 9142 | + } |
| 9143 | + }else{ |
| 9144 | + /* If there is no record loaded, load it now. */ |
| 9145 | + if( pCsr->pRec==0 ){ |
| 9146 | + int bHasRowid = 0; |
| 9147 | + int nPointer = 0; |
| 9148 | + sqlite3_int64 nPayload = 0; |
| 9149 | + sqlite3_int64 nHdr = 0; |
| 9150 | + int iHdr; |
| 9151 | + int U, X; |
| 9152 | + int nLocal; |
| 9153 | + |
| 9154 | + switch( pCsr->aPage[iOff] ){ |
| 9155 | + case 0x02: |
| 9156 | + nPointer = 4; |
| 9157 | + break; |
| 9158 | + case 0x0a: |
| 9159 | + break; |
| 9160 | + case 0x0d: |
| 9161 | + bHasRowid = 1; |
| 9162 | + break; |
| 9163 | + default: |
| 9164 | + /* This is not a b-tree page with records on it. Continue. */ |
| 9165 | + pCsr->iCell = pCsr->nCell; |
| 9166 | + break; |
| 9167 | + } |
| 9168 | + |
| 9169 | + if( pCsr->iCell>=pCsr->nCell ){ |
| 9170 | + bNextPage = 1; |
| 9171 | + }else{ |
| 9172 | + |
| 9173 | + iOff += 8 + nPointer + pCsr->iCell*2; |
| 9174 | + if( iOff>pCsr->nPage ){ |
| 9175 | + bNextPage = 1; |
| 9176 | + }else{ |
| 9177 | + iOff = get_uint16(&pCsr->aPage[iOff]); |
| 9178 | + } |
| 9179 | + |
| 9180 | + /* For an interior node cell, skip past the child-page number */ |
| 9181 | + iOff += nPointer; |
| 9182 | + |
| 9183 | + /* Load the "byte of payload including overflow" field */ |
| 9184 | + if( bNextPage || iOff>pCsr->nPage ){ |
| 9185 | + bNextPage = 1; |
| 9186 | + }else{ |
| 9187 | + iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload); |
| 9188 | + } |
| 9189 | + |
| 9190 | + /* If this is a leaf intkey cell, load the rowid */ |
| 9191 | + if( bHasRowid && !bNextPage && iOff<pCsr->nPage ){ |
| 9192 | + iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey); |
| 9193 | + } |
| 9194 | + |
| 9195 | + /* Figure out how much data to read from the local page */ |
| 9196 | + U = pCsr->nPage; |
| 9197 | + if( bHasRowid ){ |
| 9198 | + X = U-35; |
| 9199 | + }else{ |
| 9200 | + X = ((U-12)*64/255)-23; |
| 9201 | + } |
| 9202 | + if( nPayload<=X ){ |
| 9203 | + nLocal = nPayload; |
| 9204 | + }else{ |
| 9205 | + int M, K; |
| 9206 | + M = ((U-12)*32/255)-23; |
| 9207 | + K = M+((nPayload-M)%(U-4)); |
| 9208 | + if( K<=X ){ |
| 9209 | + nLocal = K; |
| 9210 | + }else{ |
| 9211 | + nLocal = M; |
| 9212 | + } |
| 9213 | + } |
| 9214 | + |
| 9215 | + if( bNextPage || nLocal+iOff>pCsr->nPage ){ |
| 9216 | + bNextPage = 1; |
| 9217 | + }else{ |
| 9218 | + |
| 9219 | + /* Allocate space for payload. And a bit more to catch small buffer |
| 9220 | + ** overruns caused by attempting to read a varint or similar from |
| 9221 | + ** near the end of a corrupt record. */ |
| 9222 | + pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES); |
| 9223 | + if( pCsr->pRec==0 ) return SQLITE_NOMEM; |
| 9224 | + memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES); |
| 9225 | + pCsr->nRec = nPayload; |
| 9226 | + |
| 9227 | + /* Load the nLocal bytes of payload */ |
| 9228 | + memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal); |
| 9229 | + iOff += nLocal; |
| 9230 | + |
| 9231 | + /* Load content from overflow pages */ |
| 9232 | + if( nPayload>nLocal ){ |
| 9233 | + sqlite3_int64 nRem = nPayload - nLocal; |
| 9234 | + unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]); |
| 9235 | + while( nRem>0 ){ |
| 9236 | + u8 *aOvfl = 0; |
| 9237 | + int nOvfl = 0; |
| 9238 | + int nCopy; |
| 9239 | + rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl); |
| 9240 | + assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage ); |
| 9241 | + if( rc!=SQLITE_OK ) return rc; |
| 9242 | + if( aOvfl==0 ) break; |
| 9243 | + |
| 9244 | + nCopy = U-4; |
| 9245 | + if( nCopy>nRem ) nCopy = nRem; |
| 9246 | + memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy); |
| 9247 | + nRem -= nCopy; |
| 9248 | + |
| 9249 | + pgnoOvfl = get_uint32(aOvfl); |
| 9250 | + sqlite3_free(aOvfl); |
| 9251 | + } |
| 9252 | + } |
| 9253 | + |
| 9254 | + iHdr = dbdataGetVarint(pCsr->pRec, &nHdr); |
| 9255 | + pCsr->nHdr = nHdr; |
| 9256 | + pCsr->pHdrPtr = &pCsr->pRec[iHdr]; |
| 9257 | + pCsr->pPtr = &pCsr->pRec[pCsr->nHdr]; |
| 9258 | + pCsr->iField = (bHasRowid ? -1 : 0); |
| 9259 | + } |
| 9260 | + } |
| 9261 | + }else{ |
| 9262 | + pCsr->iField++; |
| 9263 | + if( pCsr->iField>0 ){ |
| 9264 | + sqlite3_int64 iType; |
| 9265 | + if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){ |
| 9266 | + bNextPage = 1; |
| 9267 | + }else{ |
| 9268 | + pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType); |
| 9269 | + pCsr->pPtr += dbdataValueBytes(iType); |
| 9270 | + } |
| 9271 | + } |
| 9272 | + } |
| 9273 | + |
| 9274 | + if( bNextPage ){ |
| 9275 | + sqlite3_free(pCsr->aPage); |
| 9276 | + sqlite3_free(pCsr->pRec); |
| 9277 | + pCsr->aPage = 0; |
| 9278 | + pCsr->pRec = 0; |
| 9279 | + if( pCsr->bOnePage ) return SQLITE_OK; |
| 9280 | + pCsr->iPgno++; |
| 9281 | + }else{ |
| 9282 | + if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){ |
| 9283 | + return SQLITE_OK; |
| 9284 | + } |
| 9285 | + |
| 9286 | + /* Advance to the next cell. The next iteration of the loop will load |
| 9287 | + ** the record and so on. */ |
| 9288 | + sqlite3_free(pCsr->pRec); |
| 9289 | + pCsr->pRec = 0; |
| 9290 | + pCsr->iCell++; |
| 9291 | + } |
| 9292 | + } |
| 9293 | + } |
| 9294 | + |
| 9295 | + assert( !"can't get here" ); |
| 9296 | + return SQLITE_OK; |
| 9297 | +} |
| 9298 | + |
| 9299 | +/* |
| 9300 | +** Return true if the cursor is at EOF. |
| 9301 | +*/ |
| 9302 | +static int dbdataEof(sqlite3_vtab_cursor *pCursor){ |
| 9303 | + DbdataCursor *pCsr = (DbdataCursor*)pCursor; |
| 9304 | + return pCsr->aPage==0; |
| 9305 | +} |
| 9306 | + |
| 9307 | +/* |
| 9308 | +** Determine the size in pages of database zSchema (where zSchema is |
| 9309 | +** "main", "temp" or the name of an attached database) and set |
| 9310 | +** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise, |
| 9311 | +** an SQLite error code. |
| 9312 | +*/ |
| 9313 | +static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){ |
| 9314 | + DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab; |
| 9315 | + char *zSql = 0; |
| 9316 | + int rc, rc2; |
| 9317 | + sqlite3_stmt *pStmt = 0; |
| 9318 | + |
| 9319 | + zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema); |
| 9320 | + if( zSql==0 ) return SQLITE_NOMEM; |
| 9321 | + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); |
| 9322 | + sqlite3_free(zSql); |
| 9323 | + if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 9324 | + pCsr->szDb = sqlite3_column_int(pStmt, 0); |
| 9325 | + } |
| 9326 | + rc2 = sqlite3_finalize(pStmt); |
| 9327 | + if( rc==SQLITE_OK ) rc = rc2; |
| 9328 | + return rc; |
| 9329 | +} |
| 9330 | + |
| 9331 | +/* |
| 9332 | +** xFilter method for sqlite_dbdata and sqlite_dbptr. |
| 9333 | +*/ |
| 9334 | +static int dbdataFilter( |
| 9335 | + sqlite3_vtab_cursor *pCursor, |
| 9336 | + int idxNum, const char *idxStr, |
| 9337 | + int argc, sqlite3_value **argv |
| 9338 | +){ |
| 9339 | + DbdataCursor *pCsr = (DbdataCursor*)pCursor; |
| 9340 | + DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; |
| 9341 | + int rc = SQLITE_OK; |
| 9342 | + const char *zSchema = "main"; |
| 9343 | + |
| 9344 | + dbdataResetCursor(pCsr); |
| 9345 | + assert( pCsr->iPgno==1 ); |
| 9346 | + if( idxNum & 0x01 ){ |
| 9347 | + zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 9348 | + } |
| 9349 | + if( idxNum & 0x02 ){ |
| 9350 | + pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); |
| 9351 | + pCsr->bOnePage = 1; |
| 9352 | + }else{ |
| 9353 | + pCsr->nPage = dbdataDbsize(pCsr, zSchema); |
| 9354 | + rc = dbdataDbsize(pCsr, zSchema); |
| 9355 | + } |
| 9356 | + |
| 9357 | + if( rc==SQLITE_OK ){ |
| 9358 | + if( pTab->pStmt ){ |
| 9359 | + pCsr->pStmt = pTab->pStmt; |
| 9360 | + pTab->pStmt = 0; |
| 9361 | + }else{ |
| 9362 | + rc = sqlite3_prepare_v2(pTab->db, |
| 9363 | + "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, |
| 9364 | + &pCsr->pStmt, 0 |
| 9365 | + ); |
| 9366 | + } |
| 9367 | + } |
| 9368 | + if( rc==SQLITE_OK ){ |
| 9369 | + rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); |
| 9370 | + }else{ |
| 9371 | + pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); |
| 9372 | + } |
| 9373 | + if( rc==SQLITE_OK ){ |
| 9374 | + rc = dbdataNext(pCursor); |
| 9375 | + } |
| 9376 | + return rc; |
| 9377 | +} |
| 9378 | + |
| 9379 | +/* |
| 9380 | +** Return a column for the sqlite_dbdata or sqlite_dbptr table. |
| 9381 | +*/ |
| 9382 | +static int dbdataColumn( |
| 9383 | + sqlite3_vtab_cursor *pCursor, |
| 9384 | + sqlite3_context *ctx, |
| 9385 | + int i |
| 9386 | +){ |
| 9387 | + DbdataCursor *pCsr = (DbdataCursor*)pCursor; |
| 9388 | + DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; |
| 9389 | + if( pTab->bPtr ){ |
| 9390 | + switch( i ){ |
| 9391 | + case DBPTR_COLUMN_PGNO: |
| 9392 | + sqlite3_result_int64(ctx, pCsr->iPgno); |
| 9393 | + break; |
| 9394 | + case DBPTR_COLUMN_CHILD: { |
| 9395 | + int iOff = pCsr->iPgno==1 ? 100 : 0; |
| 9396 | + if( pCsr->iCell<0 ){ |
| 9397 | + iOff += 8; |
| 9398 | + }else{ |
| 9399 | + iOff += 12 + pCsr->iCell*2; |
| 9400 | + if( iOff>pCsr->nPage ) return SQLITE_OK; |
| 9401 | + iOff = get_uint16(&pCsr->aPage[iOff]); |
| 9402 | + } |
| 9403 | + if( iOff<=pCsr->nPage ){ |
| 9404 | + sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff])); |
| 9405 | + } |
| 9406 | + break; |
| 9407 | + } |
| 9408 | + } |
| 9409 | + }else{ |
| 9410 | + switch( i ){ |
| 9411 | + case DBDATA_COLUMN_PGNO: |
| 9412 | + sqlite3_result_int64(ctx, pCsr->iPgno); |
| 9413 | + break; |
| 9414 | + case DBDATA_COLUMN_CELL: |
| 9415 | + sqlite3_result_int(ctx, pCsr->iCell); |
| 9416 | + break; |
| 9417 | + case DBDATA_COLUMN_FIELD: |
| 9418 | + sqlite3_result_int(ctx, pCsr->iField); |
| 9419 | + break; |
| 9420 | + case DBDATA_COLUMN_VALUE: { |
| 9421 | + if( pCsr->iField<0 ){ |
| 9422 | + sqlite3_result_int64(ctx, pCsr->iIntkey); |
| 9423 | + }else{ |
| 9424 | + sqlite3_int64 iType; |
| 9425 | + dbdataGetVarint(pCsr->pHdrPtr, &iType); |
| 9426 | + dbdataValue( |
| 9427 | + ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr |
| 9428 | + ); |
| 9429 | + } |
| 9430 | + break; |
| 9431 | + } |
| 9432 | + } |
| 9433 | + } |
| 9434 | + return SQLITE_OK; |
| 9435 | +} |
| 9436 | + |
| 9437 | +/* |
| 9438 | +** Return the rowid for an sqlite_dbdata or sqlite_dptr table. |
| 9439 | +*/ |
| 9440 | +static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ |
| 9441 | + DbdataCursor *pCsr = (DbdataCursor*)pCursor; |
| 9442 | + *pRowid = pCsr->iRowid; |
| 9443 | + return SQLITE_OK; |
| 9444 | +} |
| 9445 | + |
| 9446 | + |
| 9447 | +/* |
| 9448 | +** Invoke this routine to register the "sqlite_dbdata" virtual table module |
| 9449 | +*/ |
| 9450 | +static int sqlite3DbdataRegister(sqlite3 *db){ |
| 9451 | + static sqlite3_module dbdata_module = { |
| 9452 | + 0, /* iVersion */ |
| 9453 | + 0, /* xCreate */ |
| 9454 | + dbdataConnect, /* xConnect */ |
| 9455 | + dbdataBestIndex, /* xBestIndex */ |
| 9456 | + dbdataDisconnect, /* xDisconnect */ |
| 9457 | + 0, /* xDestroy */ |
| 9458 | + dbdataOpen, /* xOpen - open a cursor */ |
| 9459 | + dbdataClose, /* xClose - close a cursor */ |
| 9460 | + dbdataFilter, /* xFilter - configure scan constraints */ |
| 9461 | + dbdataNext, /* xNext - advance a cursor */ |
| 9462 | + dbdataEof, /* xEof - check for end of scan */ |
| 9463 | + dbdataColumn, /* xColumn - read data */ |
| 9464 | + dbdataRowid, /* xRowid - read data */ |
| 9465 | + 0, /* xUpdate */ |
| 9466 | + 0, /* xBegin */ |
| 9467 | + 0, /* xSync */ |
| 9468 | + 0, /* xCommit */ |
| 9469 | + 0, /* xRollback */ |
| 9470 | + 0, /* xFindMethod */ |
| 9471 | + 0, /* xRename */ |
| 9472 | + 0, /* xSavepoint */ |
| 9473 | + 0, /* xRelease */ |
| 9474 | + 0, /* xRollbackTo */ |
| 9475 | + 0 /* xShadowName */ |
| 9476 | + }; |
| 9477 | + |
| 9478 | + int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0); |
| 9479 | + if( rc==SQLITE_OK ){ |
| 9480 | + rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); |
| 9481 | + } |
| 9482 | + return rc; |
| 9483 | +} |
| 9484 | + |
| 9485 | +#ifdef _WIN32 |
| 9486 | + |
| 9487 | +#endif |
| 9488 | +int sqlite3_dbdata_init( |
| 9489 | + sqlite3 *db, |
| 9490 | + char **pzErrMsg, |
| 9491 | + const sqlite3_api_routines *pApi |
| 9492 | +){ |
| 9493 | + SQLITE_EXTENSION_INIT2(pApi); |
| 9494 | + return sqlite3DbdataRegister(db); |
| 9495 | +} |
| 9496 | + |
| 9497 | +/************************* End ../ext/misc/dbdata.c ********************/ |
| 9498 | +#endif |
| 8633 | 9499 | |
| 8634 | 9500 | #if defined(SQLITE_ENABLE_SESSION) |
| 8635 | 9501 | /* |
| 8636 | 9502 | ** State information for a single open session |
| 8637 | 9503 | */ |
| | @@ -9358,10 +10224,12 @@ |
| 9358 | 10224 | ** |
| 9359 | 10225 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 9360 | 10226 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 9361 | 10227 | */ |
| 9362 | 10228 | static void printSchemaLine(FILE *out, const char *z, const char *zTail){ |
| 10229 | + if( z==0 ) return; |
| 10230 | + if( zTail==0 ) return; |
| 9363 | 10231 | if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){ |
| 9364 | 10232 | utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); |
| 9365 | 10233 | }else{ |
| 9366 | 10234 | utf8_printf(out, "%s%s", z, zTail); |
| 9367 | 10235 | } |
| | @@ -10427,10 +11295,70 @@ |
| 10427 | 11295 | #endif |
| 10428 | 11296 | #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) |
| 10429 | 11297 | sqlite3WhereTrace = savedWhereTrace; |
| 10430 | 11298 | #endif |
| 10431 | 11299 | } |
| 11300 | + |
| 11301 | +/* Create the TEMP table used to store parameter bindings */ |
| 11302 | +static void bind_table_init(ShellState *p){ |
| 11303 | + int wrSchema = 0; |
| 11304 | + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); |
| 11305 | + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); |
| 11306 | + sqlite3_exec(p->db, |
| 11307 | + "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n" |
| 11308 | + " key TEXT PRIMARY KEY,\n" |
| 11309 | + " value ANY\n" |
| 11310 | + ") WITHOUT ROWID;", |
| 11311 | + 0, 0, 0); |
| 11312 | + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); |
| 11313 | +} |
| 11314 | + |
| 11315 | +/* |
| 11316 | +** Bind parameters on a prepared statement. |
| 11317 | +** |
| 11318 | +** Parameter bindings are taken from a TEMP table of the form: |
| 11319 | +** |
| 11320 | +** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value) |
| 11321 | +** WITHOUT ROWID; |
| 11322 | +** |
| 11323 | +** No bindings occur if this table does not exist. The special character '$' |
| 11324 | +** is included in the table name to help prevent collisions with actual tables. |
| 11325 | +** The table must be in the TEMP schema. |
| 11326 | +*/ |
| 11327 | +static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){ |
| 11328 | + int nVar; |
| 11329 | + int i; |
| 11330 | + int rc; |
| 11331 | + sqlite3_stmt *pQ = 0; |
| 11332 | + |
| 11333 | + nVar = sqlite3_bind_parameter_count(pStmt); |
| 11334 | + if( nVar==0 ) return; /* Nothing to do */ |
| 11335 | + if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters", |
| 11336 | + "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){ |
| 11337 | + return; /* Parameter table does not exist */ |
| 11338 | + } |
| 11339 | + rc = sqlite3_prepare_v2(pArg->db, |
| 11340 | + "SELECT value FROM temp.sqlite_parameters" |
| 11341 | + " WHERE key=?1", -1, &pQ, 0); |
| 11342 | + if( rc || pQ==0 ) return; |
| 11343 | + for(i=1; i<=nVar; i++){ |
| 11344 | + char zNum[30]; |
| 11345 | + const char *zVar = sqlite3_bind_parameter_name(pStmt, i); |
| 11346 | + if( zVar==0 ){ |
| 11347 | + sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i); |
| 11348 | + zVar = zNum; |
| 11349 | + } |
| 11350 | + sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC); |
| 11351 | + if( sqlite3_step(pQ)==SQLITE_ROW ){ |
| 11352 | + sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0)); |
| 11353 | + }else{ |
| 11354 | + sqlite3_bind_null(pStmt, i); |
| 11355 | + } |
| 11356 | + sqlite3_reset(pQ); |
| 11357 | + } |
| 11358 | + sqlite3_finalize(pQ); |
| 11359 | +} |
| 10432 | 11360 | |
| 10433 | 11361 | /* |
| 10434 | 11362 | ** Run a prepared statement |
| 10435 | 11363 | */ |
| 10436 | 11364 | static void exec_prepared_stmt( |
| | @@ -10680,11 +11608,11 @@ |
| 10680 | 11608 | if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){ |
| 10681 | 11609 | utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); |
| 10682 | 11610 | } |
| 10683 | 11611 | |
| 10684 | 11612 | /* Show the EXPLAIN QUERY PLAN if .eqp is on */ |
| 10685 | | - if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){ |
| 11613 | + if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){ |
| 10686 | 11614 | sqlite3_stmt *pExplain; |
| 10687 | 11615 | char *zEQP; |
| 10688 | 11616 | int triggerEQP = 0; |
| 10689 | 11617 | disable_debug_trace_modes(); |
| 10690 | 11618 | sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP); |
| | @@ -10729,17 +11657,14 @@ |
| 10729 | 11657 | } |
| 10730 | 11658 | |
| 10731 | 11659 | if( pArg ){ |
| 10732 | 11660 | pArg->cMode = pArg->mode; |
| 10733 | 11661 | if( pArg->autoExplain ){ |
| 10734 | | - if( sqlite3_column_count(pStmt)==8 |
| 10735 | | - && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0 |
| 10736 | | - ){ |
| 11662 | + if( sqlite3_stmt_isexplain(pStmt)==1 ){ |
| 10737 | 11663 | pArg->cMode = MODE_Explain; |
| 10738 | 11664 | } |
| 10739 | | - if( sqlite3_column_count(pStmt)==4 |
| 10740 | | - && sqlite3_strlike("EXPLAIN QUERY PLAN%", zStmtSql,0)==0 ){ |
| 11665 | + if( sqlite3_stmt_isexplain(pStmt)==2 ){ |
| 10741 | 11666 | pArg->cMode = MODE_EQP; |
| 10742 | 11667 | } |
| 10743 | 11668 | } |
| 10744 | 11669 | |
| 10745 | 11670 | /* If the shell is currently in ".explain" mode, gather the extra |
| | @@ -10747,10 +11672,11 @@ |
| 10747 | 11672 | if( pArg->cMode==MODE_Explain ){ |
| 10748 | 11673 | explain_data_prepare(pArg, pStmt); |
| 10749 | 11674 | } |
| 10750 | 11675 | } |
| 10751 | 11676 | |
| 11677 | + bind_prepared_stmt(pArg, pStmt); |
| 10752 | 11678 | exec_prepared_stmt(pArg, pStmt); |
| 10753 | 11679 | explain_data_delete(pArg); |
| 10754 | 11680 | eqp_render(pArg); |
| 10755 | 11681 | |
| 10756 | 11682 | /* print usage stats if stats on */ |
| | @@ -11076,11 +12002,12 @@ |
| 11076 | 12002 | static const char *(azHelp[]) = { |
| 11077 | 12003 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 11078 | 12004 | ".archive ... Manage SQL archives", |
| 11079 | 12005 | " Each command must have exactly one of the following options:", |
| 11080 | 12006 | " -c, --create Create a new archive", |
| 11081 | | - " -u, --update Update or add files to an existing archive", |
| 12007 | + " -u, --update Add files or update files with changed mtime", |
| 12008 | + " -i, --insert Like -u but always add even if mtime unchanged", |
| 11082 | 12009 | " -t, --list List contents of archive", |
| 11083 | 12010 | " -x, --extract Extract files from archive", |
| 11084 | 12011 | " Optional arguments:", |
| 11085 | 12012 | " -v, --verbose Print each filename as it is processed", |
| 11086 | 12013 | " -f FILE, --file FILE Operate on archive FILE (default is current db)", |
| | @@ -11111,11 +12038,11 @@ |
| 11111 | 12038 | ".dbinfo ?DB? Show status information about the database", |
| 11112 | 12039 | ".dump ?TABLE? ... Render all database content as SQL", |
| 11113 | 12040 | " Options:", |
| 11114 | 12041 | " --preserve-rowids Include ROWID values in the output", |
| 11115 | 12042 | " --newlines Allow unescaped newline characters in output", |
| 11116 | | - " TABLE is LIKE pattern for the tables to dump", |
| 12043 | + " TABLE is a LIKE pattern for the tables to dump", |
| 11117 | 12044 | ".echo on|off Turn command echo on or off", |
| 11118 | 12045 | ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", |
| 11119 | 12046 | " Other Modes:", |
| 11120 | 12047 | #ifdef SQLITE_DEBUG |
| 11121 | 12048 | " test Show raw EXPLAIN QUERY PLAN output", |
| | @@ -11178,10 +12105,17 @@ |
| 11178 | 12105 | " --new Initialize FILE to an empty database", |
| 11179 | 12106 | " --readonly Open FILE readonly", |
| 11180 | 12107 | " --zip FILE is a ZIP archive", |
| 11181 | 12108 | ".output ?FILE? Send output to FILE or stdout if FILE is omitted", |
| 11182 | 12109 | " If FILE begins with '|' then open it as a pipe.", |
| 12110 | + ".parameter CMD ... Manage SQL parameter bindings", |
| 12111 | + " clear Erase all bindings", |
| 12112 | + " init Initialize the TEMP table that holds bindings", |
| 12113 | + " list List the current parameter bindings", |
| 12114 | + " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE", |
| 12115 | + " PARAMETER should start with '$', ':', '@', or '?'", |
| 12116 | + " unset PARAMETER Remove PARAMETER from the binding table", |
| 11183 | 12117 | ".print STRING... Print literal STRING", |
| 11184 | 12118 | #ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
| 11185 | 12119 | ".progress N Invoke progress handler after every N opcodes", |
| 11186 | 12120 | " --limit N Interrupt after N progress callbacks", |
| 11187 | 12121 | " --once Do no more than one progress interrupt", |
| | @@ -11189,10 +12123,13 @@ |
| 11189 | 12123 | " --reset Reset the count for each input and interrupt", |
| 11190 | 12124 | #endif |
| 11191 | 12125 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 11192 | 12126 | ".quit Exit this program", |
| 11193 | 12127 | ".read FILE Read input from FILE", |
| 12128 | +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 12129 | + ".recover Recover as much data as possible from corrupt db.", |
| 12130 | +#endif |
| 11194 | 12131 | ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", |
| 11195 | 12132 | ".save FILE Write in-memory database into FILE", |
| 11196 | 12133 | ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", |
| 11197 | 12134 | ".schema ?PATTERN? Show the CREATE statements matching PATTERN", |
| 11198 | 12135 | " Options:", |
| | @@ -11473,11 +12410,11 @@ |
| 11473 | 12410 | int pgsz = 0; |
| 11474 | 12411 | int iOffset = 0; |
| 11475 | 12412 | int j, k; |
| 11476 | 12413 | int rc; |
| 11477 | 12414 | FILE *in; |
| 11478 | | - unsigned char x[16]; |
| 12415 | + unsigned int x[16]; |
| 11479 | 12416 | char zLine[1000]; |
| 11480 | 12417 | if( p->zDbFilename ){ |
| 11481 | 12418 | in = fopen(p->zDbFilename, "r"); |
| 11482 | 12419 | if( in==0 ){ |
| 11483 | 12420 | utf8_printf(stderr, "cannot open \"%s\" for reading\n", p->zDbFilename); |
| | @@ -11485,18 +12422,19 @@ |
| 11485 | 12422 | } |
| 11486 | 12423 | nLine = 0; |
| 11487 | 12424 | }else{ |
| 11488 | 12425 | in = p->in; |
| 11489 | 12426 | nLine = p->lineno; |
| 12427 | + if( in==0 ) in = stdin; |
| 11490 | 12428 | } |
| 11491 | 12429 | *pnData = 0; |
| 11492 | 12430 | nLine++; |
| 11493 | 12431 | if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; |
| 11494 | 12432 | rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); |
| 11495 | 12433 | if( rc!=2 ) goto readHexDb_error; |
| 11496 | | - if( n<=0 ) goto readHexDb_error; |
| 11497 | | - a = sqlite3_malloc( n ); |
| 12434 | + if( n<0 ) goto readHexDb_error; |
| 12435 | + a = sqlite3_malloc( n ? n : 1 ); |
| 11498 | 12436 | if( a==0 ){ |
| 11499 | 12437 | utf8_printf(stderr, "Out of memory!\n"); |
| 11500 | 12438 | goto readHexDb_error; |
| 11501 | 12439 | } |
| 11502 | 12440 | memset(a, 0, n); |
| | @@ -11511,18 +12449,18 @@ |
| 11511 | 12449 | continue; |
| 11512 | 12450 | } |
| 11513 | 12451 | if( strncmp(zLine, "| end ", 6)==0 ){ |
| 11514 | 12452 | break; |
| 11515 | 12453 | } |
| 11516 | | - rc = sscanf(zLine,"| %d: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx" |
| 11517 | | - " %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx", |
| 12454 | + rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", |
| 11518 | 12455 | &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], |
| 11519 | 12456 | &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); |
| 11520 | 12457 | if( rc==17 ){ |
| 11521 | 12458 | k = iOffset+j; |
| 11522 | 12459 | if( k+16<=n ){ |
| 11523 | | - memcpy(a+k, x, 16); |
| 12460 | + int ii; |
| 12461 | + for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; |
| 11524 | 12462 | } |
| 11525 | 12463 | } |
| 11526 | 12464 | } |
| 11527 | 12465 | *pnData = n; |
| 11528 | 12466 | if( in!=p->in ){ |
| | @@ -11531,11 +12469,11 @@ |
| 11531 | 12469 | p->lineno = nLine; |
| 11532 | 12470 | } |
| 11533 | 12471 | return a; |
| 11534 | 12472 | |
| 11535 | 12473 | readHexDb_error: |
| 11536 | | - if( in!=stdin ){ |
| 12474 | + if( in!=p->in ){ |
| 11537 | 12475 | fclose(in); |
| 11538 | 12476 | }else{ |
| 11539 | 12477 | while( fgets(zLine, sizeof(zLine), p->in)!=0 ){ |
| 11540 | 12478 | nLine++; |
| 11541 | 12479 | if(strncmp(zLine, "| end ", 6)==0 ) break; |
| | @@ -11545,10 +12483,131 @@ |
| 11545 | 12483 | sqlite3_free(a); |
| 11546 | 12484 | utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine); |
| 11547 | 12485 | return 0; |
| 11548 | 12486 | } |
| 11549 | 12487 | #endif /* SQLITE_ENABLE_DESERIALIZE */ |
| 12488 | + |
| 12489 | +/* |
| 12490 | +** Scalar function "shell_int32". The first argument to this function |
| 12491 | +** must be a blob. The second a non-negative integer. This function |
| 12492 | +** reads and returns a 32-bit big-endian integer from byte |
| 12493 | +** offset (4*<arg2>) of the blob. |
| 12494 | +*/ |
| 12495 | +static void shellInt32( |
| 12496 | + sqlite3_context *context, |
| 12497 | + int argc, |
| 12498 | + sqlite3_value **argv |
| 12499 | +){ |
| 12500 | + const unsigned char *pBlob; |
| 12501 | + int nBlob; |
| 12502 | + int iInt; |
| 12503 | + |
| 12504 | + UNUSED_PARAMETER(argc); |
| 12505 | + nBlob = sqlite3_value_bytes(argv[0]); |
| 12506 | + pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]); |
| 12507 | + iInt = sqlite3_value_int(argv[1]); |
| 12508 | + |
| 12509 | + if( iInt>=0 && (iInt+1)*4<=nBlob ){ |
| 12510 | + const unsigned char *a = &pBlob[iInt*4]; |
| 12511 | + sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24) |
| 12512 | + + ((sqlite3_int64)a[1]<<16) |
| 12513 | + + ((sqlite3_int64)a[2]<< 8) |
| 12514 | + + ((sqlite3_int64)a[3]<< 0); |
| 12515 | + sqlite3_result_int64(context, iVal); |
| 12516 | + } |
| 12517 | +} |
| 12518 | + |
| 12519 | +/* |
| 12520 | +** Scalar function "shell_escape_crnl" used by the .recover command. |
| 12521 | +** The argument passed to this function is the output of built-in |
| 12522 | +** function quote(). If the first character of the input is "'", |
| 12523 | +** indicating that the value passed to quote() was a text value, |
| 12524 | +** then this function searches the input for "\n" and "\r" characters |
| 12525 | +** and adds a wrapper similar to the following: |
| 12526 | +** |
| 12527 | +** replace(replace(<input>, '\n', char(10), '\r', char(13)); |
| 12528 | +** |
| 12529 | +** Or, if the first character of the input is not "'", then a copy |
| 12530 | +** of the input is returned. |
| 12531 | +*/ |
| 12532 | +static void shellEscapeCrnl( |
| 12533 | + sqlite3_context *context, |
| 12534 | + int argc, |
| 12535 | + sqlite3_value **argv |
| 12536 | +){ |
| 12537 | + const char *zText = (const char*)sqlite3_value_text(argv[0]); |
| 12538 | + UNUSED_PARAMETER(argc); |
| 12539 | + if( zText[0]=='\'' ){ |
| 12540 | + int nText = sqlite3_value_bytes(argv[0]); |
| 12541 | + int i; |
| 12542 | + char zBuf1[20]; |
| 12543 | + char zBuf2[20]; |
| 12544 | + const char *zNL = 0; |
| 12545 | + const char *zCR = 0; |
| 12546 | + int nCR = 0; |
| 12547 | + int nNL = 0; |
| 12548 | + |
| 12549 | + for(i=0; zText[i]; i++){ |
| 12550 | + if( zNL==0 && zText[i]=='\n' ){ |
| 12551 | + zNL = unused_string(zText, "\\n", "\\012", zBuf1); |
| 12552 | + nNL = (int)strlen(zNL); |
| 12553 | + } |
| 12554 | + if( zCR==0 && zText[i]=='\r' ){ |
| 12555 | + zCR = unused_string(zText, "\\r", "\\015", zBuf2); |
| 12556 | + nCR = (int)strlen(zCR); |
| 12557 | + } |
| 12558 | + } |
| 12559 | + |
| 12560 | + if( zNL || zCR ){ |
| 12561 | + int iOut = 0; |
| 12562 | + i64 nMax = (nNL > nCR) ? nNL : nCR; |
| 12563 | + i64 nAlloc = nMax * nText + (nMax+64)*2; |
| 12564 | + char *zOut = (char*)sqlite3_malloc64(nAlloc); |
| 12565 | + if( zOut==0 ){ |
| 12566 | + sqlite3_result_error_nomem(context); |
| 12567 | + return; |
| 12568 | + } |
| 12569 | + |
| 12570 | + if( zNL && zCR ){ |
| 12571 | + memcpy(&zOut[iOut], "replace(replace(", 16); |
| 12572 | + iOut += 16; |
| 12573 | + }else{ |
| 12574 | + memcpy(&zOut[iOut], "replace(", 8); |
| 12575 | + iOut += 8; |
| 12576 | + } |
| 12577 | + for(i=0; zText[i]; i++){ |
| 12578 | + if( zText[i]=='\n' ){ |
| 12579 | + memcpy(&zOut[iOut], zNL, nNL); |
| 12580 | + iOut += nNL; |
| 12581 | + }else if( zText[i]=='\r' ){ |
| 12582 | + memcpy(&zOut[iOut], zCR, nCR); |
| 12583 | + iOut += nCR; |
| 12584 | + }else{ |
| 12585 | + zOut[iOut] = zText[i]; |
| 12586 | + iOut++; |
| 12587 | + } |
| 12588 | + } |
| 12589 | + |
| 12590 | + if( zNL ){ |
| 12591 | + memcpy(&zOut[iOut], ",'", 2); iOut += 2; |
| 12592 | + memcpy(&zOut[iOut], zNL, nNL); iOut += nNL; |
| 12593 | + memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12; |
| 12594 | + } |
| 12595 | + if( zCR ){ |
| 12596 | + memcpy(&zOut[iOut], ",'", 2); iOut += 2; |
| 12597 | + memcpy(&zOut[iOut], zCR, nCR); iOut += nCR; |
| 12598 | + memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12; |
| 12599 | + } |
| 12600 | + |
| 12601 | + sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT); |
| 12602 | + sqlite3_free(zOut); |
| 12603 | + return; |
| 12604 | + } |
| 12605 | + } |
| 12606 | + |
| 12607 | + sqlite3_result_value(context, argv[0]); |
| 12608 | +} |
| 11550 | 12609 | |
| 11551 | 12610 | /* Flags for open_db(). |
| 11552 | 12611 | ** |
| 11553 | 12612 | ** The default behavior of open_db() is to exit(1) if the database fails to |
| 11554 | 12613 | ** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error |
| | @@ -11614,10 +12673,13 @@ |
| 11614 | 12673 | sqlite3_enable_load_extension(p->db, 1); |
| 11615 | 12674 | #endif |
| 11616 | 12675 | sqlite3_fileio_init(p->db, 0, 0); |
| 11617 | 12676 | sqlite3_shathree_init(p->db, 0, 0); |
| 11618 | 12677 | sqlite3_completion_init(p->db, 0, 0); |
| 12678 | +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 12679 | + sqlite3_dbdata_init(p->db, 0, 0); |
| 12680 | +#endif |
| 11619 | 12681 | #ifdef SQLITE_HAVE_ZLIB |
| 11620 | 12682 | sqlite3_zipfile_init(p->db, 0, 0); |
| 11621 | 12683 | sqlite3_sqlar_init(p->db, 0, 0); |
| 11622 | 12684 | #endif |
| 11623 | 12685 | sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, |
| | @@ -11624,10 +12686,14 @@ |
| 11624 | 12686 | shellAddSchemaName, 0, 0); |
| 11625 | 12687 | sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, |
| 11626 | 12688 | shellModuleSchema, 0, 0); |
| 11627 | 12689 | sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, |
| 11628 | 12690 | shellPutsFunc, 0, 0); |
| 12691 | + sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0, |
| 12692 | + shellEscapeCrnl, 0, 0); |
| 12693 | + sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0, |
| 12694 | + shellInt32, 0, 0); |
| 11629 | 12695 | #ifndef SQLITE_NOHAVE_SYSTEM |
| 11630 | 12696 | sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, |
| 11631 | 12697 | editFunc, 0, 0); |
| 11632 | 12698 | sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, |
| 11633 | 12699 | editFunc, 0, 0); |
| | @@ -11647,11 +12713,10 @@ |
| 11647 | 12713 | if( p->openMode==SHELL_OPEN_DESERIALIZE ){ |
| 11648 | 12714 | aData = (unsigned char*)readFile(p->zDbFilename, &nData); |
| 11649 | 12715 | }else{ |
| 11650 | 12716 | aData = readHexDb(p, &nData); |
| 11651 | 12717 | if( aData==0 ){ |
| 11652 | | - utf8_printf(stderr, "Error in hexdb input\n"); |
| 11653 | 12718 | return; |
| 11654 | 12719 | } |
| 11655 | 12720 | } |
| 11656 | 12721 | rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, |
| 11657 | 12722 | SQLITE_DESERIALIZE_RESIZEABLE | |
| | @@ -12390,20 +13455,31 @@ |
| 12390 | 13455 | { "number of views:", |
| 12391 | 13456 | "SELECT count(*) FROM %s WHERE type='view'" }, |
| 12392 | 13457 | { "schema size:", |
| 12393 | 13458 | "SELECT total(length(sql)) FROM %s" }, |
| 12394 | 13459 | }; |
| 12395 | | - int i; |
| 13460 | + int i, rc; |
| 12396 | 13461 | unsigned iDataVersion; |
| 12397 | 13462 | char *zSchemaTab; |
| 12398 | 13463 | char *zDb = nArg>=2 ? azArg[1] : "main"; |
| 12399 | 13464 | sqlite3_stmt *pStmt = 0; |
| 12400 | 13465 | unsigned char aHdr[100]; |
| 12401 | 13466 | open_db(p, 0); |
| 12402 | 13467 | if( p->db==0 ) return 1; |
| 12403 | | - sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", |
| 12404 | | - -1, &pStmt, 0); |
| 13468 | + rc = sqlite3_prepare_v2(p->db, |
| 13469 | + "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", |
| 13470 | + -1, &pStmt, 0); |
| 13471 | + if( rc ){ |
| 13472 | + if( !sqlite3_compileoption_used("ENABLE_DBPAGE_VTAB") ){ |
| 13473 | + utf8_printf(stderr, "the \".dbinfo\" command requires the " |
| 13474 | + "-DSQLITE_ENABLE_DBPAGE_VTAB compile-time options\n"); |
| 13475 | + }else{ |
| 13476 | + utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db)); |
| 13477 | + } |
| 13478 | + sqlite3_finalize(pStmt); |
| 13479 | + return 1; |
| 13480 | + } |
| 12405 | 13481 | sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC); |
| 12406 | 13482 | if( sqlite3_step(pStmt)==SQLITE_ROW |
| 12407 | 13483 | && sqlite3_column_bytes(pStmt,0)>100 |
| 12408 | 13484 | ){ |
| 12409 | 13485 | memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100); |
| | @@ -12867,14 +13943,11 @@ |
| 12867 | 13943 | raw_printf(stderr, "Where sub-commands are:\n"); |
| 12868 | 13944 | raw_printf(stderr, " fkey-indexes\n"); |
| 12869 | 13945 | return SQLITE_ERROR; |
| 12870 | 13946 | } |
| 12871 | 13947 | |
| 12872 | | -#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) |
| 12873 | | -/********************************************************************************* |
| 12874 | | -** The ".archive" or ".ar" command. |
| 12875 | | -*/ |
| 13948 | +#if !defined SQLITE_OMIT_VIRTUALTABLE |
| 12876 | 13949 | static void shellPrepare( |
| 12877 | 13950 | sqlite3 *db, |
| 12878 | 13951 | int *pRc, |
| 12879 | 13952 | const char *zSql, |
| 12880 | 13953 | sqlite3_stmt **ppStmt |
| | @@ -12889,11 +13962,18 @@ |
| 12889 | 13962 | *pRc = rc; |
| 12890 | 13963 | } |
| 12891 | 13964 | } |
| 12892 | 13965 | } |
| 12893 | 13966 | |
| 12894 | | -static void shellPreparePrintf( |
| 13967 | +/* |
| 13968 | +** Create a prepared statement using printf-style arguments for the SQL. |
| 13969 | +** |
| 13970 | +** This routine is could be marked "static". But it is not always used, |
| 13971 | +** depending on compile-time options. By omitting the "static", we avoid |
| 13972 | +** nuisance compiler warnings about "defined but not used". |
| 13973 | +*/ |
| 13974 | +void shellPreparePrintf( |
| 12895 | 13975 | sqlite3 *db, |
| 12896 | 13976 | int *pRc, |
| 12897 | 13977 | sqlite3_stmt **ppStmt, |
| 12898 | 13978 | const char *zFmt, |
| 12899 | 13979 | ... |
| | @@ -12912,11 +13992,17 @@ |
| 12912 | 13992 | sqlite3_free(z); |
| 12913 | 13993 | } |
| 12914 | 13994 | } |
| 12915 | 13995 | } |
| 12916 | 13996 | |
| 12917 | | -static void shellFinalize( |
| 13997 | +/* Finalize the prepared statement created using shellPreparePrintf(). |
| 13998 | +** |
| 13999 | +** This routine is could be marked "static". But it is not always used, |
| 14000 | +** depending on compile-time options. By omitting the "static", we avoid |
| 14001 | +** nuisance compiler warnings about "defined but not used". |
| 14002 | +*/ |
| 14003 | +void shellFinalize( |
| 12918 | 14004 | int *pRc, |
| 12919 | 14005 | sqlite3_stmt *pStmt |
| 12920 | 14006 | ){ |
| 12921 | 14007 | if( pStmt ){ |
| 12922 | 14008 | sqlite3 *db = sqlite3_db_handle(pStmt); |
| | @@ -12928,11 +14014,17 @@ |
| 12928 | 14014 | *pRc = rc; |
| 12929 | 14015 | } |
| 12930 | 14016 | } |
| 12931 | 14017 | } |
| 12932 | 14018 | |
| 12933 | | -static void shellReset( |
| 14019 | +/* Reset the prepared statement created using shellPreparePrintf(). |
| 14020 | +** |
| 14021 | +** This routine is could be marked "static". But it is not always used, |
| 14022 | +** depending on compile-time options. By omitting the "static", we avoid |
| 14023 | +** nuisance compiler warnings about "defined but not used". |
| 14024 | +*/ |
| 14025 | +void shellReset( |
| 12934 | 14026 | int *pRc, |
| 12935 | 14027 | sqlite3_stmt *pStmt |
| 12936 | 14028 | ){ |
| 12937 | 14029 | int rc = sqlite3_reset(pStmt); |
| 12938 | 14030 | if( *pRc==SQLITE_OK ){ |
| | @@ -12941,10 +14033,16 @@ |
| 12941 | 14033 | raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); |
| 12942 | 14034 | } |
| 12943 | 14035 | *pRc = rc; |
| 12944 | 14036 | } |
| 12945 | 14037 | } |
| 14038 | +#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */ |
| 14039 | + |
| 14040 | +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) |
| 14041 | +/********************************************************************************* |
| 14042 | +** The ".archive" or ".ar" command. |
| 14043 | +*/ |
| 12946 | 14044 | /* |
| 12947 | 14045 | ** Structure representing a single ".ar" command. |
| 12948 | 14046 | */ |
| 12949 | 14047 | typedef struct ArCommand ArCommand; |
| 12950 | 14048 | struct ArCommand { |
| | @@ -12993,30 +14091,32 @@ |
| 12993 | 14091 | |
| 12994 | 14092 | /* |
| 12995 | 14093 | ** Values for ArCommand.eCmd. |
| 12996 | 14094 | */ |
| 12997 | 14095 | #define AR_CMD_CREATE 1 |
| 12998 | | -#define AR_CMD_EXTRACT 2 |
| 12999 | | -#define AR_CMD_LIST 3 |
| 13000 | | -#define AR_CMD_UPDATE 4 |
| 13001 | | -#define AR_CMD_HELP 5 |
| 14096 | +#define AR_CMD_UPDATE 2 |
| 14097 | +#define AR_CMD_INSERT 3 |
| 14098 | +#define AR_CMD_EXTRACT 4 |
| 14099 | +#define AR_CMD_LIST 5 |
| 14100 | +#define AR_CMD_HELP 6 |
| 13002 | 14101 | |
| 13003 | 14102 | /* |
| 13004 | 14103 | ** Other (non-command) switches. |
| 13005 | 14104 | */ |
| 13006 | | -#define AR_SWITCH_VERBOSE 6 |
| 13007 | | -#define AR_SWITCH_FILE 7 |
| 13008 | | -#define AR_SWITCH_DIRECTORY 8 |
| 13009 | | -#define AR_SWITCH_APPEND 9 |
| 13010 | | -#define AR_SWITCH_DRYRUN 10 |
| 14105 | +#define AR_SWITCH_VERBOSE 7 |
| 14106 | +#define AR_SWITCH_FILE 8 |
| 14107 | +#define AR_SWITCH_DIRECTORY 9 |
| 14108 | +#define AR_SWITCH_APPEND 10 |
| 14109 | +#define AR_SWITCH_DRYRUN 11 |
| 13011 | 14110 | |
| 13012 | 14111 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 13013 | 14112 | switch( eSwitch ){ |
| 13014 | 14113 | case AR_CMD_CREATE: |
| 13015 | 14114 | case AR_CMD_EXTRACT: |
| 13016 | 14115 | case AR_CMD_LIST: |
| 13017 | 14116 | case AR_CMD_UPDATE: |
| 14117 | + case AR_CMD_INSERT: |
| 13018 | 14118 | case AR_CMD_HELP: |
| 13019 | 14119 | if( pAr->eCmd ){ |
| 13020 | 14120 | return arErrorMsg(pAr, "multiple command options"); |
| 13021 | 14121 | } |
| 13022 | 14122 | pAr->eCmd = eSwitch; |
| | @@ -13059,10 +14159,11 @@ |
| 13059 | 14159 | u8 eSwitch; |
| 13060 | 14160 | u8 bArg; |
| 13061 | 14161 | } aSwitch[] = { |
| 13062 | 14162 | { "create", 'c', AR_CMD_CREATE, 0 }, |
| 13063 | 14163 | { "extract", 'x', AR_CMD_EXTRACT, 0 }, |
| 14164 | + { "insert", 'i', AR_CMD_INSERT, 0 }, |
| 13064 | 14165 | { "list", 't', AR_CMD_LIST, 0 }, |
| 13065 | 14166 | { "update", 'u', AR_CMD_UPDATE, 0 }, |
| 13066 | 14167 | { "help", 'h', AR_CMD_HELP, 0 }, |
| 13067 | 14168 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 13068 | 14169 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| | @@ -13394,23 +14495,31 @@ |
| 13394 | 14495 | return rc; |
| 13395 | 14496 | } |
| 13396 | 14497 | |
| 13397 | 14498 | |
| 13398 | 14499 | /* |
| 13399 | | -** Implementation of .ar "create" and "update" commands. |
| 14500 | +** Implementation of .ar "create", "insert", and "update" commands. |
| 14501 | +** |
| 14502 | +** create -> Create a new SQL archive |
| 14503 | +** insert -> Insert or reinsert all files listed |
| 14504 | +** update -> Insert files that have changed or that were not |
| 14505 | +** previously in the archive |
| 13400 | 14506 | ** |
| 13401 | 14507 | ** Create the "sqlar" table in the database if it does not already exist. |
| 13402 | 14508 | ** Then add each file in the azFile[] array to the archive. Directories |
| 13403 | 14509 | ** are added recursively. If argument bVerbose is non-zero, a message is |
| 13404 | 14510 | ** printed on stdout for each file archived. |
| 13405 | 14511 | ** |
| 13406 | 14512 | ** The create command is the same as update, except that it drops |
| 13407 | | -** any existing "sqlar" table before beginning. |
| 14513 | +** any existing "sqlar" table before beginning. The "insert" command |
| 14514 | +** always overwrites every file named on the command-line, where as |
| 14515 | +** "update" only overwrites if the size or mtime or mode has changed. |
| 13408 | 14516 | */ |
| 13409 | 14517 | static int arCreateOrUpdateCommand( |
| 13410 | 14518 | ArCommand *pAr, /* Command arguments and options */ |
| 13411 | | - int bUpdate /* true for a --create. false for --update */ |
| 14519 | + int bUpdate, /* true for a --create. */ |
| 14520 | + int bOnlyIfChanged /* Only update if file has changed */ |
| 13412 | 14521 | ){ |
| 13413 | 14522 | const char *zCreate = |
| 13414 | 14523 | "CREATE TABLE IF NOT EXISTS sqlar(\n" |
| 13415 | 14524 | " name TEXT PRIMARY KEY, -- name of the file\n" |
| 13416 | 14525 | " mode INT, -- access permissions\n" |
| | @@ -13428,26 +14537,28 @@ |
| 13428 | 14537 | " CASE substr(lsmode(mode),1,1)\n" |
| 13429 | 14538 | " WHEN '-' THEN length(data)\n" |
| 13430 | 14539 | " WHEN 'd' THEN 0\n" |
| 13431 | 14540 | " ELSE -1 END,\n" |
| 13432 | 14541 | " sqlar_compress(data)\n" |
| 13433 | | - " FROM fsdir(%Q,%Q)\n" |
| 13434 | | - " WHERE lsmode(mode) NOT LIKE '?%%';", |
| 14542 | + " FROM fsdir(%Q,%Q) AS disk\n" |
| 14543 | + " WHERE lsmode(mode) NOT LIKE '?%%'%s;" |
| 14544 | + , |
| 13435 | 14545 | "REPLACE INTO %s(name,mode,mtime,data)\n" |
| 13436 | 14546 | " SELECT\n" |
| 13437 | 14547 | " %s,\n" |
| 13438 | 14548 | " mode,\n" |
| 13439 | 14549 | " mtime,\n" |
| 13440 | 14550 | " data\n" |
| 13441 | | - " FROM fsdir(%Q,%Q)\n" |
| 13442 | | - " WHERE lsmode(mode) NOT LIKE '?%%';" |
| 14551 | + " FROM fsdir(%Q,%Q) AS disk\n" |
| 14552 | + " WHERE lsmode(mode) NOT LIKE '?%%'%s;" |
| 13443 | 14553 | }; |
| 13444 | 14554 | int i; /* For iterating through azFile[] */ |
| 13445 | 14555 | int rc; /* Return code */ |
| 13446 | 14556 | const char *zTab = 0; /* SQL table into which to insert */ |
| 13447 | 14557 | char *zSql; |
| 13448 | 14558 | char zTemp[50]; |
| 14559 | + char *zExists = 0; |
| 13449 | 14560 | |
| 13450 | 14561 | arExecSql(pAr, "PRAGMA page_size=512"); |
| 13451 | 14562 | rc = arExecSql(pAr, "SAVEPOINT ar;"); |
| 13452 | 14563 | if( rc!=SQLITE_OK ) return rc; |
| 13453 | 14564 | zTemp[0] = 0; |
| | @@ -13474,14 +14585,25 @@ |
| 13474 | 14585 | rc = arExecSql(pAr, zDrop); |
| 13475 | 14586 | if( rc!=SQLITE_OK ) goto end_ar_transaction; |
| 13476 | 14587 | } |
| 13477 | 14588 | rc = arExecSql(pAr, zCreate); |
| 13478 | 14589 | } |
| 14590 | + if( bOnlyIfChanged ){ |
| 14591 | + zExists = sqlite3_mprintf( |
| 14592 | + " AND NOT EXISTS(" |
| 14593 | + "SELECT 1 FROM %s AS mem" |
| 14594 | + " WHERE mem.name=disk.name" |
| 14595 | + " AND mem.mtime=disk.mtime" |
| 14596 | + " AND mem.mode=disk.mode)", zTab); |
| 14597 | + }else{ |
| 14598 | + zExists = sqlite3_mprintf(""); |
| 14599 | + } |
| 14600 | + if( zExists==0 ) rc = SQLITE_NOMEM; |
| 13479 | 14601 | for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ |
| 13480 | 14602 | char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab, |
| 13481 | 14603 | pAr->bVerbose ? "shell_putsnl(name)" : "name", |
| 13482 | | - pAr->azArg[i], pAr->zDir); |
| 14604 | + pAr->azArg[i], pAr->zDir, zExists); |
| 13483 | 14605 | rc = arExecSql(pAr, zSql2); |
| 13484 | 14606 | sqlite3_free(zSql2); |
| 13485 | 14607 | } |
| 13486 | 14608 | end_ar_transaction: |
| 13487 | 14609 | if( rc!=SQLITE_OK ){ |
| | @@ -13492,10 +14614,11 @@ |
| 13492 | 14614 | zSql = sqlite3_mprintf("DROP TABLE %s", zTemp); |
| 13493 | 14615 | arExecSql(pAr, zSql); |
| 13494 | 14616 | sqlite3_free(zSql); |
| 13495 | 14617 | } |
| 13496 | 14618 | } |
| 14619 | + sqlite3_free(zExists); |
| 13497 | 14620 | return rc; |
| 13498 | 14621 | } |
| 13499 | 14622 | |
| 13500 | 14623 | /* |
| 13501 | 14624 | ** Implementation of ".ar" dot command. |
| | @@ -13530,11 +14653,12 @@ |
| 13530 | 14653 | } |
| 13531 | 14654 | cmd.bZip = 1; |
| 13532 | 14655 | }else if( cmd.zFile ){ |
| 13533 | 14656 | int flags; |
| 13534 | 14657 | if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; |
| 13535 | | - if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){ |
| 14658 | + if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT |
| 14659 | + || cmd.eCmd==AR_CMD_UPDATE ){ |
| 13536 | 14660 | flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; |
| 13537 | 14661 | }else{ |
| 13538 | 14662 | flags = SQLITE_OPEN_READONLY; |
| 13539 | 14663 | } |
| 13540 | 14664 | cmd.db = 0; |
| | @@ -13567,11 +14691,11 @@ |
| 13567 | 14691 | cmd.zSrcTable = sqlite3_mprintf("sqlar"); |
| 13568 | 14692 | } |
| 13569 | 14693 | |
| 13570 | 14694 | switch( cmd.eCmd ){ |
| 13571 | 14695 | case AR_CMD_CREATE: |
| 13572 | | - rc = arCreateOrUpdateCommand(&cmd, 0); |
| 14696 | + rc = arCreateOrUpdateCommand(&cmd, 0, 0); |
| 13573 | 14697 | break; |
| 13574 | 14698 | |
| 13575 | 14699 | case AR_CMD_EXTRACT: |
| 13576 | 14700 | rc = arExtractCommand(&cmd); |
| 13577 | 14701 | break; |
| | @@ -13582,13 +14706,17 @@ |
| 13582 | 14706 | |
| 13583 | 14707 | case AR_CMD_HELP: |
| 13584 | 14708 | arUsage(pState->out); |
| 13585 | 14709 | break; |
| 13586 | 14710 | |
| 14711 | + case AR_CMD_INSERT: |
| 14712 | + rc = arCreateOrUpdateCommand(&cmd, 1, 0); |
| 14713 | + break; |
| 14714 | + |
| 13587 | 14715 | default: |
| 13588 | 14716 | assert( cmd.eCmd==AR_CMD_UPDATE ); |
| 13589 | | - rc = arCreateOrUpdateCommand(&cmd, 1); |
| 14717 | + rc = arCreateOrUpdateCommand(&cmd, 1, 1); |
| 13590 | 14718 | break; |
| 13591 | 14719 | } |
| 13592 | 14720 | } |
| 13593 | 14721 | end_ar_command: |
| 13594 | 14722 | if( cmd.db!=pState->db ){ |
| | @@ -13600,10 +14728,639 @@ |
| 13600 | 14728 | } |
| 13601 | 14729 | /* End of the ".archive" or ".ar" command logic |
| 13602 | 14730 | **********************************************************************************/ |
| 13603 | 14731 | #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */ |
| 13604 | 14732 | |
| 14733 | +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 14734 | +/* |
| 14735 | +** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op. |
| 14736 | +** Otherwise, the SQL statement or statements in zSql are executed using |
| 14737 | +** database connection db and the error code written to *pRc before |
| 14738 | +** this function returns. |
| 14739 | +*/ |
| 14740 | +static void shellExec(sqlite3 *db, int *pRc, const char *zSql){ |
| 14741 | + int rc = *pRc; |
| 14742 | + if( rc==SQLITE_OK ){ |
| 14743 | + char *zErr = 0; |
| 14744 | + rc = sqlite3_exec(db, zSql, 0, 0, &zErr); |
| 14745 | + if( rc!=SQLITE_OK ){ |
| 14746 | + raw_printf(stderr, "SQL error: %s\n", zErr); |
| 14747 | + } |
| 14748 | + *pRc = rc; |
| 14749 | + } |
| 14750 | +} |
| 14751 | + |
| 14752 | +/* |
| 14753 | +** Like shellExec(), except that zFmt is a printf() style format string. |
| 14754 | +*/ |
| 14755 | +static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ |
| 14756 | + char *z = 0; |
| 14757 | + if( *pRc==SQLITE_OK ){ |
| 14758 | + va_list ap; |
| 14759 | + va_start(ap, zFmt); |
| 14760 | + z = sqlite3_vmprintf(zFmt, ap); |
| 14761 | + va_end(ap); |
| 14762 | + if( z==0 ){ |
| 14763 | + *pRc = SQLITE_NOMEM; |
| 14764 | + }else{ |
| 14765 | + shellExec(db, pRc, z); |
| 14766 | + } |
| 14767 | + sqlite3_free(z); |
| 14768 | + } |
| 14769 | +} |
| 14770 | + |
| 14771 | +/* |
| 14772 | +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. |
| 14773 | +** Otherwise, an attempt is made to allocate, zero and return a pointer |
| 14774 | +** to a buffer nByte bytes in size. If an OOM error occurs, *pRc is set |
| 14775 | +** to SQLITE_NOMEM and NULL returned. |
| 14776 | +*/ |
| 14777 | +static void *shellMalloc(int *pRc, sqlite3_int64 nByte){ |
| 14778 | + void *pRet = 0; |
| 14779 | + if( *pRc==SQLITE_OK ){ |
| 14780 | + pRet = sqlite3_malloc64(nByte); |
| 14781 | + if( pRet==0 ){ |
| 14782 | + *pRc = SQLITE_NOMEM; |
| 14783 | + }else{ |
| 14784 | + memset(pRet, 0, nByte); |
| 14785 | + } |
| 14786 | + } |
| 14787 | + return pRet; |
| 14788 | +} |
| 14789 | + |
| 14790 | +/* |
| 14791 | +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. |
| 14792 | +** Otherwise, zFmt is treated as a printf() style string. The result of |
| 14793 | +** formatting it along with any trailing arguments is written into a |
| 14794 | +** buffer obtained from sqlite3_malloc(), and pointer to which is returned. |
| 14795 | +** It is the responsibility of the caller to eventually free this buffer |
| 14796 | +** using a call to sqlite3_free(). |
| 14797 | +** |
| 14798 | +** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL |
| 14799 | +** pointer returned. |
| 14800 | +*/ |
| 14801 | +static char *shellMPrintf(int *pRc, const char *zFmt, ...){ |
| 14802 | + char *z = 0; |
| 14803 | + if( *pRc==SQLITE_OK ){ |
| 14804 | + va_list ap; |
| 14805 | + va_start(ap, zFmt); |
| 14806 | + z = sqlite3_vmprintf(zFmt, ap); |
| 14807 | + va_end(ap); |
| 14808 | + if( z==0 ){ |
| 14809 | + *pRc = SQLITE_NOMEM; |
| 14810 | + } |
| 14811 | + } |
| 14812 | + return z; |
| 14813 | +} |
| 14814 | + |
| 14815 | +/* |
| 14816 | +** When running the ".recover" command, each output table, and the special |
| 14817 | +** orphaned row table if it is required, is represented by an instance |
| 14818 | +** of the following struct. |
| 14819 | +*/ |
| 14820 | +typedef struct RecoverTable RecoverTable; |
| 14821 | +struct RecoverTable { |
| 14822 | + char *zQuoted; /* Quoted version of table name */ |
| 14823 | + int nCol; /* Number of columns in table */ |
| 14824 | + char **azlCol; /* Array of column lists */ |
| 14825 | + int iPk; /* Index of IPK column */ |
| 14826 | +}; |
| 14827 | + |
| 14828 | +/* |
| 14829 | +** Free a RecoverTable object allocated by recoverFindTable() or |
| 14830 | +** recoverOrphanTable(). |
| 14831 | +*/ |
| 14832 | +static void recoverFreeTable(RecoverTable *pTab){ |
| 14833 | + if( pTab ){ |
| 14834 | + sqlite3_free(pTab->zQuoted); |
| 14835 | + if( pTab->azlCol ){ |
| 14836 | + int i; |
| 14837 | + for(i=0; i<=pTab->nCol; i++){ |
| 14838 | + sqlite3_free(pTab->azlCol[i]); |
| 14839 | + } |
| 14840 | + sqlite3_free(pTab->azlCol); |
| 14841 | + } |
| 14842 | + sqlite3_free(pTab); |
| 14843 | + } |
| 14844 | +} |
| 14845 | + |
| 14846 | +/* |
| 14847 | +** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. |
| 14848 | +** Otherwise, it allocates and returns a RecoverTable object based on the |
| 14849 | +** final four arguments passed to this function. It is the responsibility |
| 14850 | +** of the caller to eventually free the returned object using |
| 14851 | +** recoverFreeTable(). |
| 14852 | +*/ |
| 14853 | +static RecoverTable *recoverNewTable( |
| 14854 | + int *pRc, /* IN/OUT: Error code */ |
| 14855 | + const char *zName, /* Name of table */ |
| 14856 | + const char *zSql, /* CREATE TABLE statement */ |
| 14857 | + int bIntkey, |
| 14858 | + int nCol |
| 14859 | +){ |
| 14860 | + sqlite3 *dbtmp = 0; /* sqlite3 handle for testing CREATE TABLE */ |
| 14861 | + int rc = *pRc; |
| 14862 | + RecoverTable *pTab = 0; |
| 14863 | + |
| 14864 | + pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable)); |
| 14865 | + if( rc==SQLITE_OK ){ |
| 14866 | + int nSqlCol = 0; |
| 14867 | + int bSqlIntkey = 0; |
| 14868 | + sqlite3_stmt *pStmt = 0; |
| 14869 | + |
| 14870 | + rc = sqlite3_open("", &dbtmp); |
| 14871 | + if( rc==SQLITE_OK ){ |
| 14872 | + rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0); |
| 14873 | + } |
| 14874 | + if( rc==SQLITE_OK ){ |
| 14875 | + rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0); |
| 14876 | + if( rc==SQLITE_ERROR ){ |
| 14877 | + rc = SQLITE_OK; |
| 14878 | + goto finished; |
| 14879 | + } |
| 14880 | + } |
| 14881 | + shellPreparePrintf(dbtmp, &rc, &pStmt, |
| 14882 | + "SELECT count(*) FROM pragma_table_info(%Q)", zName |
| 14883 | + ); |
| 14884 | + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 14885 | + nSqlCol = sqlite3_column_int(pStmt, 0); |
| 14886 | + } |
| 14887 | + shellFinalize(&rc, pStmt); |
| 14888 | + |
| 14889 | + if( rc!=SQLITE_OK || nSqlCol<nCol ){ |
| 14890 | + goto finished; |
| 14891 | + } |
| 14892 | + |
| 14893 | + shellPreparePrintf(dbtmp, &rc, &pStmt, |
| 14894 | + "SELECT (" |
| 14895 | + " SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage" |
| 14896 | + ") FROM sqlite_master WHERE name = %Q", zName |
| 14897 | + ); |
| 14898 | + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 14899 | + bSqlIntkey = sqlite3_column_int(pStmt, 0); |
| 14900 | + } |
| 14901 | + shellFinalize(&rc, pStmt); |
| 14902 | + |
| 14903 | + if( bIntkey==bSqlIntkey ){ |
| 14904 | + int i; |
| 14905 | + const char *zPk = "_rowid_"; |
| 14906 | + sqlite3_stmt *pPkFinder = 0; |
| 14907 | + |
| 14908 | + /* If this is an intkey table and there is an INTEGER PRIMARY KEY, |
| 14909 | + ** set zPk to the name of the PK column, and pTab->iPk to the index |
| 14910 | + ** of the column, where columns are 0-numbered from left to right. |
| 14911 | + ** Or, if this is a WITHOUT ROWID table or if there is no IPK column, |
| 14912 | + ** leave zPk as "_rowid_" and pTab->iPk at -2. */ |
| 14913 | + pTab->iPk = -2; |
| 14914 | + if( bIntkey ){ |
| 14915 | + shellPreparePrintf(dbtmp, &rc, &pPkFinder, |
| 14916 | + "SELECT cid, name FROM pragma_table_info(%Q) " |
| 14917 | + " WHERE pk=1 AND type='integer' COLLATE nocase" |
| 14918 | + " AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)" |
| 14919 | + , zName, zName |
| 14920 | + ); |
| 14921 | + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){ |
| 14922 | + pTab->iPk = sqlite3_column_int(pPkFinder, 0); |
| 14923 | + zPk = (const char*)sqlite3_column_text(pPkFinder, 1); |
| 14924 | + } |
| 14925 | + } |
| 14926 | + |
| 14927 | + pTab->zQuoted = shellMPrintf(&rc, "%Q", zName); |
| 14928 | + pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1)); |
| 14929 | + pTab->nCol = nSqlCol; |
| 14930 | + |
| 14931 | + if( bIntkey ){ |
| 14932 | + pTab->azlCol[0] = shellMPrintf(&rc, "%Q", zPk); |
| 14933 | + }else{ |
| 14934 | + pTab->azlCol[0] = shellMPrintf(&rc, ""); |
| 14935 | + } |
| 14936 | + i = 1; |
| 14937 | + shellPreparePrintf(dbtmp, &rc, &pStmt, |
| 14938 | + "SELECT %Q || group_concat(name, ', ') " |
| 14939 | + " FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) " |
| 14940 | + "FROM pragma_table_info(%Q)", |
| 14941 | + bIntkey ? ", " : "", pTab->iPk, |
| 14942 | + bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ", |
| 14943 | + zName |
| 14944 | + ); |
| 14945 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 14946 | + const char *zText = (const char*)sqlite3_column_text(pStmt, 0); |
| 14947 | + pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText); |
| 14948 | + i++; |
| 14949 | + } |
| 14950 | + shellFinalize(&rc, pStmt); |
| 14951 | + |
| 14952 | + shellFinalize(&rc, pPkFinder); |
| 14953 | + } |
| 14954 | + } |
| 14955 | + |
| 14956 | + finished: |
| 14957 | + sqlite3_close(dbtmp); |
| 14958 | + *pRc = rc; |
| 14959 | + if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){ |
| 14960 | + recoverFreeTable(pTab); |
| 14961 | + pTab = 0; |
| 14962 | + } |
| 14963 | + return pTab; |
| 14964 | +} |
| 14965 | + |
| 14966 | +/* |
| 14967 | +** This function is called to search the schema recovered from the |
| 14968 | +** sqlite_master table of the (possibly) corrupt database as part |
| 14969 | +** of a ".recover" command. Specifically, for a table with root page |
| 14970 | +** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the |
| 14971 | +** table must be a WITHOUT ROWID table, or if non-zero, not one of |
| 14972 | +** those. |
| 14973 | +** |
| 14974 | +** If a table is found, a (RecoverTable*) object is returned. Or, if |
| 14975 | +** no such table is found, but bIntkey is false and iRoot is the |
| 14976 | +** root page of an index in the recovered schema, then (*pbNoop) is |
| 14977 | +** set to true and NULL returned. Or, if there is no such table or |
| 14978 | +** index, NULL is returned and (*pbNoop) set to 0, indicating that |
| 14979 | +** the caller should write data to the orphans table. |
| 14980 | +*/ |
| 14981 | +static RecoverTable *recoverFindTable( |
| 14982 | + ShellState *pState, /* Shell state object */ |
| 14983 | + int *pRc, /* IN/OUT: Error code */ |
| 14984 | + int iRoot, /* Root page of table */ |
| 14985 | + int bIntkey, /* True for an intkey table */ |
| 14986 | + int nCol, /* Number of columns in table */ |
| 14987 | + int *pbNoop /* OUT: True if iRoot is root of index */ |
| 14988 | +){ |
| 14989 | + sqlite3_stmt *pStmt = 0; |
| 14990 | + RecoverTable *pRet = 0; |
| 14991 | + int bNoop = 0; |
| 14992 | + const char *zSql = 0; |
| 14993 | + const char *zName = 0; |
| 14994 | + |
| 14995 | + /* Search the recovered schema for an object with root page iRoot. */ |
| 14996 | + shellPreparePrintf(pState->db, pRc, &pStmt, |
| 14997 | + "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot |
| 14998 | + ); |
| 14999 | + while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 15000 | + const char *zType = (const char*)sqlite3_column_text(pStmt, 0); |
| 15001 | + if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){ |
| 15002 | + bNoop = 1; |
| 15003 | + break; |
| 15004 | + } |
| 15005 | + if( sqlite3_stricmp(zType, "table")==0 ){ |
| 15006 | + zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 15007 | + zSql = (const char*)sqlite3_column_text(pStmt, 2); |
| 15008 | + pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol); |
| 15009 | + break; |
| 15010 | + } |
| 15011 | + } |
| 15012 | + |
| 15013 | + shellFinalize(pRc, pStmt); |
| 15014 | + *pbNoop = bNoop; |
| 15015 | + return pRet; |
| 15016 | +} |
| 15017 | + |
| 15018 | +/* |
| 15019 | +** Return a RecoverTable object representing the orphans table. |
| 15020 | +*/ |
| 15021 | +static RecoverTable *recoverOrphanTable( |
| 15022 | + ShellState *pState, /* Shell state object */ |
| 15023 | + int *pRc, /* IN/OUT: Error code */ |
| 15024 | + const char *zLostAndFound, /* Base name for orphans table */ |
| 15025 | + int nCol /* Number of user data columns */ |
| 15026 | +){ |
| 15027 | + RecoverTable *pTab = 0; |
| 15028 | + if( nCol>=0 && *pRc==SQLITE_OK ){ |
| 15029 | + int i; |
| 15030 | + |
| 15031 | + /* This block determines the name of the orphan table. The prefered |
| 15032 | + ** name is zLostAndFound. But if that clashes with another name |
| 15033 | + ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1 |
| 15034 | + ** and so on until a non-clashing name is found. */ |
| 15035 | + int iTab = 0; |
| 15036 | + char *zTab = shellMPrintf(pRc, "%s", zLostAndFound); |
| 15037 | + sqlite3_stmt *pTest = 0; |
| 15038 | + shellPrepare(pState->db, pRc, |
| 15039 | + "SELECT 1 FROM recovery.schema WHERE name=?", &pTest |
| 15040 | + ); |
| 15041 | + if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); |
| 15042 | + while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){ |
| 15043 | + shellReset(pRc, pTest); |
| 15044 | + sqlite3_free(zTab); |
| 15045 | + zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++); |
| 15046 | + sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); |
| 15047 | + } |
| 15048 | + shellFinalize(pRc, pTest); |
| 15049 | + |
| 15050 | + pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable)); |
| 15051 | + if( pTab ){ |
| 15052 | + pTab->zQuoted = shellMPrintf(pRc, "%Q", zTab); |
| 15053 | + pTab->nCol = nCol; |
| 15054 | + pTab->iPk = -2; |
| 15055 | + if( nCol>0 ){ |
| 15056 | + pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1)); |
| 15057 | + if( pTab->azlCol ){ |
| 15058 | + pTab->azlCol[nCol] = shellMPrintf(pRc, ""); |
| 15059 | + for(i=nCol-1; i>=0; i--){ |
| 15060 | + pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]); |
| 15061 | + } |
| 15062 | + } |
| 15063 | + } |
| 15064 | + |
| 15065 | + if( *pRc!=SQLITE_OK ){ |
| 15066 | + recoverFreeTable(pTab); |
| 15067 | + pTab = 0; |
| 15068 | + }else{ |
| 15069 | + raw_printf(pState->out, |
| 15070 | + "CREATE TABLE %s(rootpgno INTEGER, " |
| 15071 | + "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted |
| 15072 | + ); |
| 15073 | + for(i=0; i<nCol; i++){ |
| 15074 | + raw_printf(pState->out, ", c%d", i); |
| 15075 | + } |
| 15076 | + raw_printf(pState->out, ");\n"); |
| 15077 | + } |
| 15078 | + } |
| 15079 | + sqlite3_free(zTab); |
| 15080 | + } |
| 15081 | + return pTab; |
| 15082 | +} |
| 15083 | + |
| 15084 | +/* |
| 15085 | +** This function is called to recover data from the database. A script |
| 15086 | +** to construct a new database containing all recovered data is output |
| 15087 | +** on stream pState->out. |
| 15088 | +*/ |
| 15089 | +static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ |
| 15090 | + int rc = SQLITE_OK; |
| 15091 | + sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ |
| 15092 | + sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ |
| 15093 | + sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ |
| 15094 | + const char *zRecoveryDb = ""; /* Name of "recovery" database */ |
| 15095 | + const char *zLostAndFound = "lost_and_found"; |
| 15096 | + int i; |
| 15097 | + int nOrphan = -1; |
| 15098 | + RecoverTable *pOrphan = 0; |
| 15099 | + |
| 15100 | + int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ |
| 15101 | + for(i=1; i<nArg; i++){ |
| 15102 | + char *z = azArg[i]; |
| 15103 | + int n; |
| 15104 | + if( z[0]=='-' && z[1]=='-' ) z++; |
| 15105 | + n = strlen(z); |
| 15106 | + if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){ |
| 15107 | + bFreelist = 0; |
| 15108 | + }else |
| 15109 | + if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){ |
| 15110 | + i++; |
| 15111 | + zRecoveryDb = azArg[i]; |
| 15112 | + }else |
| 15113 | + if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){ |
| 15114 | + i++; |
| 15115 | + zLostAndFound = azArg[i]; |
| 15116 | + } |
| 15117 | + else{ |
| 15118 | + raw_printf(stderr, "unexpected option: %s\n", azArg[i]); |
| 15119 | + raw_printf(stderr, "options are:\n"); |
| 15120 | + raw_printf(stderr, " --freelist-corrupt\n"); |
| 15121 | + raw_printf(stderr, " --recovery-db DATABASE\n"); |
| 15122 | + raw_printf(stderr, " --lost-and-found TABLE-NAME\n"); |
| 15123 | + return 1; |
| 15124 | + } |
| 15125 | + } |
| 15126 | + |
| 15127 | + shellExecPrintf(pState->db, &rc, |
| 15128 | + /* Attach an in-memory database named 'recovery'. Create an indexed |
| 15129 | + ** cache of the sqlite_dbptr virtual table. */ |
| 15130 | + "ATTACH %Q AS recovery;" |
| 15131 | + "DROP TABLE IF EXISTS recovery.dbptr;" |
| 15132 | + "DROP TABLE IF EXISTS recovery.freelist;" |
| 15133 | + "DROP TABLE IF EXISTS recovery.map;" |
| 15134 | + "DROP TABLE IF EXISTS recovery.schema;" |
| 15135 | + "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb |
| 15136 | + ); |
| 15137 | + |
| 15138 | + if( bFreelist ){ |
| 15139 | + shellExec(pState->db, &rc, |
| 15140 | + "WITH trunk(pgno) AS (" |
| 15141 | + " SELECT shell_int32(" |
| 15142 | + " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x " |
| 15143 | + " WHERE x>0" |
| 15144 | + " UNION" |
| 15145 | + " SELECT shell_int32(" |
| 15146 | + " (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x " |
| 15147 | + " FROM trunk WHERE x>0" |
| 15148 | + ")," |
| 15149 | + "freelist(data, n, freepgno) AS (" |
| 15150 | + " SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno " |
| 15151 | + " FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno" |
| 15152 | + " UNION ALL" |
| 15153 | + " SELECT data, n-1, shell_int32(data, 2+n) " |
| 15154 | + " FROM freelist WHERE n>=0" |
| 15155 | + ")" |
| 15156 | + "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;" |
| 15157 | + ); |
| 15158 | + } |
| 15159 | + |
| 15160 | + shellExec(pState->db, &rc, |
| 15161 | + "CREATE TABLE recovery.dbptr(" |
| 15162 | + " pgno, child, PRIMARY KEY(child, pgno)" |
| 15163 | + ") WITHOUT ROWID;" |
| 15164 | + "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) " |
| 15165 | + " SELECT * FROM sqlite_dbptr" |
| 15166 | + " WHERE pgno NOT IN freelist AND child NOT IN freelist;" |
| 15167 | + |
| 15168 | + /* Delete any pointer to page 1. This ensures that page 1 is considered |
| 15169 | + ** a root page, regardless of how corrupt the db is. */ |
| 15170 | + "DELETE FROM recovery.dbptr WHERE child = 1;" |
| 15171 | + |
| 15172 | + /* Delete all pointers to any pages that have more than one pointer |
| 15173 | + ** to them. Such pages will be treated as root pages when recovering |
| 15174 | + ** data. */ |
| 15175 | + "DELETE FROM recovery.dbptr WHERE child IN (" |
| 15176 | + " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1" |
| 15177 | + ");" |
| 15178 | + |
| 15179 | + /* Create the "map" table that will (eventually) contain instructions |
| 15180 | + ** for dealing with each page in the db that contains one or more |
| 15181 | + ** records. */ |
| 15182 | + "CREATE TABLE recovery.map(" |
| 15183 | + "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT" |
| 15184 | + ");" |
| 15185 | + |
| 15186 | + /* Populate table [map]. If there are circular loops of pages in the |
| 15187 | + ** database, the following adds all pages in such a loop to the map |
| 15188 | + ** as individual root pages. This could be handled better. */ |
| 15189 | + "WITH pages(i, maxlen) AS (" |
| 15190 | + " SELECT page_count, (" |
| 15191 | + " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count" |
| 15192 | + " ) FROM pragma_page_count WHERE page_count>0" |
| 15193 | + " UNION ALL" |
| 15194 | + " SELECT i-1, (" |
| 15195 | + " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1" |
| 15196 | + " ) FROM pages WHERE i>=2" |
| 15197 | + ")" |
| 15198 | + "INSERT INTO recovery.map(pgno, maxlen, intkey, root) " |
| 15199 | + " SELECT i, maxlen, NULL, (" |
| 15200 | + " WITH p(orig, pgno, parent) AS (" |
| 15201 | + " SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)" |
| 15202 | + " UNION " |
| 15203 | + " SELECT i, p.parent, " |
| 15204 | + " (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p" |
| 15205 | + " )" |
| 15206 | + " SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)" |
| 15207 | + ") " |
| 15208 | + "FROM pages WHERE maxlen > 0 AND i NOT IN freelist;" |
| 15209 | + "UPDATE recovery.map AS o SET intkey = (" |
| 15210 | + " SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno" |
| 15211 | + ");" |
| 15212 | + |
| 15213 | + /* Extract data from page 1 and any linked pages into table |
| 15214 | + ** recovery.schema. With the same schema as an sqlite_master table. */ |
| 15215 | + "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);" |
| 15216 | + "INSERT INTO recovery.schema SELECT " |
| 15217 | + " max(CASE WHEN field=0 THEN value ELSE NULL END)," |
| 15218 | + " max(CASE WHEN field=1 THEN value ELSE NULL END)," |
| 15219 | + " max(CASE WHEN field=2 THEN value ELSE NULL END)," |
| 15220 | + " max(CASE WHEN field=3 THEN value ELSE NULL END)," |
| 15221 | + " max(CASE WHEN field=4 THEN value ELSE NULL END)" |
| 15222 | + "FROM sqlite_dbdata WHERE pgno IN (" |
| 15223 | + " SELECT pgno FROM recovery.map WHERE root=1" |
| 15224 | + ")" |
| 15225 | + "GROUP BY pgno, cell;" |
| 15226 | + "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);" |
| 15227 | + ); |
| 15228 | + |
| 15229 | + /* Open a transaction, then print out all non-virtual, non-"sqlite_%" |
| 15230 | + ** CREATE TABLE statements that extracted from the existing schema. */ |
| 15231 | + if( rc==SQLITE_OK ){ |
| 15232 | + sqlite3_stmt *pStmt = 0; |
| 15233 | + raw_printf(pState->out, "BEGIN;\n"); |
| 15234 | + raw_printf(pState->out, "PRAGMA writable_schema = on;\n"); |
| 15235 | + shellPrepare(pState->db, &rc, |
| 15236 | + "SELECT sql FROM recovery.schema " |
| 15237 | + "WHERE type='table' AND sql LIKE 'create table%'", &pStmt |
| 15238 | + ); |
| 15239 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 15240 | + const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0); |
| 15241 | + raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n", |
| 15242 | + &zCreateTable[12] |
| 15243 | + ); |
| 15244 | + } |
| 15245 | + shellFinalize(&rc, pStmt); |
| 15246 | + } |
| 15247 | + |
| 15248 | + /* Figure out if an orphan table will be required. And if so, how many |
| 15249 | + ** user columns it should contain */ |
| 15250 | + shellPrepare(pState->db, &rc, |
| 15251 | + "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1" |
| 15252 | + , &pLoop |
| 15253 | + ); |
| 15254 | + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ |
| 15255 | + nOrphan = sqlite3_column_int(pLoop, 0); |
| 15256 | + } |
| 15257 | + shellFinalize(&rc, pLoop); |
| 15258 | + pLoop = 0; |
| 15259 | + |
| 15260 | + shellPrepare(pState->db, &rc, |
| 15261 | + "SELECT pgno FROM recovery.map WHERE root=?", &pPages |
| 15262 | + ); |
| 15263 | + shellPrepare(pState->db, &rc, |
| 15264 | + "SELECT max(field), group_concat(shell_escape_crnl(quote(value)), ', ')" |
| 15265 | + "FROM sqlite_dbdata WHERE pgno = ? AND field != ?" |
| 15266 | + "GROUP BY cell", &pCells |
| 15267 | + ); |
| 15268 | + |
| 15269 | + /* Loop through each root page. */ |
| 15270 | + shellPrepare(pState->db, &rc, |
| 15271 | + "SELECT root, intkey, max(maxlen) FROM recovery.map" |
| 15272 | + " WHERE root>1 GROUP BY root, intkey ORDER BY root=(" |
| 15273 | + " SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'" |
| 15274 | + ")", &pLoop |
| 15275 | + ); |
| 15276 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ |
| 15277 | + int iRoot = sqlite3_column_int(pLoop, 0); |
| 15278 | + int bIntkey = sqlite3_column_int(pLoop, 1); |
| 15279 | + int nCol = sqlite3_column_int(pLoop, 2); |
| 15280 | + int bNoop = 0; |
| 15281 | + RecoverTable *pTab; |
| 15282 | + |
| 15283 | + pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop); |
| 15284 | + if( bNoop || rc ) continue; |
| 15285 | + if( pTab==0 ){ |
| 15286 | + if( pOrphan==0 ){ |
| 15287 | + pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); |
| 15288 | + } |
| 15289 | + pTab = pOrphan; |
| 15290 | + if( pTab==0 ) break; |
| 15291 | + } |
| 15292 | + |
| 15293 | + if( 0==sqlite3_stricmp(pTab->zQuoted, "'sqlite_sequence'") ){ |
| 15294 | + raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n"); |
| 15295 | + } |
| 15296 | + sqlite3_bind_int(pPages, 1, iRoot); |
| 15297 | + sqlite3_bind_int(pCells, 2, pTab->iPk); |
| 15298 | + |
| 15299 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){ |
| 15300 | + int iPgno = sqlite3_column_int(pPages, 0); |
| 15301 | + sqlite3_bind_int(pCells, 1, iPgno); |
| 15302 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){ |
| 15303 | + int nField = sqlite3_column_int(pCells, 0); |
| 15304 | + const char *zVal = (const char*)sqlite3_column_text(pCells, 1); |
| 15305 | + |
| 15306 | + nField = nField+1; |
| 15307 | + if( pTab==pOrphan ){ |
| 15308 | + raw_printf(pState->out, |
| 15309 | + "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n", |
| 15310 | + pTab->zQuoted, iRoot, iPgno, nField, |
| 15311 | + bIntkey ? "" : "NULL, ", zVal, pTab->azlCol[nField] |
| 15312 | + ); |
| 15313 | + }else{ |
| 15314 | + raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n", |
| 15315 | + pTab->zQuoted, pTab->azlCol[nField], zVal |
| 15316 | + ); |
| 15317 | + } |
| 15318 | + } |
| 15319 | + shellReset(&rc, pCells); |
| 15320 | + } |
| 15321 | + shellReset(&rc, pPages); |
| 15322 | + if( pTab!=pOrphan ) recoverFreeTable(pTab); |
| 15323 | + } |
| 15324 | + shellFinalize(&rc, pLoop); |
| 15325 | + shellFinalize(&rc, pPages); |
| 15326 | + shellFinalize(&rc, pCells); |
| 15327 | + recoverFreeTable(pOrphan); |
| 15328 | + |
| 15329 | + /* The rest of the schema */ |
| 15330 | + if( rc==SQLITE_OK ){ |
| 15331 | + sqlite3_stmt *pStmt = 0; |
| 15332 | + shellPrepare(pState->db, &rc, |
| 15333 | + "SELECT sql, name FROM recovery.schema " |
| 15334 | + "WHERE sql NOT LIKE 'create table%'", &pStmt |
| 15335 | + ); |
| 15336 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 15337 | + const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); |
| 15338 | + if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){ |
| 15339 | + const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 15340 | + char *zPrint = shellMPrintf(&rc, |
| 15341 | + "INSERT INTO sqlite_master VALUES('table', %Q, %Q, 0, %Q)", |
| 15342 | + zName, zName, zSql |
| 15343 | + ); |
| 15344 | + raw_printf(pState->out, "%s;\n", zPrint); |
| 15345 | + sqlite3_free(zPrint); |
| 15346 | + }else{ |
| 15347 | + raw_printf(pState->out, "%s;\n", zSql); |
| 15348 | + } |
| 15349 | + } |
| 15350 | + shellFinalize(&rc, pStmt); |
| 15351 | + } |
| 15352 | + |
| 15353 | + if( rc==SQLITE_OK ){ |
| 15354 | + raw_printf(pState->out, "PRAGMA writable_schema = off;\n"); |
| 15355 | + raw_printf(pState->out, "COMMIT;\n"); |
| 15356 | + } |
| 15357 | + sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0); |
| 15358 | + return rc; |
| 15359 | +} |
| 15360 | +#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ |
| 15361 | + |
| 13605 | 15362 | |
| 13606 | 15363 | /* |
| 13607 | 15364 | ** If an input line begins with "." then invoke this routine to |
| 13608 | 15365 | ** process that line. |
| 13609 | 15366 | ** |
| | @@ -13887,10 +15644,17 @@ |
| 13887 | 15644 | |
| 13888 | 15645 | if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 13889 | 15646 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 13890 | 15647 | }else |
| 13891 | 15648 | |
| 15649 | +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 15650 | + if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){ |
| 15651 | + open_db(p, 0); |
| 15652 | + rc = recoverDatabaseCmd(p, nArg, azArg); |
| 15653 | + }else |
| 15654 | +#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ |
| 15655 | + |
| 13892 | 15656 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ |
| 13893 | 15657 | const char *zLike = 0; |
| 13894 | 15658 | int i; |
| 13895 | 15659 | int savedShowHeader = p->showHeader; |
| 13896 | 15660 | int savedShellFlags = p->shellFlgs; |
| | @@ -13924,11 +15688,13 @@ |
| 13924 | 15688 | goto meta_command_exit; |
| 13925 | 15689 | }else{ |
| 13926 | 15690 | zLike = azArg[i]; |
| 13927 | 15691 | } |
| 13928 | 15692 | } |
| 15693 | + |
| 13929 | 15694 | open_db(p, 0); |
| 15695 | + |
| 13930 | 15696 | /* When playing back a "dump", the content might appear in an order |
| 13931 | 15697 | ** which causes immediate foreign key constraints to be violated. |
| 13932 | 15698 | ** So disable foreign-key constraint enforcement to prevent problems. */ |
| 13933 | 15699 | raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n"); |
| 13934 | 15700 | raw_printf(p->out, "BEGIN TRANSACTION;\n"); |
| | @@ -13972,11 +15738,11 @@ |
| 13972 | 15738 | raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); |
| 13973 | 15739 | p->writableSchema = 0; |
| 13974 | 15740 | } |
| 13975 | 15741 | sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); |
| 13976 | 15742 | sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); |
| 13977 | | - raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); |
| 15743 | + raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n"); |
| 13978 | 15744 | p->showHeader = savedShowHeader; |
| 13979 | 15745 | p->shellFlgs = savedShellFlags; |
| 13980 | 15746 | }else |
| 13981 | 15747 | |
| 13982 | 15748 | if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ |
| | @@ -14708,10 +16474,118 @@ |
| 14708 | 16474 | } else { |
| 14709 | 16475 | sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); |
| 14710 | 16476 | } |
| 14711 | 16477 | } |
| 14712 | 16478 | }else |
| 16479 | + |
| 16480 | + if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){ |
| 16481 | + open_db(p,0); |
| 16482 | + if( nArg<=1 ) goto parameter_syntax_error; |
| 16483 | + |
| 16484 | + /* .parameter clear |
| 16485 | + ** Clear all bind parameters by dropping the TEMP table that holds them. |
| 16486 | + */ |
| 16487 | + if( nArg==2 && strcmp(azArg[1],"clear")==0 ){ |
| 16488 | + int wrSchema = 0; |
| 16489 | + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); |
| 16490 | + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); |
| 16491 | + sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;", |
| 16492 | + 0, 0, 0); |
| 16493 | + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); |
| 16494 | + }else |
| 16495 | + |
| 16496 | + /* .parameter list |
| 16497 | + ** List all bind parameters. |
| 16498 | + */ |
| 16499 | + if( nArg==2 && strcmp(azArg[1],"list")==0 ){ |
| 16500 | + sqlite3_stmt *pStmt = 0; |
| 16501 | + int rx; |
| 16502 | + int len = 0; |
| 16503 | + rx = sqlite3_prepare_v2(p->db, |
| 16504 | + "SELECT max(length(key)) " |
| 16505 | + "FROM temp.sqlite_parameters;", -1, &pStmt, 0); |
| 16506 | + if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 16507 | + len = sqlite3_column_int(pStmt, 0); |
| 16508 | + if( len>40 ) len = 40; |
| 16509 | + } |
| 16510 | + sqlite3_finalize(pStmt); |
| 16511 | + pStmt = 0; |
| 16512 | + if( len ){ |
| 16513 | + rx = sqlite3_prepare_v2(p->db, |
| 16514 | + "SELECT key, quote(value) " |
| 16515 | + "FROM temp.sqlite_parameters;", -1, &pStmt, 0); |
| 16516 | + while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 16517 | + utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), |
| 16518 | + sqlite3_column_text(pStmt,1)); |
| 16519 | + } |
| 16520 | + sqlite3_finalize(pStmt); |
| 16521 | + } |
| 16522 | + }else |
| 16523 | + |
| 16524 | + /* .parameter init |
| 16525 | + ** Make sure the TEMP table used to hold bind parameters exists. |
| 16526 | + ** Create it if necessary. |
| 16527 | + */ |
| 16528 | + if( nArg==2 && strcmp(azArg[1],"init")==0 ){ |
| 16529 | + bind_table_init(p); |
| 16530 | + }else |
| 16531 | + |
| 16532 | + /* .parameter set NAME VALUE |
| 16533 | + ** Set or reset a bind parameter. NAME should be the full parameter |
| 16534 | + ** name exactly as it appears in the query. (ex: $abc, @def). The |
| 16535 | + ** VALUE can be in either SQL literal notation, or if not it will be |
| 16536 | + ** understood to be a text string. |
| 16537 | + */ |
| 16538 | + if( nArg==4 && strcmp(azArg[1],"set")==0 ){ |
| 16539 | + int rx; |
| 16540 | + char *zSql; |
| 16541 | + sqlite3_stmt *pStmt; |
| 16542 | + const char *zKey = azArg[2]; |
| 16543 | + const char *zValue = azArg[3]; |
| 16544 | + bind_table_init(p); |
| 16545 | + zSql = sqlite3_mprintf( |
| 16546 | + "REPLACE INTO temp.sqlite_parameters(key,value)" |
| 16547 | + "VALUES(%Q,%s);", zKey, zValue); |
| 16548 | + if( zSql==0 ) shell_out_of_memory(); |
| 16549 | + pStmt = 0; |
| 16550 | + rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 16551 | + sqlite3_free(zSql); |
| 16552 | + if( rx!=SQLITE_OK ){ |
| 16553 | + sqlite3_finalize(pStmt); |
| 16554 | + pStmt = 0; |
| 16555 | + zSql = sqlite3_mprintf( |
| 16556 | + "REPLACE INTO temp.sqlite_parameters(key,value)" |
| 16557 | + "VALUES(%Q,%Q);", zKey, zValue); |
| 16558 | + if( zSql==0 ) shell_out_of_memory(); |
| 16559 | + rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 16560 | + sqlite3_free(zSql); |
| 16561 | + if( rx!=SQLITE_OK ){ |
| 16562 | + utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db)); |
| 16563 | + sqlite3_finalize(pStmt); |
| 16564 | + pStmt = 0; |
| 16565 | + rc = 1; |
| 16566 | + } |
| 16567 | + } |
| 16568 | + sqlite3_step(pStmt); |
| 16569 | + sqlite3_finalize(pStmt); |
| 16570 | + }else |
| 16571 | + |
| 16572 | + /* .parameter unset NAME |
| 16573 | + ** Remove the NAME binding from the parameter binding table, if it |
| 16574 | + ** exists. |
| 16575 | + */ |
| 16576 | + if( nArg==3 && strcmp(azArg[1],"unset")==0 ){ |
| 16577 | + char *zSql = sqlite3_mprintf( |
| 16578 | + "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]); |
| 16579 | + if( zSql==0 ) shell_out_of_memory(); |
| 16580 | + sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 16581 | + sqlite3_free(zSql); |
| 16582 | + }else |
| 16583 | + /* If no command name matches, show a syntax error */ |
| 16584 | + parameter_syntax_error: |
| 16585 | + showHelp(p->out, "parameter"); |
| 16586 | + }else |
| 14713 | 16587 | |
| 14714 | 16588 | if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ |
| 14715 | 16589 | int i; |
| 14716 | 16590 | for(i=1; i<nArg; i++){ |
| 14717 | 16591 | if( i>1 ) raw_printf(p->out, " "); |
| 14718 | 16592 | |