| | @@ -673,11 +673,11 @@ |
| 673 | 673 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 674 | 674 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 675 | 675 | */ |
| 676 | 676 | #define SQLITE_VERSION "3.7.15" |
| 677 | 677 | #define SQLITE_VERSION_NUMBER 3007015 |
| 678 | | -#define SQLITE_SOURCE_ID "2012-10-05 07:36:34 43155b1543bddbb84a8bc13a5b7344b228ddacb9" |
| 678 | +#define SQLITE_SOURCE_ID "2012-10-07 14:14:44 bbb0d189b7b6aecfc0e0b6c2bcd9f49aaea8c34a" |
| 679 | 679 | |
| 680 | 680 | /* |
| 681 | 681 | ** CAPI3REF: Run-Time Library Version Numbers |
| 682 | 682 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 683 | 683 | ** |
| | @@ -1804,15 +1804,15 @@ |
| 1804 | 1804 | SQLITE_API int sqlite3_os_end(void); |
| 1805 | 1805 | |
| 1806 | 1806 | /* |
| 1807 | 1807 | ** CAPI3REF: Configuring The SQLite Library |
| 1808 | 1808 | ** |
| 1809 | | -** The sqlite3_config() interface is used to make global configuration |
| 1810 | | -** changes to SQLite in order to tune SQLite to the specific needs of |
| 1811 | | -** the application. The default configuration is recommended for most |
| 1812 | | -** applications and so this routine is usually not necessary. It is |
| 1813 | | -** provided to support rare applications with unusual needs. |
| 1809 | +** The sqlite3_config() and sqlite3_reconfig() interfaces are used to make |
| 1810 | +** global configuration changes to SQLite in order to tune SQLite to the |
| 1811 | +** specific needs of the application. The default configuration is recommended |
| 1812 | +** for most applications and so this routine is usually not necessary. They |
| 1813 | +** are provided to support rare applications with unusual needs. |
| 1814 | 1814 | ** |
| 1815 | 1815 | ** The sqlite3_config() interface is not threadsafe. The application |
| 1816 | 1816 | ** must insure that no other SQLite interfaces are invoked by other |
| 1817 | 1817 | ** threads while sqlite3_config() is running. Furthermore, sqlite3_config() |
| 1818 | 1818 | ** may only be invoked prior to library initialization using |
| | @@ -1820,21 +1820,27 @@ |
| 1820 | 1820 | ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before |
| 1821 | 1821 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1822 | 1822 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1823 | 1823 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1824 | 1824 | ** |
| 1825 | | -** The first argument to sqlite3_config() is an integer |
| 1826 | | -** [configuration option] that determines |
| 1825 | +** The sqlite3_reconfig() interface is threadsafe and may be called at any |
| 1826 | +** time. However, it supports only a small subset of the configuration |
| 1827 | +** options available for use with sqlite3_config(). |
| 1828 | +** |
| 1829 | +** The first argument to both sqlite3_config() and sqlite3_reconfig() is an |
| 1830 | +** integer [configuration option] that determines |
| 1827 | 1831 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1828 | 1832 | ** vary depending on the [configuration option] |
| 1829 | 1833 | ** in the first argument. |
| 1830 | 1834 | ** |
| 1831 | | -** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1835 | +** ^When a configuration option is set, both sqlite3_config() and |
| 1836 | +** sqlite3_reconfig() return [SQLITE_OK]. |
| 1832 | 1837 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1833 | | -** then this routine returns a non-zero [error code]. |
| 1838 | +** then these routines returns a non-zero [error code]. |
| 1834 | 1839 | */ |
| 1835 | 1840 | SQLITE_API int sqlite3_config(int, ...); |
| 1841 | +SQLITE_API int sqlite3_reconfig(int, ...); |
| 1836 | 1842 | |
| 1837 | 1843 | /* |
| 1838 | 1844 | ** CAPI3REF: Configure database connections |
| 1839 | 1845 | ** |
| 1840 | 1846 | ** The sqlite3_db_config() interface is used to make configuration |
| | @@ -2155,10 +2161,23 @@ |
| 2155 | 2161 | ** The ability to disable the use of covering indices for full table scans |
| 2156 | 2162 | ** is because some incorrectly coded legacy applications might malfunction |
| 2157 | 2163 | ** malfunction when the optimization is enabled. Providing the ability to |
| 2158 | 2164 | ** disable the optimization allows the older, buggy application code to work |
| 2159 | 2165 | ** without change even with newer versions of SQLite. |
| 2166 | +** |
| 2167 | +** [[SQLITE_CONFIG_READONLY]] <dt>SQLITE_CONFIG_READONLY |
| 2168 | +** <dd> This option takes a single argument of type int. If non-zero, then |
| 2169 | +** read-only mode for opening databases is globally enabled. If the parameter |
| 2170 | +** is zero, then read-only mode for opening databases is globally disabled. If |
| 2171 | +** read-only mode for opening databases is globally enabled, all databases |
| 2172 | +** opened by [sqlite3_open()], [sqlite3_open16()], or specified as part of |
| 2173 | +** [ATTACH] commands will be opened in read-only mode. Additionally, all calls |
| 2174 | +** to [sqlite3_open_v2()] must have the [SQLITE_OPEN_READONLY] flag set in the |
| 2175 | +** third argument; otherwise, a [SQLITE_READONLY] error will be returned. If it |
| 2176 | +** is globally disabled, [sqlite3_open()], [sqlite3_open16()], |
| 2177 | +** [sqlite3_open_v2()], and [ATTACH] commands will function normally. By |
| 2178 | +** default, read-only mode is globally disabled. |
| 2160 | 2179 | ** |
| 2161 | 2180 | ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] |
| 2162 | 2181 | ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE |
| 2163 | 2182 | ** <dd> These options are obsolete and should not be used by new code. |
| 2164 | 2183 | ** They are retained for backwards compatibility but are now no-ops. |
| | @@ -2182,10 +2201,11 @@ |
| 2182 | 2201 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 2183 | 2202 | #define SQLITE_CONFIG_URI 17 /* int */ |
| 2184 | 2203 | #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ |
| 2185 | 2204 | #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ |
| 2186 | 2205 | #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ |
| 2206 | +#define SQLITE_CONFIG_READONLY 21 /* int */ |
| 2187 | 2207 | |
| 2188 | 2208 | /* |
| 2189 | 2209 | ** CAPI3REF: Database Connection Configuration Options |
| 2190 | 2210 | ** |
| 2191 | 2211 | ** These constants are the available integer configuration options that |
| | @@ -10905,10 +10925,11 @@ |
| 10905 | 10925 | */ |
| 10906 | 10926 | struct SrcList { |
| 10907 | 10927 | i16 nSrc; /* Number of tables or subqueries in the FROM clause */ |
| 10908 | 10928 | i16 nAlloc; /* Number of entries allocated in a[] below */ |
| 10909 | 10929 | struct SrcList_item { |
| 10930 | + Schema *pSchema; /* Schema to which this item is fixed */ |
| 10910 | 10931 | char *zDatabase; /* Name of database holding this table */ |
| 10911 | 10932 | char *zName; /* Name of the table */ |
| 10912 | 10933 | char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ |
| 10913 | 10934 | Table *pTab; /* An SQL table corresponding to zName */ |
| 10914 | 10935 | Select *pSelect; /* A SELECT statement used in place of a table name */ |
| | @@ -11473,10 +11494,11 @@ |
| 11473 | 11494 | ** explicit. |
| 11474 | 11495 | */ |
| 11475 | 11496 | typedef struct DbFixer DbFixer; |
| 11476 | 11497 | struct DbFixer { |
| 11477 | 11498 | Parse *pParse; /* The parsing context. Error messages written here */ |
| 11499 | + Schema *pSchema; /* Fix items to this schema */ |
| 11478 | 11500 | const char *zDb; /* Make sure all objects are contained in this database */ |
| 11479 | 11501 | const char *zType; /* Type of the container - used for error messages */ |
| 11480 | 11502 | const Token *pName; /* Name of the container - used for error messages */ |
| 11481 | 11503 | }; |
| 11482 | 11504 | |
| | @@ -11516,10 +11538,11 @@ |
| 11516 | 11538 | int bMemstat; /* True to enable memory status */ |
| 11517 | 11539 | int bCoreMutex; /* True to enable core mutexing */ |
| 11518 | 11540 | int bFullMutex; /* True to enable full mutexing */ |
| 11519 | 11541 | int bOpenUri; /* True to interpret filenames as URIs */ |
| 11520 | 11542 | int bUseCis; /* Use covering indices for full-scans */ |
| 11543 | + int bReadOnly; /* True to force read-only mode */ |
| 11521 | 11544 | int mxStrlen; /* Maximum string length */ |
| 11522 | 11545 | int szLookaside; /* Default lookaside buffer size */ |
| 11523 | 11546 | int nLookaside; /* Default lookaside buffer count */ |
| 11524 | 11547 | sqlite3_mem_methods m; /* Low-level memory allocation interface */ |
| 11525 | 11548 | sqlite3_mutex_methods mutex; /* Low-level mutex interface */ |
| | @@ -11883,10 +11906,11 @@ |
| 11883 | 11906 | SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int); |
| 11884 | 11907 | SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); |
| 11885 | 11908 | SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); |
| 11886 | 11909 | SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); |
| 11887 | 11910 | SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); |
| 11911 | +SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); |
| 11888 | 11912 | SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); |
| 11889 | 11913 | SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); |
| 11890 | 11914 | SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); |
| 11891 | 11915 | SQLITE_PRIVATE void sqlite3Vacuum(Parse*); |
| 11892 | 11916 | SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*); |
| | @@ -12113,11 +12137,11 @@ |
| 12113 | 12137 | SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); |
| 12114 | 12138 | SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); |
| 12115 | 12139 | SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); |
| 12116 | 12140 | SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); |
| 12117 | 12141 | SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); |
| 12118 | | -SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*); |
| 12142 | +SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); |
| 12119 | 12143 | SQLITE_PRIVATE char sqlite3AffinityType(const char*); |
| 12120 | 12144 | SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); |
| 12121 | 12145 | SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*); |
| 12122 | 12146 | SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); |
| 12123 | 12147 | SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *); |
| | @@ -12520,10 +12544,11 @@ |
| 12520 | 12544 | SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ |
| 12521 | 12545 | 1, /* bCoreMutex */ |
| 12522 | 12546 | SQLITE_THREADSAFE==1, /* bFullMutex */ |
| 12523 | 12547 | SQLITE_USE_URI, /* bOpenUri */ |
| 12524 | 12548 | SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ |
| 12549 | + 0, /* bReadOnly */ |
| 12525 | 12550 | 0x7ffffffe, /* mxStrlen */ |
| 12526 | 12551 | 128, /* szLookaside */ |
| 12527 | 12552 | 500, /* nLookaside */ |
| 12528 | 12553 | {0,0,0,0,0,0,0,0}, /* m */ |
| 12529 | 12554 | {0,0,0,0,0,0,0,0,0}, /* mutex */ |
| | @@ -30337,11 +30362,15 @@ |
| 30337 | 30362 | #endif |
| 30338 | 30363 | |
| 30339 | 30364 | #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ |
| 30340 | 30365 | DWORD,va_list*))aSyscall[15].pCurrent) |
| 30341 | 30366 | |
| 30367 | +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) |
| 30342 | 30368 | { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, |
| 30369 | +#else |
| 30370 | + { "FreeLibrary", (SYSCALL)0, 0 }, |
| 30371 | +#endif |
| 30343 | 30372 | |
| 30344 | 30373 | #define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent) |
| 30345 | 30374 | |
| 30346 | 30375 | { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, |
| 30347 | 30376 | |
| | @@ -30418,18 +30447,22 @@ |
| 30418 | 30447 | |
| 30419 | 30448 | { "GetLastError", (SYSCALL)GetLastError, 0 }, |
| 30420 | 30449 | |
| 30421 | 30450 | #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) |
| 30422 | 30451 | |
| 30452 | +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) |
| 30423 | 30453 | #if SQLITE_OS_WINCE |
| 30424 | 30454 | /* The GetProcAddressA() routine is only available on Windows CE. */ |
| 30425 | 30455 | { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 }, |
| 30426 | 30456 | #else |
| 30427 | 30457 | /* All other Windows platforms expect GetProcAddress() to take |
| 30428 | 30458 | ** an ANSI string regardless of the _UNICODE setting */ |
| 30429 | 30459 | { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 }, |
| 30430 | 30460 | #endif |
| 30461 | +#else |
| 30462 | + { "GetProcAddressA", (SYSCALL)0, 0 }, |
| 30463 | +#endif |
| 30431 | 30464 | |
| 30432 | 30465 | #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ |
| 30433 | 30466 | LPCSTR))aSyscall[27].pCurrent) |
| 30434 | 30467 | |
| 30435 | 30468 | #if !SQLITE_OS_WINRT |
| | @@ -30529,19 +30562,20 @@ |
| 30529 | 30562 | #endif |
| 30530 | 30563 | |
| 30531 | 30564 | #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ |
| 30532 | 30565 | LPCVOID))aSyscall[41].pCurrent) |
| 30533 | 30566 | |
| 30534 | | -#if defined(SQLITE_WIN32_HAS_ANSI) |
| 30567 | +#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION) |
| 30535 | 30568 | { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, |
| 30536 | 30569 | #else |
| 30537 | 30570 | { "LoadLibraryA", (SYSCALL)0, 0 }, |
| 30538 | 30571 | #endif |
| 30539 | 30572 | |
| 30540 | 30573 | #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent) |
| 30541 | 30574 | |
| 30542 | | -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
| 30575 | +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ |
| 30576 | + !defined(SQLITE_OMIT_LOAD_EXTENSION) |
| 30543 | 30577 | { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, |
| 30544 | 30578 | #else |
| 30545 | 30579 | { "LoadLibraryW", (SYSCALL)0, 0 }, |
| 30546 | 30580 | #endif |
| 30547 | 30581 | |
| | @@ -30726,11 +30760,11 @@ |
| 30726 | 30760 | #endif |
| 30727 | 30761 | |
| 30728 | 30762 | #define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ |
| 30729 | 30763 | LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent) |
| 30730 | 30764 | |
| 30731 | | -#if SQLITE_OS_WINRT |
| 30765 | +#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) |
| 30732 | 30766 | { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, |
| 30733 | 30767 | #else |
| 30734 | 30768 | { "LoadPackagedLibrary", (SYSCALL)0, 0 }, |
| 30735 | 30769 | #endif |
| 30736 | 30770 | |
| | @@ -60050,11 +60084,13 @@ |
| 60050 | 60084 | for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ |
| 60051 | 60085 | Btree *pBt = db->aDb[i].pBt; |
| 60052 | 60086 | if( sqlite3BtreeIsInTrans(pBt) ){ |
| 60053 | 60087 | needXcommit = 1; |
| 60054 | 60088 | if( i!=1 ) nTrans++; |
| 60089 | + sqlite3BtreeEnter(pBt); |
| 60055 | 60090 | rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt)); |
| 60091 | + sqlite3BtreeLeave(pBt); |
| 60056 | 60092 | } |
| 60057 | 60093 | } |
| 60058 | 60094 | if( rc!=SQLITE_OK ){ |
| 60059 | 60095 | return rc; |
| 60060 | 60096 | } |
| | @@ -74362,10 +74398,11 @@ |
| 74362 | 74398 | pNew->nSrc = pNew->nAlloc = p->nSrc; |
| 74363 | 74399 | for(i=0; i<p->nSrc; i++){ |
| 74364 | 74400 | struct SrcList_item *pNewItem = &pNew->a[i]; |
| 74365 | 74401 | struct SrcList_item *pOldItem = &p->a[i]; |
| 74366 | 74402 | Table *pTab; |
| 74403 | + pNewItem->pSchema = pOldItem->pSchema; |
| 74367 | 74404 | pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); |
| 74368 | 74405 | pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); |
| 74369 | 74406 | pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); |
| 74370 | 74407 | pNewItem->jointype = pOldItem->jointype; |
| 74371 | 74408 | pNewItem->iCursor = pOldItem->iCursor; |
| | @@ -77988,11 +78025,11 @@ |
| 77988 | 78025 | savedDbFlags = db->flags; |
| 77989 | 78026 | if( NEVER(db->mallocFailed) ) goto exit_rename_table; |
| 77990 | 78027 | assert( pSrc->nSrc==1 ); |
| 77991 | 78028 | assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); |
| 77992 | 78029 | |
| 77993 | | - pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase); |
| 78030 | + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); |
| 77994 | 78031 | if( !pTab ) goto exit_rename_table; |
| 77995 | 78032 | iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); |
| 77996 | 78033 | zDb = db->aDb[iDb].zName; |
| 77997 | 78034 | db->flags |= SQLITE_PreferBuiltin; |
| 77998 | 78035 | |
| | @@ -78331,11 +78368,11 @@ |
| 78331 | 78368 | |
| 78332 | 78369 | /* Look up the table being altered. */ |
| 78333 | 78370 | assert( pParse->pNewTable==0 ); |
| 78334 | 78371 | assert( sqlite3BtreeHoldsAllMutexes(db) ); |
| 78335 | 78372 | if( db->mallocFailed ) goto exit_begin_add_column; |
| 78336 | | - pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase); |
| 78373 | + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); |
| 78337 | 78374 | if( !pTab ) goto exit_begin_add_column; |
| 78338 | 78375 | |
| 78339 | 78376 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 78340 | 78377 | if( IsVirtual(pTab) ){ |
| 78341 | 78378 | sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); |
| | @@ -79962,10 +79999,11 @@ |
| 79962 | 79999 | if( NEVER(iDb<0) || iDb==1 ) return 0; |
| 79963 | 80000 | db = pParse->db; |
| 79964 | 80001 | assert( db->nDb>iDb ); |
| 79965 | 80002 | pFix->pParse = pParse; |
| 79966 | 80003 | pFix->zDb = db->aDb[iDb].zName; |
| 80004 | + pFix->pSchema = db->aDb[iDb].pSchema; |
| 79967 | 80005 | pFix->zType = zType; |
| 79968 | 80006 | pFix->pName = pName; |
| 79969 | 80007 | return 1; |
| 79970 | 80008 | } |
| 79971 | 80009 | |
| | @@ -79992,18 +80030,19 @@ |
| 79992 | 80030 | struct SrcList_item *pItem; |
| 79993 | 80031 | |
| 79994 | 80032 | if( NEVER(pList==0) ) return 0; |
| 79995 | 80033 | zDb = pFix->zDb; |
| 79996 | 80034 | for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ |
| 79997 | | - if( pItem->zDatabase==0 ){ |
| 79998 | | - pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb); |
| 79999 | | - }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ |
| 80035 | + if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){ |
| 80000 | 80036 | sqlite3ErrorMsg(pFix->pParse, |
| 80001 | 80037 | "%s %T cannot reference objects in database %s", |
| 80002 | 80038 | pFix->zType, pFix->pName, pItem->zDatabase); |
| 80003 | 80039 | return 1; |
| 80004 | 80040 | } |
| 80041 | + sqlite3_free(pItem->zDatabase); |
| 80042 | + pItem->zDatabase = 0; |
| 80043 | + pItem->pSchema = pFix->pSchema; |
| 80005 | 80044 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) |
| 80006 | 80045 | if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; |
| 80007 | 80046 | if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; |
| 80008 | 80047 | #endif |
| 80009 | 80048 | } |
| | @@ -80656,10 +80695,35 @@ |
| 80656 | 80695 | } |
| 80657 | 80696 | pParse->checkSchema = 1; |
| 80658 | 80697 | } |
| 80659 | 80698 | return p; |
| 80660 | 80699 | } |
| 80700 | + |
| 80701 | +/* |
| 80702 | +** Locate the table identified by *p. |
| 80703 | +** |
| 80704 | +** This is a wrapper around sqlite3LocateTable(). The difference between |
| 80705 | +** sqlite3LocateTable() and this function is that this function restricts |
| 80706 | +** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be |
| 80707 | +** non-NULL if it is part of a view or trigger program definition. See |
| 80708 | +** sqlite3FixSrcList() for details. |
| 80709 | +*/ |
| 80710 | +SQLITE_PRIVATE Table *sqlite3LocateTableItem( |
| 80711 | + Parse *pParse, |
| 80712 | + int isView, |
| 80713 | + struct SrcList_item *p |
| 80714 | +){ |
| 80715 | + const char *zDb; |
| 80716 | + assert( p->pSchema==0 || p->zDatabase==0 ); |
| 80717 | + if( p->pSchema ){ |
| 80718 | + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); |
| 80719 | + zDb = pParse->db->aDb[iDb].zName; |
| 80720 | + }else{ |
| 80721 | + zDb = p->zDatabase; |
| 80722 | + } |
| 80723 | + return sqlite3LocateTable(pParse, isView, p->zName, zDb); |
| 80724 | +} |
| 80661 | 80725 | |
| 80662 | 80726 | /* |
| 80663 | 80727 | ** Locate the in-memory structure that describes |
| 80664 | 80728 | ** a particular index given the name of that index |
| 80665 | 80729 | ** and the name of the database that contains the index. |
| | @@ -81633,14 +81697,11 @@ |
| 81633 | 81697 | u8 initbusy = db->init.busy; |
| 81634 | 81698 | CollSeq *pColl; |
| 81635 | 81699 | |
| 81636 | 81700 | pColl = sqlite3FindCollSeq(db, enc, zName, initbusy); |
| 81637 | 81701 | if( !initbusy && (!pColl || !pColl->xCmp) ){ |
| 81638 | | - pColl = sqlite3GetCollSeq(db, enc, pColl, zName); |
| 81639 | | - if( !pColl ){ |
| 81640 | | - sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); |
| 81641 | | - } |
| 81702 | + pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName); |
| 81642 | 81703 | } |
| 81643 | 81704 | |
| 81644 | 81705 | return pColl; |
| 81645 | 81706 | } |
| 81646 | 81707 | |
| | @@ -82452,12 +82513,11 @@ |
| 82452 | 82513 | goto exit_drop_table; |
| 82453 | 82514 | } |
| 82454 | 82515 | assert( pParse->nErr==0 ); |
| 82455 | 82516 | assert( pName->nSrc==1 ); |
| 82456 | 82517 | if( noErr ) db->suppressErr++; |
| 82457 | | - pTab = sqlite3LocateTable(pParse, isView, |
| 82458 | | - pName->a[0].zName, pName->a[0].zDatabase); |
| 82518 | + pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); |
| 82459 | 82519 | if( noErr ) db->suppressErr--; |
| 82460 | 82520 | |
| 82461 | 82521 | if( pTab==0 ){ |
| 82462 | 82522 | if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); |
| 82463 | 82523 | goto exit_drop_table; |
| | @@ -82893,12 +82953,11 @@ |
| 82893 | 82953 | ){ |
| 82894 | 82954 | /* Because the parser constructs pTblName from a single identifier, |
| 82895 | 82955 | ** sqlite3FixSrcList can never fail. */ |
| 82896 | 82956 | assert(0); |
| 82897 | 82957 | } |
| 82898 | | - pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName, |
| 82899 | | - pTblName->a[0].zDatabase); |
| 82958 | + pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]); |
| 82900 | 82959 | if( !pTab || db->mallocFailed ) goto exit_create_index; |
| 82901 | 82960 | assert( db->aDb[iDb].pSchema==pTab->pSchema ); |
| 82902 | 82961 | }else{ |
| 82903 | 82962 | assert( pName==0 ); |
| 82904 | 82963 | assert( pStart==0 ); |
| | @@ -84254,21 +84313,22 @@ |
| 84254 | 84313 | ** If it is not NULL, then pColl must point to the database native encoding |
| 84255 | 84314 | ** collation sequence with name zName, length nName. |
| 84256 | 84315 | ** |
| 84257 | 84316 | ** The return value is either the collation sequence to be used in database |
| 84258 | 84317 | ** db for collation type name zName, length nName, or NULL, if no collation |
| 84259 | | -** sequence can be found. |
| 84318 | +** sequence can be found. If no collation is found, leave an error message. |
| 84260 | 84319 | ** |
| 84261 | 84320 | ** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() |
| 84262 | 84321 | */ |
| 84263 | 84322 | SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( |
| 84264 | | - sqlite3* db, /* The database connection */ |
| 84323 | + Parse *pParse, /* Parsing context */ |
| 84265 | 84324 | u8 enc, /* The desired encoding for the collating sequence */ |
| 84266 | 84325 | CollSeq *pColl, /* Collating sequence with native encoding, or NULL */ |
| 84267 | 84326 | const char *zName /* Collating sequence name */ |
| 84268 | 84327 | ){ |
| 84269 | 84328 | CollSeq *p; |
| 84329 | + sqlite3 *db = pParse->db; |
| 84270 | 84330 | |
| 84271 | 84331 | p = pColl; |
| 84272 | 84332 | if( !p ){ |
| 84273 | 84333 | p = sqlite3FindCollSeq(db, enc, zName, 0); |
| 84274 | 84334 | } |
| | @@ -84281,10 +84341,13 @@ |
| 84281 | 84341 | } |
| 84282 | 84342 | if( p && !p->xCmp && synthCollSeq(db, p) ){ |
| 84283 | 84343 | p = 0; |
| 84284 | 84344 | } |
| 84285 | 84345 | assert( !p || p->xCmp ); |
| 84346 | + if( p==0 ){ |
| 84347 | + sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); |
| 84348 | + } |
| 84286 | 84349 | return p; |
| 84287 | 84350 | } |
| 84288 | 84351 | |
| 84289 | 84352 | /* |
| 84290 | 84353 | ** This routine is called on a collation sequence before it is used to |
| | @@ -84299,14 +84362,12 @@ |
| 84299 | 84362 | */ |
| 84300 | 84363 | SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ |
| 84301 | 84364 | if( pColl ){ |
| 84302 | 84365 | const char *zName = pColl->zName; |
| 84303 | 84366 | sqlite3 *db = pParse->db; |
| 84304 | | - CollSeq *p = sqlite3GetCollSeq(db, ENC(db), pColl, zName); |
| 84367 | + CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName); |
| 84305 | 84368 | if( !p ){ |
| 84306 | | - sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); |
| 84307 | | - pParse->nErr++; |
| 84308 | 84369 | return SQLITE_ERROR; |
| 84309 | 84370 | } |
| 84310 | 84371 | assert( p==pColl ); |
| 84311 | 84372 | } |
| 84312 | 84373 | return SQLITE_OK; |
| | @@ -84689,11 +84750,11 @@ |
| 84689 | 84750 | */ |
| 84690 | 84751 | SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ |
| 84691 | 84752 | struct SrcList_item *pItem = pSrc->a; |
| 84692 | 84753 | Table *pTab; |
| 84693 | 84754 | assert( pItem && pSrc->nSrc==1 ); |
| 84694 | | - pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase); |
| 84755 | + pTab = sqlite3LocateTableItem(pParse, 0, pItem); |
| 84695 | 84756 | sqlite3DeleteTable(pParse->db, pItem->pTab); |
| 84696 | 84757 | pItem->pTab = pTab; |
| 84697 | 84758 | if( pTab ){ |
| 84698 | 84759 | pTab->nRef++; |
| 84699 | 84760 | } |
| | @@ -89415,11 +89476,13 @@ |
| 89415 | 89476 | ExprList *pCheck = pTab->pCheck; |
| 89416 | 89477 | pParse->ckBase = regData; |
| 89417 | 89478 | onError = overrideError!=OE_Default ? overrideError : OE_Abort; |
| 89418 | 89479 | for(i=0; i<pCheck->nExpr; i++){ |
| 89419 | 89480 | int allOk = sqlite3VdbeMakeLabel(v); |
| 89420 | | - sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL); |
| 89481 | + Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0); |
| 89482 | + if( pDup==0 ) break; |
| 89483 | + sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL); |
| 89421 | 89484 | if( onError==OE_Ignore ){ |
| 89422 | 89485 | sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); |
| 89423 | 89486 | }else{ |
| 89424 | 89487 | char *zConsName = pCheck->a[i].zName; |
| 89425 | 89488 | if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ |
| | @@ -89429,10 +89492,11 @@ |
| 89429 | 89492 | zConsName = 0; |
| 89430 | 89493 | } |
| 89431 | 89494 | sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC); |
| 89432 | 89495 | } |
| 89433 | 89496 | sqlite3VdbeResolveLabel(v, allOk); |
| 89497 | + sqlite3ExprDelete(db, pDup); |
| 89434 | 89498 | } |
| 89435 | 89499 | } |
| 89436 | 89500 | #endif /* !defined(SQLITE_OMIT_CHECK) */ |
| 89437 | 89501 | |
| 89438 | 89502 | /* If we have an INTEGER PRIMARY KEY, make sure the primary key |
| | @@ -89884,11 +89948,11 @@ |
| 89884 | 89948 | /* At this point we have established that the statement is of the |
| 89885 | 89949 | ** correct syntactic form to participate in this optimization. Now |
| 89886 | 89950 | ** we have to check the semantics. |
| 89887 | 89951 | */ |
| 89888 | 89952 | pItem = pSelect->pSrc->a; |
| 89889 | | - pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase); |
| 89953 | + pSrc = sqlite3LocateTableItem(pParse, 0, pItem); |
| 89890 | 89954 | if( pSrc==0 ){ |
| 89891 | 89955 | return 0; /* FROM clause does not contain a real table */ |
| 89892 | 89956 | } |
| 89893 | 89957 | if( pSrc==pDest ){ |
| 89894 | 89958 | return 0; /* tab1 and tab2 may not be the same table */ |
| | @@ -97153,12 +97217,11 @@ |
| 97153 | 97217 | pTab->tabFlags |= TF_Ephemeral; |
| 97154 | 97218 | #endif |
| 97155 | 97219 | }else{ |
| 97156 | 97220 | /* An ordinary table or view name in the FROM clause */ |
| 97157 | 97221 | assert( pFrom->pTab==0 ); |
| 97158 | | - pFrom->pTab = pTab = |
| 97159 | | - sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase); |
| 97222 | + pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); |
| 97160 | 97223 | if( pTab==0 ) return WRC_Abort; |
| 97161 | 97224 | pTab->nRef++; |
| 97162 | 97225 | #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) |
| 97163 | 97226 | if( pTab->pSelect || IsVirtual(pTab) ){ |
| 97164 | 97227 | /* We reach here if the named table is a really a view */ |
| | @@ -101095,10 +101158,11 @@ |
| 101095 | 101158 | */ |
| 101096 | 101159 | SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){ |
| 101097 | 101160 | if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); |
| 101098 | 101161 | if( p->azModuleArg ){ |
| 101099 | 101162 | int i; |
| 101163 | + assert( p->nModuleArg<2 || p->azModuleArg[1]==0 ); |
| 101100 | 101164 | for(i=0; i<p->nModuleArg; i++){ |
| 101101 | 101165 | sqlite3DbFree(db, p->azModuleArg[i]); |
| 101102 | 101166 | } |
| 101103 | 101167 | sqlite3DbFree(db, p->azModuleArg); |
| 101104 | 101168 | } |
| | @@ -101156,11 +101220,11 @@ |
| 101156 | 101220 | assert( iDb>=0 ); |
| 101157 | 101221 | |
| 101158 | 101222 | pTable->tabFlags |= TF_Virtual; |
| 101159 | 101223 | pTable->nModuleArg = 0; |
| 101160 | 101224 | addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); |
| 101161 | | - addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName)); |
| 101225 | + addModuleArgument(db, pTable, 0); |
| 101162 | 101226 | addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); |
| 101163 | 101227 | pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z); |
| 101164 | 101228 | |
| 101165 | 101229 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 101166 | 101230 | /* Creating a virtual table invokes the authorization callback twice. |
| | @@ -101313,10 +101377,11 @@ |
| 101313 | 101377 | int rc; |
| 101314 | 101378 | const char *const*azArg = (const char *const*)pTab->azModuleArg; |
| 101315 | 101379 | int nArg = pTab->nModuleArg; |
| 101316 | 101380 | char *zErr = 0; |
| 101317 | 101381 | char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); |
| 101382 | + int iDb; |
| 101318 | 101383 | |
| 101319 | 101384 | if( !zModuleName ){ |
| 101320 | 101385 | return SQLITE_NOMEM; |
| 101321 | 101386 | } |
| 101322 | 101387 | |
| | @@ -101326,10 +101391,14 @@ |
| 101326 | 101391 | return SQLITE_NOMEM; |
| 101327 | 101392 | } |
| 101328 | 101393 | pVTable->db = db; |
| 101329 | 101394 | pVTable->pMod = pMod; |
| 101330 | 101395 | |
| 101396 | + assert( pTab->azModuleArg[1]==0 ); |
| 101397 | + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 101398 | + pTab->azModuleArg[1] = db->aDb[iDb].zName; |
| 101399 | + |
| 101331 | 101400 | /* Invoke the virtual table constructor */ |
| 101332 | 101401 | assert( &db->pVtabCtx ); |
| 101333 | 101402 | assert( xConstruct ); |
| 101334 | 101403 | sCtx.pTab = pTab; |
| 101335 | 101404 | sCtx.pVTable = pVTable; |
| | @@ -101336,10 +101405,11 @@ |
| 101336 | 101405 | pPriorCtx = db->pVtabCtx; |
| 101337 | 101406 | db->pVtabCtx = &sCtx; |
| 101338 | 101407 | rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); |
| 101339 | 101408 | db->pVtabCtx = pPriorCtx; |
| 101340 | 101409 | if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; |
| 101410 | + pTab->azModuleArg[1] = 0; |
| 101341 | 101411 | |
| 101342 | 101412 | if( SQLITE_OK!=rc ){ |
| 101343 | 101413 | if( zErr==0 ){ |
| 101344 | 101414 | *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); |
| 101345 | 101415 | }else { |
| | @@ -104344,14 +104414,12 @@ |
| 104344 | 104414 | if( eType==SQLITE_BLOB ){ |
| 104345 | 104415 | z = (const u8 *)sqlite3_value_blob(pVal); |
| 104346 | 104416 | pColl = db->pDfltColl; |
| 104347 | 104417 | assert( pColl->enc==SQLITE_UTF8 ); |
| 104348 | 104418 | }else{ |
| 104349 | | - pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl); |
| 104419 | + pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl); |
| 104350 | 104420 | if( pColl==0 ){ |
| 104351 | | - sqlite3ErrorMsg(pParse, "no such collation sequence: %s", |
| 104352 | | - *pIdx->azColl); |
| 104353 | 104421 | return SQLITE_ERROR; |
| 104354 | 104422 | } |
| 104355 | 104423 | z = (const u8 *)sqlite3ValueText(pVal, pColl->enc); |
| 104356 | 104424 | if( !z ){ |
| 104357 | 104425 | return SQLITE_NOMEM; |
| | @@ -112545,10 +112613,49 @@ |
| 112545 | 112613 | |
| 112546 | 112614 | case SQLITE_CONFIG_COVERING_INDEX_SCAN: { |
| 112547 | 112615 | sqlite3GlobalConfig.bUseCis = va_arg(ap, int); |
| 112548 | 112616 | break; |
| 112549 | 112617 | } |
| 112618 | + |
| 112619 | + case SQLITE_CONFIG_READONLY: { |
| 112620 | + sqlite3GlobalConfig.bReadOnly = va_arg(ap, int); |
| 112621 | + break; |
| 112622 | + } |
| 112623 | + |
| 112624 | + default: { |
| 112625 | + rc = SQLITE_ERROR; |
| 112626 | + break; |
| 112627 | + } |
| 112628 | + } |
| 112629 | + va_end(ap); |
| 112630 | + return rc; |
| 112631 | +} |
| 112632 | + |
| 112633 | +/* |
| 112634 | +** This API allows applications to modify the global configuration of |
| 112635 | +** the SQLite library at run-time. |
| 112636 | +** |
| 112637 | +** This routine differs from sqlite3_config() in that it may be called when |
| 112638 | +** there are outstanding database connections and/or memory allocations. |
| 112639 | +** This routine is threadsafe. |
| 112640 | +*/ |
| 112641 | +SQLITE_API int sqlite3_reconfig(int op, ...){ |
| 112642 | + va_list ap; |
| 112643 | + int rc = SQLITE_OK; |
| 112644 | + |
| 112645 | + va_start(ap, op); |
| 112646 | + switch( op ){ |
| 112647 | + case SQLITE_CONFIG_READONLY: { |
| 112648 | + /* |
| 112649 | + ** On platforms where assignment of an integer value is atomic, there |
| 112650 | + ** is no need for a mutex here. On other platforms, there could be a |
| 112651 | + ** subtle race condition here; however, the effect would simply be that |
| 112652 | + ** a call to open a database would fail with SQLITE_READONLY. |
| 112653 | + */ |
| 112654 | + sqlite3GlobalConfig.bReadOnly = va_arg(ap, int); |
| 112655 | + break; |
| 112656 | + } |
| 112550 | 112657 | |
| 112551 | 112658 | default: { |
| 112552 | 112659 | rc = SQLITE_ERROR; |
| 112553 | 112660 | break; |
| 112554 | 112661 | } |
| | @@ -114268,11 +114375,12 @@ |
| 114268 | 114375 | */ |
| 114269 | 114376 | static int openDatabase( |
| 114270 | 114377 | const char *zFilename, /* Database filename UTF-8 encoded */ |
| 114271 | 114378 | sqlite3 **ppDb, /* OUT: Returned database handle */ |
| 114272 | 114379 | unsigned int flags, /* Operational flags */ |
| 114273 | | - const char *zVfs /* Name of the VFS to use */ |
| 114380 | + const char *zVfs, /* Name of the VFS to use */ |
| 114381 | + int defaultFlags /* Zero if opening via sqlite3_open_v2 */ |
| 114274 | 114382 | ){ |
| 114275 | 114383 | sqlite3 *db; /* Store allocated handle here */ |
| 114276 | 114384 | int rc; /* Return code */ |
| 114277 | 114385 | int isThreadsafe; /* True for threadsafe connections */ |
| 114278 | 114386 | char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ |
| | @@ -114337,10 +114445,20 @@ |
| 114337 | 114445 | SQLITE_OPEN_MASTER_JOURNAL | |
| 114338 | 114446 | SQLITE_OPEN_NOMUTEX | |
| 114339 | 114447 | SQLITE_OPEN_FULLMUTEX | |
| 114340 | 114448 | SQLITE_OPEN_WAL |
| 114341 | 114449 | ); |
| 114450 | + |
| 114451 | + /* Check for global read-only mode */ |
| 114452 | + if( sqlite3GlobalConfig.bReadOnly ){ |
| 114453 | + if( defaultFlags ){ |
| 114454 | + flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); |
| 114455 | + flags |= SQLITE_OPEN_READONLY; |
| 114456 | + }else if( flags & SQLITE_OPEN_READWRITE ){ |
| 114457 | + return SQLITE_READONLY; |
| 114458 | + } |
| 114459 | + } |
| 114342 | 114460 | |
| 114343 | 114461 | /* Allocate the sqlite data structure */ |
| 114344 | 114462 | db = sqlite3MallocZero( sizeof(sqlite3) ); |
| 114345 | 114463 | if( db==0 ) goto opendb_out; |
| 114346 | 114464 | if( isThreadsafe ){ |
| | @@ -114528,19 +114646,19 @@ |
| 114528 | 114646 | SQLITE_API int sqlite3_open( |
| 114529 | 114647 | const char *zFilename, |
| 114530 | 114648 | sqlite3 **ppDb |
| 114531 | 114649 | ){ |
| 114532 | 114650 | return openDatabase(zFilename, ppDb, |
| 114533 | | - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); |
| 114651 | + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0, 1); |
| 114534 | 114652 | } |
| 114535 | 114653 | SQLITE_API int sqlite3_open_v2( |
| 114536 | 114654 | const char *filename, /* Database filename (UTF-8) */ |
| 114537 | 114655 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 114538 | 114656 | int flags, /* Flags */ |
| 114539 | 114657 | const char *zVfs /* Name of VFS module to use */ |
| 114540 | 114658 | ){ |
| 114541 | | - return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); |
| 114659 | + return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, 0); |
| 114542 | 114660 | } |
| 114543 | 114661 | |
| 114544 | 114662 | #ifndef SQLITE_OMIT_UTF16 |
| 114545 | 114663 | /* |
| 114546 | 114664 | ** Open a new database handle. |
| | @@ -114563,11 +114681,11 @@ |
| 114563 | 114681 | pVal = sqlite3ValueNew(0); |
| 114564 | 114682 | sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); |
| 114565 | 114683 | zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); |
| 114566 | 114684 | if( zFilename8 ){ |
| 114567 | 114685 | rc = openDatabase(zFilename8, ppDb, |
| 114568 | | - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); |
| 114686 | + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0, 1); |
| 114569 | 114687 | assert( *ppDb || rc==SQLITE_NOMEM ); |
| 114570 | 114688 | if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){ |
| 114571 | 114689 | ENC(*ppDb) = SQLITE_UTF16NATIVE; |
| 114572 | 114690 | } |
| 114573 | 114691 | }else{ |
| | @@ -136800,5 +136918,3794 @@ |
| 136800 | 136918 | |
| 136801 | 136919 | #endif /* defined(SQLITE_ENABLE_ICU) */ |
| 136802 | 136920 | #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
| 136803 | 136921 | |
| 136804 | 136922 | /************** End of fts3_icu.c ********************************************/ |
| 136923 | +/* |
| 136924 | +** 2001 September 15 |
| 136925 | +** |
| 136926 | +** The author disclaims copyright to this source code. In place of |
| 136927 | +** a legal notice, here is a blessing: |
| 136928 | +** |
| 136929 | +** May you do good and not evil. |
| 136930 | +** May you find forgiveness for yourself and forgive others. |
| 136931 | +** May you share freely, never taking more than you give. |
| 136932 | +** |
| 136933 | +************************************************************************* |
| 136934 | +** A TCL Interface to SQLite. Append this file to sqlite3.c and |
| 136935 | +** compile the whole thing to build a TCL-enabled version of SQLite. |
| 136936 | +** |
| 136937 | +** Compile-time options: |
| 136938 | +** |
| 136939 | +** -DTCLSH=1 Add a "main()" routine that works as a tclsh. |
| 136940 | +** |
| 136941 | +** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add |
| 136942 | +** four new commands to the TCL interpreter for |
| 136943 | +** generating MD5 checksums: md5, md5file, |
| 136944 | +** md5-10x8, and md5file-10x8. |
| 136945 | +** |
| 136946 | +** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add |
| 136947 | +** hundreds of new commands used for testing |
| 136948 | +** SQLite. This option implies -DSQLITE_TCLMD5. |
| 136949 | +*/ |
| 136950 | +#include "tcl.h" |
| 136951 | +#include <errno.h> |
| 136952 | + |
| 136953 | +/* |
| 136954 | +** Some additional include files are needed if this file is not |
| 136955 | +** appended to the amalgamation. |
| 136956 | +*/ |
| 136957 | +#ifndef SQLITE_AMALGAMATION |
| 136958 | +# include "sqlite3.h" |
| 136959 | +# include <stdlib.h> |
| 136960 | +# include <string.h> |
| 136961 | +# include <assert.h> |
| 136962 | + typedef unsigned char u8; |
| 136963 | +#endif |
| 136964 | +#include <ctype.h> |
| 136965 | + |
| 136966 | +/* |
| 136967 | + * Windows needs to know which symbols to export. Unix does not. |
| 136968 | + * BUILD_sqlite should be undefined for Unix. |
| 136969 | + */ |
| 136970 | +#ifdef BUILD_sqlite |
| 136971 | +#undef TCL_STORAGE_CLASS |
| 136972 | +#define TCL_STORAGE_CLASS DLLEXPORT |
| 136973 | +#endif /* BUILD_sqlite */ |
| 136974 | + |
| 136975 | +#define NUM_PREPARED_STMTS 10 |
| 136976 | +#define MAX_PREPARED_STMTS 100 |
| 136977 | + |
| 136978 | +/* Forward declaration */ |
| 136979 | +typedef struct SqliteDb SqliteDb; |
| 136980 | + |
| 136981 | +/* |
| 136982 | +** New SQL functions can be created as TCL scripts. Each such function |
| 136983 | +** is described by an instance of the following structure. |
| 136984 | +*/ |
| 136985 | +typedef struct SqlFunc SqlFunc; |
| 136986 | +struct SqlFunc { |
| 136987 | + Tcl_Interp *interp; /* The TCL interpret to execute the function */ |
| 136988 | + Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ |
| 136989 | + SqliteDb *pDb; /* Database connection that owns this function */ |
| 136990 | + int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ |
| 136991 | + char *zName; /* Name of this function */ |
| 136992 | + SqlFunc *pNext; /* Next function on the list of them all */ |
| 136993 | +}; |
| 136994 | + |
| 136995 | +/* |
| 136996 | +** New collation sequences function can be created as TCL scripts. Each such |
| 136997 | +** function is described by an instance of the following structure. |
| 136998 | +*/ |
| 136999 | +typedef struct SqlCollate SqlCollate; |
| 137000 | +struct SqlCollate { |
| 137001 | + Tcl_Interp *interp; /* The TCL interpret to execute the function */ |
| 137002 | + char *zScript; /* The script to be run */ |
| 137003 | + SqlCollate *pNext; /* Next function on the list of them all */ |
| 137004 | +}; |
| 137005 | + |
| 137006 | +/* |
| 137007 | +** Prepared statements are cached for faster execution. Each prepared |
| 137008 | +** statement is described by an instance of the following structure. |
| 137009 | +*/ |
| 137010 | +typedef struct SqlPreparedStmt SqlPreparedStmt; |
| 137011 | +struct SqlPreparedStmt { |
| 137012 | + SqlPreparedStmt *pNext; /* Next in linked list */ |
| 137013 | + SqlPreparedStmt *pPrev; /* Previous on the list */ |
| 137014 | + sqlite3_stmt *pStmt; /* The prepared statement */ |
| 137015 | + int nSql; /* chars in zSql[] */ |
| 137016 | + const char *zSql; /* Text of the SQL statement */ |
| 137017 | + int nParm; /* Size of apParm array */ |
| 137018 | + Tcl_Obj **apParm; /* Array of referenced object pointers */ |
| 137019 | +}; |
| 137020 | + |
| 137021 | +typedef struct IncrblobChannel IncrblobChannel; |
| 137022 | + |
| 137023 | +/* |
| 137024 | +** There is one instance of this structure for each SQLite database |
| 137025 | +** that has been opened by the SQLite TCL interface. |
| 137026 | +** |
| 137027 | +** If this module is built with SQLITE_TEST defined (to create the SQLite |
| 137028 | +** testfixture executable), then it may be configured to use either |
| 137029 | +** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements. |
| 137030 | +** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used. |
| 137031 | +*/ |
| 137032 | +struct SqliteDb { |
| 137033 | + sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ |
| 137034 | + Tcl_Interp *interp; /* The interpreter used for this database */ |
| 137035 | + char *zBusy; /* The busy callback routine */ |
| 137036 | + char *zCommit; /* The commit hook callback routine */ |
| 137037 | + char *zTrace; /* The trace callback routine */ |
| 137038 | + char *zProfile; /* The profile callback routine */ |
| 137039 | + char *zProgress; /* The progress callback routine */ |
| 137040 | + char *zAuth; /* The authorization callback routine */ |
| 137041 | + int disableAuth; /* Disable the authorizer if it exists */ |
| 137042 | + char *zNull; /* Text to substitute for an SQL NULL value */ |
| 137043 | + SqlFunc *pFunc; /* List of SQL functions */ |
| 137044 | + Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ |
| 137045 | + Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ |
| 137046 | + Tcl_Obj *pWalHook; /* WAL hook script (if any) */ |
| 137047 | + Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */ |
| 137048 | + SqlCollate *pCollate; /* List of SQL collation functions */ |
| 137049 | + int rc; /* Return code of most recent sqlite3_exec() */ |
| 137050 | + Tcl_Obj *pCollateNeeded; /* Collation needed script */ |
| 137051 | + SqlPreparedStmt *stmtList; /* List of prepared statements*/ |
| 137052 | + SqlPreparedStmt *stmtLast; /* Last statement in the list */ |
| 137053 | + int maxStmt; /* The next maximum number of stmtList */ |
| 137054 | + int nStmt; /* Number of statements in stmtList */ |
| 137055 | + IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ |
| 137056 | + int nStep, nSort, nIndex; /* Statistics for most recent operation */ |
| 137057 | + int nTransaction; /* Number of nested [transaction] methods */ |
| 137058 | +#ifdef SQLITE_TEST |
| 137059 | + int bLegacyPrepare; /* True to use sqlite3_prepare() */ |
| 137060 | +#endif |
| 137061 | +}; |
| 137062 | + |
| 137063 | +struct IncrblobChannel { |
| 137064 | + sqlite3_blob *pBlob; /* sqlite3 blob handle */ |
| 137065 | + SqliteDb *pDb; /* Associated database connection */ |
| 137066 | + int iSeek; /* Current seek offset */ |
| 137067 | + Tcl_Channel channel; /* Channel identifier */ |
| 137068 | + IncrblobChannel *pNext; /* Linked list of all open incrblob channels */ |
| 137069 | + IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */ |
| 137070 | +}; |
| 137071 | + |
| 137072 | +/* |
| 137073 | +** Compute a string length that is limited to what can be stored in |
| 137074 | +** lower 30 bits of a 32-bit signed integer. |
| 137075 | +*/ |
| 137076 | +static int strlen30(const char *z){ |
| 137077 | + const char *z2 = z; |
| 137078 | + while( *z2 ){ z2++; } |
| 137079 | + return 0x3fffffff & (int)(z2 - z); |
| 137080 | +} |
| 137081 | + |
| 137082 | + |
| 137083 | +#ifndef SQLITE_OMIT_INCRBLOB |
| 137084 | +/* |
| 137085 | +** Close all incrblob channels opened using database connection pDb. |
| 137086 | +** This is called when shutting down the database connection. |
| 137087 | +*/ |
| 137088 | +static void closeIncrblobChannels(SqliteDb *pDb){ |
| 137089 | + IncrblobChannel *p; |
| 137090 | + IncrblobChannel *pNext; |
| 137091 | + |
| 137092 | + for(p=pDb->pIncrblob; p; p=pNext){ |
| 137093 | + pNext = p->pNext; |
| 137094 | + |
| 137095 | + /* Note: Calling unregister here call Tcl_Close on the incrblob channel, |
| 137096 | + ** which deletes the IncrblobChannel structure at *p. So do not |
| 137097 | + ** call Tcl_Free() here. |
| 137098 | + */ |
| 137099 | + Tcl_UnregisterChannel(pDb->interp, p->channel); |
| 137100 | + } |
| 137101 | +} |
| 137102 | + |
| 137103 | +/* |
| 137104 | +** Close an incremental blob channel. |
| 137105 | +*/ |
| 137106 | +static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){ |
| 137107 | + IncrblobChannel *p = (IncrblobChannel *)instanceData; |
| 137108 | + int rc = sqlite3_blob_close(p->pBlob); |
| 137109 | + sqlite3 *db = p->pDb->db; |
| 137110 | + |
| 137111 | + /* Remove the channel from the SqliteDb.pIncrblob list. */ |
| 137112 | + if( p->pNext ){ |
| 137113 | + p->pNext->pPrev = p->pPrev; |
| 137114 | + } |
| 137115 | + if( p->pPrev ){ |
| 137116 | + p->pPrev->pNext = p->pNext; |
| 137117 | + } |
| 137118 | + if( p->pDb->pIncrblob==p ){ |
| 137119 | + p->pDb->pIncrblob = p->pNext; |
| 137120 | + } |
| 137121 | + |
| 137122 | + /* Free the IncrblobChannel structure */ |
| 137123 | + Tcl_Free((char *)p); |
| 137124 | + |
| 137125 | + if( rc!=SQLITE_OK ){ |
| 137126 | + Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); |
| 137127 | + return TCL_ERROR; |
| 137128 | + } |
| 137129 | + return TCL_OK; |
| 137130 | +} |
| 137131 | + |
| 137132 | +/* |
| 137133 | +** Read data from an incremental blob channel. |
| 137134 | +*/ |
| 137135 | +static int incrblobInput( |
| 137136 | + ClientData instanceData, |
| 137137 | + char *buf, |
| 137138 | + int bufSize, |
| 137139 | + int *errorCodePtr |
| 137140 | +){ |
| 137141 | + IncrblobChannel *p = (IncrblobChannel *)instanceData; |
| 137142 | + int nRead = bufSize; /* Number of bytes to read */ |
| 137143 | + int nBlob; /* Total size of the blob */ |
| 137144 | + int rc; /* sqlite error code */ |
| 137145 | + |
| 137146 | + nBlob = sqlite3_blob_bytes(p->pBlob); |
| 137147 | + if( (p->iSeek+nRead)>nBlob ){ |
| 137148 | + nRead = nBlob-p->iSeek; |
| 137149 | + } |
| 137150 | + if( nRead<=0 ){ |
| 137151 | + return 0; |
| 137152 | + } |
| 137153 | + |
| 137154 | + rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek); |
| 137155 | + if( rc!=SQLITE_OK ){ |
| 137156 | + *errorCodePtr = rc; |
| 137157 | + return -1; |
| 137158 | + } |
| 137159 | + |
| 137160 | + p->iSeek += nRead; |
| 137161 | + return nRead; |
| 137162 | +} |
| 137163 | + |
| 137164 | +/* |
| 137165 | +** Write data to an incremental blob channel. |
| 137166 | +*/ |
| 137167 | +static int incrblobOutput( |
| 137168 | + ClientData instanceData, |
| 137169 | + CONST char *buf, |
| 137170 | + int toWrite, |
| 137171 | + int *errorCodePtr |
| 137172 | +){ |
| 137173 | + IncrblobChannel *p = (IncrblobChannel *)instanceData; |
| 137174 | + int nWrite = toWrite; /* Number of bytes to write */ |
| 137175 | + int nBlob; /* Total size of the blob */ |
| 137176 | + int rc; /* sqlite error code */ |
| 137177 | + |
| 137178 | + nBlob = sqlite3_blob_bytes(p->pBlob); |
| 137179 | + if( (p->iSeek+nWrite)>nBlob ){ |
| 137180 | + *errorCodePtr = EINVAL; |
| 137181 | + return -1; |
| 137182 | + } |
| 137183 | + if( nWrite<=0 ){ |
| 137184 | + return 0; |
| 137185 | + } |
| 137186 | + |
| 137187 | + rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek); |
| 137188 | + if( rc!=SQLITE_OK ){ |
| 137189 | + *errorCodePtr = EIO; |
| 137190 | + return -1; |
| 137191 | + } |
| 137192 | + |
| 137193 | + p->iSeek += nWrite; |
| 137194 | + return nWrite; |
| 137195 | +} |
| 137196 | + |
| 137197 | +/* |
| 137198 | +** Seek an incremental blob channel. |
| 137199 | +*/ |
| 137200 | +static int incrblobSeek( |
| 137201 | + ClientData instanceData, |
| 137202 | + long offset, |
| 137203 | + int seekMode, |
| 137204 | + int *errorCodePtr |
| 137205 | +){ |
| 137206 | + IncrblobChannel *p = (IncrblobChannel *)instanceData; |
| 137207 | + |
| 137208 | + switch( seekMode ){ |
| 137209 | + case SEEK_SET: |
| 137210 | + p->iSeek = offset; |
| 137211 | + break; |
| 137212 | + case SEEK_CUR: |
| 137213 | + p->iSeek += offset; |
| 137214 | + break; |
| 137215 | + case SEEK_END: |
| 137216 | + p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset; |
| 137217 | + break; |
| 137218 | + |
| 137219 | + default: assert(!"Bad seekMode"); |
| 137220 | + } |
| 137221 | + |
| 137222 | + return p->iSeek; |
| 137223 | +} |
| 137224 | + |
| 137225 | + |
| 137226 | +static void incrblobWatch(ClientData instanceData, int mode){ |
| 137227 | + /* NO-OP */ |
| 137228 | +} |
| 137229 | +static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){ |
| 137230 | + return TCL_ERROR; |
| 137231 | +} |
| 137232 | + |
| 137233 | +static Tcl_ChannelType IncrblobChannelType = { |
| 137234 | + "incrblob", /* typeName */ |
| 137235 | + TCL_CHANNEL_VERSION_2, /* version */ |
| 137236 | + incrblobClose, /* closeProc */ |
| 137237 | + incrblobInput, /* inputProc */ |
| 137238 | + incrblobOutput, /* outputProc */ |
| 137239 | + incrblobSeek, /* seekProc */ |
| 137240 | + 0, /* setOptionProc */ |
| 137241 | + 0, /* getOptionProc */ |
| 137242 | + incrblobWatch, /* watchProc (this is a no-op) */ |
| 137243 | + incrblobHandle, /* getHandleProc (always returns error) */ |
| 137244 | + 0, /* close2Proc */ |
| 137245 | + 0, /* blockModeProc */ |
| 137246 | + 0, /* flushProc */ |
| 137247 | + 0, /* handlerProc */ |
| 137248 | + 0, /* wideSeekProc */ |
| 137249 | +}; |
| 137250 | + |
| 137251 | +/* |
| 137252 | +** Create a new incrblob channel. |
| 137253 | +*/ |
| 137254 | +static int createIncrblobChannel( |
| 137255 | + Tcl_Interp *interp, |
| 137256 | + SqliteDb *pDb, |
| 137257 | + const char *zDb, |
| 137258 | + const char *zTable, |
| 137259 | + const char *zColumn, |
| 137260 | + sqlite_int64 iRow, |
| 137261 | + int isReadonly |
| 137262 | +){ |
| 137263 | + IncrblobChannel *p; |
| 137264 | + sqlite3 *db = pDb->db; |
| 137265 | + sqlite3_blob *pBlob; |
| 137266 | + int rc; |
| 137267 | + int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE); |
| 137268 | + |
| 137269 | + /* This variable is used to name the channels: "incrblob_[incr count]" */ |
| 137270 | + static int count = 0; |
| 137271 | + char zChannel[64]; |
| 137272 | + |
| 137273 | + rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob); |
| 137274 | + if( rc!=SQLITE_OK ){ |
| 137275 | + Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); |
| 137276 | + return TCL_ERROR; |
| 137277 | + } |
| 137278 | + |
| 137279 | + p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel)); |
| 137280 | + p->iSeek = 0; |
| 137281 | + p->pBlob = pBlob; |
| 137282 | + |
| 137283 | + sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count); |
| 137284 | + p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags); |
| 137285 | + Tcl_RegisterChannel(interp, p->channel); |
| 137286 | + |
| 137287 | + /* Link the new channel into the SqliteDb.pIncrblob list. */ |
| 137288 | + p->pNext = pDb->pIncrblob; |
| 137289 | + p->pPrev = 0; |
| 137290 | + if( p->pNext ){ |
| 137291 | + p->pNext->pPrev = p; |
| 137292 | + } |
| 137293 | + pDb->pIncrblob = p; |
| 137294 | + p->pDb = pDb; |
| 137295 | + |
| 137296 | + Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE); |
| 137297 | + return TCL_OK; |
| 137298 | +} |
| 137299 | +#else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */ |
| 137300 | + #define closeIncrblobChannels(pDb) |
| 137301 | +#endif |
| 137302 | + |
| 137303 | +/* |
| 137304 | +** Look at the script prefix in pCmd. We will be executing this script |
| 137305 | +** after first appending one or more arguments. This routine analyzes |
| 137306 | +** the script to see if it is safe to use Tcl_EvalObjv() on the script |
| 137307 | +** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much |
| 137308 | +** faster. |
| 137309 | +** |
| 137310 | +** Scripts that are safe to use with Tcl_EvalObjv() consists of a |
| 137311 | +** command name followed by zero or more arguments with no [...] or $ |
| 137312 | +** or {...} or ; to be seen anywhere. Most callback scripts consist |
| 137313 | +** of just a single procedure name and they meet this requirement. |
| 137314 | +*/ |
| 137315 | +static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ |
| 137316 | + /* We could try to do something with Tcl_Parse(). But we will instead |
| 137317 | + ** just do a search for forbidden characters. If any of the forbidden |
| 137318 | + ** characters appear in pCmd, we will report the string as unsafe. |
| 137319 | + */ |
| 137320 | + const char *z; |
| 137321 | + int n; |
| 137322 | + z = Tcl_GetStringFromObj(pCmd, &n); |
| 137323 | + while( n-- > 0 ){ |
| 137324 | + int c = *(z++); |
| 137325 | + if( c=='$' || c=='[' || c==';' ) return 0; |
| 137326 | + } |
| 137327 | + return 1; |
| 137328 | +} |
| 137329 | + |
| 137330 | +/* |
| 137331 | +** Find an SqlFunc structure with the given name. Or create a new |
| 137332 | +** one if an existing one cannot be found. Return a pointer to the |
| 137333 | +** structure. |
| 137334 | +*/ |
| 137335 | +static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ |
| 137336 | + SqlFunc *p, *pNew; |
| 137337 | + int i; |
| 137338 | + pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 ); |
| 137339 | + pNew->zName = (char*)&pNew[1]; |
| 137340 | + for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); } |
| 137341 | + pNew->zName[i] = 0; |
| 137342 | + for(p=pDb->pFunc; p; p=p->pNext){ |
| 137343 | + if( strcmp(p->zName, pNew->zName)==0 ){ |
| 137344 | + Tcl_Free((char*)pNew); |
| 137345 | + return p; |
| 137346 | + } |
| 137347 | + } |
| 137348 | + pNew->interp = pDb->interp; |
| 137349 | + pNew->pDb = pDb; |
| 137350 | + pNew->pScript = 0; |
| 137351 | + pNew->pNext = pDb->pFunc; |
| 137352 | + pDb->pFunc = pNew; |
| 137353 | + return pNew; |
| 137354 | +} |
| 137355 | + |
| 137356 | +/* |
| 137357 | +** Free a single SqlPreparedStmt object. |
| 137358 | +*/ |
| 137359 | +static void dbFreeStmt(SqlPreparedStmt *pStmt){ |
| 137360 | +#ifdef SQLITE_TEST |
| 137361 | + if( sqlite3_sql(pStmt->pStmt)==0 ){ |
| 137362 | + Tcl_Free((char *)pStmt->zSql); |
| 137363 | + } |
| 137364 | +#endif |
| 137365 | + sqlite3_finalize(pStmt->pStmt); |
| 137366 | + Tcl_Free((char *)pStmt); |
| 137367 | +} |
| 137368 | + |
| 137369 | +/* |
| 137370 | +** Finalize and free a list of prepared statements |
| 137371 | +*/ |
| 137372 | +static void flushStmtCache(SqliteDb *pDb){ |
| 137373 | + SqlPreparedStmt *pPreStmt; |
| 137374 | + SqlPreparedStmt *pNext; |
| 137375 | + |
| 137376 | + for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){ |
| 137377 | + pNext = pPreStmt->pNext; |
| 137378 | + dbFreeStmt(pPreStmt); |
| 137379 | + } |
| 137380 | + pDb->nStmt = 0; |
| 137381 | + pDb->stmtLast = 0; |
| 137382 | + pDb->stmtList = 0; |
| 137383 | +} |
| 137384 | + |
| 137385 | +/* |
| 137386 | +** TCL calls this procedure when an sqlite3 database command is |
| 137387 | +** deleted. |
| 137388 | +*/ |
| 137389 | +static void DbDeleteCmd(void *db){ |
| 137390 | + SqliteDb *pDb = (SqliteDb*)db; |
| 137391 | + flushStmtCache(pDb); |
| 137392 | + closeIncrblobChannels(pDb); |
| 137393 | + sqlite3_close(pDb->db); |
| 137394 | + while( pDb->pFunc ){ |
| 137395 | + SqlFunc *pFunc = pDb->pFunc; |
| 137396 | + pDb->pFunc = pFunc->pNext; |
| 137397 | + assert( pFunc->pDb==pDb ); |
| 137398 | + Tcl_DecrRefCount(pFunc->pScript); |
| 137399 | + Tcl_Free((char*)pFunc); |
| 137400 | + } |
| 137401 | + while( pDb->pCollate ){ |
| 137402 | + SqlCollate *pCollate = pDb->pCollate; |
| 137403 | + pDb->pCollate = pCollate->pNext; |
| 137404 | + Tcl_Free((char*)pCollate); |
| 137405 | + } |
| 137406 | + if( pDb->zBusy ){ |
| 137407 | + Tcl_Free(pDb->zBusy); |
| 137408 | + } |
| 137409 | + if( pDb->zTrace ){ |
| 137410 | + Tcl_Free(pDb->zTrace); |
| 137411 | + } |
| 137412 | + if( pDb->zProfile ){ |
| 137413 | + Tcl_Free(pDb->zProfile); |
| 137414 | + } |
| 137415 | + if( pDb->zAuth ){ |
| 137416 | + Tcl_Free(pDb->zAuth); |
| 137417 | + } |
| 137418 | + if( pDb->zNull ){ |
| 137419 | + Tcl_Free(pDb->zNull); |
| 137420 | + } |
| 137421 | + if( pDb->pUpdateHook ){ |
| 137422 | + Tcl_DecrRefCount(pDb->pUpdateHook); |
| 137423 | + } |
| 137424 | + if( pDb->pRollbackHook ){ |
| 137425 | + Tcl_DecrRefCount(pDb->pRollbackHook); |
| 137426 | + } |
| 137427 | + if( pDb->pWalHook ){ |
| 137428 | + Tcl_DecrRefCount(pDb->pWalHook); |
| 137429 | + } |
| 137430 | + if( pDb->pCollateNeeded ){ |
| 137431 | + Tcl_DecrRefCount(pDb->pCollateNeeded); |
| 137432 | + } |
| 137433 | + Tcl_Free((char*)pDb); |
| 137434 | +} |
| 137435 | + |
| 137436 | +/* |
| 137437 | +** This routine is called when a database file is locked while trying |
| 137438 | +** to execute SQL. |
| 137439 | +*/ |
| 137440 | +static int DbBusyHandler(void *cd, int nTries){ |
| 137441 | + SqliteDb *pDb = (SqliteDb*)cd; |
| 137442 | + int rc; |
| 137443 | + char zVal[30]; |
| 137444 | + |
| 137445 | + sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries); |
| 137446 | + rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0); |
| 137447 | + if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ |
| 137448 | + return 0; |
| 137449 | + } |
| 137450 | + return 1; |
| 137451 | +} |
| 137452 | + |
| 137453 | +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
| 137454 | +/* |
| 137455 | +** This routine is invoked as the 'progress callback' for the database. |
| 137456 | +*/ |
| 137457 | +static int DbProgressHandler(void *cd){ |
| 137458 | + SqliteDb *pDb = (SqliteDb*)cd; |
| 137459 | + int rc; |
| 137460 | + |
| 137461 | + assert( pDb->zProgress ); |
| 137462 | + rc = Tcl_Eval(pDb->interp, pDb->zProgress); |
| 137463 | + if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ |
| 137464 | + return 1; |
| 137465 | + } |
| 137466 | + return 0; |
| 137467 | +} |
| 137468 | +#endif |
| 137469 | + |
| 137470 | +#ifndef SQLITE_OMIT_TRACE |
| 137471 | +/* |
| 137472 | +** This routine is called by the SQLite trace handler whenever a new |
| 137473 | +** block of SQL is executed. The TCL script in pDb->zTrace is executed. |
| 137474 | +*/ |
| 137475 | +static void DbTraceHandler(void *cd, const char *zSql){ |
| 137476 | + SqliteDb *pDb = (SqliteDb*)cd; |
| 137477 | + Tcl_DString str; |
| 137478 | + |
| 137479 | + Tcl_DStringInit(&str); |
| 137480 | + Tcl_DStringAppend(&str, pDb->zTrace, -1); |
| 137481 | + Tcl_DStringAppendElement(&str, zSql); |
| 137482 | + Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); |
| 137483 | + Tcl_DStringFree(&str); |
| 137484 | + Tcl_ResetResult(pDb->interp); |
| 137485 | +} |
| 137486 | +#endif |
| 137487 | + |
| 137488 | +#ifndef SQLITE_OMIT_TRACE |
| 137489 | +/* |
| 137490 | +** This routine is called by the SQLite profile handler after a statement |
| 137491 | +** SQL has executed. The TCL script in pDb->zProfile is evaluated. |
| 137492 | +*/ |
| 137493 | +static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ |
| 137494 | + SqliteDb *pDb = (SqliteDb*)cd; |
| 137495 | + Tcl_DString str; |
| 137496 | + char zTm[100]; |
| 137497 | + |
| 137498 | + sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm); |
| 137499 | + Tcl_DStringInit(&str); |
| 137500 | + Tcl_DStringAppend(&str, pDb->zProfile, -1); |
| 137501 | + Tcl_DStringAppendElement(&str, zSql); |
| 137502 | + Tcl_DStringAppendElement(&str, zTm); |
| 137503 | + Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); |
| 137504 | + Tcl_DStringFree(&str); |
| 137505 | + Tcl_ResetResult(pDb->interp); |
| 137506 | +} |
| 137507 | +#endif |
| 137508 | + |
| 137509 | +/* |
| 137510 | +** This routine is called when a transaction is committed. The |
| 137511 | +** TCL script in pDb->zCommit is executed. If it returns non-zero or |
| 137512 | +** if it throws an exception, the transaction is rolled back instead |
| 137513 | +** of being committed. |
| 137514 | +*/ |
| 137515 | +static int DbCommitHandler(void *cd){ |
| 137516 | + SqliteDb *pDb = (SqliteDb*)cd; |
| 137517 | + int rc; |
| 137518 | + |
| 137519 | + rc = Tcl_Eval(pDb->interp, pDb->zCommit); |
| 137520 | + if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ |
| 137521 | + return 1; |
| 137522 | + } |
| 137523 | + return 0; |
| 137524 | +} |
| 137525 | + |
| 137526 | +static void DbRollbackHandler(void *clientData){ |
| 137527 | + SqliteDb *pDb = (SqliteDb*)clientData; |
| 137528 | + assert(pDb->pRollbackHook); |
| 137529 | + if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ |
| 137530 | + Tcl_BackgroundError(pDb->interp); |
| 137531 | + } |
| 137532 | +} |
| 137533 | + |
| 137534 | +/* |
| 137535 | +** This procedure handles wal_hook callbacks. |
| 137536 | +*/ |
| 137537 | +static int DbWalHandler( |
| 137538 | + void *clientData, |
| 137539 | + sqlite3 *db, |
| 137540 | + const char *zDb, |
| 137541 | + int nEntry |
| 137542 | +){ |
| 137543 | + int ret = SQLITE_OK; |
| 137544 | + Tcl_Obj *p; |
| 137545 | + SqliteDb *pDb = (SqliteDb*)clientData; |
| 137546 | + Tcl_Interp *interp = pDb->interp; |
| 137547 | + assert(pDb->pWalHook); |
| 137548 | + |
| 137549 | + p = Tcl_DuplicateObj(pDb->pWalHook); |
| 137550 | + Tcl_IncrRefCount(p); |
| 137551 | + Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); |
| 137552 | + Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry)); |
| 137553 | + if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0) |
| 137554 | + || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret) |
| 137555 | + ){ |
| 137556 | + Tcl_BackgroundError(interp); |
| 137557 | + } |
| 137558 | + Tcl_DecrRefCount(p); |
| 137559 | + |
| 137560 | + return ret; |
| 137561 | +} |
| 137562 | + |
| 137563 | +#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) |
| 137564 | +static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){ |
| 137565 | + char zBuf[64]; |
| 137566 | + sprintf(zBuf, "%d", iArg); |
| 137567 | + Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY); |
| 137568 | + sprintf(zBuf, "%d", nArg); |
| 137569 | + Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY); |
| 137570 | +} |
| 137571 | +#else |
| 137572 | +# define setTestUnlockNotifyVars(x,y,z) |
| 137573 | +#endif |
| 137574 | + |
| 137575 | +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY |
| 137576 | +static void DbUnlockNotify(void **apArg, int nArg){ |
| 137577 | + int i; |
| 137578 | + for(i=0; i<nArg; i++){ |
| 137579 | + const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); |
| 137580 | + SqliteDb *pDb = (SqliteDb *)apArg[i]; |
| 137581 | + setTestUnlockNotifyVars(pDb->interp, i, nArg); |
| 137582 | + assert( pDb->pUnlockNotify); |
| 137583 | + Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags); |
| 137584 | + Tcl_DecrRefCount(pDb->pUnlockNotify); |
| 137585 | + pDb->pUnlockNotify = 0; |
| 137586 | + } |
| 137587 | +} |
| 137588 | +#endif |
| 137589 | + |
| 137590 | +static void DbUpdateHandler( |
| 137591 | + void *p, |
| 137592 | + int op, |
| 137593 | + const char *zDb, |
| 137594 | + const char *zTbl, |
| 137595 | + sqlite_int64 rowid |
| 137596 | +){ |
| 137597 | + SqliteDb *pDb = (SqliteDb *)p; |
| 137598 | + Tcl_Obj *pCmd; |
| 137599 | + |
| 137600 | + assert( pDb->pUpdateHook ); |
| 137601 | + assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); |
| 137602 | + |
| 137603 | + pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); |
| 137604 | + Tcl_IncrRefCount(pCmd); |
| 137605 | + Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj( |
| 137606 | + ( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1)); |
| 137607 | + Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); |
| 137608 | + Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); |
| 137609 | + Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); |
| 137610 | + Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); |
| 137611 | + Tcl_DecrRefCount(pCmd); |
| 137612 | +} |
| 137613 | + |
| 137614 | +static void tclCollateNeeded( |
| 137615 | + void *pCtx, |
| 137616 | + sqlite3 *db, |
| 137617 | + int enc, |
| 137618 | + const char *zName |
| 137619 | +){ |
| 137620 | + SqliteDb *pDb = (SqliteDb *)pCtx; |
| 137621 | + Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); |
| 137622 | + Tcl_IncrRefCount(pScript); |
| 137623 | + Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); |
| 137624 | + Tcl_EvalObjEx(pDb->interp, pScript, 0); |
| 137625 | + Tcl_DecrRefCount(pScript); |
| 137626 | +} |
| 137627 | + |
| 137628 | +/* |
| 137629 | +** This routine is called to evaluate an SQL collation function implemented |
| 137630 | +** using TCL script. |
| 137631 | +*/ |
| 137632 | +static int tclSqlCollate( |
| 137633 | + void *pCtx, |
| 137634 | + int nA, |
| 137635 | + const void *zA, |
| 137636 | + int nB, |
| 137637 | + const void *zB |
| 137638 | +){ |
| 137639 | + SqlCollate *p = (SqlCollate *)pCtx; |
| 137640 | + Tcl_Obj *pCmd; |
| 137641 | + |
| 137642 | + pCmd = Tcl_NewStringObj(p->zScript, -1); |
| 137643 | + Tcl_IncrRefCount(pCmd); |
| 137644 | + Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); |
| 137645 | + Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); |
| 137646 | + Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); |
| 137647 | + Tcl_DecrRefCount(pCmd); |
| 137648 | + return (atoi(Tcl_GetStringResult(p->interp))); |
| 137649 | +} |
| 137650 | + |
| 137651 | +/* |
| 137652 | +** This routine is called to evaluate an SQL function implemented |
| 137653 | +** using TCL script. |
| 137654 | +*/ |
| 137655 | +static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ |
| 137656 | + SqlFunc *p = sqlite3_user_data(context); |
| 137657 | + Tcl_Obj *pCmd; |
| 137658 | + int i; |
| 137659 | + int rc; |
| 137660 | + |
| 137661 | + if( argc==0 ){ |
| 137662 | + /* If there are no arguments to the function, call Tcl_EvalObjEx on the |
| 137663 | + ** script object directly. This allows the TCL compiler to generate |
| 137664 | + ** bytecode for the command on the first invocation and thus make |
| 137665 | + ** subsequent invocations much faster. */ |
| 137666 | + pCmd = p->pScript; |
| 137667 | + Tcl_IncrRefCount(pCmd); |
| 137668 | + rc = Tcl_EvalObjEx(p->interp, pCmd, 0); |
| 137669 | + Tcl_DecrRefCount(pCmd); |
| 137670 | + }else{ |
| 137671 | + /* If there are arguments to the function, make a shallow copy of the |
| 137672 | + ** script object, lappend the arguments, then evaluate the copy. |
| 137673 | + ** |
| 137674 | + ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated. |
| 137675 | + ** The new Tcl_Obj contains pointers to the original list elements. |
| 137676 | + ** That way, when Tcl_EvalObjv() is run and shimmers the first element |
| 137677 | + ** of the list to tclCmdNameType, that alternate representation will |
| 137678 | + ** be preserved and reused on the next invocation. |
| 137679 | + */ |
| 137680 | + Tcl_Obj **aArg; |
| 137681 | + int nArg; |
| 137682 | + if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ |
| 137683 | + sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); |
| 137684 | + return; |
| 137685 | + } |
| 137686 | + pCmd = Tcl_NewListObj(nArg, aArg); |
| 137687 | + Tcl_IncrRefCount(pCmd); |
| 137688 | + for(i=0; i<argc; i++){ |
| 137689 | + sqlite3_value *pIn = argv[i]; |
| 137690 | + Tcl_Obj *pVal; |
| 137691 | + |
| 137692 | + /* Set pVal to contain the i'th column of this row. */ |
| 137693 | + switch( sqlite3_value_type(pIn) ){ |
| 137694 | + case SQLITE_BLOB: { |
| 137695 | + int bytes = sqlite3_value_bytes(pIn); |
| 137696 | + pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); |
| 137697 | + break; |
| 137698 | + } |
| 137699 | + case SQLITE_INTEGER: { |
| 137700 | + sqlite_int64 v = sqlite3_value_int64(pIn); |
| 137701 | + if( v>=-2147483647 && v<=2147483647 ){ |
| 137702 | + pVal = Tcl_NewIntObj((int)v); |
| 137703 | + }else{ |
| 137704 | + pVal = Tcl_NewWideIntObj(v); |
| 137705 | + } |
| 137706 | + break; |
| 137707 | + } |
| 137708 | + case SQLITE_FLOAT: { |
| 137709 | + double r = sqlite3_value_double(pIn); |
| 137710 | + pVal = Tcl_NewDoubleObj(r); |
| 137711 | + break; |
| 137712 | + } |
| 137713 | + case SQLITE_NULL: { |
| 137714 | + pVal = Tcl_NewStringObj(p->pDb->zNull, -1); |
| 137715 | + break; |
| 137716 | + } |
| 137717 | + default: { |
| 137718 | + int bytes = sqlite3_value_bytes(pIn); |
| 137719 | + pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); |
| 137720 | + break; |
| 137721 | + } |
| 137722 | + } |
| 137723 | + rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); |
| 137724 | + if( rc ){ |
| 137725 | + Tcl_DecrRefCount(pCmd); |
| 137726 | + sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); |
| 137727 | + return; |
| 137728 | + } |
| 137729 | + } |
| 137730 | + if( !p->useEvalObjv ){ |
| 137731 | + /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd |
| 137732 | + ** is a list without a string representation. To prevent this from |
| 137733 | + ** happening, make sure pCmd has a valid string representation */ |
| 137734 | + Tcl_GetString(pCmd); |
| 137735 | + } |
| 137736 | + rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); |
| 137737 | + Tcl_DecrRefCount(pCmd); |
| 137738 | + } |
| 137739 | + |
| 137740 | + if( rc && rc!=TCL_RETURN ){ |
| 137741 | + sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); |
| 137742 | + }else{ |
| 137743 | + Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); |
| 137744 | + int n; |
| 137745 | + u8 *data; |
| 137746 | + const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); |
| 137747 | + char c = zType[0]; |
| 137748 | + if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ |
| 137749 | + /* Only return a BLOB type if the Tcl variable is a bytearray and |
| 137750 | + ** has no string representation. */ |
| 137751 | + data = Tcl_GetByteArrayFromObj(pVar, &n); |
| 137752 | + sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); |
| 137753 | + }else if( c=='b' && strcmp(zType,"boolean")==0 ){ |
| 137754 | + Tcl_GetIntFromObj(0, pVar, &n); |
| 137755 | + sqlite3_result_int(context, n); |
| 137756 | + }else if( c=='d' && strcmp(zType,"double")==0 ){ |
| 137757 | + double r; |
| 137758 | + Tcl_GetDoubleFromObj(0, pVar, &r); |
| 137759 | + sqlite3_result_double(context, r); |
| 137760 | + }else if( (c=='w' && strcmp(zType,"wideInt")==0) || |
| 137761 | + (c=='i' && strcmp(zType,"int")==0) ){ |
| 137762 | + Tcl_WideInt v; |
| 137763 | + Tcl_GetWideIntFromObj(0, pVar, &v); |
| 137764 | + sqlite3_result_int64(context, v); |
| 137765 | + }else{ |
| 137766 | + data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); |
| 137767 | + sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); |
| 137768 | + } |
| 137769 | + } |
| 137770 | +} |
| 137771 | + |
| 137772 | +#ifndef SQLITE_OMIT_AUTHORIZATION |
| 137773 | +/* |
| 137774 | +** This is the authentication function. It appends the authentication |
| 137775 | +** type code and the two arguments to zCmd[] then invokes the result |
| 137776 | +** on the interpreter. The reply is examined to determine if the |
| 137777 | +** authentication fails or succeeds. |
| 137778 | +*/ |
| 137779 | +static int auth_callback( |
| 137780 | + void *pArg, |
| 137781 | + int code, |
| 137782 | + const char *zArg1, |
| 137783 | + const char *zArg2, |
| 137784 | + const char *zArg3, |
| 137785 | + const char *zArg4 |
| 137786 | +){ |
| 137787 | + char *zCode; |
| 137788 | + Tcl_DString str; |
| 137789 | + int rc; |
| 137790 | + const char *zReply; |
| 137791 | + SqliteDb *pDb = (SqliteDb*)pArg; |
| 137792 | + if( pDb->disableAuth ) return SQLITE_OK; |
| 137793 | + |
| 137794 | + switch( code ){ |
| 137795 | + case SQLITE_COPY : zCode="SQLITE_COPY"; break; |
| 137796 | + case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; |
| 137797 | + case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; |
| 137798 | + case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; |
| 137799 | + case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; |
| 137800 | + case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; |
| 137801 | + case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; |
| 137802 | + case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; |
| 137803 | + case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; |
| 137804 | + case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; |
| 137805 | + case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; |
| 137806 | + case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; |
| 137807 | + case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; |
| 137808 | + case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; |
| 137809 | + case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; |
| 137810 | + case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; |
| 137811 | + case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; |
| 137812 | + case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; |
| 137813 | + case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; |
| 137814 | + case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; |
| 137815 | + case SQLITE_READ : zCode="SQLITE_READ"; break; |
| 137816 | + case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; |
| 137817 | + case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; |
| 137818 | + case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; |
| 137819 | + case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; |
| 137820 | + case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; |
| 137821 | + case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; |
| 137822 | + case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; |
| 137823 | + case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; |
| 137824 | + case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; |
| 137825 | + case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; |
| 137826 | + case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break; |
| 137827 | + case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break; |
| 137828 | + default : zCode="????"; break; |
| 137829 | + } |
| 137830 | + Tcl_DStringInit(&str); |
| 137831 | + Tcl_DStringAppend(&str, pDb->zAuth, -1); |
| 137832 | + Tcl_DStringAppendElement(&str, zCode); |
| 137833 | + Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); |
| 137834 | + Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); |
| 137835 | + Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); |
| 137836 | + Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); |
| 137837 | + rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); |
| 137838 | + Tcl_DStringFree(&str); |
| 137839 | + zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; |
| 137840 | + if( strcmp(zReply,"SQLITE_OK")==0 ){ |
| 137841 | + rc = SQLITE_OK; |
| 137842 | + }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ |
| 137843 | + rc = SQLITE_DENY; |
| 137844 | + }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ |
| 137845 | + rc = SQLITE_IGNORE; |
| 137846 | + }else{ |
| 137847 | + rc = 999; |
| 137848 | + } |
| 137849 | + return rc; |
| 137850 | +} |
| 137851 | +#endif /* SQLITE_OMIT_AUTHORIZATION */ |
| 137852 | + |
| 137853 | +/* |
| 137854 | +** This routine reads a line of text from FILE in, stores |
| 137855 | +** the text in memory obtained from malloc() and returns a pointer |
| 137856 | +** to the text. NULL is returned at end of file, or if malloc() |
| 137857 | +** fails. |
| 137858 | +** |
| 137859 | +** The interface is like "readline" but no command-line editing |
| 137860 | +** is done. |
| 137861 | +** |
| 137862 | +** copied from shell.c from '.import' command |
| 137863 | +*/ |
| 137864 | +static char *local_getline(char *zPrompt, FILE *in){ |
| 137865 | + char *zLine; |
| 137866 | + int nLine; |
| 137867 | + int n; |
| 137868 | + |
| 137869 | + nLine = 100; |
| 137870 | + zLine = malloc( nLine ); |
| 137871 | + if( zLine==0 ) return 0; |
| 137872 | + n = 0; |
| 137873 | + while( 1 ){ |
| 137874 | + if( n+100>nLine ){ |
| 137875 | + nLine = nLine*2 + 100; |
| 137876 | + zLine = realloc(zLine, nLine); |
| 137877 | + if( zLine==0 ) return 0; |
| 137878 | + } |
| 137879 | + if( fgets(&zLine[n], nLine - n, in)==0 ){ |
| 137880 | + if( n==0 ){ |
| 137881 | + free(zLine); |
| 137882 | + return 0; |
| 137883 | + } |
| 137884 | + zLine[n] = 0; |
| 137885 | + break; |
| 137886 | + } |
| 137887 | + while( zLine[n] ){ n++; } |
| 137888 | + if( n>0 && zLine[n-1]=='\n' ){ |
| 137889 | + n--; |
| 137890 | + zLine[n] = 0; |
| 137891 | + break; |
| 137892 | + } |
| 137893 | + } |
| 137894 | + zLine = realloc( zLine, n+1 ); |
| 137895 | + return zLine; |
| 137896 | +} |
| 137897 | + |
| 137898 | + |
| 137899 | +/* |
| 137900 | +** This function is part of the implementation of the command: |
| 137901 | +** |
| 137902 | +** $db transaction [-deferred|-immediate|-exclusive] SCRIPT |
| 137903 | +** |
| 137904 | +** It is invoked after evaluating the script SCRIPT to commit or rollback |
| 137905 | +** the transaction or savepoint opened by the [transaction] command. |
| 137906 | +*/ |
| 137907 | +static int DbTransPostCmd( |
| 137908 | + ClientData data[], /* data[0] is the Sqlite3Db* for $db */ |
| 137909 | + Tcl_Interp *interp, /* Tcl interpreter */ |
| 137910 | + int result /* Result of evaluating SCRIPT */ |
| 137911 | +){ |
| 137912 | + static const char *azEnd[] = { |
| 137913 | + "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ |
| 137914 | + "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ |
| 137915 | + "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", |
| 137916 | + "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */ |
| 137917 | + }; |
| 137918 | + SqliteDb *pDb = (SqliteDb*)data[0]; |
| 137919 | + int rc = result; |
| 137920 | + const char *zEnd; |
| 137921 | + |
| 137922 | + pDb->nTransaction--; |
| 137923 | + zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; |
| 137924 | + |
| 137925 | + pDb->disableAuth++; |
| 137926 | + if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ |
| 137927 | + /* This is a tricky scenario to handle. The most likely cause of an |
| 137928 | + ** error is that the exec() above was an attempt to commit the |
| 137929 | + ** top-level transaction that returned SQLITE_BUSY. Or, less likely, |
| 137930 | + ** that an IO-error has occured. In either case, throw a Tcl exception |
| 137931 | + ** and try to rollback the transaction. |
| 137932 | + ** |
| 137933 | + ** But it could also be that the user executed one or more BEGIN, |
| 137934 | + ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing |
| 137935 | + ** this method's logic. Not clear how this would be best handled. |
| 137936 | + */ |
| 137937 | + if( rc!=TCL_ERROR ){ |
| 137938 | + Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); |
| 137939 | + rc = TCL_ERROR; |
| 137940 | + } |
| 137941 | + sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); |
| 137942 | + } |
| 137943 | + pDb->disableAuth--; |
| 137944 | + |
| 137945 | + return rc; |
| 137946 | +} |
| 137947 | + |
| 137948 | +/* |
| 137949 | +** Unless SQLITE_TEST is defined, this function is a simple wrapper around |
| 137950 | +** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either |
| 137951 | +** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending |
| 137952 | +** on whether or not the [db_use_legacy_prepare] command has been used to |
| 137953 | +** configure the connection. |
| 137954 | +*/ |
| 137955 | +static int dbPrepare( |
| 137956 | + SqliteDb *pDb, /* Database object */ |
| 137957 | + const char *zSql, /* SQL to compile */ |
| 137958 | + sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ |
| 137959 | + const char **pzOut /* OUT: Pointer to next SQL statement */ |
| 137960 | +){ |
| 137961 | +#ifdef SQLITE_TEST |
| 137962 | + if( pDb->bLegacyPrepare ){ |
| 137963 | + return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut); |
| 137964 | + } |
| 137965 | +#endif |
| 137966 | + return sqlite3_prepare_v2(pDb->db, zSql, -1, ppStmt, pzOut); |
| 137967 | +} |
| 137968 | + |
| 137969 | +/* |
| 137970 | +** Search the cache for a prepared-statement object that implements the |
| 137971 | +** first SQL statement in the buffer pointed to by parameter zIn. If |
| 137972 | +** no such prepared-statement can be found, allocate and prepare a new |
| 137973 | +** one. In either case, bind the current values of the relevant Tcl |
| 137974 | +** variables to any $var, :var or @var variables in the statement. Before |
| 137975 | +** returning, set *ppPreStmt to point to the prepared-statement object. |
| 137976 | +** |
| 137977 | +** Output parameter *pzOut is set to point to the next SQL statement in |
| 137978 | +** buffer zIn, or to the '\0' byte at the end of zIn if there is no |
| 137979 | +** next statement. |
| 137980 | +** |
| 137981 | +** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned |
| 137982 | +** and an error message loaded into interpreter pDb->interp. |
| 137983 | +*/ |
| 137984 | +static int dbPrepareAndBind( |
| 137985 | + SqliteDb *pDb, /* Database object */ |
| 137986 | + char const *zIn, /* SQL to compile */ |
| 137987 | + char const **pzOut, /* OUT: Pointer to next SQL statement */ |
| 137988 | + SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ |
| 137989 | +){ |
| 137990 | + const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ |
| 137991 | + sqlite3_stmt *pStmt; /* Prepared statement object */ |
| 137992 | + SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ |
| 137993 | + int nSql; /* Length of zSql in bytes */ |
| 137994 | + int nVar; /* Number of variables in statement */ |
| 137995 | + int iParm = 0; /* Next free entry in apParm */ |
| 137996 | + int i; |
| 137997 | + Tcl_Interp *interp = pDb->interp; |
| 137998 | + |
| 137999 | + *ppPreStmt = 0; |
| 138000 | + |
| 138001 | + /* Trim spaces from the start of zSql and calculate the remaining length. */ |
| 138002 | + while( isspace(zSql[0]) ){ zSql++; } |
| 138003 | + nSql = strlen30(zSql); |
| 138004 | + |
| 138005 | + for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ |
| 138006 | + int n = pPreStmt->nSql; |
| 138007 | + if( nSql>=n |
| 138008 | + && memcmp(pPreStmt->zSql, zSql, n)==0 |
| 138009 | + && (zSql[n]==0 || zSql[n-1]==';') |
| 138010 | + ){ |
| 138011 | + pStmt = pPreStmt->pStmt; |
| 138012 | + *pzOut = &zSql[pPreStmt->nSql]; |
| 138013 | + |
| 138014 | + /* When a prepared statement is found, unlink it from the |
| 138015 | + ** cache list. It will later be added back to the beginning |
| 138016 | + ** of the cache list in order to implement LRU replacement. |
| 138017 | + */ |
| 138018 | + if( pPreStmt->pPrev ){ |
| 138019 | + pPreStmt->pPrev->pNext = pPreStmt->pNext; |
| 138020 | + }else{ |
| 138021 | + pDb->stmtList = pPreStmt->pNext; |
| 138022 | + } |
| 138023 | + if( pPreStmt->pNext ){ |
| 138024 | + pPreStmt->pNext->pPrev = pPreStmt->pPrev; |
| 138025 | + }else{ |
| 138026 | + pDb->stmtLast = pPreStmt->pPrev; |
| 138027 | + } |
| 138028 | + pDb->nStmt--; |
| 138029 | + nVar = sqlite3_bind_parameter_count(pStmt); |
| 138030 | + break; |
| 138031 | + } |
| 138032 | + } |
| 138033 | + |
| 138034 | + /* If no prepared statement was found. Compile the SQL text. Also allocate |
| 138035 | + ** a new SqlPreparedStmt structure. */ |
| 138036 | + if( pPreStmt==0 ){ |
| 138037 | + int nByte; |
| 138038 | + |
| 138039 | + if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ |
| 138040 | + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); |
| 138041 | + return TCL_ERROR; |
| 138042 | + } |
| 138043 | + if( pStmt==0 ){ |
| 138044 | + if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ |
| 138045 | + /* A compile-time error in the statement. */ |
| 138046 | + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); |
| 138047 | + return TCL_ERROR; |
| 138048 | + }else{ |
| 138049 | + /* The statement was a no-op. Continue to the next statement |
| 138050 | + ** in the SQL string. |
| 138051 | + */ |
| 138052 | + return TCL_OK; |
| 138053 | + } |
| 138054 | + } |
| 138055 | + |
| 138056 | + assert( pPreStmt==0 ); |
| 138057 | + nVar = sqlite3_bind_parameter_count(pStmt); |
| 138058 | + nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *); |
| 138059 | + pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte); |
| 138060 | + memset(pPreStmt, 0, nByte); |
| 138061 | + |
| 138062 | + pPreStmt->pStmt = pStmt; |
| 138063 | + pPreStmt->nSql = (int)(*pzOut - zSql); |
| 138064 | + pPreStmt->zSql = sqlite3_sql(pStmt); |
| 138065 | + pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; |
| 138066 | +#ifdef SQLITE_TEST |
| 138067 | + if( pPreStmt->zSql==0 ){ |
| 138068 | + char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1); |
| 138069 | + memcpy(zCopy, zSql, pPreStmt->nSql); |
| 138070 | + zCopy[pPreStmt->nSql] = '\0'; |
| 138071 | + pPreStmt->zSql = zCopy; |
| 138072 | + } |
| 138073 | +#endif |
| 138074 | + } |
| 138075 | + assert( pPreStmt ); |
| 138076 | + assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); |
| 138077 | + assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); |
| 138078 | + |
| 138079 | + /* Bind values to parameters that begin with $ or : */ |
| 138080 | + for(i=1; i<=nVar; i++){ |
| 138081 | + const char *zVar = sqlite3_bind_parameter_name(pStmt, i); |
| 138082 | + if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ |
| 138083 | + Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); |
| 138084 | + if( pVar ){ |
| 138085 | + int n; |
| 138086 | + u8 *data; |
| 138087 | + const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); |
| 138088 | + char c = zType[0]; |
| 138089 | + if( zVar[0]=='@' || |
| 138090 | + (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ |
| 138091 | + /* Load a BLOB type if the Tcl variable is a bytearray and |
| 138092 | + ** it has no string representation or the host |
| 138093 | + ** parameter name begins with "@". */ |
| 138094 | + data = Tcl_GetByteArrayFromObj(pVar, &n); |
| 138095 | + sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); |
| 138096 | + Tcl_IncrRefCount(pVar); |
| 138097 | + pPreStmt->apParm[iParm++] = pVar; |
| 138098 | + }else if( c=='b' && strcmp(zType,"boolean")==0 ){ |
| 138099 | + Tcl_GetIntFromObj(interp, pVar, &n); |
| 138100 | + sqlite3_bind_int(pStmt, i, n); |
| 138101 | + }else if( c=='d' && strcmp(zType,"double")==0 ){ |
| 138102 | + double r; |
| 138103 | + Tcl_GetDoubleFromObj(interp, pVar, &r); |
| 138104 | + sqlite3_bind_double(pStmt, i, r); |
| 138105 | + }else if( (c=='w' && strcmp(zType,"wideInt")==0) || |
| 138106 | + (c=='i' && strcmp(zType,"int")==0) ){ |
| 138107 | + Tcl_WideInt v; |
| 138108 | + Tcl_GetWideIntFromObj(interp, pVar, &v); |
| 138109 | + sqlite3_bind_int64(pStmt, i, v); |
| 138110 | + }else{ |
| 138111 | + data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); |
| 138112 | + sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); |
| 138113 | + Tcl_IncrRefCount(pVar); |
| 138114 | + pPreStmt->apParm[iParm++] = pVar; |
| 138115 | + } |
| 138116 | + }else{ |
| 138117 | + sqlite3_bind_null(pStmt, i); |
| 138118 | + } |
| 138119 | + } |
| 138120 | + } |
| 138121 | + pPreStmt->nParm = iParm; |
| 138122 | + *ppPreStmt = pPreStmt; |
| 138123 | + |
| 138124 | + return TCL_OK; |
| 138125 | +} |
| 138126 | + |
| 138127 | +/* |
| 138128 | +** Release a statement reference obtained by calling dbPrepareAndBind(). |
| 138129 | +** There should be exactly one call to this function for each call to |
| 138130 | +** dbPrepareAndBind(). |
| 138131 | +** |
| 138132 | +** If the discard parameter is non-zero, then the statement is deleted |
| 138133 | +** immediately. Otherwise it is added to the LRU list and may be returned |
| 138134 | +** by a subsequent call to dbPrepareAndBind(). |
| 138135 | +*/ |
| 138136 | +static void dbReleaseStmt( |
| 138137 | + SqliteDb *pDb, /* Database handle */ |
| 138138 | + SqlPreparedStmt *pPreStmt, /* Prepared statement handle to release */ |
| 138139 | + int discard /* True to delete (not cache) the pPreStmt */ |
| 138140 | +){ |
| 138141 | + int i; |
| 138142 | + |
| 138143 | + /* Free the bound string and blob parameters */ |
| 138144 | + for(i=0; i<pPreStmt->nParm; i++){ |
| 138145 | + Tcl_DecrRefCount(pPreStmt->apParm[i]); |
| 138146 | + } |
| 138147 | + pPreStmt->nParm = 0; |
| 138148 | + |
| 138149 | + if( pDb->maxStmt<=0 || discard ){ |
| 138150 | + /* If the cache is turned off, deallocated the statement */ |
| 138151 | + dbFreeStmt(pPreStmt); |
| 138152 | + }else{ |
| 138153 | + /* Add the prepared statement to the beginning of the cache list. */ |
| 138154 | + pPreStmt->pNext = pDb->stmtList; |
| 138155 | + pPreStmt->pPrev = 0; |
| 138156 | + if( pDb->stmtList ){ |
| 138157 | + pDb->stmtList->pPrev = pPreStmt; |
| 138158 | + } |
| 138159 | + pDb->stmtList = pPreStmt; |
| 138160 | + if( pDb->stmtLast==0 ){ |
| 138161 | + assert( pDb->nStmt==0 ); |
| 138162 | + pDb->stmtLast = pPreStmt; |
| 138163 | + }else{ |
| 138164 | + assert( pDb->nStmt>0 ); |
| 138165 | + } |
| 138166 | + pDb->nStmt++; |
| 138167 | + |
| 138168 | + /* If we have too many statement in cache, remove the surplus from |
| 138169 | + ** the end of the cache list. */ |
| 138170 | + while( pDb->nStmt>pDb->maxStmt ){ |
| 138171 | + SqlPreparedStmt *pLast = pDb->stmtLast; |
| 138172 | + pDb->stmtLast = pLast->pPrev; |
| 138173 | + pDb->stmtLast->pNext = 0; |
| 138174 | + pDb->nStmt--; |
| 138175 | + dbFreeStmt(pLast); |
| 138176 | + } |
| 138177 | + } |
| 138178 | +} |
| 138179 | + |
| 138180 | +/* |
| 138181 | +** Structure used with dbEvalXXX() functions: |
| 138182 | +** |
| 138183 | +** dbEvalInit() |
| 138184 | +** dbEvalStep() |
| 138185 | +** dbEvalFinalize() |
| 138186 | +** dbEvalRowInfo() |
| 138187 | +** dbEvalColumnValue() |
| 138188 | +*/ |
| 138189 | +typedef struct DbEvalContext DbEvalContext; |
| 138190 | +struct DbEvalContext { |
| 138191 | + SqliteDb *pDb; /* Database handle */ |
| 138192 | + Tcl_Obj *pSql; /* Object holding string zSql */ |
| 138193 | + const char *zSql; /* Remaining SQL to execute */ |
| 138194 | + SqlPreparedStmt *pPreStmt; /* Current statement */ |
| 138195 | + int nCol; /* Number of columns returned by pStmt */ |
| 138196 | + Tcl_Obj *pArray; /* Name of array variable */ |
| 138197 | + Tcl_Obj **apColName; /* Array of column names */ |
| 138198 | +}; |
| 138199 | + |
| 138200 | +/* |
| 138201 | +** Release any cache of column names currently held as part of |
| 138202 | +** the DbEvalContext structure passed as the first argument. |
| 138203 | +*/ |
| 138204 | +static void dbReleaseColumnNames(DbEvalContext *p){ |
| 138205 | + if( p->apColName ){ |
| 138206 | + int i; |
| 138207 | + for(i=0; i<p->nCol; i++){ |
| 138208 | + Tcl_DecrRefCount(p->apColName[i]); |
| 138209 | + } |
| 138210 | + Tcl_Free((char *)p->apColName); |
| 138211 | + p->apColName = 0; |
| 138212 | + } |
| 138213 | + p->nCol = 0; |
| 138214 | +} |
| 138215 | + |
| 138216 | +/* |
| 138217 | +** Initialize a DbEvalContext structure. |
| 138218 | +** |
| 138219 | +** If pArray is not NULL, then it contains the name of a Tcl array |
| 138220 | +** variable. The "*" member of this array is set to a list containing |
| 138221 | +** the names of the columns returned by the statement as part of each |
| 138222 | +** call to dbEvalStep(), in order from left to right. e.g. if the names |
| 138223 | +** of the returned columns are a, b and c, it does the equivalent of the |
| 138224 | +** tcl command: |
| 138225 | +** |
| 138226 | +** set ${pArray}(*) {a b c} |
| 138227 | +*/ |
| 138228 | +static void dbEvalInit( |
| 138229 | + DbEvalContext *p, /* Pointer to structure to initialize */ |
| 138230 | + SqliteDb *pDb, /* Database handle */ |
| 138231 | + Tcl_Obj *pSql, /* Object containing SQL script */ |
| 138232 | + Tcl_Obj *pArray /* Name of Tcl array to set (*) element of */ |
| 138233 | +){ |
| 138234 | + memset(p, 0, sizeof(DbEvalContext)); |
| 138235 | + p->pDb = pDb; |
| 138236 | + p->zSql = Tcl_GetString(pSql); |
| 138237 | + p->pSql = pSql; |
| 138238 | + Tcl_IncrRefCount(pSql); |
| 138239 | + if( pArray ){ |
| 138240 | + p->pArray = pArray; |
| 138241 | + Tcl_IncrRefCount(pArray); |
| 138242 | + } |
| 138243 | +} |
| 138244 | + |
| 138245 | +/* |
| 138246 | +** Obtain information about the row that the DbEvalContext passed as the |
| 138247 | +** first argument currently points to. |
| 138248 | +*/ |
| 138249 | +static void dbEvalRowInfo( |
| 138250 | + DbEvalContext *p, /* Evaluation context */ |
| 138251 | + int *pnCol, /* OUT: Number of column names */ |
| 138252 | + Tcl_Obj ***papColName /* OUT: Array of column names */ |
| 138253 | +){ |
| 138254 | + /* Compute column names */ |
| 138255 | + if( 0==p->apColName ){ |
| 138256 | + sqlite3_stmt *pStmt = p->pPreStmt->pStmt; |
| 138257 | + int i; /* Iterator variable */ |
| 138258 | + int nCol; /* Number of columns returned by pStmt */ |
| 138259 | + Tcl_Obj **apColName = 0; /* Array of column names */ |
| 138260 | + |
| 138261 | + p->nCol = nCol = sqlite3_column_count(pStmt); |
| 138262 | + if( nCol>0 && (papColName || p->pArray) ){ |
| 138263 | + apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); |
| 138264 | + for(i=0; i<nCol; i++){ |
| 138265 | + apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1); |
| 138266 | + Tcl_IncrRefCount(apColName[i]); |
| 138267 | + } |
| 138268 | + p->apColName = apColName; |
| 138269 | + } |
| 138270 | + |
| 138271 | + /* If results are being stored in an array variable, then create |
| 138272 | + ** the array(*) entry for that array |
| 138273 | + */ |
| 138274 | + if( p->pArray ){ |
| 138275 | + Tcl_Interp *interp = p->pDb->interp; |
| 138276 | + Tcl_Obj *pColList = Tcl_NewObj(); |
| 138277 | + Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); |
| 138278 | + |
| 138279 | + for(i=0; i<nCol; i++){ |
| 138280 | + Tcl_ListObjAppendElement(interp, pColList, apColName[i]); |
| 138281 | + } |
| 138282 | + Tcl_IncrRefCount(pStar); |
| 138283 | + Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0); |
| 138284 | + Tcl_DecrRefCount(pStar); |
| 138285 | + } |
| 138286 | + } |
| 138287 | + |
| 138288 | + if( papColName ){ |
| 138289 | + *papColName = p->apColName; |
| 138290 | + } |
| 138291 | + if( pnCol ){ |
| 138292 | + *pnCol = p->nCol; |
| 138293 | + } |
| 138294 | +} |
| 138295 | + |
| 138296 | +/* |
| 138297 | +** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is |
| 138298 | +** returned, then an error message is stored in the interpreter before |
| 138299 | +** returning. |
| 138300 | +** |
| 138301 | +** A return value of TCL_OK means there is a row of data available. The |
| 138302 | +** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This |
| 138303 | +** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK |
| 138304 | +** is returned, then the SQL script has finished executing and there are |
| 138305 | +** no further rows available. This is similar to SQLITE_DONE. |
| 138306 | +*/ |
| 138307 | +static int dbEvalStep(DbEvalContext *p){ |
| 138308 | + const char *zPrevSql = 0; /* Previous value of p->zSql */ |
| 138309 | + |
| 138310 | + while( p->zSql[0] || p->pPreStmt ){ |
| 138311 | + int rc; |
| 138312 | + if( p->pPreStmt==0 ){ |
| 138313 | + zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql); |
| 138314 | + rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); |
| 138315 | + if( rc!=TCL_OK ) return rc; |
| 138316 | + }else{ |
| 138317 | + int rcs; |
| 138318 | + SqliteDb *pDb = p->pDb; |
| 138319 | + SqlPreparedStmt *pPreStmt = p->pPreStmt; |
| 138320 | + sqlite3_stmt *pStmt = pPreStmt->pStmt; |
| 138321 | + |
| 138322 | + rcs = sqlite3_step(pStmt); |
| 138323 | + if( rcs==SQLITE_ROW ){ |
| 138324 | + return TCL_OK; |
| 138325 | + } |
| 138326 | + if( p->pArray ){ |
| 138327 | + dbEvalRowInfo(p, 0, 0); |
| 138328 | + } |
| 138329 | + rcs = sqlite3_reset(pStmt); |
| 138330 | + |
| 138331 | + pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1); |
| 138332 | + pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1); |
| 138333 | + pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1); |
| 138334 | + dbReleaseColumnNames(p); |
| 138335 | + p->pPreStmt = 0; |
| 138336 | + |
| 138337 | + if( rcs!=SQLITE_OK ){ |
| 138338 | + /* If a run-time error occurs, report the error and stop reading |
| 138339 | + ** the SQL. */ |
| 138340 | + dbReleaseStmt(pDb, pPreStmt, 1); |
| 138341 | +#if SQLITE_TEST |
| 138342 | + if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ |
| 138343 | + /* If the runtime error was an SQLITE_SCHEMA, and the database |
| 138344 | + ** handle is configured to use the legacy sqlite3_prepare() |
| 138345 | + ** interface, retry prepare()/step() on the same SQL statement. |
| 138346 | + ** This only happens once. If there is a second SQLITE_SCHEMA |
| 138347 | + ** error, the error will be returned to the caller. */ |
| 138348 | + p->zSql = zPrevSql; |
| 138349 | + continue; |
| 138350 | + } |
| 138351 | +#endif |
| 138352 | + Tcl_SetObjResult(pDb->interp, |
| 138353 | + Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); |
| 138354 | + return TCL_ERROR; |
| 138355 | + }else{ |
| 138356 | + dbReleaseStmt(pDb, pPreStmt, 0); |
| 138357 | + } |
| 138358 | + } |
| 138359 | + } |
| 138360 | + |
| 138361 | + /* Finished */ |
| 138362 | + return TCL_BREAK; |
| 138363 | +} |
| 138364 | + |
| 138365 | +/* |
| 138366 | +** Free all resources currently held by the DbEvalContext structure passed |
| 138367 | +** as the first argument. There should be exactly one call to this function |
| 138368 | +** for each call to dbEvalInit(). |
| 138369 | +*/ |
| 138370 | +static void dbEvalFinalize(DbEvalContext *p){ |
| 138371 | + if( p->pPreStmt ){ |
| 138372 | + sqlite3_reset(p->pPreStmt->pStmt); |
| 138373 | + dbReleaseStmt(p->pDb, p->pPreStmt, 0); |
| 138374 | + p->pPreStmt = 0; |
| 138375 | + } |
| 138376 | + if( p->pArray ){ |
| 138377 | + Tcl_DecrRefCount(p->pArray); |
| 138378 | + p->pArray = 0; |
| 138379 | + } |
| 138380 | + Tcl_DecrRefCount(p->pSql); |
| 138381 | + dbReleaseColumnNames(p); |
| 138382 | +} |
| 138383 | + |
| 138384 | +/* |
| 138385 | +** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains |
| 138386 | +** the value for the iCol'th column of the row currently pointed to by |
| 138387 | +** the DbEvalContext structure passed as the first argument. |
| 138388 | +*/ |
| 138389 | +static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ |
| 138390 | + sqlite3_stmt *pStmt = p->pPreStmt->pStmt; |
| 138391 | + switch( sqlite3_column_type(pStmt, iCol) ){ |
| 138392 | + case SQLITE_BLOB: { |
| 138393 | + int bytes = sqlite3_column_bytes(pStmt, iCol); |
| 138394 | + const char *zBlob = sqlite3_column_blob(pStmt, iCol); |
| 138395 | + if( !zBlob ) bytes = 0; |
| 138396 | + return Tcl_NewByteArrayObj((u8*)zBlob, bytes); |
| 138397 | + } |
| 138398 | + case SQLITE_INTEGER: { |
| 138399 | + sqlite_int64 v = sqlite3_column_int64(pStmt, iCol); |
| 138400 | + if( v>=-2147483647 && v<=2147483647 ){ |
| 138401 | + return Tcl_NewIntObj((int)v); |
| 138402 | + }else{ |
| 138403 | + return Tcl_NewWideIntObj(v); |
| 138404 | + } |
| 138405 | + } |
| 138406 | + case SQLITE_FLOAT: { |
| 138407 | + return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol)); |
| 138408 | + } |
| 138409 | + case SQLITE_NULL: { |
| 138410 | + return Tcl_NewStringObj(p->pDb->zNull, -1); |
| 138411 | + } |
| 138412 | + } |
| 138413 | + |
| 138414 | + return Tcl_NewStringObj((char*)sqlite3_column_text(pStmt, iCol), -1); |
| 138415 | +} |
| 138416 | + |
| 138417 | +/* |
| 138418 | +** If using Tcl version 8.6 or greater, use the NR functions to avoid |
| 138419 | +** recursive evalution of scripts by the [db eval] and [db trans] |
| 138420 | +** commands. Even if the headers used while compiling the extension |
| 138421 | +** are 8.6 or newer, the code still tests the Tcl version at runtime. |
| 138422 | +** This allows stubs-enabled builds to be used with older Tcl libraries. |
| 138423 | +*/ |
| 138424 | +#if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6) |
| 138425 | +# define SQLITE_TCL_NRE 1 |
| 138426 | +static int DbUseNre(void){ |
| 138427 | + int major, minor; |
| 138428 | + Tcl_GetVersion(&major, &minor, 0, 0); |
| 138429 | + return( (major==8 && minor>=6) || major>8 ); |
| 138430 | +} |
| 138431 | +#else |
| 138432 | +/* |
| 138433 | +** Compiling using headers earlier than 8.6. In this case NR cannot be |
| 138434 | +** used, so DbUseNre() to always return zero. Add #defines for the other |
| 138435 | +** Tcl_NRxxx() functions to prevent them from causing compilation errors, |
| 138436 | +** even though the only invocations of them are within conditional blocks |
| 138437 | +** of the form: |
| 138438 | +** |
| 138439 | +** if( DbUseNre() ) { ... } |
| 138440 | +*/ |
| 138441 | +# define SQLITE_TCL_NRE 0 |
| 138442 | +# define DbUseNre() 0 |
| 138443 | +# define Tcl_NRAddCallback(a,b,c,d,e,f) 0 |
| 138444 | +# define Tcl_NREvalObj(a,b,c) 0 |
| 138445 | +# define Tcl_NRCreateCommand(a,b,c,d,e,f) 0 |
| 138446 | +#endif |
| 138447 | + |
| 138448 | +/* |
| 138449 | +** This function is part of the implementation of the command: |
| 138450 | +** |
| 138451 | +** $db eval SQL ?ARRAYNAME? SCRIPT |
| 138452 | +*/ |
| 138453 | +static int DbEvalNextCmd( |
| 138454 | + ClientData data[], /* data[0] is the (DbEvalContext*) */ |
| 138455 | + Tcl_Interp *interp, /* Tcl interpreter */ |
| 138456 | + int result /* Result so far */ |
| 138457 | +){ |
| 138458 | + int rc = result; /* Return code */ |
| 138459 | + |
| 138460 | + /* The first element of the data[] array is a pointer to a DbEvalContext |
| 138461 | + ** structure allocated using Tcl_Alloc(). The second element of data[] |
| 138462 | + ** is a pointer to a Tcl_Obj containing the script to run for each row |
| 138463 | + ** returned by the queries encapsulated in data[0]. */ |
| 138464 | + DbEvalContext *p = (DbEvalContext *)data[0]; |
| 138465 | + Tcl_Obj *pScript = (Tcl_Obj *)data[1]; |
| 138466 | + Tcl_Obj *pArray = p->pArray; |
| 138467 | + |
| 138468 | + while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){ |
| 138469 | + int i; |
| 138470 | + int nCol; |
| 138471 | + Tcl_Obj **apColName; |
| 138472 | + dbEvalRowInfo(p, &nCol, &apColName); |
| 138473 | + for(i=0; i<nCol; i++){ |
| 138474 | + Tcl_Obj *pVal = dbEvalColumnValue(p, i); |
| 138475 | + if( pArray==0 ){ |
| 138476 | + Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); |
| 138477 | + }else{ |
| 138478 | + Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); |
| 138479 | + } |
| 138480 | + } |
| 138481 | + |
| 138482 | + /* The required interpreter variables are now populated with the data |
| 138483 | + ** from the current row. If using NRE, schedule callbacks to evaluate |
| 138484 | + ** script pScript, then to invoke this function again to fetch the next |
| 138485 | + ** row (or clean up if there is no next row or the script throws an |
| 138486 | + ** exception). After scheduling the callbacks, return control to the |
| 138487 | + ** caller. |
| 138488 | + ** |
| 138489 | + ** If not using NRE, evaluate pScript directly and continue with the |
| 138490 | + ** next iteration of this while(...) loop. */ |
| 138491 | + if( DbUseNre() ){ |
| 138492 | + Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0); |
| 138493 | + return Tcl_NREvalObj(interp, pScript, 0); |
| 138494 | + }else{ |
| 138495 | + rc = Tcl_EvalObjEx(interp, pScript, 0); |
| 138496 | + } |
| 138497 | + } |
| 138498 | + |
| 138499 | + Tcl_DecrRefCount(pScript); |
| 138500 | + dbEvalFinalize(p); |
| 138501 | + Tcl_Free((char *)p); |
| 138502 | + |
| 138503 | + if( rc==TCL_OK || rc==TCL_BREAK ){ |
| 138504 | + Tcl_ResetResult(interp); |
| 138505 | + rc = TCL_OK; |
| 138506 | + } |
| 138507 | + return rc; |
| 138508 | +} |
| 138509 | + |
| 138510 | +/* |
| 138511 | +** The "sqlite" command below creates a new Tcl command for each |
| 138512 | +** connection it opens to an SQLite database. This routine is invoked |
| 138513 | +** whenever one of those connection-specific commands is executed |
| 138514 | +** in Tcl. For example, if you run Tcl code like this: |
| 138515 | +** |
| 138516 | +** sqlite3 db1 "my_database" |
| 138517 | +** db1 close |
| 138518 | +** |
| 138519 | +** The first command opens a connection to the "my_database" database |
| 138520 | +** and calls that connection "db1". The second command causes this |
| 138521 | +** subroutine to be invoked. |
| 138522 | +*/ |
| 138523 | +static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
| 138524 | + SqliteDb *pDb = (SqliteDb*)cd; |
| 138525 | + int choice; |
| 138526 | + int rc = TCL_OK; |
| 138527 | + static const char *DB_strs[] = { |
| 138528 | + "authorizer", "backup", "busy", |
| 138529 | + "cache", "changes", "close", |
| 138530 | + "collate", "collation_needed", "commit_hook", |
| 138531 | + "complete", "copy", "enable_load_extension", |
| 138532 | + "errorcode", "eval", "exists", |
| 138533 | + "function", "incrblob", "interrupt", |
| 138534 | + "last_insert_rowid", "nullvalue", "onecolumn", |
| 138535 | + "profile", "progress", "rekey", |
| 138536 | + "restore", "rollback_hook", "status", |
| 138537 | + "timeout", "total_changes", "trace", |
| 138538 | + "transaction", "unlock_notify", "update_hook", |
| 138539 | + "version", "wal_hook", 0 |
| 138540 | + }; |
| 138541 | + enum DB_enum { |
| 138542 | + DB_AUTHORIZER, DB_BACKUP, DB_BUSY, |
| 138543 | + DB_CACHE, DB_CHANGES, DB_CLOSE, |
| 138544 | + DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, |
| 138545 | + DB_COMPLETE, DB_COPY, DB_ENABLE_LOAD_EXTENSION, |
| 138546 | + DB_ERRORCODE, DB_EVAL, DB_EXISTS, |
| 138547 | + DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT, |
| 138548 | + DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, |
| 138549 | + DB_PROFILE, DB_PROGRESS, DB_REKEY, |
| 138550 | + DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS, |
| 138551 | + DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, |
| 138552 | + DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, |
| 138553 | + DB_VERSION, DB_WAL_HOOK |
| 138554 | + }; |
| 138555 | + /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ |
| 138556 | + |
| 138557 | + if( objc<2 ){ |
| 138558 | + Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); |
| 138559 | + return TCL_ERROR; |
| 138560 | + } |
| 138561 | + if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ |
| 138562 | + return TCL_ERROR; |
| 138563 | + } |
| 138564 | + |
| 138565 | + switch( (enum DB_enum)choice ){ |
| 138566 | + |
| 138567 | + /* $db authorizer ?CALLBACK? |
| 138568 | + ** |
| 138569 | + ** Invoke the given callback to authorize each SQL operation as it is |
| 138570 | + ** compiled. 5 arguments are appended to the callback before it is |
| 138571 | + ** invoked: |
| 138572 | + ** |
| 138573 | + ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) |
| 138574 | + ** (2) First descriptive name (depends on authorization type) |
| 138575 | + ** (3) Second descriptive name |
| 138576 | + ** (4) Name of the database (ex: "main", "temp") |
| 138577 | + ** (5) Name of trigger that is doing the access |
| 138578 | + ** |
| 138579 | + ** The callback should return on of the following strings: SQLITE_OK, |
| 138580 | + ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. |
| 138581 | + ** |
| 138582 | + ** If this method is invoked with no arguments, the current authorization |
| 138583 | + ** callback string is returned. |
| 138584 | + */ |
| 138585 | + case DB_AUTHORIZER: { |
| 138586 | +#ifdef SQLITE_OMIT_AUTHORIZATION |
| 138587 | + Tcl_AppendResult(interp, "authorization not available in this build", 0); |
| 138588 | + return TCL_ERROR; |
| 138589 | +#else |
| 138590 | + if( objc>3 ){ |
| 138591 | + Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); |
| 138592 | + return TCL_ERROR; |
| 138593 | + }else if( objc==2 ){ |
| 138594 | + if( pDb->zAuth ){ |
| 138595 | + Tcl_AppendResult(interp, pDb->zAuth, 0); |
| 138596 | + } |
| 138597 | + }else{ |
| 138598 | + char *zAuth; |
| 138599 | + int len; |
| 138600 | + if( pDb->zAuth ){ |
| 138601 | + Tcl_Free(pDb->zAuth); |
| 138602 | + } |
| 138603 | + zAuth = Tcl_GetStringFromObj(objv[2], &len); |
| 138604 | + if( zAuth && len>0 ){ |
| 138605 | + pDb->zAuth = Tcl_Alloc( len + 1 ); |
| 138606 | + memcpy(pDb->zAuth, zAuth, len+1); |
| 138607 | + }else{ |
| 138608 | + pDb->zAuth = 0; |
| 138609 | + } |
| 138610 | + if( pDb->zAuth ){ |
| 138611 | + pDb->interp = interp; |
| 138612 | + sqlite3_set_authorizer(pDb->db, auth_callback, pDb); |
| 138613 | + }else{ |
| 138614 | + sqlite3_set_authorizer(pDb->db, 0, 0); |
| 138615 | + } |
| 138616 | + } |
| 138617 | +#endif |
| 138618 | + break; |
| 138619 | + } |
| 138620 | + |
| 138621 | + /* $db backup ?DATABASE? FILENAME |
| 138622 | + ** |
| 138623 | + ** Open or create a database file named FILENAME. Transfer the |
| 138624 | + ** content of local database DATABASE (default: "main") into the |
| 138625 | + ** FILENAME database. |
| 138626 | + */ |
| 138627 | + case DB_BACKUP: { |
| 138628 | + const char *zDestFile; |
| 138629 | + const char *zSrcDb; |
| 138630 | + sqlite3 *pDest; |
| 138631 | + sqlite3_backup *pBackup; |
| 138632 | + |
| 138633 | + if( objc==3 ){ |
| 138634 | + zSrcDb = "main"; |
| 138635 | + zDestFile = Tcl_GetString(objv[2]); |
| 138636 | + }else if( objc==4 ){ |
| 138637 | + zSrcDb = Tcl_GetString(objv[2]); |
| 138638 | + zDestFile = Tcl_GetString(objv[3]); |
| 138639 | + }else{ |
| 138640 | + Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); |
| 138641 | + return TCL_ERROR; |
| 138642 | + } |
| 138643 | + rc = sqlite3_open(zDestFile, &pDest); |
| 138644 | + if( rc!=SQLITE_OK ){ |
| 138645 | + Tcl_AppendResult(interp, "cannot open target database: ", |
| 138646 | + sqlite3_errmsg(pDest), (char*)0); |
| 138647 | + sqlite3_close(pDest); |
| 138648 | + return TCL_ERROR; |
| 138649 | + } |
| 138650 | + pBackup = sqlite3_backup_init(pDest, "main", pDb->db, zSrcDb); |
| 138651 | + if( pBackup==0 ){ |
| 138652 | + Tcl_AppendResult(interp, "backup failed: ", |
| 138653 | + sqlite3_errmsg(pDest), (char*)0); |
| 138654 | + sqlite3_close(pDest); |
| 138655 | + return TCL_ERROR; |
| 138656 | + } |
| 138657 | + while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} |
| 138658 | + sqlite3_backup_finish(pBackup); |
| 138659 | + if( rc==SQLITE_DONE ){ |
| 138660 | + rc = TCL_OK; |
| 138661 | + }else{ |
| 138662 | + Tcl_AppendResult(interp, "backup failed: ", |
| 138663 | + sqlite3_errmsg(pDest), (char*)0); |
| 138664 | + rc = TCL_ERROR; |
| 138665 | + } |
| 138666 | + sqlite3_close(pDest); |
| 138667 | + break; |
| 138668 | + } |
| 138669 | + |
| 138670 | + /* $db busy ?CALLBACK? |
| 138671 | + ** |
| 138672 | + ** Invoke the given callback if an SQL statement attempts to open |
| 138673 | + ** a locked database file. |
| 138674 | + */ |
| 138675 | + case DB_BUSY: { |
| 138676 | + if( objc>3 ){ |
| 138677 | + Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); |
| 138678 | + return TCL_ERROR; |
| 138679 | + }else if( objc==2 ){ |
| 138680 | + if( pDb->zBusy ){ |
| 138681 | + Tcl_AppendResult(interp, pDb->zBusy, 0); |
| 138682 | + } |
| 138683 | + }else{ |
| 138684 | + char *zBusy; |
| 138685 | + int len; |
| 138686 | + if( pDb->zBusy ){ |
| 138687 | + Tcl_Free(pDb->zBusy); |
| 138688 | + } |
| 138689 | + zBusy = Tcl_GetStringFromObj(objv[2], &len); |
| 138690 | + if( zBusy && len>0 ){ |
| 138691 | + pDb->zBusy = Tcl_Alloc( len + 1 ); |
| 138692 | + memcpy(pDb->zBusy, zBusy, len+1); |
| 138693 | + }else{ |
| 138694 | + pDb->zBusy = 0; |
| 138695 | + } |
| 138696 | + if( pDb->zBusy ){ |
| 138697 | + pDb->interp = interp; |
| 138698 | + sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); |
| 138699 | + }else{ |
| 138700 | + sqlite3_busy_handler(pDb->db, 0, 0); |
| 138701 | + } |
| 138702 | + } |
| 138703 | + break; |
| 138704 | + } |
| 138705 | + |
| 138706 | + /* $db cache flush |
| 138707 | + ** $db cache size n |
| 138708 | + ** |
| 138709 | + ** Flush the prepared statement cache, or set the maximum number of |
| 138710 | + ** cached statements. |
| 138711 | + */ |
| 138712 | + case DB_CACHE: { |
| 138713 | + char *subCmd; |
| 138714 | + int n; |
| 138715 | + |
| 138716 | + if( objc<=2 ){ |
| 138717 | + Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); |
| 138718 | + return TCL_ERROR; |
| 138719 | + } |
| 138720 | + subCmd = Tcl_GetStringFromObj( objv[2], 0 ); |
| 138721 | + if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ |
| 138722 | + if( objc!=3 ){ |
| 138723 | + Tcl_WrongNumArgs(interp, 2, objv, "flush"); |
| 138724 | + return TCL_ERROR; |
| 138725 | + }else{ |
| 138726 | + flushStmtCache( pDb ); |
| 138727 | + } |
| 138728 | + }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ |
| 138729 | + if( objc!=4 ){ |
| 138730 | + Tcl_WrongNumArgs(interp, 2, objv, "size n"); |
| 138731 | + return TCL_ERROR; |
| 138732 | + }else{ |
| 138733 | + if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ |
| 138734 | + Tcl_AppendResult( interp, "cannot convert \"", |
| 138735 | + Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0); |
| 138736 | + return TCL_ERROR; |
| 138737 | + }else{ |
| 138738 | + if( n<0 ){ |
| 138739 | + flushStmtCache( pDb ); |
| 138740 | + n = 0; |
| 138741 | + }else if( n>MAX_PREPARED_STMTS ){ |
| 138742 | + n = MAX_PREPARED_STMTS; |
| 138743 | + } |
| 138744 | + pDb->maxStmt = n; |
| 138745 | + } |
| 138746 | + } |
| 138747 | + }else{ |
| 138748 | + Tcl_AppendResult( interp, "bad option \"", |
| 138749 | + Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 0); |
| 138750 | + return TCL_ERROR; |
| 138751 | + } |
| 138752 | + break; |
| 138753 | + } |
| 138754 | + |
| 138755 | + /* $db changes |
| 138756 | + ** |
| 138757 | + ** Return the number of rows that were modified, inserted, or deleted by |
| 138758 | + ** the most recent INSERT, UPDATE or DELETE statement, not including |
| 138759 | + ** any changes made by trigger programs. |
| 138760 | + */ |
| 138761 | + case DB_CHANGES: { |
| 138762 | + Tcl_Obj *pResult; |
| 138763 | + if( objc!=2 ){ |
| 138764 | + Tcl_WrongNumArgs(interp, 2, objv, ""); |
| 138765 | + return TCL_ERROR; |
| 138766 | + } |
| 138767 | + pResult = Tcl_GetObjResult(interp); |
| 138768 | + Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); |
| 138769 | + break; |
| 138770 | + } |
| 138771 | + |
| 138772 | + /* $db close |
| 138773 | + ** |
| 138774 | + ** Shutdown the database |
| 138775 | + */ |
| 138776 | + case DB_CLOSE: { |
| 138777 | + Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); |
| 138778 | + break; |
| 138779 | + } |
| 138780 | + |
| 138781 | + /* |
| 138782 | + ** $db collate NAME SCRIPT |
| 138783 | + ** |
| 138784 | + ** Create a new SQL collation function called NAME. Whenever |
| 138785 | + ** that function is called, invoke SCRIPT to evaluate the function. |
| 138786 | + */ |
| 138787 | + case DB_COLLATE: { |
| 138788 | + SqlCollate *pCollate; |
| 138789 | + char *zName; |
| 138790 | + char *zScript; |
| 138791 | + int nScript; |
| 138792 | + if( objc!=4 ){ |
| 138793 | + Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); |
| 138794 | + return TCL_ERROR; |
| 138795 | + } |
| 138796 | + zName = Tcl_GetStringFromObj(objv[2], 0); |
| 138797 | + zScript = Tcl_GetStringFromObj(objv[3], &nScript); |
| 138798 | + pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); |
| 138799 | + if( pCollate==0 ) return TCL_ERROR; |
| 138800 | + pCollate->interp = interp; |
| 138801 | + pCollate->pNext = pDb->pCollate; |
| 138802 | + pCollate->zScript = (char*)&pCollate[1]; |
| 138803 | + pDb->pCollate = pCollate; |
| 138804 | + memcpy(pCollate->zScript, zScript, nScript+1); |
| 138805 | + if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, |
| 138806 | + pCollate, tclSqlCollate) ){ |
| 138807 | + Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); |
| 138808 | + return TCL_ERROR; |
| 138809 | + } |
| 138810 | + break; |
| 138811 | + } |
| 138812 | + |
| 138813 | + /* |
| 138814 | + ** $db collation_needed SCRIPT |
| 138815 | + ** |
| 138816 | + ** Create a new SQL collation function called NAME. Whenever |
| 138817 | + ** that function is called, invoke SCRIPT to evaluate the function. |
| 138818 | + */ |
| 138819 | + case DB_COLLATION_NEEDED: { |
| 138820 | + if( objc!=3 ){ |
| 138821 | + Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); |
| 138822 | + return TCL_ERROR; |
| 138823 | + } |
| 138824 | + if( pDb->pCollateNeeded ){ |
| 138825 | + Tcl_DecrRefCount(pDb->pCollateNeeded); |
| 138826 | + } |
| 138827 | + pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); |
| 138828 | + Tcl_IncrRefCount(pDb->pCollateNeeded); |
| 138829 | + sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); |
| 138830 | + break; |
| 138831 | + } |
| 138832 | + |
| 138833 | + /* $db commit_hook ?CALLBACK? |
| 138834 | + ** |
| 138835 | + ** Invoke the given callback just before committing every SQL transaction. |
| 138836 | + ** If the callback throws an exception or returns non-zero, then the |
| 138837 | + ** transaction is aborted. If CALLBACK is an empty string, the callback |
| 138838 | + ** is disabled. |
| 138839 | + */ |
| 138840 | + case DB_COMMIT_HOOK: { |
| 138841 | + if( objc>3 ){ |
| 138842 | + Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); |
| 138843 | + return TCL_ERROR; |
| 138844 | + }else if( objc==2 ){ |
| 138845 | + if( pDb->zCommit ){ |
| 138846 | + Tcl_AppendResult(interp, pDb->zCommit, 0); |
| 138847 | + } |
| 138848 | + }else{ |
| 138849 | + char *zCommit; |
| 138850 | + int len; |
| 138851 | + if( pDb->zCommit ){ |
| 138852 | + Tcl_Free(pDb->zCommit); |
| 138853 | + } |
| 138854 | + zCommit = Tcl_GetStringFromObj(objv[2], &len); |
| 138855 | + if( zCommit && len>0 ){ |
| 138856 | + pDb->zCommit = Tcl_Alloc( len + 1 ); |
| 138857 | + memcpy(pDb->zCommit, zCommit, len+1); |
| 138858 | + }else{ |
| 138859 | + pDb->zCommit = 0; |
| 138860 | + } |
| 138861 | + if( pDb->zCommit ){ |
| 138862 | + pDb->interp = interp; |
| 138863 | + sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); |
| 138864 | + }else{ |
| 138865 | + sqlite3_commit_hook(pDb->db, 0, 0); |
| 138866 | + } |
| 138867 | + } |
| 138868 | + break; |
| 138869 | + } |
| 138870 | + |
| 138871 | + /* $db complete SQL |
| 138872 | + ** |
| 138873 | + ** Return TRUE if SQL is a complete SQL statement. Return FALSE if |
| 138874 | + ** additional lines of input are needed. This is similar to the |
| 138875 | + ** built-in "info complete" command of Tcl. |
| 138876 | + */ |
| 138877 | + case DB_COMPLETE: { |
| 138878 | +#ifndef SQLITE_OMIT_COMPLETE |
| 138879 | + Tcl_Obj *pResult; |
| 138880 | + int isComplete; |
| 138881 | + if( objc!=3 ){ |
| 138882 | + Tcl_WrongNumArgs(interp, 2, objv, "SQL"); |
| 138883 | + return TCL_ERROR; |
| 138884 | + } |
| 138885 | + isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); |
| 138886 | + pResult = Tcl_GetObjResult(interp); |
| 138887 | + Tcl_SetBooleanObj(pResult, isComplete); |
| 138888 | +#endif |
| 138889 | + break; |
| 138890 | + } |
| 138891 | + |
| 138892 | + /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? |
| 138893 | + ** |
| 138894 | + ** Copy data into table from filename, optionally using SEPARATOR |
| 138895 | + ** as column separators. If a column contains a null string, or the |
| 138896 | + ** value of NULLINDICATOR, a NULL is inserted for the column. |
| 138897 | + ** conflict-algorithm is one of the sqlite conflict algorithms: |
| 138898 | + ** rollback, abort, fail, ignore, replace |
| 138899 | + ** On success, return the number of lines processed, not necessarily same |
| 138900 | + ** as 'db changes' due to conflict-algorithm selected. |
| 138901 | + ** |
| 138902 | + ** This code is basically an implementation/enhancement of |
| 138903 | + ** the sqlite3 shell.c ".import" command. |
| 138904 | + ** |
| 138905 | + ** This command usage is equivalent to the sqlite2.x COPY statement, |
| 138906 | + ** which imports file data into a table using the PostgreSQL COPY file format: |
| 138907 | + ** $db copy $conflit_algo $table_name $filename \t \\N |
| 138908 | + */ |
| 138909 | + case DB_COPY: { |
| 138910 | + char *zTable; /* Insert data into this table */ |
| 138911 | + char *zFile; /* The file from which to extract data */ |
| 138912 | + char *zConflict; /* The conflict algorithm to use */ |
| 138913 | + sqlite3_stmt *pStmt; /* A statement */ |
| 138914 | + int nCol; /* Number of columns in the table */ |
| 138915 | + int nByte; /* Number of bytes in an SQL string */ |
| 138916 | + int i, j; /* Loop counters */ |
| 138917 | + int nSep; /* Number of bytes in zSep[] */ |
| 138918 | + int nNull; /* Number of bytes in zNull[] */ |
| 138919 | + char *zSql; /* An SQL statement */ |
| 138920 | + char *zLine; /* A single line of input from the file */ |
| 138921 | + char **azCol; /* zLine[] broken up into columns */ |
| 138922 | + char *zCommit; /* How to commit changes */ |
| 138923 | + FILE *in; /* The input file */ |
| 138924 | + int lineno = 0; /* Line number of input file */ |
| 138925 | + char zLineNum[80]; /* Line number print buffer */ |
| 138926 | + Tcl_Obj *pResult; /* interp result */ |
| 138927 | + |
| 138928 | + char *zSep; |
| 138929 | + char *zNull; |
| 138930 | + if( objc<5 || objc>7 ){ |
| 138931 | + Tcl_WrongNumArgs(interp, 2, objv, |
| 138932 | + "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); |
| 138933 | + return TCL_ERROR; |
| 138934 | + } |
| 138935 | + if( objc>=6 ){ |
| 138936 | + zSep = Tcl_GetStringFromObj(objv[5], 0); |
| 138937 | + }else{ |
| 138938 | + zSep = "\t"; |
| 138939 | + } |
| 138940 | + if( objc>=7 ){ |
| 138941 | + zNull = Tcl_GetStringFromObj(objv[6], 0); |
| 138942 | + }else{ |
| 138943 | + zNull = ""; |
| 138944 | + } |
| 138945 | + zConflict = Tcl_GetStringFromObj(objv[2], 0); |
| 138946 | + zTable = Tcl_GetStringFromObj(objv[3], 0); |
| 138947 | + zFile = Tcl_GetStringFromObj(objv[4], 0); |
| 138948 | + nSep = strlen30(zSep); |
| 138949 | + nNull = strlen30(zNull); |
| 138950 | + if( nSep==0 ){ |
| 138951 | + Tcl_AppendResult(interp,"Error: non-null separator required for copy",0); |
| 138952 | + return TCL_ERROR; |
| 138953 | + } |
| 138954 | + if(strcmp(zConflict, "rollback") != 0 && |
| 138955 | + strcmp(zConflict, "abort" ) != 0 && |
| 138956 | + strcmp(zConflict, "fail" ) != 0 && |
| 138957 | + strcmp(zConflict, "ignore" ) != 0 && |
| 138958 | + strcmp(zConflict, "replace" ) != 0 ) { |
| 138959 | + Tcl_AppendResult(interp, "Error: \"", zConflict, |
| 138960 | + "\", conflict-algorithm must be one of: rollback, " |
| 138961 | + "abort, fail, ignore, or replace", 0); |
| 138962 | + return TCL_ERROR; |
| 138963 | + } |
| 138964 | + zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); |
| 138965 | + if( zSql==0 ){ |
| 138966 | + Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0); |
| 138967 | + return TCL_ERROR; |
| 138968 | + } |
| 138969 | + nByte = strlen30(zSql); |
| 138970 | + rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); |
| 138971 | + sqlite3_free(zSql); |
| 138972 | + if( rc ){ |
| 138973 | + Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); |
| 138974 | + nCol = 0; |
| 138975 | + }else{ |
| 138976 | + nCol = sqlite3_column_count(pStmt); |
| 138977 | + } |
| 138978 | + sqlite3_finalize(pStmt); |
| 138979 | + if( nCol==0 ) { |
| 138980 | + return TCL_ERROR; |
| 138981 | + } |
| 138982 | + zSql = malloc( nByte + 50 + nCol*2 ); |
| 138983 | + if( zSql==0 ) { |
| 138984 | + Tcl_AppendResult(interp, "Error: can't malloc()", 0); |
| 138985 | + return TCL_ERROR; |
| 138986 | + } |
| 138987 | + sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", |
| 138988 | + zConflict, zTable); |
| 138989 | + j = strlen30(zSql); |
| 138990 | + for(i=1; i<nCol; i++){ |
| 138991 | + zSql[j++] = ','; |
| 138992 | + zSql[j++] = '?'; |
| 138993 | + } |
| 138994 | + zSql[j++] = ')'; |
| 138995 | + zSql[j] = 0; |
| 138996 | + rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); |
| 138997 | + free(zSql); |
| 138998 | + if( rc ){ |
| 138999 | + Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); |
| 139000 | + sqlite3_finalize(pStmt); |
| 139001 | + return TCL_ERROR; |
| 139002 | + } |
| 139003 | + in = fopen(zFile, "rb"); |
| 139004 | + if( in==0 ){ |
| 139005 | + Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL); |
| 139006 | + sqlite3_finalize(pStmt); |
| 139007 | + return TCL_ERROR; |
| 139008 | + } |
| 139009 | + azCol = malloc( sizeof(azCol[0])*(nCol+1) ); |
| 139010 | + if( azCol==0 ) { |
| 139011 | + Tcl_AppendResult(interp, "Error: can't malloc()", 0); |
| 139012 | + fclose(in); |
| 139013 | + return TCL_ERROR; |
| 139014 | + } |
| 139015 | + (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); |
| 139016 | + zCommit = "COMMIT"; |
| 139017 | + while( (zLine = local_getline(0, in))!=0 ){ |
| 139018 | + char *z; |
| 139019 | + lineno++; |
| 139020 | + azCol[0] = zLine; |
| 139021 | + for(i=0, z=zLine; *z; z++){ |
| 139022 | + if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ |
| 139023 | + *z = 0; |
| 139024 | + i++; |
| 139025 | + if( i<nCol ){ |
| 139026 | + azCol[i] = &z[nSep]; |
| 139027 | + z += nSep-1; |
| 139028 | + } |
| 139029 | + } |
| 139030 | + } |
| 139031 | + if( i+1!=nCol ){ |
| 139032 | + char *zErr; |
| 139033 | + int nErr = strlen30(zFile) + 200; |
| 139034 | + zErr = malloc(nErr); |
| 139035 | + if( zErr ){ |
| 139036 | + sqlite3_snprintf(nErr, zErr, |
| 139037 | + "Error: %s line %d: expected %d columns of data but found %d", |
| 139038 | + zFile, lineno, nCol, i+1); |
| 139039 | + Tcl_AppendResult(interp, zErr, 0); |
| 139040 | + free(zErr); |
| 139041 | + } |
| 139042 | + zCommit = "ROLLBACK"; |
| 139043 | + break; |
| 139044 | + } |
| 139045 | + for(i=0; i<nCol; i++){ |
| 139046 | + /* check for null data, if so, bind as null */ |
| 139047 | + if( (nNull>0 && strcmp(azCol[i], zNull)==0) |
| 139048 | + || strlen30(azCol[i])==0 |
| 139049 | + ){ |
| 139050 | + sqlite3_bind_null(pStmt, i+1); |
| 139051 | + }else{ |
| 139052 | + sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); |
| 139053 | + } |
| 139054 | + } |
| 139055 | + sqlite3_step(pStmt); |
| 139056 | + rc = sqlite3_reset(pStmt); |
| 139057 | + free(zLine); |
| 139058 | + if( rc!=SQLITE_OK ){ |
| 139059 | + Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0); |
| 139060 | + zCommit = "ROLLBACK"; |
| 139061 | + break; |
| 139062 | + } |
| 139063 | + } |
| 139064 | + free(azCol); |
| 139065 | + fclose(in); |
| 139066 | + sqlite3_finalize(pStmt); |
| 139067 | + (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0); |
| 139068 | + |
| 139069 | + if( zCommit[0] == 'C' ){ |
| 139070 | + /* success, set result as number of lines processed */ |
| 139071 | + pResult = Tcl_GetObjResult(interp); |
| 139072 | + Tcl_SetIntObj(pResult, lineno); |
| 139073 | + rc = TCL_OK; |
| 139074 | + }else{ |
| 139075 | + /* failure, append lineno where failed */ |
| 139076 | + sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); |
| 139077 | + Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0); |
| 139078 | + rc = TCL_ERROR; |
| 139079 | + } |
| 139080 | + break; |
| 139081 | + } |
| 139082 | + |
| 139083 | + /* |
| 139084 | + ** $db enable_load_extension BOOLEAN |
| 139085 | + ** |
| 139086 | + ** Turn the extension loading feature on or off. It if off by |
| 139087 | + ** default. |
| 139088 | + */ |
| 139089 | + case DB_ENABLE_LOAD_EXTENSION: { |
| 139090 | +#ifndef SQLITE_OMIT_LOAD_EXTENSION |
| 139091 | + int onoff; |
| 139092 | + if( objc!=3 ){ |
| 139093 | + Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN"); |
| 139094 | + return TCL_ERROR; |
| 139095 | + } |
| 139096 | + if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){ |
| 139097 | + return TCL_ERROR; |
| 139098 | + } |
| 139099 | + sqlite3_enable_load_extension(pDb->db, onoff); |
| 139100 | + break; |
| 139101 | +#else |
| 139102 | + Tcl_AppendResult(interp, "extension loading is turned off at compile-time", |
| 139103 | + 0); |
| 139104 | + return TCL_ERROR; |
| 139105 | +#endif |
| 139106 | + } |
| 139107 | + |
| 139108 | + /* |
| 139109 | + ** $db errorcode |
| 139110 | + ** |
| 139111 | + ** Return the numeric error code that was returned by the most recent |
| 139112 | + ** call to sqlite3_exec(). |
| 139113 | + */ |
| 139114 | + case DB_ERRORCODE: { |
| 139115 | + Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); |
| 139116 | + break; |
| 139117 | + } |
| 139118 | + |
| 139119 | + /* |
| 139120 | + ** $db exists $sql |
| 139121 | + ** $db onecolumn $sql |
| 139122 | + ** |
| 139123 | + ** The onecolumn method is the equivalent of: |
| 139124 | + ** lindex [$db eval $sql] 0 |
| 139125 | + */ |
| 139126 | + case DB_EXISTS: |
| 139127 | + case DB_ONECOLUMN: { |
| 139128 | + DbEvalContext sEval; |
| 139129 | + if( objc!=3 ){ |
| 139130 | + Tcl_WrongNumArgs(interp, 2, objv, "SQL"); |
| 139131 | + return TCL_ERROR; |
| 139132 | + } |
| 139133 | + |
| 139134 | + dbEvalInit(&sEval, pDb, objv[2], 0); |
| 139135 | + rc = dbEvalStep(&sEval); |
| 139136 | + if( choice==DB_ONECOLUMN ){ |
| 139137 | + if( rc==TCL_OK ){ |
| 139138 | + Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0)); |
| 139139 | + }else if( rc==TCL_BREAK ){ |
| 139140 | + Tcl_ResetResult(interp); |
| 139141 | + } |
| 139142 | + }else if( rc==TCL_BREAK || rc==TCL_OK ){ |
| 139143 | + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK)); |
| 139144 | + } |
| 139145 | + dbEvalFinalize(&sEval); |
| 139146 | + |
| 139147 | + if( rc==TCL_BREAK ){ |
| 139148 | + rc = TCL_OK; |
| 139149 | + } |
| 139150 | + break; |
| 139151 | + } |
| 139152 | + |
| 139153 | + /* |
| 139154 | + ** $db eval $sql ?array? ?{ ...code... }? |
| 139155 | + ** |
| 139156 | + ** The SQL statement in $sql is evaluated. For each row, the values are |
| 139157 | + ** placed in elements of the array named "array" and ...code... is executed. |
| 139158 | + ** If "array" and "code" are omitted, then no callback is every invoked. |
| 139159 | + ** If "array" is an empty string, then the values are placed in variables |
| 139160 | + ** that have the same name as the fields extracted by the query. |
| 139161 | + */ |
| 139162 | + case DB_EVAL: { |
| 139163 | + if( objc<3 || objc>5 ){ |
| 139164 | + Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); |
| 139165 | + return TCL_ERROR; |
| 139166 | + } |
| 139167 | + |
| 139168 | + if( objc==3 ){ |
| 139169 | + DbEvalContext sEval; |
| 139170 | + Tcl_Obj *pRet = Tcl_NewObj(); |
| 139171 | + Tcl_IncrRefCount(pRet); |
| 139172 | + dbEvalInit(&sEval, pDb, objv[2], 0); |
| 139173 | + while( TCL_OK==(rc = dbEvalStep(&sEval)) ){ |
| 139174 | + int i; |
| 139175 | + int nCol; |
| 139176 | + dbEvalRowInfo(&sEval, &nCol, 0); |
| 139177 | + for(i=0; i<nCol; i++){ |
| 139178 | + Tcl_ListObjAppendElement(interp, pRet, dbEvalColumnValue(&sEval, i)); |
| 139179 | + } |
| 139180 | + } |
| 139181 | + dbEvalFinalize(&sEval); |
| 139182 | + if( rc==TCL_BREAK ){ |
| 139183 | + Tcl_SetObjResult(interp, pRet); |
| 139184 | + rc = TCL_OK; |
| 139185 | + } |
| 139186 | + Tcl_DecrRefCount(pRet); |
| 139187 | + }else{ |
| 139188 | + ClientData cd[2]; |
| 139189 | + DbEvalContext *p; |
| 139190 | + Tcl_Obj *pArray = 0; |
| 139191 | + Tcl_Obj *pScript; |
| 139192 | + |
| 139193 | + if( objc==5 && *(char *)Tcl_GetString(objv[3]) ){ |
| 139194 | + pArray = objv[3]; |
| 139195 | + } |
| 139196 | + pScript = objv[objc-1]; |
| 139197 | + Tcl_IncrRefCount(pScript); |
| 139198 | + |
| 139199 | + p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); |
| 139200 | + dbEvalInit(p, pDb, objv[2], pArray); |
| 139201 | + |
| 139202 | + cd[0] = (void *)p; |
| 139203 | + cd[1] = (void *)pScript; |
| 139204 | + rc = DbEvalNextCmd(cd, interp, TCL_OK); |
| 139205 | + } |
| 139206 | + break; |
| 139207 | + } |
| 139208 | + |
| 139209 | + /* |
| 139210 | + ** $db function NAME [-argcount N] SCRIPT |
| 139211 | + ** |
| 139212 | + ** Create a new SQL function called NAME. Whenever that function is |
| 139213 | + ** called, invoke SCRIPT to evaluate the function. |
| 139214 | + */ |
| 139215 | + case DB_FUNCTION: { |
| 139216 | + SqlFunc *pFunc; |
| 139217 | + Tcl_Obj *pScript; |
| 139218 | + char *zName; |
| 139219 | + int nArg = -1; |
| 139220 | + if( objc==6 ){ |
| 139221 | + const char *z = Tcl_GetString(objv[3]); |
| 139222 | + int n = strlen30(z); |
| 139223 | + if( n>2 && strncmp(z, "-argcount",n)==0 ){ |
| 139224 | + if( Tcl_GetIntFromObj(interp, objv[4], &nArg) ) return TCL_ERROR; |
| 139225 | + if( nArg<0 ){ |
| 139226 | + Tcl_AppendResult(interp, "number of arguments must be non-negative", |
| 139227 | + (char*)0); |
| 139228 | + return TCL_ERROR; |
| 139229 | + } |
| 139230 | + } |
| 139231 | + pScript = objv[5]; |
| 139232 | + }else if( objc!=4 ){ |
| 139233 | + Tcl_WrongNumArgs(interp, 2, objv, "NAME [-argcount N] SCRIPT"); |
| 139234 | + return TCL_ERROR; |
| 139235 | + }else{ |
| 139236 | + pScript = objv[3]; |
| 139237 | + } |
| 139238 | + zName = Tcl_GetStringFromObj(objv[2], 0); |
| 139239 | + pFunc = findSqlFunc(pDb, zName); |
| 139240 | + if( pFunc==0 ) return TCL_ERROR; |
| 139241 | + if( pFunc->pScript ){ |
| 139242 | + Tcl_DecrRefCount(pFunc->pScript); |
| 139243 | + } |
| 139244 | + pFunc->pScript = pScript; |
| 139245 | + Tcl_IncrRefCount(pScript); |
| 139246 | + pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); |
| 139247 | + rc = sqlite3_create_function(pDb->db, zName, nArg, SQLITE_UTF8, |
| 139248 | + pFunc, tclSqlFunc, 0, 0); |
| 139249 | + if( rc!=SQLITE_OK ){ |
| 139250 | + rc = TCL_ERROR; |
| 139251 | + Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); |
| 139252 | + } |
| 139253 | + break; |
| 139254 | + } |
| 139255 | + |
| 139256 | + /* |
| 139257 | + ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID |
| 139258 | + */ |
| 139259 | + case DB_INCRBLOB: { |
| 139260 | +#ifdef SQLITE_OMIT_INCRBLOB |
| 139261 | + Tcl_AppendResult(interp, "incrblob not available in this build", 0); |
| 139262 | + return TCL_ERROR; |
| 139263 | +#else |
| 139264 | + int isReadonly = 0; |
| 139265 | + const char *zDb = "main"; |
| 139266 | + const char *zTable; |
| 139267 | + const char *zColumn; |
| 139268 | + Tcl_WideInt iRow; |
| 139269 | + |
| 139270 | + /* Check for the -readonly option */ |
| 139271 | + if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){ |
| 139272 | + isReadonly = 1; |
| 139273 | + } |
| 139274 | + |
| 139275 | + if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ |
| 139276 | + Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); |
| 139277 | + return TCL_ERROR; |
| 139278 | + } |
| 139279 | + |
| 139280 | + if( objc==(6+isReadonly) ){ |
| 139281 | + zDb = Tcl_GetString(objv[2]); |
| 139282 | + } |
| 139283 | + zTable = Tcl_GetString(objv[objc-3]); |
| 139284 | + zColumn = Tcl_GetString(objv[objc-2]); |
| 139285 | + rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow); |
| 139286 | + |
| 139287 | + if( rc==TCL_OK ){ |
| 139288 | + rc = createIncrblobChannel( |
| 139289 | + interp, pDb, zDb, zTable, zColumn, iRow, isReadonly |
| 139290 | + ); |
| 139291 | + } |
| 139292 | +#endif |
| 139293 | + break; |
| 139294 | + } |
| 139295 | + |
| 139296 | + /* |
| 139297 | + ** $db interrupt |
| 139298 | + ** |
| 139299 | + ** Interrupt the execution of the inner-most SQL interpreter. This |
| 139300 | + ** causes the SQL statement to return an error of SQLITE_INTERRUPT. |
| 139301 | + */ |
| 139302 | + case DB_INTERRUPT: { |
| 139303 | + sqlite3_interrupt(pDb->db); |
| 139304 | + break; |
| 139305 | + } |
| 139306 | + |
| 139307 | + /* |
| 139308 | + ** $db nullvalue ?STRING? |
| 139309 | + ** |
| 139310 | + ** Change text used when a NULL comes back from the database. If ?STRING? |
| 139311 | + ** is not present, then the current string used for NULL is returned. |
| 139312 | + ** If STRING is present, then STRING is returned. |
| 139313 | + ** |
| 139314 | + */ |
| 139315 | + case DB_NULLVALUE: { |
| 139316 | + if( objc!=2 && objc!=3 ){ |
| 139317 | + Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); |
| 139318 | + return TCL_ERROR; |
| 139319 | + } |
| 139320 | + if( objc==3 ){ |
| 139321 | + int len; |
| 139322 | + char *zNull = Tcl_GetStringFromObj(objv[2], &len); |
| 139323 | + if( pDb->zNull ){ |
| 139324 | + Tcl_Free(pDb->zNull); |
| 139325 | + } |
| 139326 | + if( zNull && len>0 ){ |
| 139327 | + pDb->zNull = Tcl_Alloc( len + 1 ); |
| 139328 | + memcpy(pDb->zNull, zNull, len); |
| 139329 | + pDb->zNull[len] = '\0'; |
| 139330 | + }else{ |
| 139331 | + pDb->zNull = 0; |
| 139332 | + } |
| 139333 | + } |
| 139334 | + Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); |
| 139335 | + break; |
| 139336 | + } |
| 139337 | + |
| 139338 | + /* |
| 139339 | + ** $db last_insert_rowid |
| 139340 | + ** |
| 139341 | + ** Return an integer which is the ROWID for the most recent insert. |
| 139342 | + */ |
| 139343 | + case DB_LAST_INSERT_ROWID: { |
| 139344 | + Tcl_Obj *pResult; |
| 139345 | + Tcl_WideInt rowid; |
| 139346 | + if( objc!=2 ){ |
| 139347 | + Tcl_WrongNumArgs(interp, 2, objv, ""); |
| 139348 | + return TCL_ERROR; |
| 139349 | + } |
| 139350 | + rowid = sqlite3_last_insert_rowid(pDb->db); |
| 139351 | + pResult = Tcl_GetObjResult(interp); |
| 139352 | + Tcl_SetWideIntObj(pResult, rowid); |
| 139353 | + break; |
| 139354 | + } |
| 139355 | + |
| 139356 | + /* |
| 139357 | + ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. |
| 139358 | + */ |
| 139359 | + |
| 139360 | + /* $db progress ?N CALLBACK? |
| 139361 | + ** |
| 139362 | + ** Invoke the given callback every N virtual machine opcodes while executing |
| 139363 | + ** queries. |
| 139364 | + */ |
| 139365 | + case DB_PROGRESS: { |
| 139366 | + if( objc==2 ){ |
| 139367 | + if( pDb->zProgress ){ |
| 139368 | + Tcl_AppendResult(interp, pDb->zProgress, 0); |
| 139369 | + } |
| 139370 | + }else if( objc==4 ){ |
| 139371 | + char *zProgress; |
| 139372 | + int len; |
| 139373 | + int N; |
| 139374 | + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ |
| 139375 | + return TCL_ERROR; |
| 139376 | + }; |
| 139377 | + if( pDb->zProgress ){ |
| 139378 | + Tcl_Free(pDb->zProgress); |
| 139379 | + } |
| 139380 | + zProgress = Tcl_GetStringFromObj(objv[3], &len); |
| 139381 | + if( zProgress && len>0 ){ |
| 139382 | + pDb->zProgress = Tcl_Alloc( len + 1 ); |
| 139383 | + memcpy(pDb->zProgress, zProgress, len+1); |
| 139384 | + }else{ |
| 139385 | + pDb->zProgress = 0; |
| 139386 | + } |
| 139387 | +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
| 139388 | + if( pDb->zProgress ){ |
| 139389 | + pDb->interp = interp; |
| 139390 | + sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); |
| 139391 | + }else{ |
| 139392 | + sqlite3_progress_handler(pDb->db, 0, 0, 0); |
| 139393 | + } |
| 139394 | +#endif |
| 139395 | + }else{ |
| 139396 | + Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); |
| 139397 | + return TCL_ERROR; |
| 139398 | + } |
| 139399 | + break; |
| 139400 | + } |
| 139401 | + |
| 139402 | + /* $db profile ?CALLBACK? |
| 139403 | + ** |
| 139404 | + ** Make arrangements to invoke the CALLBACK routine after each SQL statement |
| 139405 | + ** that has run. The text of the SQL and the amount of elapse time are |
| 139406 | + ** appended to CALLBACK before the script is run. |
| 139407 | + */ |
| 139408 | + case DB_PROFILE: { |
| 139409 | + if( objc>3 ){ |
| 139410 | + Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); |
| 139411 | + return TCL_ERROR; |
| 139412 | + }else if( objc==2 ){ |
| 139413 | + if( pDb->zProfile ){ |
| 139414 | + Tcl_AppendResult(interp, pDb->zProfile, 0); |
| 139415 | + } |
| 139416 | + }else{ |
| 139417 | + char *zProfile; |
| 139418 | + int len; |
| 139419 | + if( pDb->zProfile ){ |
| 139420 | + Tcl_Free(pDb->zProfile); |
| 139421 | + } |
| 139422 | + zProfile = Tcl_GetStringFromObj(objv[2], &len); |
| 139423 | + if( zProfile && len>0 ){ |
| 139424 | + pDb->zProfile = Tcl_Alloc( len + 1 ); |
| 139425 | + memcpy(pDb->zProfile, zProfile, len+1); |
| 139426 | + }else{ |
| 139427 | + pDb->zProfile = 0; |
| 139428 | + } |
| 139429 | +#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) |
| 139430 | + if( pDb->zProfile ){ |
| 139431 | + pDb->interp = interp; |
| 139432 | + sqlite3_profile(pDb->db, DbProfileHandler, pDb); |
| 139433 | + }else{ |
| 139434 | + sqlite3_profile(pDb->db, 0, 0); |
| 139435 | + } |
| 139436 | +#endif |
| 139437 | + } |
| 139438 | + break; |
| 139439 | + } |
| 139440 | + |
| 139441 | + /* |
| 139442 | + ** $db rekey KEY |
| 139443 | + ** |
| 139444 | + ** Change the encryption key on the currently open database. |
| 139445 | + */ |
| 139446 | + case DB_REKEY: { |
| 139447 | +#ifdef SQLITE_HAS_CODEC |
| 139448 | + int nKey; |
| 139449 | + void *pKey; |
| 139450 | +#endif |
| 139451 | + if( objc!=3 ){ |
| 139452 | + Tcl_WrongNumArgs(interp, 2, objv, "KEY"); |
| 139453 | + return TCL_ERROR; |
| 139454 | + } |
| 139455 | +#ifdef SQLITE_HAS_CODEC |
| 139456 | + pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); |
| 139457 | + rc = sqlite3_rekey(pDb->db, pKey, nKey); |
| 139458 | + if( rc ){ |
| 139459 | + Tcl_AppendResult(interp, sqlite3_errstr(rc), 0); |
| 139460 | + rc = TCL_ERROR; |
| 139461 | + } |
| 139462 | +#endif |
| 139463 | + break; |
| 139464 | + } |
| 139465 | + |
| 139466 | + /* $db restore ?DATABASE? FILENAME |
| 139467 | + ** |
| 139468 | + ** Open a database file named FILENAME. Transfer the content |
| 139469 | + ** of FILENAME into the local database DATABASE (default: "main"). |
| 139470 | + */ |
| 139471 | + case DB_RESTORE: { |
| 139472 | + const char *zSrcFile; |
| 139473 | + const char *zDestDb; |
| 139474 | + sqlite3 *pSrc; |
| 139475 | + sqlite3_backup *pBackup; |
| 139476 | + int nTimeout = 0; |
| 139477 | + |
| 139478 | + if( objc==3 ){ |
| 139479 | + zDestDb = "main"; |
| 139480 | + zSrcFile = Tcl_GetString(objv[2]); |
| 139481 | + }else if( objc==4 ){ |
| 139482 | + zDestDb = Tcl_GetString(objv[2]); |
| 139483 | + zSrcFile = Tcl_GetString(objv[3]); |
| 139484 | + }else{ |
| 139485 | + Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); |
| 139486 | + return TCL_ERROR; |
| 139487 | + } |
| 139488 | + rc = sqlite3_open_v2(zSrcFile, &pSrc, SQLITE_OPEN_READONLY, 0); |
| 139489 | + if( rc!=SQLITE_OK ){ |
| 139490 | + Tcl_AppendResult(interp, "cannot open source database: ", |
| 139491 | + sqlite3_errmsg(pSrc), (char*)0); |
| 139492 | + sqlite3_close(pSrc); |
| 139493 | + return TCL_ERROR; |
| 139494 | + } |
| 139495 | + pBackup = sqlite3_backup_init(pDb->db, zDestDb, pSrc, "main"); |
| 139496 | + if( pBackup==0 ){ |
| 139497 | + Tcl_AppendResult(interp, "restore failed: ", |
| 139498 | + sqlite3_errmsg(pDb->db), (char*)0); |
| 139499 | + sqlite3_close(pSrc); |
| 139500 | + return TCL_ERROR; |
| 139501 | + } |
| 139502 | + while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK |
| 139503 | + || rc==SQLITE_BUSY ){ |
| 139504 | + if( rc==SQLITE_BUSY ){ |
| 139505 | + if( nTimeout++ >= 3 ) break; |
| 139506 | + sqlite3_sleep(100); |
| 139507 | + } |
| 139508 | + } |
| 139509 | + sqlite3_backup_finish(pBackup); |
| 139510 | + if( rc==SQLITE_DONE ){ |
| 139511 | + rc = TCL_OK; |
| 139512 | + }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ |
| 139513 | + Tcl_AppendResult(interp, "restore failed: source database busy", |
| 139514 | + (char*)0); |
| 139515 | + rc = TCL_ERROR; |
| 139516 | + }else{ |
| 139517 | + Tcl_AppendResult(interp, "restore failed: ", |
| 139518 | + sqlite3_errmsg(pDb->db), (char*)0); |
| 139519 | + rc = TCL_ERROR; |
| 139520 | + } |
| 139521 | + sqlite3_close(pSrc); |
| 139522 | + break; |
| 139523 | + } |
| 139524 | + |
| 139525 | + /* |
| 139526 | + ** $db status (step|sort|autoindex) |
| 139527 | + ** |
| 139528 | + ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or |
| 139529 | + ** SQLITE_STMTSTATUS_SORT for the most recent eval. |
| 139530 | + */ |
| 139531 | + case DB_STATUS: { |
| 139532 | + int v; |
| 139533 | + const char *zOp; |
| 139534 | + if( objc!=3 ){ |
| 139535 | + Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)"); |
| 139536 | + return TCL_ERROR; |
| 139537 | + } |
| 139538 | + zOp = Tcl_GetString(objv[2]); |
| 139539 | + if( strcmp(zOp, "step")==0 ){ |
| 139540 | + v = pDb->nStep; |
| 139541 | + }else if( strcmp(zOp, "sort")==0 ){ |
| 139542 | + v = pDb->nSort; |
| 139543 | + }else if( strcmp(zOp, "autoindex")==0 ){ |
| 139544 | + v = pDb->nIndex; |
| 139545 | + }else{ |
| 139546 | + Tcl_AppendResult(interp, |
| 139547 | + "bad argument: should be autoindex, step, or sort", |
| 139548 | + (char*)0); |
| 139549 | + return TCL_ERROR; |
| 139550 | + } |
| 139551 | + Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); |
| 139552 | + break; |
| 139553 | + } |
| 139554 | + |
| 139555 | + /* |
| 139556 | + ** $db timeout MILLESECONDS |
| 139557 | + ** |
| 139558 | + ** Delay for the number of milliseconds specified when a file is locked. |
| 139559 | + */ |
| 139560 | + case DB_TIMEOUT: { |
| 139561 | + int ms; |
| 139562 | + if( objc!=3 ){ |
| 139563 | + Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); |
| 139564 | + return TCL_ERROR; |
| 139565 | + } |
| 139566 | + if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; |
| 139567 | + sqlite3_busy_timeout(pDb->db, ms); |
| 139568 | + break; |
| 139569 | + } |
| 139570 | + |
| 139571 | + /* |
| 139572 | + ** $db total_changes |
| 139573 | + ** |
| 139574 | + ** Return the number of rows that were modified, inserted, or deleted |
| 139575 | + ** since the database handle was created. |
| 139576 | + */ |
| 139577 | + case DB_TOTAL_CHANGES: { |
| 139578 | + Tcl_Obj *pResult; |
| 139579 | + if( objc!=2 ){ |
| 139580 | + Tcl_WrongNumArgs(interp, 2, objv, ""); |
| 139581 | + return TCL_ERROR; |
| 139582 | + } |
| 139583 | + pResult = Tcl_GetObjResult(interp); |
| 139584 | + Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); |
| 139585 | + break; |
| 139586 | + } |
| 139587 | + |
| 139588 | + /* $db trace ?CALLBACK? |
| 139589 | + ** |
| 139590 | + ** Make arrangements to invoke the CALLBACK routine for each SQL statement |
| 139591 | + ** that is executed. The text of the SQL is appended to CALLBACK before |
| 139592 | + ** it is executed. |
| 139593 | + */ |
| 139594 | + case DB_TRACE: { |
| 139595 | + if( objc>3 ){ |
| 139596 | + Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); |
| 139597 | + return TCL_ERROR; |
| 139598 | + }else if( objc==2 ){ |
| 139599 | + if( pDb->zTrace ){ |
| 139600 | + Tcl_AppendResult(interp, pDb->zTrace, 0); |
| 139601 | + } |
| 139602 | + }else{ |
| 139603 | + char *zTrace; |
| 139604 | + int len; |
| 139605 | + if( pDb->zTrace ){ |
| 139606 | + Tcl_Free(pDb->zTrace); |
| 139607 | + } |
| 139608 | + zTrace = Tcl_GetStringFromObj(objv[2], &len); |
| 139609 | + if( zTrace && len>0 ){ |
| 139610 | + pDb->zTrace = Tcl_Alloc( len + 1 ); |
| 139611 | + memcpy(pDb->zTrace, zTrace, len+1); |
| 139612 | + }else{ |
| 139613 | + pDb->zTrace = 0; |
| 139614 | + } |
| 139615 | +#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) |
| 139616 | + if( pDb->zTrace ){ |
| 139617 | + pDb->interp = interp; |
| 139618 | + sqlite3_trace(pDb->db, DbTraceHandler, pDb); |
| 139619 | + }else{ |
| 139620 | + sqlite3_trace(pDb->db, 0, 0); |
| 139621 | + } |
| 139622 | +#endif |
| 139623 | + } |
| 139624 | + break; |
| 139625 | + } |
| 139626 | + |
| 139627 | + /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT |
| 139628 | + ** |
| 139629 | + ** Start a new transaction (if we are not already in the midst of a |
| 139630 | + ** transaction) and execute the TCL script SCRIPT. After SCRIPT |
| 139631 | + ** completes, either commit the transaction or roll it back if SCRIPT |
| 139632 | + ** throws an exception. Or if no new transation was started, do nothing. |
| 139633 | + ** pass the exception on up the stack. |
| 139634 | + ** |
| 139635 | + ** This command was inspired by Dave Thomas's talk on Ruby at the |
| 139636 | + ** 2005 O'Reilly Open Source Convention (OSCON). |
| 139637 | + */ |
| 139638 | + case DB_TRANSACTION: { |
| 139639 | + Tcl_Obj *pScript; |
| 139640 | + const char *zBegin = "SAVEPOINT _tcl_transaction"; |
| 139641 | + if( objc!=3 && objc!=4 ){ |
| 139642 | + Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); |
| 139643 | + return TCL_ERROR; |
| 139644 | + } |
| 139645 | + |
| 139646 | + if( pDb->nTransaction==0 && objc==4 ){ |
| 139647 | + static const char *TTYPE_strs[] = { |
| 139648 | + "deferred", "exclusive", "immediate", 0 |
| 139649 | + }; |
| 139650 | + enum TTYPE_enum { |
| 139651 | + TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE |
| 139652 | + }; |
| 139653 | + int ttype; |
| 139654 | + if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", |
| 139655 | + 0, &ttype) ){ |
| 139656 | + return TCL_ERROR; |
| 139657 | + } |
| 139658 | + switch( (enum TTYPE_enum)ttype ){ |
| 139659 | + case TTYPE_DEFERRED: /* no-op */; break; |
| 139660 | + case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; |
| 139661 | + case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; |
| 139662 | + } |
| 139663 | + } |
| 139664 | + pScript = objv[objc-1]; |
| 139665 | + |
| 139666 | + /* Run the SQLite BEGIN command to open a transaction or savepoint. */ |
| 139667 | + pDb->disableAuth++; |
| 139668 | + rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); |
| 139669 | + pDb->disableAuth--; |
| 139670 | + if( rc!=SQLITE_OK ){ |
| 139671 | + Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); |
| 139672 | + return TCL_ERROR; |
| 139673 | + } |
| 139674 | + pDb->nTransaction++; |
| 139675 | + |
| 139676 | + /* If using NRE, schedule a callback to invoke the script pScript, then |
| 139677 | + ** a second callback to commit (or rollback) the transaction or savepoint |
| 139678 | + ** opened above. If not using NRE, evaluate the script directly, then |
| 139679 | + ** call function DbTransPostCmd() to commit (or rollback) the transaction |
| 139680 | + ** or savepoint. */ |
| 139681 | + if( DbUseNre() ){ |
| 139682 | + Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); |
| 139683 | + Tcl_NREvalObj(interp, pScript, 0); |
| 139684 | + }else{ |
| 139685 | + rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); |
| 139686 | + } |
| 139687 | + break; |
| 139688 | + } |
| 139689 | + |
| 139690 | + /* |
| 139691 | + ** $db unlock_notify ?script? |
| 139692 | + */ |
| 139693 | + case DB_UNLOCK_NOTIFY: { |
| 139694 | +#ifndef SQLITE_ENABLE_UNLOCK_NOTIFY |
| 139695 | + Tcl_AppendResult(interp, "unlock_notify not available in this build", 0); |
| 139696 | + rc = TCL_ERROR; |
| 139697 | +#else |
| 139698 | + if( objc!=2 && objc!=3 ){ |
| 139699 | + Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); |
| 139700 | + rc = TCL_ERROR; |
| 139701 | + }else{ |
| 139702 | + void (*xNotify)(void **, int) = 0; |
| 139703 | + void *pNotifyArg = 0; |
| 139704 | + |
| 139705 | + if( pDb->pUnlockNotify ){ |
| 139706 | + Tcl_DecrRefCount(pDb->pUnlockNotify); |
| 139707 | + pDb->pUnlockNotify = 0; |
| 139708 | + } |
| 139709 | + |
| 139710 | + if( objc==3 ){ |
| 139711 | + xNotify = DbUnlockNotify; |
| 139712 | + pNotifyArg = (void *)pDb; |
| 139713 | + pDb->pUnlockNotify = objv[2]; |
| 139714 | + Tcl_IncrRefCount(pDb->pUnlockNotify); |
| 139715 | + } |
| 139716 | + |
| 139717 | + if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ |
| 139718 | + Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); |
| 139719 | + rc = TCL_ERROR; |
| 139720 | + } |
| 139721 | + } |
| 139722 | +#endif |
| 139723 | + break; |
| 139724 | + } |
| 139725 | + |
| 139726 | + /* |
| 139727 | + ** $db wal_hook ?script? |
| 139728 | + ** $db update_hook ?script? |
| 139729 | + ** $db rollback_hook ?script? |
| 139730 | + */ |
| 139731 | + case DB_WAL_HOOK: |
| 139732 | + case DB_UPDATE_HOOK: |
| 139733 | + case DB_ROLLBACK_HOOK: { |
| 139734 | + |
| 139735 | + /* set ppHook to point at pUpdateHook or pRollbackHook, depending on |
| 139736 | + ** whether [$db update_hook] or [$db rollback_hook] was invoked. |
| 139737 | + */ |
| 139738 | + Tcl_Obj **ppHook; |
| 139739 | + if( choice==DB_UPDATE_HOOK ){ |
| 139740 | + ppHook = &pDb->pUpdateHook; |
| 139741 | + }else if( choice==DB_WAL_HOOK ){ |
| 139742 | + ppHook = &pDb->pWalHook; |
| 139743 | + }else{ |
| 139744 | + ppHook = &pDb->pRollbackHook; |
| 139745 | + } |
| 139746 | + |
| 139747 | + if( objc!=2 && objc!=3 ){ |
| 139748 | + Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); |
| 139749 | + return TCL_ERROR; |
| 139750 | + } |
| 139751 | + if( *ppHook ){ |
| 139752 | + Tcl_SetObjResult(interp, *ppHook); |
| 139753 | + if( objc==3 ){ |
| 139754 | + Tcl_DecrRefCount(*ppHook); |
| 139755 | + *ppHook = 0; |
| 139756 | + } |
| 139757 | + } |
| 139758 | + if( objc==3 ){ |
| 139759 | + assert( !(*ppHook) ); |
| 139760 | + if( Tcl_GetCharLength(objv[2])>0 ){ |
| 139761 | + *ppHook = objv[2]; |
| 139762 | + Tcl_IncrRefCount(*ppHook); |
| 139763 | + } |
| 139764 | + } |
| 139765 | + |
| 139766 | + sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); |
| 139767 | + sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb); |
| 139768 | + sqlite3_wal_hook(pDb->db,(pDb->pWalHook?DbWalHandler:0),pDb); |
| 139769 | + |
| 139770 | + break; |
| 139771 | + } |
| 139772 | + |
| 139773 | + /* $db version |
| 139774 | + ** |
| 139775 | + ** Return the version string for this database. |
| 139776 | + */ |
| 139777 | + case DB_VERSION: { |
| 139778 | + Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); |
| 139779 | + break; |
| 139780 | + } |
| 139781 | + |
| 139782 | + |
| 139783 | + } /* End of the SWITCH statement */ |
| 139784 | + return rc; |
| 139785 | +} |
| 139786 | + |
| 139787 | +#if SQLITE_TCL_NRE |
| 139788 | +/* |
| 139789 | +** Adaptor that provides an objCmd interface to the NRE-enabled |
| 139790 | +** interface implementation. |
| 139791 | +*/ |
| 139792 | +static int DbObjCmdAdaptor( |
| 139793 | + void *cd, |
| 139794 | + Tcl_Interp *interp, |
| 139795 | + int objc, |
| 139796 | + Tcl_Obj *const*objv |
| 139797 | +){ |
| 139798 | + return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv); |
| 139799 | +} |
| 139800 | +#endif /* SQLITE_TCL_NRE */ |
| 139801 | + |
| 139802 | +/* |
| 139803 | +** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? |
| 139804 | +** ?-create BOOLEAN? ?-nomutex BOOLEAN? |
| 139805 | +** |
| 139806 | +** This is the main Tcl command. When the "sqlite" Tcl command is |
| 139807 | +** invoked, this routine runs to process that command. |
| 139808 | +** |
| 139809 | +** The first argument, DBNAME, is an arbitrary name for a new |
| 139810 | +** database connection. This command creates a new command named |
| 139811 | +** DBNAME that is used to control that connection. The database |
| 139812 | +** connection is deleted when the DBNAME command is deleted. |
| 139813 | +** |
| 139814 | +** The second argument is the name of the database file. |
| 139815 | +** |
| 139816 | +*/ |
| 139817 | +static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
| 139818 | + SqliteDb *p; |
| 139819 | + const char *zArg; |
| 139820 | + char *zErrMsg; |
| 139821 | + int i; |
| 139822 | + const char *zFile; |
| 139823 | + const char *zVfs = 0; |
| 139824 | + int flags; |
| 139825 | + Tcl_DString translatedFilename; |
| 139826 | +#ifdef SQLITE_HAS_CODEC |
| 139827 | + void *pKey = 0; |
| 139828 | + int nKey = 0; |
| 139829 | +#endif |
| 139830 | + int rc; |
| 139831 | + |
| 139832 | + /* In normal use, each TCL interpreter runs in a single thread. So |
| 139833 | + ** by default, we can turn of mutexing on SQLite database connections. |
| 139834 | + ** However, for testing purposes it is useful to have mutexes turned |
| 139835 | + ** on. So, by default, mutexes default off. But if compiled with |
| 139836 | + ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on. |
| 139837 | + */ |
| 139838 | +#ifdef SQLITE_TCL_DEFAULT_FULLMUTEX |
| 139839 | + flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; |
| 139840 | +#else |
| 139841 | + flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; |
| 139842 | +#endif |
| 139843 | + |
| 139844 | + if( objc==2 ){ |
| 139845 | + zArg = Tcl_GetStringFromObj(objv[1], 0); |
| 139846 | + if( strcmp(zArg,"-version")==0 ){ |
| 139847 | + Tcl_AppendResult(interp,sqlite3_version,0); |
| 139848 | + return TCL_OK; |
| 139849 | + } |
| 139850 | + if( strcmp(zArg,"-has-codec")==0 ){ |
| 139851 | +#ifdef SQLITE_HAS_CODEC |
| 139852 | + Tcl_AppendResult(interp,"1",0); |
| 139853 | +#else |
| 139854 | + Tcl_AppendResult(interp,"0",0); |
| 139855 | +#endif |
| 139856 | + return TCL_OK; |
| 139857 | + } |
| 139858 | + } |
| 139859 | + for(i=3; i+1<objc; i+=2){ |
| 139860 | + zArg = Tcl_GetString(objv[i]); |
| 139861 | + if( strcmp(zArg,"-key")==0 ){ |
| 139862 | +#ifdef SQLITE_HAS_CODEC |
| 139863 | + pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey); |
| 139864 | +#endif |
| 139865 | + }else if( strcmp(zArg, "-vfs")==0 ){ |
| 139866 | + zVfs = Tcl_GetString(objv[i+1]); |
| 139867 | + }else if( strcmp(zArg, "-readonly")==0 ){ |
| 139868 | + int b; |
| 139869 | + if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
| 139870 | + if( b ){ |
| 139871 | + flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); |
| 139872 | + flags |= SQLITE_OPEN_READONLY; |
| 139873 | + }else{ |
| 139874 | + flags &= ~SQLITE_OPEN_READONLY; |
| 139875 | + flags |= SQLITE_OPEN_READWRITE; |
| 139876 | + } |
| 139877 | + }else if( strcmp(zArg, "-create")==0 ){ |
| 139878 | + int b; |
| 139879 | + if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
| 139880 | + if( b && (flags & SQLITE_OPEN_READONLY)==0 ){ |
| 139881 | + flags |= SQLITE_OPEN_CREATE; |
| 139882 | + }else{ |
| 139883 | + flags &= ~SQLITE_OPEN_CREATE; |
| 139884 | + } |
| 139885 | + }else if( strcmp(zArg, "-nomutex")==0 ){ |
| 139886 | + int b; |
| 139887 | + if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
| 139888 | + if( b ){ |
| 139889 | + flags |= SQLITE_OPEN_NOMUTEX; |
| 139890 | + flags &= ~SQLITE_OPEN_FULLMUTEX; |
| 139891 | + }else{ |
| 139892 | + flags &= ~SQLITE_OPEN_NOMUTEX; |
| 139893 | + } |
| 139894 | + }else if( strcmp(zArg, "-fullmutex")==0 ){ |
| 139895 | + int b; |
| 139896 | + if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
| 139897 | + if( b ){ |
| 139898 | + flags |= SQLITE_OPEN_FULLMUTEX; |
| 139899 | + flags &= ~SQLITE_OPEN_NOMUTEX; |
| 139900 | + }else{ |
| 139901 | + flags &= ~SQLITE_OPEN_FULLMUTEX; |
| 139902 | + } |
| 139903 | + }else if( strcmp(zArg, "-uri")==0 ){ |
| 139904 | + int b; |
| 139905 | + if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
| 139906 | + if( b ){ |
| 139907 | + flags |= SQLITE_OPEN_URI; |
| 139908 | + }else{ |
| 139909 | + flags &= ~SQLITE_OPEN_URI; |
| 139910 | + } |
| 139911 | + }else{ |
| 139912 | + Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); |
| 139913 | + return TCL_ERROR; |
| 139914 | + } |
| 139915 | + } |
| 139916 | + if( objc<3 || (objc&1)!=1 ){ |
| 139917 | + Tcl_WrongNumArgs(interp, 1, objv, |
| 139918 | + "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" |
| 139919 | + " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" |
| 139920 | +#ifdef SQLITE_HAS_CODEC |
| 139921 | + " ?-key CODECKEY?" |
| 139922 | +#endif |
| 139923 | + ); |
| 139924 | + return TCL_ERROR; |
| 139925 | + } |
| 139926 | + zErrMsg = 0; |
| 139927 | + p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); |
| 139928 | + if( p==0 ){ |
| 139929 | + Tcl_SetResult(interp, "malloc failed", TCL_STATIC); |
| 139930 | + return TCL_ERROR; |
| 139931 | + } |
| 139932 | + memset(p, 0, sizeof(*p)); |
| 139933 | + zFile = Tcl_GetStringFromObj(objv[2], 0); |
| 139934 | + zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); |
| 139935 | + rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); |
| 139936 | + Tcl_DStringFree(&translatedFilename); |
| 139937 | + if( p->db ){ |
| 139938 | + if( SQLITE_OK!=sqlite3_errcode(p->db) ){ |
| 139939 | + zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); |
| 139940 | + sqlite3_close(p->db); |
| 139941 | + p->db = 0; |
| 139942 | + } |
| 139943 | + }else{ |
| 139944 | + zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); |
| 139945 | + } |
| 139946 | +#ifdef SQLITE_HAS_CODEC |
| 139947 | + if( p->db ){ |
| 139948 | + sqlite3_key(p->db, pKey, nKey); |
| 139949 | + } |
| 139950 | +#endif |
| 139951 | + if( p->db==0 ){ |
| 139952 | + Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); |
| 139953 | + Tcl_Free((char*)p); |
| 139954 | + sqlite3_free(zErrMsg); |
| 139955 | + return TCL_ERROR; |
| 139956 | + } |
| 139957 | + p->maxStmt = NUM_PREPARED_STMTS; |
| 139958 | + p->interp = interp; |
| 139959 | + zArg = Tcl_GetStringFromObj(objv[1], 0); |
| 139960 | + if( DbUseNre() ){ |
| 139961 | + Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd, |
| 139962 | + (char*)p, DbDeleteCmd); |
| 139963 | + }else{ |
| 139964 | + Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); |
| 139965 | + } |
| 139966 | + return TCL_OK; |
| 139967 | +} |
| 139968 | + |
| 139969 | +/* |
| 139970 | +** Provide a dummy Tcl_InitStubs if we are using this as a static |
| 139971 | +** library. |
| 139972 | +*/ |
| 139973 | +#ifndef USE_TCL_STUBS |
| 139974 | +# undef Tcl_InitStubs |
| 139975 | +# define Tcl_InitStubs(a,b,c) |
| 139976 | +#endif |
| 139977 | + |
| 139978 | +/* |
| 139979 | +** Make sure we have a PACKAGE_VERSION macro defined. This will be |
| 139980 | +** defined automatically by the TEA makefile. But other makefiles |
| 139981 | +** do not define it. |
| 139982 | +*/ |
| 139983 | +#ifndef PACKAGE_VERSION |
| 139984 | +# define PACKAGE_VERSION SQLITE_VERSION |
| 139985 | +#endif |
| 139986 | + |
| 139987 | +/* |
| 139988 | +** Initialize this module. |
| 139989 | +** |
| 139990 | +** This Tcl module contains only a single new Tcl command named "sqlite". |
| 139991 | +** (Hence there is no namespace. There is no point in using a namespace |
| 139992 | +** if the extension only supplies one new name!) The "sqlite" command is |
| 139993 | +** used to open a new SQLite database. See the DbMain() routine above |
| 139994 | +** for additional information. |
| 139995 | +** |
| 139996 | +** The EXTERN macros are required by TCL in order to work on windows. |
| 139997 | +*/ |
| 139998 | +EXTERN int Sqlite3_Init(Tcl_Interp *interp){ |
| 139999 | + Tcl_InitStubs(interp, "8.4", 0); |
| 140000 | + Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); |
| 140001 | + Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); |
| 140002 | + |
| 140003 | +#ifndef SQLITE_3_SUFFIX_ONLY |
| 140004 | + /* The "sqlite" alias is undocumented. It is here only to support |
| 140005 | + ** legacy scripts. All new scripts should use only the "sqlite3" |
| 140006 | + ** command. |
| 140007 | + */ |
| 140008 | + Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); |
| 140009 | +#endif |
| 140010 | + |
| 140011 | + return TCL_OK; |
| 140012 | +} |
| 140013 | +EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } |
| 140014 | +EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
| 140015 | +EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
| 140016 | + |
| 140017 | +/* Because it accesses the file-system and uses persistent state, SQLite |
| 140018 | +** is not considered appropriate for safe interpreters. Hence, we deliberately |
| 140019 | +** omit the _SafeInit() interfaces. |
| 140020 | +*/ |
| 140021 | + |
| 140022 | +#ifndef SQLITE_3_SUFFIX_ONLY |
| 140023 | +int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } |
| 140024 | +int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } |
| 140025 | +int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
| 140026 | +int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
| 140027 | +#endif |
| 140028 | + |
| 140029 | +#ifdef TCLSH |
| 140030 | +/***************************************************************************** |
| 140031 | +** All of the code that follows is used to build standalone TCL interpreters |
| 140032 | +** that are statically linked with SQLite. Enable these by compiling |
| 140033 | +** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard |
| 140034 | +** tclsh but with SQLite built in. An n of 2 generates the SQLite space |
| 140035 | +** analysis program. |
| 140036 | +*/ |
| 140037 | + |
| 140038 | +#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) |
| 140039 | +/* |
| 140040 | + * This code implements the MD5 message-digest algorithm. |
| 140041 | + * The algorithm is due to Ron Rivest. This code was |
| 140042 | + * written by Colin Plumb in 1993, no copyright is claimed. |
| 140043 | + * This code is in the public domain; do with it what you wish. |
| 140044 | + * |
| 140045 | + * Equivalent code is available from RSA Data Security, Inc. |
| 140046 | + * This code has been tested against that, and is equivalent, |
| 140047 | + * except that you don't need to include two pages of legalese |
| 140048 | + * with every copy. |
| 140049 | + * |
| 140050 | + * To compute the message digest of a chunk of bytes, declare an |
| 140051 | + * MD5Context structure, pass it to MD5Init, call MD5Update as |
| 140052 | + * needed on buffers full of bytes, and then call MD5Final, which |
| 140053 | + * will fill a supplied 16-byte array with the digest. |
| 140054 | + */ |
| 140055 | + |
| 140056 | +/* |
| 140057 | + * If compiled on a machine that doesn't have a 32-bit integer, |
| 140058 | + * you just set "uint32" to the appropriate datatype for an |
| 140059 | + * unsigned 32-bit integer. For example: |
| 140060 | + * |
| 140061 | + * cc -Duint32='unsigned long' md5.c |
| 140062 | + * |
| 140063 | + */ |
| 140064 | +#ifndef uint32 |
| 140065 | +# define uint32 unsigned int |
| 140066 | +#endif |
| 140067 | + |
| 140068 | +struct MD5Context { |
| 140069 | + int isInit; |
| 140070 | + uint32 buf[4]; |
| 140071 | + uint32 bits[2]; |
| 140072 | + unsigned char in[64]; |
| 140073 | +}; |
| 140074 | +typedef struct MD5Context MD5Context; |
| 140075 | + |
| 140076 | +/* |
| 140077 | + * Note: this code is harmless on little-endian machines. |
| 140078 | + */ |
| 140079 | +static void byteReverse (unsigned char *buf, unsigned longs){ |
| 140080 | + uint32 t; |
| 140081 | + do { |
| 140082 | + t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | |
| 140083 | + ((unsigned)buf[1]<<8 | buf[0]); |
| 140084 | + *(uint32 *)buf = t; |
| 140085 | + buf += 4; |
| 140086 | + } while (--longs); |
| 140087 | +} |
| 140088 | +/* The four core functions - F1 is optimized somewhat */ |
| 140089 | + |
| 140090 | +/* #define F1(x, y, z) (x & y | ~x & z) */ |
| 140091 | +#define F1(x, y, z) (z ^ (x & (y ^ z))) |
| 140092 | +#define F2(x, y, z) F1(z, x, y) |
| 140093 | +#define F3(x, y, z) (x ^ y ^ z) |
| 140094 | +#define F4(x, y, z) (y ^ (x | ~z)) |
| 140095 | + |
| 140096 | +/* This is the central step in the MD5 algorithm. */ |
| 140097 | +#define MD5STEP(f, w, x, y, z, data, s) \ |
| 140098 | + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) |
| 140099 | + |
| 140100 | +/* |
| 140101 | + * The core of the MD5 algorithm, this alters an existing MD5 hash to |
| 140102 | + * reflect the addition of 16 longwords of new data. MD5Update blocks |
| 140103 | + * the data and converts bytes into longwords for this routine. |
| 140104 | + */ |
| 140105 | +static void MD5Transform(uint32 buf[4], const uint32 in[16]){ |
| 140106 | + register uint32 a, b, c, d; |
| 140107 | + |
| 140108 | + a = buf[0]; |
| 140109 | + b = buf[1]; |
| 140110 | + c = buf[2]; |
| 140111 | + d = buf[3]; |
| 140112 | + |
| 140113 | + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); |
| 140114 | + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); |
| 140115 | + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); |
| 140116 | + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); |
| 140117 | + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); |
| 140118 | + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); |
| 140119 | + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); |
| 140120 | + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); |
| 140121 | + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); |
| 140122 | + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); |
| 140123 | + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); |
| 140124 | + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); |
| 140125 | + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); |
| 140126 | + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); |
| 140127 | + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); |
| 140128 | + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); |
| 140129 | + |
| 140130 | + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); |
| 140131 | + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); |
| 140132 | + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); |
| 140133 | + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); |
| 140134 | + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); |
| 140135 | + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); |
| 140136 | + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); |
| 140137 | + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); |
| 140138 | + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); |
| 140139 | + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); |
| 140140 | + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); |
| 140141 | + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); |
| 140142 | + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); |
| 140143 | + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); |
| 140144 | + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); |
| 140145 | + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); |
| 140146 | + |
| 140147 | + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); |
| 140148 | + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); |
| 140149 | + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); |
| 140150 | + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); |
| 140151 | + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); |
| 140152 | + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); |
| 140153 | + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); |
| 140154 | + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); |
| 140155 | + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); |
| 140156 | + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); |
| 140157 | + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); |
| 140158 | + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); |
| 140159 | + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); |
| 140160 | + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); |
| 140161 | + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); |
| 140162 | + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); |
| 140163 | + |
| 140164 | + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); |
| 140165 | + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); |
| 140166 | + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); |
| 140167 | + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); |
| 140168 | + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); |
| 140169 | + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); |
| 140170 | + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); |
| 140171 | + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); |
| 140172 | + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); |
| 140173 | + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); |
| 140174 | + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); |
| 140175 | + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); |
| 140176 | + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); |
| 140177 | + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); |
| 140178 | + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); |
| 140179 | + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); |
| 140180 | + |
| 140181 | + buf[0] += a; |
| 140182 | + buf[1] += b; |
| 140183 | + buf[2] += c; |
| 140184 | + buf[3] += d; |
| 140185 | +} |
| 140186 | + |
| 140187 | +/* |
| 140188 | + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious |
| 140189 | + * initialization constants. |
| 140190 | + */ |
| 140191 | +static void MD5Init(MD5Context *ctx){ |
| 140192 | + ctx->isInit = 1; |
| 140193 | + ctx->buf[0] = 0x67452301; |
| 140194 | + ctx->buf[1] = 0xefcdab89; |
| 140195 | + ctx->buf[2] = 0x98badcfe; |
| 140196 | + ctx->buf[3] = 0x10325476; |
| 140197 | + ctx->bits[0] = 0; |
| 140198 | + ctx->bits[1] = 0; |
| 140199 | +} |
| 140200 | + |
| 140201 | +/* |
| 140202 | + * Update context to reflect the concatenation of another buffer full |
| 140203 | + * of bytes. |
| 140204 | + */ |
| 140205 | +static |
| 140206 | +void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ |
| 140207 | + uint32 t; |
| 140208 | + |
| 140209 | + /* Update bitcount */ |
| 140210 | + |
| 140211 | + t = ctx->bits[0]; |
| 140212 | + if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) |
| 140213 | + ctx->bits[1]++; /* Carry from low to high */ |
| 140214 | + ctx->bits[1] += len >> 29; |
| 140215 | + |
| 140216 | + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ |
| 140217 | + |
| 140218 | + /* Handle any leading odd-sized chunks */ |
| 140219 | + |
| 140220 | + if ( t ) { |
| 140221 | + unsigned char *p = (unsigned char *)ctx->in + t; |
| 140222 | + |
| 140223 | + t = 64-t; |
| 140224 | + if (len < t) { |
| 140225 | + memcpy(p, buf, len); |
| 140226 | + return; |
| 140227 | + } |
| 140228 | + memcpy(p, buf, t); |
| 140229 | + byteReverse(ctx->in, 16); |
| 140230 | + MD5Transform(ctx->buf, (uint32 *)ctx->in); |
| 140231 | + buf += t; |
| 140232 | + len -= t; |
| 140233 | + } |
| 140234 | + |
| 140235 | + /* Process data in 64-byte chunks */ |
| 140236 | + |
| 140237 | + while (len >= 64) { |
| 140238 | + memcpy(ctx->in, buf, 64); |
| 140239 | + byteReverse(ctx->in, 16); |
| 140240 | + MD5Transform(ctx->buf, (uint32 *)ctx->in); |
| 140241 | + buf += 64; |
| 140242 | + len -= 64; |
| 140243 | + } |
| 140244 | + |
| 140245 | + /* Handle any remaining bytes of data. */ |
| 140246 | + |
| 140247 | + memcpy(ctx->in, buf, len); |
| 140248 | +} |
| 140249 | + |
| 140250 | +/* |
| 140251 | + * Final wrapup - pad to 64-byte boundary with the bit pattern |
| 140252 | + * 1 0* (64-bit count of bits processed, MSB-first) |
| 140253 | + */ |
| 140254 | +static void MD5Final(unsigned char digest[16], MD5Context *ctx){ |
| 140255 | + unsigned count; |
| 140256 | + unsigned char *p; |
| 140257 | + |
| 140258 | + /* Compute number of bytes mod 64 */ |
| 140259 | + count = (ctx->bits[0] >> 3) & 0x3F; |
| 140260 | + |
| 140261 | + /* Set the first char of padding to 0x80. This is safe since there is |
| 140262 | + always at least one byte free */ |
| 140263 | + p = ctx->in + count; |
| 140264 | + *p++ = 0x80; |
| 140265 | + |
| 140266 | + /* Bytes of padding needed to make 64 bytes */ |
| 140267 | + count = 64 - 1 - count; |
| 140268 | + |
| 140269 | + /* Pad out to 56 mod 64 */ |
| 140270 | + if (count < 8) { |
| 140271 | + /* Two lots of padding: Pad the first block to 64 bytes */ |
| 140272 | + memset(p, 0, count); |
| 140273 | + byteReverse(ctx->in, 16); |
| 140274 | + MD5Transform(ctx->buf, (uint32 *)ctx->in); |
| 140275 | + |
| 140276 | + /* Now fill the next block with 56 bytes */ |
| 140277 | + memset(ctx->in, 0, 56); |
| 140278 | + } else { |
| 140279 | + /* Pad block to 56 bytes */ |
| 140280 | + memset(p, 0, count-8); |
| 140281 | + } |
| 140282 | + byteReverse(ctx->in, 14); |
| 140283 | + |
| 140284 | + /* Append length in bits and transform */ |
| 140285 | + ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; |
| 140286 | + ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; |
| 140287 | + |
| 140288 | + MD5Transform(ctx->buf, (uint32 *)ctx->in); |
| 140289 | + byteReverse((unsigned char *)ctx->buf, 4); |
| 140290 | + memcpy(digest, ctx->buf, 16); |
| 140291 | + memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */ |
| 140292 | +} |
| 140293 | + |
| 140294 | +/* |
| 140295 | +** Convert a 128-bit MD5 digest into a 32-digit base-16 number. |
| 140296 | +*/ |
| 140297 | +static void MD5DigestToBase16(unsigned char *digest, char *zBuf){ |
| 140298 | + static char const zEncode[] = "0123456789abcdef"; |
| 140299 | + int i, j; |
| 140300 | + |
| 140301 | + for(j=i=0; i<16; i++){ |
| 140302 | + int a = digest[i]; |
| 140303 | + zBuf[j++] = zEncode[(a>>4)&0xf]; |
| 140304 | + zBuf[j++] = zEncode[a & 0xf]; |
| 140305 | + } |
| 140306 | + zBuf[j] = 0; |
| 140307 | +} |
| 140308 | + |
| 140309 | + |
| 140310 | +/* |
| 140311 | +** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers |
| 140312 | +** each representing 16 bits of the digest and separated from each |
| 140313 | +** other by a "-" character. |
| 140314 | +*/ |
| 140315 | +static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){ |
| 140316 | + int i, j; |
| 140317 | + unsigned int x; |
| 140318 | + for(i=j=0; i<16; i+=2){ |
| 140319 | + x = digest[i]*256 + digest[i+1]; |
| 140320 | + if( i>0 ) zDigest[j++] = '-'; |
| 140321 | + sprintf(&zDigest[j], "%05u", x); |
| 140322 | + j += 5; |
| 140323 | + } |
| 140324 | + zDigest[j] = 0; |
| 140325 | +} |
| 140326 | + |
| 140327 | +/* |
| 140328 | +** A TCL command for md5. The argument is the text to be hashed. The |
| 140329 | +** Result is the hash in base64. |
| 140330 | +*/ |
| 140331 | +static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ |
| 140332 | + MD5Context ctx; |
| 140333 | + unsigned char digest[16]; |
| 140334 | + char zBuf[50]; |
| 140335 | + void (*converter)(unsigned char*, char*); |
| 140336 | + |
| 140337 | + if( argc!=2 ){ |
| 140338 | + Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], |
| 140339 | + " TEXT\"", 0); |
| 140340 | + return TCL_ERROR; |
| 140341 | + } |
| 140342 | + MD5Init(&ctx); |
| 140343 | + MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); |
| 140344 | + MD5Final(digest, &ctx); |
| 140345 | + converter = (void(*)(unsigned char*,char*))cd; |
| 140346 | + converter(digest, zBuf); |
| 140347 | + Tcl_AppendResult(interp, zBuf, (char*)0); |
| 140348 | + return TCL_OK; |
| 140349 | +} |
| 140350 | + |
| 140351 | +/* |
| 140352 | +** A TCL command to take the md5 hash of a file. The argument is the |
| 140353 | +** name of the file. |
| 140354 | +*/ |
| 140355 | +static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ |
| 140356 | + FILE *in; |
| 140357 | + MD5Context ctx; |
| 140358 | + void (*converter)(unsigned char*, char*); |
| 140359 | + unsigned char digest[16]; |
| 140360 | + char zBuf[10240]; |
| 140361 | + |
| 140362 | + if( argc!=2 ){ |
| 140363 | + Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], |
| 140364 | + " FILENAME\"", 0); |
| 140365 | + return TCL_ERROR; |
| 140366 | + } |
| 140367 | + in = fopen(argv[1],"rb"); |
| 140368 | + if( in==0 ){ |
| 140369 | + Tcl_AppendResult(interp,"unable to open file \"", argv[1], |
| 140370 | + "\" for reading", 0); |
| 140371 | + return TCL_ERROR; |
| 140372 | + } |
| 140373 | + MD5Init(&ctx); |
| 140374 | + for(;;){ |
| 140375 | + int n; |
| 140376 | + n = (int)fread(zBuf, 1, sizeof(zBuf), in); |
| 140377 | + if( n<=0 ) break; |
| 140378 | + MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); |
| 140379 | + } |
| 140380 | + fclose(in); |
| 140381 | + MD5Final(digest, &ctx); |
| 140382 | + converter = (void(*)(unsigned char*,char*))cd; |
| 140383 | + converter(digest, zBuf); |
| 140384 | + Tcl_AppendResult(interp, zBuf, (char*)0); |
| 140385 | + return TCL_OK; |
| 140386 | +} |
| 140387 | + |
| 140388 | +/* |
| 140389 | +** Register the four new TCL commands for generating MD5 checksums |
| 140390 | +** with the TCL interpreter. |
| 140391 | +*/ |
| 140392 | +int Md5_Init(Tcl_Interp *interp){ |
| 140393 | + Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, |
| 140394 | + MD5DigestToBase16, 0); |
| 140395 | + Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd, |
| 140396 | + MD5DigestToBase10x8, 0); |
| 140397 | + Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, |
| 140398 | + MD5DigestToBase16, 0); |
| 140399 | + Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd, |
| 140400 | + MD5DigestToBase10x8, 0); |
| 140401 | + return TCL_OK; |
| 140402 | +} |
| 140403 | +#endif /* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */ |
| 140404 | + |
| 140405 | +#if defined(SQLITE_TEST) |
| 140406 | +/* |
| 140407 | +** During testing, the special md5sum() aggregate function is available. |
| 140408 | +** inside SQLite. The following routines implement that function. |
| 140409 | +*/ |
| 140410 | +static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| 140411 | + MD5Context *p; |
| 140412 | + int i; |
| 140413 | + if( argc<1 ) return; |
| 140414 | + p = sqlite3_aggregate_context(context, sizeof(*p)); |
| 140415 | + if( p==0 ) return; |
| 140416 | + if( !p->isInit ){ |
| 140417 | + MD5Init(p); |
| 140418 | + } |
| 140419 | + for(i=0; i<argc; i++){ |
| 140420 | + const char *zData = (char*)sqlite3_value_text(argv[i]); |
| 140421 | + if( zData ){ |
| 140422 | + MD5Update(p, (unsigned char*)zData, (int)strlen(zData)); |
| 140423 | + } |
| 140424 | + } |
| 140425 | +} |
| 140426 | +static void md5finalize(sqlite3_context *context){ |
| 140427 | + MD5Context *p; |
| 140428 | + unsigned char digest[16]; |
| 140429 | + char zBuf[33]; |
| 140430 | + p = sqlite3_aggregate_context(context, sizeof(*p)); |
| 140431 | + MD5Final(digest,p); |
| 140432 | + MD5DigestToBase16(digest, zBuf); |
| 140433 | + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); |
| 140434 | +} |
| 140435 | +int Md5_Register(sqlite3 *db){ |
| 140436 | + int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0, |
| 140437 | + md5step, md5finalize); |
| 140438 | + sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */ |
| 140439 | + return rc; |
| 140440 | +} |
| 140441 | +#endif /* defined(SQLITE_TEST) */ |
| 140442 | + |
| 140443 | + |
| 140444 | +/* |
| 140445 | +** If the macro TCLSH is one, then put in code this for the |
| 140446 | +** "main" routine that will initialize Tcl and take input from |
| 140447 | +** standard input, or if a file is named on the command line |
| 140448 | +** the TCL interpreter reads and evaluates that file. |
| 140449 | +*/ |
| 140450 | +#if TCLSH==1 |
| 140451 | +static const char *tclsh_main_loop(void){ |
| 140452 | + static const char zMainloop[] = |
| 140453 | + "set line {}\n" |
| 140454 | + "while {![eof stdin]} {\n" |
| 140455 | + "if {$line!=\"\"} {\n" |
| 140456 | + "puts -nonewline \"> \"\n" |
| 140457 | + "} else {\n" |
| 140458 | + "puts -nonewline \"% \"\n" |
| 140459 | + "}\n" |
| 140460 | + "flush stdout\n" |
| 140461 | + "append line [gets stdin]\n" |
| 140462 | + "if {[info complete $line]} {\n" |
| 140463 | + "if {[catch {uplevel #0 $line} result]} {\n" |
| 140464 | + "puts stderr \"Error: $result\"\n" |
| 140465 | + "} elseif {$result!=\"\"} {\n" |
| 140466 | + "puts $result\n" |
| 140467 | + "}\n" |
| 140468 | + "set line {}\n" |
| 140469 | + "} else {\n" |
| 140470 | + "append line \\n\n" |
| 140471 | + "}\n" |
| 140472 | + "}\n" |
| 140473 | + ; |
| 140474 | + return zMainloop; |
| 140475 | +} |
| 140476 | +#endif |
| 140477 | +#if TCLSH==2 |
| 140478 | +static const char *tclsh_main_loop(void); |
| 140479 | +#endif |
| 140480 | + |
| 140481 | +#ifdef SQLITE_TEST |
| 140482 | +static void init_all(Tcl_Interp *); |
| 140483 | +static int init_all_cmd( |
| 140484 | + ClientData cd, |
| 140485 | + Tcl_Interp *interp, |
| 140486 | + int objc, |
| 140487 | + Tcl_Obj *CONST objv[] |
| 140488 | +){ |
| 140489 | + |
| 140490 | + Tcl_Interp *slave; |
| 140491 | + if( objc!=2 ){ |
| 140492 | + Tcl_WrongNumArgs(interp, 1, objv, "SLAVE"); |
| 140493 | + return TCL_ERROR; |
| 140494 | + } |
| 140495 | + |
| 140496 | + slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1])); |
| 140497 | + if( !slave ){ |
| 140498 | + return TCL_ERROR; |
| 140499 | + } |
| 140500 | + |
| 140501 | + init_all(slave); |
| 140502 | + return TCL_OK; |
| 140503 | +} |
| 140504 | + |
| 140505 | +/* |
| 140506 | +** Tclcmd: db_use_legacy_prepare DB BOOLEAN |
| 140507 | +** |
| 140508 | +** The first argument to this command must be a database command created by |
| 140509 | +** [sqlite3]. If the second argument is true, then the handle is configured |
| 140510 | +** to use the sqlite3_prepare_v2() function to prepare statements. If it |
| 140511 | +** is false, sqlite3_prepare(). |
| 140512 | +*/ |
| 140513 | +static int db_use_legacy_prepare_cmd( |
| 140514 | + ClientData cd, |
| 140515 | + Tcl_Interp *interp, |
| 140516 | + int objc, |
| 140517 | + Tcl_Obj *CONST objv[] |
| 140518 | +){ |
| 140519 | + Tcl_CmdInfo cmdInfo; |
| 140520 | + SqliteDb *pDb; |
| 140521 | + int bPrepare; |
| 140522 | + |
| 140523 | + if( objc!=3 ){ |
| 140524 | + Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN"); |
| 140525 | + return TCL_ERROR; |
| 140526 | + } |
| 140527 | + |
| 140528 | + if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ |
| 140529 | + Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0); |
| 140530 | + return TCL_ERROR; |
| 140531 | + } |
| 140532 | + pDb = (SqliteDb*)cmdInfo.objClientData; |
| 140533 | + if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){ |
| 140534 | + return TCL_ERROR; |
| 140535 | + } |
| 140536 | + |
| 140537 | + pDb->bLegacyPrepare = bPrepare; |
| 140538 | + |
| 140539 | + Tcl_ResetResult(interp); |
| 140540 | + return TCL_OK; |
| 140541 | +} |
| 140542 | +#endif |
| 140543 | + |
| 140544 | +/* |
| 140545 | +** Configure the interpreter passed as the first argument to have access |
| 140546 | +** to the commands and linked variables that make up: |
| 140547 | +** |
| 140548 | +** * the [sqlite3] extension itself, |
| 140549 | +** |
| 140550 | +** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and |
| 140551 | +** |
| 140552 | +** * If SQLITE_TEST is set, the various test interfaces used by the Tcl |
| 140553 | +** test suite. |
| 140554 | +*/ |
| 140555 | +static void init_all(Tcl_Interp *interp){ |
| 140556 | + Sqlite3_Init(interp); |
| 140557 | + |
| 140558 | +#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) |
| 140559 | + Md5_Init(interp); |
| 140560 | +#endif |
| 140561 | + |
| 140562 | + /* Install the [register_dbstat_vtab] command to access the implementation |
| 140563 | + ** of virtual table dbstat (source file test_stat.c). This command is |
| 140564 | + ** required for testfixture and sqlite3_analyzer, but not by the production |
| 140565 | + ** Tcl extension. */ |
| 140566 | +#if defined(SQLITE_TEST) || TCLSH==2 |
| 140567 | + { |
| 140568 | + extern int SqlitetestStat_Init(Tcl_Interp*); |
| 140569 | + SqlitetestStat_Init(interp); |
| 140570 | + } |
| 140571 | +#endif |
| 140572 | + |
| 140573 | +#ifdef SQLITE_TEST |
| 140574 | + { |
| 140575 | + extern int Sqliteconfig_Init(Tcl_Interp*); |
| 140576 | + extern int Sqlitetest1_Init(Tcl_Interp*); |
| 140577 | + extern int Sqlitetest2_Init(Tcl_Interp*); |
| 140578 | + extern int Sqlitetest3_Init(Tcl_Interp*); |
| 140579 | + extern int Sqlitetest4_Init(Tcl_Interp*); |
| 140580 | + extern int Sqlitetest5_Init(Tcl_Interp*); |
| 140581 | + extern int Sqlitetest6_Init(Tcl_Interp*); |
| 140582 | + extern int Sqlitetest7_Init(Tcl_Interp*); |
| 140583 | + extern int Sqlitetest8_Init(Tcl_Interp*); |
| 140584 | + extern int Sqlitetest9_Init(Tcl_Interp*); |
| 140585 | + extern int Sqlitetestasync_Init(Tcl_Interp*); |
| 140586 | + extern int Sqlitetest_autoext_Init(Tcl_Interp*); |
| 140587 | + extern int Sqlitetest_demovfs_Init(Tcl_Interp *); |
| 140588 | + extern int Sqlitetest_func_Init(Tcl_Interp*); |
| 140589 | + extern int Sqlitetest_hexio_Init(Tcl_Interp*); |
| 140590 | + extern int Sqlitetest_init_Init(Tcl_Interp*); |
| 140591 | + extern int Sqlitetest_malloc_Init(Tcl_Interp*); |
| 140592 | + extern int Sqlitetest_mutex_Init(Tcl_Interp*); |
| 140593 | + extern int Sqlitetestschema_Init(Tcl_Interp*); |
| 140594 | + extern int Sqlitetestsse_Init(Tcl_Interp*); |
| 140595 | + extern int Sqlitetesttclvar_Init(Tcl_Interp*); |
| 140596 | + extern int SqlitetestThread_Init(Tcl_Interp*); |
| 140597 | + extern int SqlitetestOnefile_Init(); |
| 140598 | + extern int SqlitetestOsinst_Init(Tcl_Interp*); |
| 140599 | + extern int Sqlitetestbackup_Init(Tcl_Interp*); |
| 140600 | + extern int Sqlitetestintarray_Init(Tcl_Interp*); |
| 140601 | + extern int Sqlitetestvfs_Init(Tcl_Interp *); |
| 140602 | + extern int Sqlitetestrtree_Init(Tcl_Interp*); |
| 140603 | + extern int Sqlitequota_Init(Tcl_Interp*); |
| 140604 | + extern int Sqlitemultiplex_Init(Tcl_Interp*); |
| 140605 | + extern int SqliteSuperlock_Init(Tcl_Interp*); |
| 140606 | + extern int SqlitetestSyscall_Init(Tcl_Interp*); |
| 140607 | + extern int Sqlitetestfuzzer_Init(Tcl_Interp*); |
| 140608 | + extern int Sqlitetestwholenumber_Init(Tcl_Interp*); |
| 140609 | + |
| 140610 | +#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) |
| 140611 | + extern int Sqlitetestfts3_Init(Tcl_Interp *interp); |
| 140612 | +#endif |
| 140613 | + |
| 140614 | +#ifdef SQLITE_ENABLE_ZIPVFS |
| 140615 | + extern int Zipvfs_Init(Tcl_Interp*); |
| 140616 | + Zipvfs_Init(interp); |
| 140617 | +#endif |
| 140618 | + |
| 140619 | + Sqliteconfig_Init(interp); |
| 140620 | + Sqlitetest1_Init(interp); |
| 140621 | + Sqlitetest2_Init(interp); |
| 140622 | + Sqlitetest3_Init(interp); |
| 140623 | + Sqlitetest4_Init(interp); |
| 140624 | + Sqlitetest5_Init(interp); |
| 140625 | + Sqlitetest6_Init(interp); |
| 140626 | + Sqlitetest7_Init(interp); |
| 140627 | + Sqlitetest8_Init(interp); |
| 140628 | + Sqlitetest9_Init(interp); |
| 140629 | + Sqlitetestasync_Init(interp); |
| 140630 | + Sqlitetest_autoext_Init(interp); |
| 140631 | + Sqlitetest_demovfs_Init(interp); |
| 140632 | + Sqlitetest_func_Init(interp); |
| 140633 | + Sqlitetest_hexio_Init(interp); |
| 140634 | + Sqlitetest_init_Init(interp); |
| 140635 | + Sqlitetest_malloc_Init(interp); |
| 140636 | + Sqlitetest_mutex_Init(interp); |
| 140637 | + Sqlitetestschema_Init(interp); |
| 140638 | + Sqlitetesttclvar_Init(interp); |
| 140639 | + SqlitetestThread_Init(interp); |
| 140640 | + SqlitetestOnefile_Init(interp); |
| 140641 | + SqlitetestOsinst_Init(interp); |
| 140642 | + Sqlitetestbackup_Init(interp); |
| 140643 | + Sqlitetestintarray_Init(interp); |
| 140644 | + Sqlitetestvfs_Init(interp); |
| 140645 | + Sqlitetestrtree_Init(interp); |
| 140646 | + Sqlitequota_Init(interp); |
| 140647 | + Sqlitemultiplex_Init(interp); |
| 140648 | + SqliteSuperlock_Init(interp); |
| 140649 | + SqlitetestSyscall_Init(interp); |
| 140650 | + Sqlitetestfuzzer_Init(interp); |
| 140651 | + Sqlitetestwholenumber_Init(interp); |
| 140652 | + |
| 140653 | +#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) |
| 140654 | + Sqlitetestfts3_Init(interp); |
| 140655 | +#endif |
| 140656 | + |
| 140657 | + Tcl_CreateObjCommand( |
| 140658 | + interp, "load_testfixture_extensions", init_all_cmd, 0, 0 |
| 140659 | + ); |
| 140660 | + Tcl_CreateObjCommand( |
| 140661 | + interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 |
| 140662 | + ); |
| 140663 | + |
| 140664 | +#ifdef SQLITE_SSE |
| 140665 | + Sqlitetestsse_Init(interp); |
| 140666 | +#endif |
| 140667 | + } |
| 140668 | +#endif |
| 140669 | +} |
| 140670 | + |
| 140671 | +#define TCLSH_MAIN main /* Needed to fake out mktclapp */ |
| 140672 | +int TCLSH_MAIN(int argc, char **argv){ |
| 140673 | + Tcl_Interp *interp; |
| 140674 | + |
| 140675 | + /* Call sqlite3_shutdown() once before doing anything else. This is to |
| 140676 | + ** test that sqlite3_shutdown() can be safely called by a process before |
| 140677 | + ** sqlite3_initialize() is. */ |
| 140678 | + sqlite3_shutdown(); |
| 140679 | + |
| 140680 | + Tcl_FindExecutable(argv[0]); |
| 140681 | + interp = Tcl_CreateInterp(); |
| 140682 | + |
| 140683 | +#if TCLSH==2 |
| 140684 | + sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 140685 | +#endif |
| 140686 | + |
| 140687 | + init_all(interp); |
| 140688 | + if( argc>=2 ){ |
| 140689 | + int i; |
| 140690 | + char zArgc[32]; |
| 140691 | + sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH)); |
| 140692 | + Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); |
| 140693 | + Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); |
| 140694 | + Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); |
| 140695 | + for(i=3-TCLSH; i<argc; i++){ |
| 140696 | + Tcl_SetVar(interp, "argv", argv[i], |
| 140697 | + TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); |
| 140698 | + } |
| 140699 | + if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ |
| 140700 | + const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); |
| 140701 | + if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp); |
| 140702 | + fprintf(stderr,"%s: %s\n", *argv, zInfo); |
| 140703 | + return 1; |
| 140704 | + } |
| 140705 | + } |
| 140706 | + if( TCLSH==2 || argc<=1 ){ |
| 140707 | + Tcl_GlobalEval(interp, tclsh_main_loop()); |
| 140708 | + } |
| 140709 | + return 0; |
| 140710 | +} |
| 140711 | +#endif /* TCLSH */ |
| 136805 | 140712 | |