diff options
Diffstat (limited to 'libraries/sqlite/win32/tclsqlite.c')
-rwxr-xr-x | libraries/sqlite/win32/tclsqlite.c | 2551 |
1 files changed, 0 insertions, 2551 deletions
diff --git a/libraries/sqlite/win32/tclsqlite.c b/libraries/sqlite/win32/tclsqlite.c deleted file mode 100755 index e81846e..0000000 --- a/libraries/sqlite/win32/tclsqlite.c +++ /dev/null | |||
@@ -1,2551 +0,0 @@ | |||
1 | /* | ||
2 | ** 2001 September 15 | ||
3 | ** | ||
4 | ** The author disclaims copyright to this source code. In place of | ||
5 | ** a legal notice, here is a blessing: | ||
6 | ** | ||
7 | ** May you do good and not evil. | ||
8 | ** May you find forgiveness for yourself and forgive others. | ||
9 | ** May you share freely, never taking more than you give. | ||
10 | ** | ||
11 | ************************************************************************* | ||
12 | ** A TCL Interface to SQLite. Append this file to sqlite3.c and | ||
13 | ** compile the whole thing to build a TCL-enabled version of SQLite. | ||
14 | ** | ||
15 | ** $Id: tclsqlite.c,v 1.203 2007/09/14 16:20:01 danielk1977 Exp $ | ||
16 | */ | ||
17 | #include "tcl.h" | ||
18 | #include <errno.h> | ||
19 | |||
20 | /* | ||
21 | ** Some additional include files are needed if this file is not | ||
22 | ** appended to the amalgamation. | ||
23 | */ | ||
24 | #ifndef SQLITE_AMALGAMATION | ||
25 | # include "sqliteInt.h" | ||
26 | # include <stdlib.h> | ||
27 | # include <string.h> | ||
28 | # include <assert.h> | ||
29 | # include <ctype.h> | ||
30 | #endif | ||
31 | |||
32 | /* | ||
33 | * Windows needs to know which symbols to export. Unix does not. | ||
34 | * BUILD_sqlite should be undefined for Unix. | ||
35 | */ | ||
36 | #ifdef BUILD_sqlite | ||
37 | #undef TCL_STORAGE_CLASS | ||
38 | #define TCL_STORAGE_CLASS DLLEXPORT | ||
39 | #endif /* BUILD_sqlite */ | ||
40 | |||
41 | #define NUM_PREPARED_STMTS 10 | ||
42 | #define MAX_PREPARED_STMTS 100 | ||
43 | |||
44 | /* | ||
45 | ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we | ||
46 | ** have to do a translation when going between the two. Set the | ||
47 | ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do | ||
48 | ** this translation. | ||
49 | */ | ||
50 | #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8) | ||
51 | # define UTF_TRANSLATION_NEEDED 1 | ||
52 | #endif | ||
53 | |||
54 | /* | ||
55 | ** New SQL functions can be created as TCL scripts. Each such function | ||
56 | ** is described by an instance of the following structure. | ||
57 | */ | ||
58 | typedef struct SqlFunc SqlFunc; | ||
59 | struct SqlFunc { | ||
60 | Tcl_Interp *interp; /* The TCL interpret to execute the function */ | ||
61 | Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ | ||
62 | int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ | ||
63 | char *zName; /* Name of this function */ | ||
64 | SqlFunc *pNext; /* Next function on the list of them all */ | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | ** New collation sequences function can be created as TCL scripts. Each such | ||
69 | ** function is described by an instance of the following structure. | ||
70 | */ | ||
71 | typedef struct SqlCollate SqlCollate; | ||
72 | struct SqlCollate { | ||
73 | Tcl_Interp *interp; /* The TCL interpret to execute the function */ | ||
74 | char *zScript; /* The script to be run */ | ||
75 | SqlCollate *pNext; /* Next function on the list of them all */ | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | ** Prepared statements are cached for faster execution. Each prepared | ||
80 | ** statement is described by an instance of the following structure. | ||
81 | */ | ||
82 | typedef struct SqlPreparedStmt SqlPreparedStmt; | ||
83 | struct SqlPreparedStmt { | ||
84 | SqlPreparedStmt *pNext; /* Next in linked list */ | ||
85 | SqlPreparedStmt *pPrev; /* Previous on the list */ | ||
86 | sqlite3_stmt *pStmt; /* The prepared statement */ | ||
87 | int nSql; /* chars in zSql[] */ | ||
88 | char zSql[1]; /* Text of the SQL statement */ | ||
89 | }; | ||
90 | |||
91 | typedef struct IncrblobChannel IncrblobChannel; | ||
92 | |||
93 | /* | ||
94 | ** There is one instance of this structure for each SQLite database | ||
95 | ** that has been opened by the SQLite TCL interface. | ||
96 | */ | ||
97 | typedef struct SqliteDb SqliteDb; | ||
98 | struct SqliteDb { | ||
99 | sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ | ||
100 | Tcl_Interp *interp; /* The interpreter used for this database */ | ||
101 | char *zBusy; /* The busy callback routine */ | ||
102 | char *zCommit; /* The commit hook callback routine */ | ||
103 | char *zTrace; /* The trace callback routine */ | ||
104 | char *zProfile; /* The profile callback routine */ | ||
105 | char *zProgress; /* The progress callback routine */ | ||
106 | char *zAuth; /* The authorization callback routine */ | ||
107 | char *zNull; /* Text to substitute for an SQL NULL value */ | ||
108 | SqlFunc *pFunc; /* List of SQL functions */ | ||
109 | Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ | ||
110 | Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ | ||
111 | SqlCollate *pCollate; /* List of SQL collation functions */ | ||
112 | int rc; /* Return code of most recent sqlite3_exec() */ | ||
113 | Tcl_Obj *pCollateNeeded; /* Collation needed script */ | ||
114 | SqlPreparedStmt *stmtList; /* List of prepared statements*/ | ||
115 | SqlPreparedStmt *stmtLast; /* Last statement in the list */ | ||
116 | int maxStmt; /* The next maximum number of stmtList */ | ||
117 | int nStmt; /* Number of statements in stmtList */ | ||
118 | IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ | ||
119 | }; | ||
120 | |||
121 | struct IncrblobChannel { | ||
122 | sqlite3_blob *pBlob; /* sqlite3 blob handle */ | ||
123 | SqliteDb *pDb; /* Associated database connection */ | ||
124 | int iSeek; /* Current seek offset */ | ||
125 | Tcl_Channel channel; /* Channel identifier */ | ||
126 | IncrblobChannel *pNext; /* Linked list of all open incrblob channels */ | ||
127 | IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */ | ||
128 | }; | ||
129 | |||
130 | #ifndef SQLITE_OMIT_INCRBLOB | ||
131 | /* | ||
132 | ** Close all incrblob channels opened using database connection pDb. | ||
133 | ** This is called when shutting down the database connection. | ||
134 | */ | ||
135 | static void closeIncrblobChannels(SqliteDb *pDb){ | ||
136 | IncrblobChannel *p; | ||
137 | IncrblobChannel *pNext; | ||
138 | |||
139 | for(p=pDb->pIncrblob; p; p=pNext){ | ||
140 | pNext = p->pNext; | ||
141 | |||
142 | /* Note: Calling unregister here call Tcl_Close on the incrblob channel, | ||
143 | ** which deletes the IncrblobChannel structure at *p. So do not | ||
144 | ** call Tcl_Free() here. | ||
145 | */ | ||
146 | Tcl_UnregisterChannel(pDb->interp, p->channel); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | ** Close an incremental blob channel. | ||
152 | */ | ||
153 | static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){ | ||
154 | IncrblobChannel *p = (IncrblobChannel *)instanceData; | ||
155 | int rc = sqlite3_blob_close(p->pBlob); | ||
156 | sqlite3 *db = p->pDb->db; | ||
157 | |||
158 | /* Remove the channel from the SqliteDb.pIncrblob list. */ | ||
159 | if( p->pNext ){ | ||
160 | p->pNext->pPrev = p->pPrev; | ||
161 | } | ||
162 | if( p->pPrev ){ | ||
163 | p->pPrev->pNext = p->pNext; | ||
164 | } | ||
165 | if( p->pDb->pIncrblob==p ){ | ||
166 | p->pDb->pIncrblob = p->pNext; | ||
167 | } | ||
168 | |||
169 | /* Free the IncrblobChannel structure */ | ||
170 | Tcl_Free((char *)p); | ||
171 | |||
172 | if( rc!=SQLITE_OK ){ | ||
173 | Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); | ||
174 | return TCL_ERROR; | ||
175 | } | ||
176 | return TCL_OK; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | ** Read data from an incremental blob channel. | ||
181 | */ | ||
182 | static int incrblobInput( | ||
183 | ClientData instanceData, | ||
184 | char *buf, | ||
185 | int bufSize, | ||
186 | int *errorCodePtr | ||
187 | ){ | ||
188 | IncrblobChannel *p = (IncrblobChannel *)instanceData; | ||
189 | int nRead = bufSize; /* Number of bytes to read */ | ||
190 | int nBlob; /* Total size of the blob */ | ||
191 | int rc; /* sqlite error code */ | ||
192 | |||
193 | nBlob = sqlite3_blob_bytes(p->pBlob); | ||
194 | if( (p->iSeek+nRead)>nBlob ){ | ||
195 | nRead = nBlob-p->iSeek; | ||
196 | } | ||
197 | if( nRead<=0 ){ | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek); | ||
202 | if( rc!=SQLITE_OK ){ | ||
203 | *errorCodePtr = rc; | ||
204 | return -1; | ||
205 | } | ||
206 | |||
207 | p->iSeek += nRead; | ||
208 | return nRead; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | ** Write data to an incremental blob channel. | ||
213 | */ | ||
214 | static int incrblobOutput( | ||
215 | ClientData instanceData, | ||
216 | CONST char *buf, | ||
217 | int toWrite, | ||
218 | int *errorCodePtr | ||
219 | ){ | ||
220 | IncrblobChannel *p = (IncrblobChannel *)instanceData; | ||
221 | int nWrite = toWrite; /* Number of bytes to write */ | ||
222 | int nBlob; /* Total size of the blob */ | ||
223 | int rc; /* sqlite error code */ | ||
224 | |||
225 | nBlob = sqlite3_blob_bytes(p->pBlob); | ||
226 | if( (p->iSeek+nWrite)>nBlob ){ | ||
227 | *errorCodePtr = EINVAL; | ||
228 | return -1; | ||
229 | } | ||
230 | if( nWrite<=0 ){ | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek); | ||
235 | if( rc!=SQLITE_OK ){ | ||
236 | *errorCodePtr = EIO; | ||
237 | return -1; | ||
238 | } | ||
239 | |||
240 | p->iSeek += nWrite; | ||
241 | return nWrite; | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | ** Seek an incremental blob channel. | ||
246 | */ | ||
247 | static int incrblobSeek( | ||
248 | ClientData instanceData, | ||
249 | long offset, | ||
250 | int seekMode, | ||
251 | int *errorCodePtr | ||
252 | ){ | ||
253 | IncrblobChannel *p = (IncrblobChannel *)instanceData; | ||
254 | |||
255 | switch( seekMode ){ | ||
256 | case SEEK_SET: | ||
257 | p->iSeek = offset; | ||
258 | break; | ||
259 | case SEEK_CUR: | ||
260 | p->iSeek += offset; | ||
261 | break; | ||
262 | case SEEK_END: | ||
263 | p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset; | ||
264 | break; | ||
265 | |||
266 | default: assert(!"Bad seekMode"); | ||
267 | } | ||
268 | |||
269 | return p->iSeek; | ||
270 | } | ||
271 | |||
272 | |||
273 | static void incrblobWatch(ClientData instanceData, int mode){ | ||
274 | /* NO-OP */ | ||
275 | } | ||
276 | static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){ | ||
277 | return TCL_ERROR; | ||
278 | } | ||
279 | |||
280 | static Tcl_ChannelType IncrblobChannelType = { | ||
281 | "incrblob", /* typeName */ | ||
282 | TCL_CHANNEL_VERSION_2, /* version */ | ||
283 | incrblobClose, /* closeProc */ | ||
284 | incrblobInput, /* inputProc */ | ||
285 | incrblobOutput, /* outputProc */ | ||
286 | incrblobSeek, /* seekProc */ | ||
287 | 0, /* setOptionProc */ | ||
288 | 0, /* getOptionProc */ | ||
289 | incrblobWatch, /* watchProc (this is a no-op) */ | ||
290 | incrblobHandle, /* getHandleProc (always returns error) */ | ||
291 | 0, /* close2Proc */ | ||
292 | 0, /* blockModeProc */ | ||
293 | 0, /* flushProc */ | ||
294 | 0, /* handlerProc */ | ||
295 | 0, /* wideSeekProc */ | ||
296 | }; | ||
297 | |||
298 | /* | ||
299 | ** Create a new incrblob channel. | ||
300 | */ | ||
301 | static int createIncrblobChannel( | ||
302 | Tcl_Interp *interp, | ||
303 | SqliteDb *pDb, | ||
304 | const char *zDb, | ||
305 | const char *zTable, | ||
306 | const char *zColumn, | ||
307 | sqlite_int64 iRow, | ||
308 | int isReadonly | ||
309 | ){ | ||
310 | IncrblobChannel *p; | ||
311 | sqlite3 *db = pDb->db; | ||
312 | sqlite3_blob *pBlob; | ||
313 | int rc; | ||
314 | int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE); | ||
315 | |||
316 | /* This variable is used to name the channels: "incrblob_[incr count]" */ | ||
317 | static int count = 0; | ||
318 | char zChannel[64]; | ||
319 | |||
320 | rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob); | ||
321 | if( rc!=SQLITE_OK ){ | ||
322 | Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); | ||
323 | return TCL_ERROR; | ||
324 | } | ||
325 | |||
326 | p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel)); | ||
327 | p->iSeek = 0; | ||
328 | p->pBlob = pBlob; | ||
329 | |||
330 | sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count); | ||
331 | p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags); | ||
332 | Tcl_RegisterChannel(interp, p->channel); | ||
333 | |||
334 | /* Link the new channel into the SqliteDb.pIncrblob list. */ | ||
335 | p->pNext = pDb->pIncrblob; | ||
336 | p->pPrev = 0; | ||
337 | if( p->pNext ){ | ||
338 | p->pNext->pPrev = p; | ||
339 | } | ||
340 | pDb->pIncrblob = p; | ||
341 | p->pDb = pDb; | ||
342 | |||
343 | Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE); | ||
344 | return TCL_OK; | ||
345 | } | ||
346 | #else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */ | ||
347 | #define closeIncrblobChannels(pDb) | ||
348 | #endif | ||
349 | |||
350 | /* | ||
351 | ** Look at the script prefix in pCmd. We will be executing this script | ||
352 | ** after first appending one or more arguments. This routine analyzes | ||
353 | ** the script to see if it is safe to use Tcl_EvalObjv() on the script | ||
354 | ** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much | ||
355 | ** faster. | ||
356 | ** | ||
357 | ** Scripts that are safe to use with Tcl_EvalObjv() consists of a | ||
358 | ** command name followed by zero or more arguments with no [...] or $ | ||
359 | ** or {...} or ; to be seen anywhere. Most callback scripts consist | ||
360 | ** of just a single procedure name and they meet this requirement. | ||
361 | */ | ||
362 | static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ | ||
363 | /* We could try to do something with Tcl_Parse(). But we will instead | ||
364 | ** just do a search for forbidden characters. If any of the forbidden | ||
365 | ** characters appear in pCmd, we will report the string as unsafe. | ||
366 | */ | ||
367 | const char *z; | ||
368 | int n; | ||
369 | z = Tcl_GetStringFromObj(pCmd, &n); | ||
370 | while( n-- > 0 ){ | ||
371 | int c = *(z++); | ||
372 | if( c=='$' || c=='[' || c==';' ) return 0; | ||
373 | } | ||
374 | return 1; | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | ** Find an SqlFunc structure with the given name. Or create a new | ||
379 | ** one if an existing one cannot be found. Return a pointer to the | ||
380 | ** structure. | ||
381 | */ | ||
382 | static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ | ||
383 | SqlFunc *p, *pNew; | ||
384 | int i; | ||
385 | pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen(zName) + 1 ); | ||
386 | pNew->zName = (char*)&pNew[1]; | ||
387 | for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); } | ||
388 | pNew->zName[i] = 0; | ||
389 | for(p=pDb->pFunc; p; p=p->pNext){ | ||
390 | if( strcmp(p->zName, pNew->zName)==0 ){ | ||
391 | Tcl_Free((char*)pNew); | ||
392 | return p; | ||
393 | } | ||
394 | } | ||
395 | pNew->interp = pDb->interp; | ||
396 | pNew->pScript = 0; | ||
397 | pNew->pNext = pDb->pFunc; | ||
398 | pDb->pFunc = pNew; | ||
399 | return pNew; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | ** Finalize and free a list of prepared statements | ||
404 | */ | ||
405 | static void flushStmtCache( SqliteDb *pDb ){ | ||
406 | SqlPreparedStmt *pPreStmt; | ||
407 | |||
408 | while( pDb->stmtList ){ | ||
409 | sqlite3_finalize( pDb->stmtList->pStmt ); | ||
410 | pPreStmt = pDb->stmtList; | ||
411 | pDb->stmtList = pDb->stmtList->pNext; | ||
412 | Tcl_Free( (char*)pPreStmt ); | ||
413 | } | ||
414 | pDb->nStmt = 0; | ||
415 | pDb->stmtLast = 0; | ||
416 | } | ||
417 | |||
418 | /* | ||
419 | ** TCL calls this procedure when an sqlite3 database command is | ||
420 | ** deleted. | ||
421 | */ | ||
422 | static void DbDeleteCmd(void *db){ | ||
423 | SqliteDb *pDb = (SqliteDb*)db; | ||
424 | flushStmtCache(pDb); | ||
425 | closeIncrblobChannels(pDb); | ||
426 | sqlite3_close(pDb->db); | ||
427 | while( pDb->pFunc ){ | ||
428 | SqlFunc *pFunc = pDb->pFunc; | ||
429 | pDb->pFunc = pFunc->pNext; | ||
430 | Tcl_DecrRefCount(pFunc->pScript); | ||
431 | Tcl_Free((char*)pFunc); | ||
432 | } | ||
433 | while( pDb->pCollate ){ | ||
434 | SqlCollate *pCollate = pDb->pCollate; | ||
435 | pDb->pCollate = pCollate->pNext; | ||
436 | Tcl_Free((char*)pCollate); | ||
437 | } | ||
438 | if( pDb->zBusy ){ | ||
439 | Tcl_Free(pDb->zBusy); | ||
440 | } | ||
441 | if( pDb->zTrace ){ | ||
442 | Tcl_Free(pDb->zTrace); | ||
443 | } | ||
444 | if( pDb->zProfile ){ | ||
445 | Tcl_Free(pDb->zProfile); | ||
446 | } | ||
447 | if( pDb->zAuth ){ | ||
448 | Tcl_Free(pDb->zAuth); | ||
449 | } | ||
450 | if( pDb->zNull ){ | ||
451 | Tcl_Free(pDb->zNull); | ||
452 | } | ||
453 | if( pDb->pUpdateHook ){ | ||
454 | Tcl_DecrRefCount(pDb->pUpdateHook); | ||
455 | } | ||
456 | if( pDb->pRollbackHook ){ | ||
457 | Tcl_DecrRefCount(pDb->pRollbackHook); | ||
458 | } | ||
459 | if( pDb->pCollateNeeded ){ | ||
460 | Tcl_DecrRefCount(pDb->pCollateNeeded); | ||
461 | } | ||
462 | Tcl_Free((char*)pDb); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | ** This routine is called when a database file is locked while trying | ||
467 | ** to execute SQL. | ||
468 | */ | ||
469 | static int DbBusyHandler(void *cd, int nTries){ | ||
470 | SqliteDb *pDb = (SqliteDb*)cd; | ||
471 | int rc; | ||
472 | char zVal[30]; | ||
473 | |||
474 | sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries); | ||
475 | rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0); | ||
476 | if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ | ||
477 | return 0; | ||
478 | } | ||
479 | return 1; | ||
480 | } | ||
481 | |||
482 | /* | ||
483 | ** This routine is invoked as the 'progress callback' for the database. | ||
484 | */ | ||
485 | static int DbProgressHandler(void *cd){ | ||
486 | SqliteDb *pDb = (SqliteDb*)cd; | ||
487 | int rc; | ||
488 | |||
489 | assert( pDb->zProgress ); | ||
490 | rc = Tcl_Eval(pDb->interp, pDb->zProgress); | ||
491 | if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ | ||
492 | return 1; | ||
493 | } | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | #ifndef SQLITE_OMIT_TRACE | ||
498 | /* | ||
499 | ** This routine is called by the SQLite trace handler whenever a new | ||
500 | ** block of SQL is executed. The TCL script in pDb->zTrace is executed. | ||
501 | */ | ||
502 | static void DbTraceHandler(void *cd, const char *zSql){ | ||
503 | SqliteDb *pDb = (SqliteDb*)cd; | ||
504 | Tcl_DString str; | ||
505 | |||
506 | Tcl_DStringInit(&str); | ||
507 | Tcl_DStringAppend(&str, pDb->zTrace, -1); | ||
508 | Tcl_DStringAppendElement(&str, zSql); | ||
509 | Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); | ||
510 | Tcl_DStringFree(&str); | ||
511 | Tcl_ResetResult(pDb->interp); | ||
512 | } | ||
513 | #endif | ||
514 | |||
515 | #ifndef SQLITE_OMIT_TRACE | ||
516 | /* | ||
517 | ** This routine is called by the SQLite profile handler after a statement | ||
518 | ** SQL has executed. The TCL script in pDb->zProfile is evaluated. | ||
519 | */ | ||
520 | static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ | ||
521 | SqliteDb *pDb = (SqliteDb*)cd; | ||
522 | Tcl_DString str; | ||
523 | char zTm[100]; | ||
524 | |||
525 | sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm); | ||
526 | Tcl_DStringInit(&str); | ||
527 | Tcl_DStringAppend(&str, pDb->zProfile, -1); | ||
528 | Tcl_DStringAppendElement(&str, zSql); | ||
529 | Tcl_DStringAppendElement(&str, zTm); | ||
530 | Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); | ||
531 | Tcl_DStringFree(&str); | ||
532 | Tcl_ResetResult(pDb->interp); | ||
533 | } | ||
534 | #endif | ||
535 | |||
536 | /* | ||
537 | ** This routine is called when a transaction is committed. The | ||
538 | ** TCL script in pDb->zCommit is executed. If it returns non-zero or | ||
539 | ** if it throws an exception, the transaction is rolled back instead | ||
540 | ** of being committed. | ||
541 | */ | ||
542 | static int DbCommitHandler(void *cd){ | ||
543 | SqliteDb *pDb = (SqliteDb*)cd; | ||
544 | int rc; | ||
545 | |||
546 | rc = Tcl_Eval(pDb->interp, pDb->zCommit); | ||
547 | if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ | ||
548 | return 1; | ||
549 | } | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static void DbRollbackHandler(void *clientData){ | ||
554 | SqliteDb *pDb = (SqliteDb*)clientData; | ||
555 | assert(pDb->pRollbackHook); | ||
556 | if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ | ||
557 | Tcl_BackgroundError(pDb->interp); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | static void DbUpdateHandler( | ||
562 | void *p, | ||
563 | int op, | ||
564 | const char *zDb, | ||
565 | const char *zTbl, | ||
566 | sqlite_int64 rowid | ||
567 | ){ | ||
568 | SqliteDb *pDb = (SqliteDb *)p; | ||
569 | Tcl_Obj *pCmd; | ||
570 | |||
571 | assert( pDb->pUpdateHook ); | ||
572 | assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); | ||
573 | |||
574 | pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); | ||
575 | Tcl_IncrRefCount(pCmd); | ||
576 | Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj( | ||
577 | ( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1)); | ||
578 | Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); | ||
579 | Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); | ||
580 | Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); | ||
581 | Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); | ||
582 | } | ||
583 | |||
584 | static void tclCollateNeeded( | ||
585 | void *pCtx, | ||
586 | sqlite3 *db, | ||
587 | int enc, | ||
588 | const char *zName | ||
589 | ){ | ||
590 | SqliteDb *pDb = (SqliteDb *)pCtx; | ||
591 | Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); | ||
592 | Tcl_IncrRefCount(pScript); | ||
593 | Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); | ||
594 | Tcl_EvalObjEx(pDb->interp, pScript, 0); | ||
595 | Tcl_DecrRefCount(pScript); | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | ** This routine is called to evaluate an SQL collation function implemented | ||
600 | ** using TCL script. | ||
601 | */ | ||
602 | static int tclSqlCollate( | ||
603 | void *pCtx, | ||
604 | int nA, | ||
605 | const void *zA, | ||
606 | int nB, | ||
607 | const void *zB | ||
608 | ){ | ||
609 | SqlCollate *p = (SqlCollate *)pCtx; | ||
610 | Tcl_Obj *pCmd; | ||
611 | |||
612 | pCmd = Tcl_NewStringObj(p->zScript, -1); | ||
613 | Tcl_IncrRefCount(pCmd); | ||
614 | Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); | ||
615 | Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); | ||
616 | Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); | ||
617 | Tcl_DecrRefCount(pCmd); | ||
618 | return (atoi(Tcl_GetStringResult(p->interp))); | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | ** This routine is called to evaluate an SQL function implemented | ||
623 | ** using TCL script. | ||
624 | */ | ||
625 | static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ | ||
626 | SqlFunc *p = sqlite3_user_data(context); | ||
627 | Tcl_Obj *pCmd; | ||
628 | int i; | ||
629 | int rc; | ||
630 | |||
631 | if( argc==0 ){ | ||
632 | /* If there are no arguments to the function, call Tcl_EvalObjEx on the | ||
633 | ** script object directly. This allows the TCL compiler to generate | ||
634 | ** bytecode for the command on the first invocation and thus make | ||
635 | ** subsequent invocations much faster. */ | ||
636 | pCmd = p->pScript; | ||
637 | Tcl_IncrRefCount(pCmd); | ||
638 | rc = Tcl_EvalObjEx(p->interp, pCmd, 0); | ||
639 | Tcl_DecrRefCount(pCmd); | ||
640 | }else{ | ||
641 | /* If there are arguments to the function, make a shallow copy of the | ||
642 | ** script object, lappend the arguments, then evaluate the copy. | ||
643 | ** | ||
644 | ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated. | ||
645 | ** The new Tcl_Obj contains pointers to the original list elements. | ||
646 | ** That way, when Tcl_EvalObjv() is run and shimmers the first element | ||
647 | ** of the list to tclCmdNameType, that alternate representation will | ||
648 | ** be preserved and reused on the next invocation. | ||
649 | */ | ||
650 | Tcl_Obj **aArg; | ||
651 | int nArg; | ||
652 | if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ | ||
653 | sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); | ||
654 | return; | ||
655 | } | ||
656 | pCmd = Tcl_NewListObj(nArg, aArg); | ||
657 | Tcl_IncrRefCount(pCmd); | ||
658 | for(i=0; i<argc; i++){ | ||
659 | sqlite3_value *pIn = argv[i]; | ||
660 | Tcl_Obj *pVal; | ||
661 | |||
662 | /* Set pVal to contain the i'th column of this row. */ | ||
663 | switch( sqlite3_value_type(pIn) ){ | ||
664 | case SQLITE_BLOB: { | ||
665 | int bytes = sqlite3_value_bytes(pIn); | ||
666 | pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); | ||
667 | break; | ||
668 | } | ||
669 | case SQLITE_INTEGER: { | ||
670 | sqlite_int64 v = sqlite3_value_int64(pIn); | ||
671 | if( v>=-2147483647 && v<=2147483647 ){ | ||
672 | pVal = Tcl_NewIntObj(v); | ||
673 | }else{ | ||
674 | pVal = Tcl_NewWideIntObj(v); | ||
675 | } | ||
676 | break; | ||
677 | } | ||
678 | case SQLITE_FLOAT: { | ||
679 | double r = sqlite3_value_double(pIn); | ||
680 | pVal = Tcl_NewDoubleObj(r); | ||
681 | break; | ||
682 | } | ||
683 | case SQLITE_NULL: { | ||
684 | pVal = Tcl_NewStringObj("", 0); | ||
685 | break; | ||
686 | } | ||
687 | default: { | ||
688 | int bytes = sqlite3_value_bytes(pIn); | ||
689 | pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); | ||
690 | break; | ||
691 | } | ||
692 | } | ||
693 | rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); | ||
694 | if( rc ){ | ||
695 | Tcl_DecrRefCount(pCmd); | ||
696 | sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); | ||
697 | return; | ||
698 | } | ||
699 | } | ||
700 | if( !p->useEvalObjv ){ | ||
701 | /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd | ||
702 | ** is a list without a string representation. To prevent this from | ||
703 | ** happening, make sure pCmd has a valid string representation */ | ||
704 | Tcl_GetString(pCmd); | ||
705 | } | ||
706 | rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); | ||
707 | Tcl_DecrRefCount(pCmd); | ||
708 | } | ||
709 | |||
710 | if( rc && rc!=TCL_RETURN ){ | ||
711 | sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); | ||
712 | }else{ | ||
713 | Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); | ||
714 | int n; | ||
715 | u8 *data; | ||
716 | char *zType = pVar->typePtr ? pVar->typePtr->name : ""; | ||
717 | char c = zType[0]; | ||
718 | if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ | ||
719 | /* Only return a BLOB type if the Tcl variable is a bytearray and | ||
720 | ** has no string representation. */ | ||
721 | data = Tcl_GetByteArrayFromObj(pVar, &n); | ||
722 | sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); | ||
723 | }else if( c=='b' && strcmp(zType,"boolean")==0 ){ | ||
724 | Tcl_GetIntFromObj(0, pVar, &n); | ||
725 | sqlite3_result_int(context, n); | ||
726 | }else if( c=='d' && strcmp(zType,"double")==0 ){ | ||
727 | double r; | ||
728 | Tcl_GetDoubleFromObj(0, pVar, &r); | ||
729 | sqlite3_result_double(context, r); | ||
730 | }else if( (c=='w' && strcmp(zType,"wideInt")==0) || | ||
731 | (c=='i' && strcmp(zType,"int")==0) ){ | ||
732 | Tcl_WideInt v; | ||
733 | Tcl_GetWideIntFromObj(0, pVar, &v); | ||
734 | sqlite3_result_int64(context, v); | ||
735 | }else{ | ||
736 | data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); | ||
737 | sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); | ||
738 | } | ||
739 | } | ||
740 | } | ||
741 | |||
742 | #ifndef SQLITE_OMIT_AUTHORIZATION | ||
743 | /* | ||
744 | ** This is the authentication function. It appends the authentication | ||
745 | ** type code and the two arguments to zCmd[] then invokes the result | ||
746 | ** on the interpreter. The reply is examined to determine if the | ||
747 | ** authentication fails or succeeds. | ||
748 | */ | ||
749 | static int auth_callback( | ||
750 | void *pArg, | ||
751 | int code, | ||
752 | const char *zArg1, | ||
753 | const char *zArg2, | ||
754 | const char *zArg3, | ||
755 | const char *zArg4 | ||
756 | ){ | ||
757 | char *zCode; | ||
758 | Tcl_DString str; | ||
759 | int rc; | ||
760 | const char *zReply; | ||
761 | SqliteDb *pDb = (SqliteDb*)pArg; | ||
762 | |||
763 | switch( code ){ | ||
764 | case SQLITE_COPY : zCode="SQLITE_COPY"; break; | ||
765 | case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; | ||
766 | case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; | ||
767 | case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; | ||
768 | case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; | ||
769 | case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; | ||
770 | case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; | ||
771 | case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; | ||
772 | case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; | ||
773 | case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; | ||
774 | case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; | ||
775 | case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; | ||
776 | case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; | ||
777 | case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; | ||
778 | case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; | ||
779 | case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; | ||
780 | case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; | ||
781 | case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; | ||
782 | case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; | ||
783 | case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; | ||
784 | case SQLITE_READ : zCode="SQLITE_READ"; break; | ||
785 | case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; | ||
786 | case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; | ||
787 | case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; | ||
788 | case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; | ||
789 | case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; | ||
790 | case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; | ||
791 | case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; | ||
792 | case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; | ||
793 | case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; | ||
794 | case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; | ||
795 | case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break; | ||
796 | default : zCode="????"; break; | ||
797 | } | ||
798 | Tcl_DStringInit(&str); | ||
799 | Tcl_DStringAppend(&str, pDb->zAuth, -1); | ||
800 | Tcl_DStringAppendElement(&str, zCode); | ||
801 | Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); | ||
802 | Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); | ||
803 | Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); | ||
804 | Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); | ||
805 | rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); | ||
806 | Tcl_DStringFree(&str); | ||
807 | zReply = Tcl_GetStringResult(pDb->interp); | ||
808 | if( strcmp(zReply,"SQLITE_OK")==0 ){ | ||
809 | rc = SQLITE_OK; | ||
810 | }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ | ||
811 | rc = SQLITE_DENY; | ||
812 | }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ | ||
813 | rc = SQLITE_IGNORE; | ||
814 | }else{ | ||
815 | rc = 999; | ||
816 | } | ||
817 | return rc; | ||
818 | } | ||
819 | #endif /* SQLITE_OMIT_AUTHORIZATION */ | ||
820 | |||
821 | /* | ||
822 | ** zText is a pointer to text obtained via an sqlite3_result_text() | ||
823 | ** or similar interface. This routine returns a Tcl string object, | ||
824 | ** reference count set to 0, containing the text. If a translation | ||
825 | ** between iso8859 and UTF-8 is required, it is preformed. | ||
826 | */ | ||
827 | static Tcl_Obj *dbTextToObj(char const *zText){ | ||
828 | Tcl_Obj *pVal; | ||
829 | #ifdef UTF_TRANSLATION_NEEDED | ||
830 | Tcl_DString dCol; | ||
831 | Tcl_DStringInit(&dCol); | ||
832 | Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol); | ||
833 | pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1); | ||
834 | Tcl_DStringFree(&dCol); | ||
835 | #else | ||
836 | pVal = Tcl_NewStringObj(zText, -1); | ||
837 | #endif | ||
838 | return pVal; | ||
839 | } | ||
840 | |||
841 | /* | ||
842 | ** This routine reads a line of text from FILE in, stores | ||
843 | ** the text in memory obtained from malloc() and returns a pointer | ||
844 | ** to the text. NULL is returned at end of file, or if malloc() | ||
845 | ** fails. | ||
846 | ** | ||
847 | ** The interface is like "readline" but no command-line editing | ||
848 | ** is done. | ||
849 | ** | ||
850 | ** copied from shell.c from '.import' command | ||
851 | */ | ||
852 | static char *local_getline(char *zPrompt, FILE *in){ | ||
853 | char *zLine; | ||
854 | int nLine; | ||
855 | int n; | ||
856 | int eol; | ||
857 | |||
858 | nLine = 100; | ||
859 | zLine = malloc( nLine ); | ||
860 | if( zLine==0 ) return 0; | ||
861 | n = 0; | ||
862 | eol = 0; | ||
863 | while( !eol ){ | ||
864 | if( n+100>nLine ){ | ||
865 | nLine = nLine*2 + 100; | ||
866 | zLine = realloc(zLine, nLine); | ||
867 | if( zLine==0 ) return 0; | ||
868 | } | ||
869 | if( fgets(&zLine[n], nLine - n, in)==0 ){ | ||
870 | if( n==0 ){ | ||
871 | free(zLine); | ||
872 | return 0; | ||
873 | } | ||
874 | zLine[n] = 0; | ||
875 | eol = 1; | ||
876 | break; | ||
877 | } | ||
878 | while( zLine[n] ){ n++; } | ||
879 | if( n>0 && zLine[n-1]=='\n' ){ | ||
880 | n--; | ||
881 | zLine[n] = 0; | ||
882 | eol = 1; | ||
883 | } | ||
884 | } | ||
885 | zLine = realloc( zLine, n+1 ); | ||
886 | return zLine; | ||
887 | } | ||
888 | |||
889 | /* | ||
890 | ** The "sqlite" command below creates a new Tcl command for each | ||
891 | ** connection it opens to an SQLite database. This routine is invoked | ||
892 | ** whenever one of those connection-specific commands is executed | ||
893 | ** in Tcl. For example, if you run Tcl code like this: | ||
894 | ** | ||
895 | ** sqlite3 db1 "my_database" | ||
896 | ** db1 close | ||
897 | ** | ||
898 | ** The first command opens a connection to the "my_database" database | ||
899 | ** and calls that connection "db1". The second command causes this | ||
900 | ** subroutine to be invoked. | ||
901 | */ | ||
902 | static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ | ||
903 | SqliteDb *pDb = (SqliteDb*)cd; | ||
904 | int choice; | ||
905 | int rc = TCL_OK; | ||
906 | static const char *DB_strs[] = { | ||
907 | "authorizer", "busy", "cache", | ||
908 | "changes", "close", "collate", | ||
909 | "collation_needed", "commit_hook", "complete", | ||
910 | "copy", "enable_load_extension","errorcode", | ||
911 | "eval", "exists", "function", | ||
912 | "incrblob", "interrupt", "last_insert_rowid", | ||
913 | "nullvalue", "onecolumn", "profile", | ||
914 | "progress", "rekey", "rollback_hook", | ||
915 | "timeout", "total_changes", "trace", | ||
916 | "transaction", "update_hook", "version", | ||
917 | 0 | ||
918 | }; | ||
919 | enum DB_enum { | ||
920 | DB_AUTHORIZER, DB_BUSY, DB_CACHE, | ||
921 | DB_CHANGES, DB_CLOSE, DB_COLLATE, | ||
922 | DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, | ||
923 | DB_COPY, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE, | ||
924 | DB_EVAL, DB_EXISTS, DB_FUNCTION, | ||
925 | DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID, | ||
926 | DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, | ||
927 | DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK, | ||
928 | DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, | ||
929 | DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION | ||
930 | }; | ||
931 | /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ | ||
932 | |||
933 | if( objc<2 ){ | ||
934 | Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); | ||
935 | return TCL_ERROR; | ||
936 | } | ||
937 | if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ | ||
938 | return TCL_ERROR; | ||
939 | } | ||
940 | |||
941 | switch( (enum DB_enum)choice ){ | ||
942 | |||
943 | /* $db authorizer ?CALLBACK? | ||
944 | ** | ||
945 | ** Invoke the given callback to authorize each SQL operation as it is | ||
946 | ** compiled. 5 arguments are appended to the callback before it is | ||
947 | ** invoked: | ||
948 | ** | ||
949 | ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) | ||
950 | ** (2) First descriptive name (depends on authorization type) | ||
951 | ** (3) Second descriptive name | ||
952 | ** (4) Name of the database (ex: "main", "temp") | ||
953 | ** (5) Name of trigger that is doing the access | ||
954 | ** | ||
955 | ** The callback should return on of the following strings: SQLITE_OK, | ||
956 | ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. | ||
957 | ** | ||
958 | ** If this method is invoked with no arguments, the current authorization | ||
959 | ** callback string is returned. | ||
960 | */ | ||
961 | case DB_AUTHORIZER: { | ||
962 | #ifdef SQLITE_OMIT_AUTHORIZATION | ||
963 | Tcl_AppendResult(interp, "authorization not available in this build", 0); | ||
964 | return TCL_ERROR; | ||
965 | #else | ||
966 | if( objc>3 ){ | ||
967 | Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); | ||
968 | return TCL_ERROR; | ||
969 | }else if( objc==2 ){ | ||
970 | if( pDb->zAuth ){ | ||
971 | Tcl_AppendResult(interp, pDb->zAuth, 0); | ||
972 | } | ||
973 | }else{ | ||
974 | char *zAuth; | ||
975 | int len; | ||
976 | if( pDb->zAuth ){ | ||
977 | Tcl_Free(pDb->zAuth); | ||
978 | } | ||
979 | zAuth = Tcl_GetStringFromObj(objv[2], &len); | ||
980 | if( zAuth && len>0 ){ | ||
981 | pDb->zAuth = Tcl_Alloc( len + 1 ); | ||
982 | memcpy(pDb->zAuth, zAuth, len+1); | ||
983 | }else{ | ||
984 | pDb->zAuth = 0; | ||
985 | } | ||
986 | if( pDb->zAuth ){ | ||
987 | pDb->interp = interp; | ||
988 | sqlite3_set_authorizer(pDb->db, auth_callback, pDb); | ||
989 | }else{ | ||
990 | sqlite3_set_authorizer(pDb->db, 0, 0); | ||
991 | } | ||
992 | } | ||
993 | #endif | ||
994 | break; | ||
995 | } | ||
996 | |||
997 | /* $db busy ?CALLBACK? | ||
998 | ** | ||
999 | ** Invoke the given callback if an SQL statement attempts to open | ||
1000 | ** a locked database file. | ||
1001 | */ | ||
1002 | case DB_BUSY: { | ||
1003 | if( objc>3 ){ | ||
1004 | Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); | ||
1005 | return TCL_ERROR; | ||
1006 | }else if( objc==2 ){ | ||
1007 | if( pDb->zBusy ){ | ||
1008 | Tcl_AppendResult(interp, pDb->zBusy, 0); | ||
1009 | } | ||
1010 | }else{ | ||
1011 | char *zBusy; | ||
1012 | int len; | ||
1013 | if( pDb->zBusy ){ | ||
1014 | Tcl_Free(pDb->zBusy); | ||
1015 | } | ||
1016 | zBusy = Tcl_GetStringFromObj(objv[2], &len); | ||
1017 | if( zBusy && len>0 ){ | ||
1018 | pDb->zBusy = Tcl_Alloc( len + 1 ); | ||
1019 | memcpy(pDb->zBusy, zBusy, len+1); | ||
1020 | }else{ | ||
1021 | pDb->zBusy = 0; | ||
1022 | } | ||
1023 | if( pDb->zBusy ){ | ||
1024 | pDb->interp = interp; | ||
1025 | sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); | ||
1026 | }else{ | ||
1027 | sqlite3_busy_handler(pDb->db, 0, 0); | ||
1028 | } | ||
1029 | } | ||
1030 | break; | ||
1031 | } | ||
1032 | |||
1033 | /* $db cache flush | ||
1034 | ** $db cache size n | ||
1035 | ** | ||
1036 | ** Flush the prepared statement cache, or set the maximum number of | ||
1037 | ** cached statements. | ||
1038 | */ | ||
1039 | case DB_CACHE: { | ||
1040 | char *subCmd; | ||
1041 | int n; | ||
1042 | |||
1043 | if( objc<=2 ){ | ||
1044 | Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); | ||
1045 | return TCL_ERROR; | ||
1046 | } | ||
1047 | subCmd = Tcl_GetStringFromObj( objv[2], 0 ); | ||
1048 | if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ | ||
1049 | if( objc!=3 ){ | ||
1050 | Tcl_WrongNumArgs(interp, 2, objv, "flush"); | ||
1051 | return TCL_ERROR; | ||
1052 | }else{ | ||
1053 | flushStmtCache( pDb ); | ||
1054 | } | ||
1055 | }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ | ||
1056 | if( objc!=4 ){ | ||
1057 | Tcl_WrongNumArgs(interp, 2, objv, "size n"); | ||
1058 | return TCL_ERROR; | ||
1059 | }else{ | ||
1060 | if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ | ||
1061 | Tcl_AppendResult( interp, "cannot convert \"", | ||
1062 | Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0); | ||
1063 | return TCL_ERROR; | ||
1064 | }else{ | ||
1065 | if( n<0 ){ | ||
1066 | flushStmtCache( pDb ); | ||
1067 | n = 0; | ||
1068 | }else if( n>MAX_PREPARED_STMTS ){ | ||
1069 | n = MAX_PREPARED_STMTS; | ||
1070 | } | ||
1071 | pDb->maxStmt = n; | ||
1072 | } | ||
1073 | } | ||
1074 | }else{ | ||
1075 | Tcl_AppendResult( interp, "bad option \"", | ||
1076 | Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0); | ||
1077 | return TCL_ERROR; | ||
1078 | } | ||
1079 | break; | ||
1080 | } | ||
1081 | |||
1082 | /* $db changes | ||
1083 | ** | ||
1084 | ** Return the number of rows that were modified, inserted, or deleted by | ||
1085 | ** the most recent INSERT, UPDATE or DELETE statement, not including | ||
1086 | ** any changes made by trigger programs. | ||
1087 | */ | ||
1088 | case DB_CHANGES: { | ||
1089 | Tcl_Obj *pResult; | ||
1090 | if( objc!=2 ){ | ||
1091 | Tcl_WrongNumArgs(interp, 2, objv, ""); | ||
1092 | return TCL_ERROR; | ||
1093 | } | ||
1094 | pResult = Tcl_GetObjResult(interp); | ||
1095 | Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); | ||
1096 | break; | ||
1097 | } | ||
1098 | |||
1099 | /* $db close | ||
1100 | ** | ||
1101 | ** Shutdown the database | ||
1102 | */ | ||
1103 | case DB_CLOSE: { | ||
1104 | Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); | ||
1105 | break; | ||
1106 | } | ||
1107 | |||
1108 | /* | ||
1109 | ** $db collate NAME SCRIPT | ||
1110 | ** | ||
1111 | ** Create a new SQL collation function called NAME. Whenever | ||
1112 | ** that function is called, invoke SCRIPT to evaluate the function. | ||
1113 | */ | ||
1114 | case DB_COLLATE: { | ||
1115 | SqlCollate *pCollate; | ||
1116 | char *zName; | ||
1117 | char *zScript; | ||
1118 | int nScript; | ||
1119 | if( objc!=4 ){ | ||
1120 | Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); | ||
1121 | return TCL_ERROR; | ||
1122 | } | ||
1123 | zName = Tcl_GetStringFromObj(objv[2], 0); | ||
1124 | zScript = Tcl_GetStringFromObj(objv[3], &nScript); | ||
1125 | pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); | ||
1126 | if( pCollate==0 ) return TCL_ERROR; | ||
1127 | pCollate->interp = interp; | ||
1128 | pCollate->pNext = pDb->pCollate; | ||
1129 | pCollate->zScript = (char*)&pCollate[1]; | ||
1130 | pDb->pCollate = pCollate; | ||
1131 | memcpy(pCollate->zScript, zScript, nScript+1); | ||
1132 | if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, | ||
1133 | pCollate, tclSqlCollate) ){ | ||
1134 | Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); | ||
1135 | return TCL_ERROR; | ||
1136 | } | ||
1137 | break; | ||
1138 | } | ||
1139 | |||
1140 | /* | ||
1141 | ** $db collation_needed SCRIPT | ||
1142 | ** | ||
1143 | ** Create a new SQL collation function called NAME. Whenever | ||
1144 | ** that function is called, invoke SCRIPT to evaluate the function. | ||
1145 | */ | ||
1146 | case DB_COLLATION_NEEDED: { | ||
1147 | if( objc!=3 ){ | ||
1148 | Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); | ||
1149 | return TCL_ERROR; | ||
1150 | } | ||
1151 | if( pDb->pCollateNeeded ){ | ||
1152 | Tcl_DecrRefCount(pDb->pCollateNeeded); | ||
1153 | } | ||
1154 | pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); | ||
1155 | Tcl_IncrRefCount(pDb->pCollateNeeded); | ||
1156 | sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); | ||
1157 | break; | ||
1158 | } | ||
1159 | |||
1160 | /* $db commit_hook ?CALLBACK? | ||
1161 | ** | ||
1162 | ** Invoke the given callback just before committing every SQL transaction. | ||
1163 | ** If the callback throws an exception or returns non-zero, then the | ||
1164 | ** transaction is aborted. If CALLBACK is an empty string, the callback | ||
1165 | ** is disabled. | ||
1166 | */ | ||
1167 | case DB_COMMIT_HOOK: { | ||
1168 | if( objc>3 ){ | ||
1169 | Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); | ||
1170 | return TCL_ERROR; | ||
1171 | }else if( objc==2 ){ | ||
1172 | if( pDb->zCommit ){ | ||
1173 | Tcl_AppendResult(interp, pDb->zCommit, 0); | ||
1174 | } | ||
1175 | }else{ | ||
1176 | char *zCommit; | ||
1177 | int len; | ||
1178 | if( pDb->zCommit ){ | ||
1179 | Tcl_Free(pDb->zCommit); | ||
1180 | } | ||
1181 | zCommit = Tcl_GetStringFromObj(objv[2], &len); | ||
1182 | if( zCommit && len>0 ){ | ||
1183 | pDb->zCommit = Tcl_Alloc( len + 1 ); | ||
1184 | memcpy(pDb->zCommit, zCommit, len+1); | ||
1185 | }else{ | ||
1186 | pDb->zCommit = 0; | ||
1187 | } | ||
1188 | if( pDb->zCommit ){ | ||
1189 | pDb->interp = interp; | ||
1190 | sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); | ||
1191 | }else{ | ||
1192 | sqlite3_commit_hook(pDb->db, 0, 0); | ||
1193 | } | ||
1194 | } | ||
1195 | break; | ||
1196 | } | ||
1197 | |||
1198 | /* $db complete SQL | ||
1199 | ** | ||
1200 | ** Return TRUE if SQL is a complete SQL statement. Return FALSE if | ||
1201 | ** additional lines of input are needed. This is similar to the | ||
1202 | ** built-in "info complete" command of Tcl. | ||
1203 | */ | ||
1204 | case DB_COMPLETE: { | ||
1205 | #ifndef SQLITE_OMIT_COMPLETE | ||
1206 | Tcl_Obj *pResult; | ||
1207 | int isComplete; | ||
1208 | if( objc!=3 ){ | ||
1209 | Tcl_WrongNumArgs(interp, 2, objv, "SQL"); | ||
1210 | return TCL_ERROR; | ||
1211 | } | ||
1212 | isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); | ||
1213 | pResult = Tcl_GetObjResult(interp); | ||
1214 | Tcl_SetBooleanObj(pResult, isComplete); | ||
1215 | #endif | ||
1216 | break; | ||
1217 | } | ||
1218 | |||
1219 | /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? | ||
1220 | ** | ||
1221 | ** Copy data into table from filename, optionally using SEPARATOR | ||
1222 | ** as column separators. If a column contains a null string, or the | ||
1223 | ** value of NULLINDICATOR, a NULL is inserted for the column. | ||
1224 | ** conflict-algorithm is one of the sqlite conflict algorithms: | ||
1225 | ** rollback, abort, fail, ignore, replace | ||
1226 | ** On success, return the number of lines processed, not necessarily same | ||
1227 | ** as 'db changes' due to conflict-algorithm selected. | ||
1228 | ** | ||
1229 | ** This code is basically an implementation/enhancement of | ||
1230 | ** the sqlite3 shell.c ".import" command. | ||
1231 | ** | ||
1232 | ** This command usage is equivalent to the sqlite2.x COPY statement, | ||
1233 | ** which imports file data into a table using the PostgreSQL COPY file format: | ||
1234 | ** $db copy $conflit_algo $table_name $filename \t \\N | ||
1235 | */ | ||
1236 | case DB_COPY: { | ||
1237 | char *zTable; /* Insert data into this table */ | ||
1238 | char *zFile; /* The file from which to extract data */ | ||
1239 | char *zConflict; /* The conflict algorithm to use */ | ||
1240 | sqlite3_stmt *pStmt; /* A statement */ | ||
1241 | int rc; /* Result code */ | ||
1242 | int nCol; /* Number of columns in the table */ | ||
1243 | int nByte; /* Number of bytes in an SQL string */ | ||
1244 | int i, j; /* Loop counters */ | ||
1245 | int nSep; /* Number of bytes in zSep[] */ | ||
1246 | int nNull; /* Number of bytes in zNull[] */ | ||
1247 | char *zSql; /* An SQL statement */ | ||
1248 | char *zLine; /* A single line of input from the file */ | ||
1249 | char **azCol; /* zLine[] broken up into columns */ | ||
1250 | char *zCommit; /* How to commit changes */ | ||
1251 | FILE *in; /* The input file */ | ||
1252 | int lineno = 0; /* Line number of input file */ | ||
1253 | char zLineNum[80]; /* Line number print buffer */ | ||
1254 | Tcl_Obj *pResult; /* interp result */ | ||
1255 | |||
1256 | char *zSep; | ||
1257 | char *zNull; | ||
1258 | if( objc<5 || objc>7 ){ | ||
1259 | Tcl_WrongNumArgs(interp, 2, objv, | ||
1260 | "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); | ||
1261 | return TCL_ERROR; | ||
1262 | } | ||
1263 | if( objc>=6 ){ | ||
1264 | zSep = Tcl_GetStringFromObj(objv[5], 0); | ||
1265 | }else{ | ||
1266 | zSep = "\t"; | ||
1267 | } | ||
1268 | if( objc>=7 ){ | ||
1269 | zNull = Tcl_GetStringFromObj(objv[6], 0); | ||
1270 | }else{ | ||
1271 | zNull = ""; | ||
1272 | } | ||
1273 | zConflict = Tcl_GetStringFromObj(objv[2], 0); | ||
1274 | zTable = Tcl_GetStringFromObj(objv[3], 0); | ||
1275 | zFile = Tcl_GetStringFromObj(objv[4], 0); | ||
1276 | nSep = strlen(zSep); | ||
1277 | nNull = strlen(zNull); | ||
1278 | if( nSep==0 ){ | ||
1279 | Tcl_AppendResult(interp,"Error: non-null separator required for copy",0); | ||
1280 | return TCL_ERROR; | ||
1281 | } | ||
1282 | if(sqlite3StrICmp(zConflict, "rollback") != 0 && | ||
1283 | sqlite3StrICmp(zConflict, "abort" ) != 0 && | ||
1284 | sqlite3StrICmp(zConflict, "fail" ) != 0 && | ||
1285 | sqlite3StrICmp(zConflict, "ignore" ) != 0 && | ||
1286 | sqlite3StrICmp(zConflict, "replace" ) != 0 ) { | ||
1287 | Tcl_AppendResult(interp, "Error: \"", zConflict, | ||
1288 | "\", conflict-algorithm must be one of: rollback, " | ||
1289 | "abort, fail, ignore, or replace", 0); | ||
1290 | return TCL_ERROR; | ||
1291 | } | ||
1292 | zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); | ||
1293 | if( zSql==0 ){ | ||
1294 | Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0); | ||
1295 | return TCL_ERROR; | ||
1296 | } | ||
1297 | nByte = strlen(zSql); | ||
1298 | rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); | ||
1299 | sqlite3_free(zSql); | ||
1300 | if( rc ){ | ||
1301 | Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); | ||
1302 | nCol = 0; | ||
1303 | }else{ | ||
1304 | nCol = sqlite3_column_count(pStmt); | ||
1305 | } | ||
1306 | sqlite3_finalize(pStmt); | ||
1307 | if( nCol==0 ) { | ||
1308 | return TCL_ERROR; | ||
1309 | } | ||
1310 | zSql = malloc( nByte + 50 + nCol*2 ); | ||
1311 | if( zSql==0 ) { | ||
1312 | Tcl_AppendResult(interp, "Error: can't malloc()", 0); | ||
1313 | return TCL_ERROR; | ||
1314 | } | ||
1315 | sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", | ||
1316 | zConflict, zTable); | ||
1317 | j = strlen(zSql); | ||
1318 | for(i=1; i<nCol; i++){ | ||
1319 | zSql[j++] = ','; | ||
1320 | zSql[j++] = '?'; | ||
1321 | } | ||
1322 | zSql[j++] = ')'; | ||
1323 | zSql[j] = 0; | ||
1324 | rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); | ||
1325 | free(zSql); | ||
1326 | if( rc ){ | ||
1327 | Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); | ||
1328 | sqlite3_finalize(pStmt); | ||
1329 | return TCL_ERROR; | ||
1330 | } | ||
1331 | in = fopen(zFile, "rb"); | ||
1332 | if( in==0 ){ | ||
1333 | Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL); | ||
1334 | sqlite3_finalize(pStmt); | ||
1335 | return TCL_ERROR; | ||
1336 | } | ||
1337 | azCol = malloc( sizeof(azCol[0])*(nCol+1) ); | ||
1338 | if( azCol==0 ) { | ||
1339 | Tcl_AppendResult(interp, "Error: can't malloc()", 0); | ||
1340 | fclose(in); | ||
1341 | return TCL_ERROR; | ||
1342 | } | ||
1343 | (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); | ||
1344 | zCommit = "COMMIT"; | ||
1345 | while( (zLine = local_getline(0, in))!=0 ){ | ||
1346 | char *z; | ||
1347 | i = 0; | ||
1348 | lineno++; | ||
1349 | azCol[0] = zLine; | ||
1350 | for(i=0, z=zLine; *z; z++){ | ||
1351 | if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ | ||
1352 | *z = 0; | ||
1353 | i++; | ||
1354 | if( i<nCol ){ | ||
1355 | azCol[i] = &z[nSep]; | ||
1356 | z += nSep-1; | ||
1357 | } | ||
1358 | } | ||
1359 | } | ||
1360 | if( i+1!=nCol ){ | ||
1361 | char *zErr; | ||
1362 | int nErr = strlen(zFile) + 200; | ||
1363 | zErr = malloc(nErr); | ||
1364 | if( zErr ){ | ||
1365 | sqlite3_snprintf(nErr, zErr, | ||
1366 | "Error: %s line %d: expected %d columns of data but found %d", | ||
1367 | zFile, lineno, nCol, i+1); | ||
1368 | Tcl_AppendResult(interp, zErr, 0); | ||
1369 | free(zErr); | ||
1370 | } | ||
1371 | zCommit = "ROLLBACK"; | ||
1372 | break; | ||
1373 | } | ||
1374 | for(i=0; i<nCol; i++){ | ||
1375 | /* check for null data, if so, bind as null */ | ||
1376 | if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) { | ||
1377 | sqlite3_bind_null(pStmt, i+1); | ||
1378 | }else{ | ||
1379 | sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); | ||
1380 | } | ||
1381 | } | ||
1382 | sqlite3_step(pStmt); | ||
1383 | rc = sqlite3_reset(pStmt); | ||
1384 | free(zLine); | ||
1385 | if( rc!=SQLITE_OK ){ | ||
1386 | Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0); | ||
1387 | zCommit = "ROLLBACK"; | ||
1388 | break; | ||
1389 | } | ||
1390 | } | ||
1391 | free(azCol); | ||
1392 | fclose(in); | ||
1393 | sqlite3_finalize(pStmt); | ||
1394 | (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0); | ||
1395 | |||
1396 | if( zCommit[0] == 'C' ){ | ||
1397 | /* success, set result as number of lines processed */ | ||
1398 | pResult = Tcl_GetObjResult(interp); | ||
1399 | Tcl_SetIntObj(pResult, lineno); | ||
1400 | rc = TCL_OK; | ||
1401 | }else{ | ||
1402 | /* failure, append lineno where failed */ | ||
1403 | sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); | ||
1404 | Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0); | ||
1405 | rc = TCL_ERROR; | ||
1406 | } | ||
1407 | break; | ||
1408 | } | ||
1409 | |||
1410 | /* | ||
1411 | ** $db enable_load_extension BOOLEAN | ||
1412 | ** | ||
1413 | ** Turn the extension loading feature on or off. It if off by | ||
1414 | ** default. | ||
1415 | */ | ||
1416 | case DB_ENABLE_LOAD_EXTENSION: { | ||
1417 | #ifndef SQLITE_OMIT_LOAD_EXTENSION | ||
1418 | int onoff; | ||
1419 | if( objc!=3 ){ | ||
1420 | Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN"); | ||
1421 | return TCL_ERROR; | ||
1422 | } | ||
1423 | if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){ | ||
1424 | return TCL_ERROR; | ||
1425 | } | ||
1426 | sqlite3_enable_load_extension(pDb->db, onoff); | ||
1427 | break; | ||
1428 | #else | ||
1429 | Tcl_AppendResult(interp, "extension loading is turned off at compile-time", | ||
1430 | 0); | ||
1431 | return TCL_ERROR; | ||
1432 | #endif | ||
1433 | } | ||
1434 | |||
1435 | /* | ||
1436 | ** $db errorcode | ||
1437 | ** | ||
1438 | ** Return the numeric error code that was returned by the most recent | ||
1439 | ** call to sqlite3_exec(). | ||
1440 | */ | ||
1441 | case DB_ERRORCODE: { | ||
1442 | Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); | ||
1443 | break; | ||
1444 | } | ||
1445 | |||
1446 | /* | ||
1447 | ** $db eval $sql ?array? ?{ ...code... }? | ||
1448 | ** $db onecolumn $sql | ||
1449 | ** | ||
1450 | ** The SQL statement in $sql is evaluated. For each row, the values are | ||
1451 | ** placed in elements of the array named "array" and ...code... is executed. | ||
1452 | ** If "array" and "code" are omitted, then no callback is every invoked. | ||
1453 | ** If "array" is an empty string, then the values are placed in variables | ||
1454 | ** that have the same name as the fields extracted by the query. | ||
1455 | ** | ||
1456 | ** The onecolumn method is the equivalent of: | ||
1457 | ** lindex [$db eval $sql] 0 | ||
1458 | */ | ||
1459 | case DB_ONECOLUMN: | ||
1460 | case DB_EVAL: | ||
1461 | case DB_EXISTS: { | ||
1462 | char const *zSql; /* Next SQL statement to execute */ | ||
1463 | char const *zLeft; /* What is left after first stmt in zSql */ | ||
1464 | sqlite3_stmt *pStmt; /* Compiled SQL statment */ | ||
1465 | Tcl_Obj *pArray; /* Name of array into which results are written */ | ||
1466 | Tcl_Obj *pScript; /* Script to run for each result set */ | ||
1467 | Tcl_Obj **apParm; /* Parameters that need a Tcl_DecrRefCount() */ | ||
1468 | int nParm; /* Number of entries used in apParm[] */ | ||
1469 | Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */ | ||
1470 | Tcl_Obj *pRet; /* Value to be returned */ | ||
1471 | SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */ | ||
1472 | int rc2; | ||
1473 | |||
1474 | if( choice==DB_EVAL ){ | ||
1475 | if( objc<3 || objc>5 ){ | ||
1476 | Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); | ||
1477 | return TCL_ERROR; | ||
1478 | } | ||
1479 | pRet = Tcl_NewObj(); | ||
1480 | Tcl_IncrRefCount(pRet); | ||
1481 | }else{ | ||
1482 | if( objc!=3 ){ | ||
1483 | Tcl_WrongNumArgs(interp, 2, objv, "SQL"); | ||
1484 | return TCL_ERROR; | ||
1485 | } | ||
1486 | if( choice==DB_EXISTS ){ | ||
1487 | pRet = Tcl_NewBooleanObj(0); | ||
1488 | Tcl_IncrRefCount(pRet); | ||
1489 | }else{ | ||
1490 | pRet = 0; | ||
1491 | } | ||
1492 | } | ||
1493 | if( objc==3 ){ | ||
1494 | pArray = pScript = 0; | ||
1495 | }else if( objc==4 ){ | ||
1496 | pArray = 0; | ||
1497 | pScript = objv[3]; | ||
1498 | }else{ | ||
1499 | pArray = objv[3]; | ||
1500 | if( Tcl_GetString(pArray)[0]==0 ) pArray = 0; | ||
1501 | pScript = objv[4]; | ||
1502 | } | ||
1503 | |||
1504 | Tcl_IncrRefCount(objv[2]); | ||
1505 | zSql = Tcl_GetStringFromObj(objv[2], 0); | ||
1506 | while( rc==TCL_OK && zSql[0] ){ | ||
1507 | int i; /* Loop counter */ | ||
1508 | int nVar; /* Number of bind parameters in the pStmt */ | ||
1509 | int nCol; /* Number of columns in the result set */ | ||
1510 | Tcl_Obj **apColName = 0; /* Array of column names */ | ||
1511 | int len; /* String length of zSql */ | ||
1512 | |||
1513 | /* Try to find a SQL statement that has already been compiled and | ||
1514 | ** which matches the next sequence of SQL. | ||
1515 | */ | ||
1516 | pStmt = 0; | ||
1517 | pPreStmt = pDb->stmtList; | ||
1518 | len = strlen(zSql); | ||
1519 | if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){ | ||
1520 | flushStmtCache(pDb); | ||
1521 | pPreStmt = 0; | ||
1522 | } | ||
1523 | for(; pPreStmt; pPreStmt=pPreStmt->pNext){ | ||
1524 | int n = pPreStmt->nSql; | ||
1525 | if( len>=n | ||
1526 | && memcmp(pPreStmt->zSql, zSql, n)==0 | ||
1527 | && (zSql[n]==0 || zSql[n-1]==';') | ||
1528 | ){ | ||
1529 | pStmt = pPreStmt->pStmt; | ||
1530 | zLeft = &zSql[pPreStmt->nSql]; | ||
1531 | |||
1532 | /* When a prepared statement is found, unlink it from the | ||
1533 | ** cache list. It will later be added back to the beginning | ||
1534 | ** of the cache list in order to implement LRU replacement. | ||
1535 | */ | ||
1536 | if( pPreStmt->pPrev ){ | ||
1537 | pPreStmt->pPrev->pNext = pPreStmt->pNext; | ||
1538 | }else{ | ||
1539 | pDb->stmtList = pPreStmt->pNext; | ||
1540 | } | ||
1541 | if( pPreStmt->pNext ){ | ||
1542 | pPreStmt->pNext->pPrev = pPreStmt->pPrev; | ||
1543 | }else{ | ||
1544 | pDb->stmtLast = pPreStmt->pPrev; | ||
1545 | } | ||
1546 | pDb->nStmt--; | ||
1547 | break; | ||
1548 | } | ||
1549 | } | ||
1550 | |||
1551 | /* If no prepared statement was found. Compile the SQL text | ||
1552 | */ | ||
1553 | if( pStmt==0 ){ | ||
1554 | if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){ | ||
1555 | Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); | ||
1556 | rc = TCL_ERROR; | ||
1557 | break; | ||
1558 | } | ||
1559 | if( pStmt==0 ){ | ||
1560 | if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ | ||
1561 | /* A compile-time error in the statement | ||
1562 | */ | ||
1563 | Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); | ||
1564 | rc = TCL_ERROR; | ||
1565 | break; | ||
1566 | }else{ | ||
1567 | /* The statement was a no-op. Continue to the next statement | ||
1568 | ** in the SQL string. | ||
1569 | */ | ||
1570 | zSql = zLeft; | ||
1571 | continue; | ||
1572 | } | ||
1573 | } | ||
1574 | assert( pPreStmt==0 ); | ||
1575 | } | ||
1576 | |||
1577 | /* Bind values to parameters that begin with $ or : | ||
1578 | */ | ||
1579 | nVar = sqlite3_bind_parameter_count(pStmt); | ||
1580 | nParm = 0; | ||
1581 | if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){ | ||
1582 | apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0])); | ||
1583 | }else{ | ||
1584 | apParm = aParm; | ||
1585 | } | ||
1586 | for(i=1; i<=nVar; i++){ | ||
1587 | const char *zVar = sqlite3_bind_parameter_name(pStmt, i); | ||
1588 | if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ | ||
1589 | Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); | ||
1590 | if( pVar ){ | ||
1591 | int n; | ||
1592 | u8 *data; | ||
1593 | char *zType = pVar->typePtr ? pVar->typePtr->name : ""; | ||
1594 | char c = zType[0]; | ||
1595 | if( zVar[0]=='@' || | ||
1596 | (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ | ||
1597 | /* Load a BLOB type if the Tcl variable is a bytearray and | ||
1598 | ** it has no string representation or the host | ||
1599 | ** parameter name begins with "@". */ | ||
1600 | data = Tcl_GetByteArrayFromObj(pVar, &n); | ||
1601 | sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); | ||
1602 | Tcl_IncrRefCount(pVar); | ||
1603 | apParm[nParm++] = pVar; | ||
1604 | }else if( c=='b' && strcmp(zType,"boolean")==0 ){ | ||
1605 | Tcl_GetIntFromObj(interp, pVar, &n); | ||
1606 | sqlite3_bind_int(pStmt, i, n); | ||
1607 | }else if( c=='d' && strcmp(zType,"double")==0 ){ | ||
1608 | double r; | ||
1609 | Tcl_GetDoubleFromObj(interp, pVar, &r); | ||
1610 | sqlite3_bind_double(pStmt, i, r); | ||
1611 | }else if( (c=='w' && strcmp(zType,"wideInt")==0) || | ||
1612 | (c=='i' && strcmp(zType,"int")==0) ){ | ||
1613 | Tcl_WideInt v; | ||
1614 | Tcl_GetWideIntFromObj(interp, pVar, &v); | ||
1615 | sqlite3_bind_int64(pStmt, i, v); | ||
1616 | }else{ | ||
1617 | data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); | ||
1618 | sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); | ||
1619 | Tcl_IncrRefCount(pVar); | ||
1620 | apParm[nParm++] = pVar; | ||
1621 | } | ||
1622 | }else{ | ||
1623 | sqlite3_bind_null( pStmt, i ); | ||
1624 | } | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | /* Compute column names */ | ||
1629 | nCol = sqlite3_column_count(pStmt); | ||
1630 | if( pScript ){ | ||
1631 | apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); | ||
1632 | if( apColName==0 ) break; | ||
1633 | for(i=0; i<nCol; i++){ | ||
1634 | apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i)); | ||
1635 | Tcl_IncrRefCount(apColName[i]); | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | /* If results are being stored in an array variable, then create | ||
1640 | ** the array(*) entry for that array | ||
1641 | */ | ||
1642 | if( pArray ){ | ||
1643 | Tcl_Obj *pColList = Tcl_NewObj(); | ||
1644 | Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); | ||
1645 | Tcl_IncrRefCount(pColList); | ||
1646 | for(i=0; i<nCol; i++){ | ||
1647 | Tcl_ListObjAppendElement(interp, pColList, apColName[i]); | ||
1648 | } | ||
1649 | Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0); | ||
1650 | Tcl_DecrRefCount(pColList); | ||
1651 | } | ||
1652 | |||
1653 | /* Execute the SQL | ||
1654 | */ | ||
1655 | while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){ | ||
1656 | for(i=0; i<nCol; i++){ | ||
1657 | Tcl_Obj *pVal; | ||
1658 | |||
1659 | /* Set pVal to contain the i'th column of this row. */ | ||
1660 | switch( sqlite3_column_type(pStmt, i) ){ | ||
1661 | case SQLITE_BLOB: { | ||
1662 | int bytes = sqlite3_column_bytes(pStmt, i); | ||
1663 | pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes); | ||
1664 | break; | ||
1665 | } | ||
1666 | case SQLITE_INTEGER: { | ||
1667 | sqlite_int64 v = sqlite3_column_int64(pStmt, i); | ||
1668 | if( v>=-2147483647 && v<=2147483647 ){ | ||
1669 | pVal = Tcl_NewIntObj(v); | ||
1670 | }else{ | ||
1671 | pVal = Tcl_NewWideIntObj(v); | ||
1672 | } | ||
1673 | break; | ||
1674 | } | ||
1675 | case SQLITE_FLOAT: { | ||
1676 | double r = sqlite3_column_double(pStmt, i); | ||
1677 | pVal = Tcl_NewDoubleObj(r); | ||
1678 | break; | ||
1679 | } | ||
1680 | case SQLITE_NULL: { | ||
1681 | pVal = dbTextToObj(pDb->zNull); | ||
1682 | break; | ||
1683 | } | ||
1684 | default: { | ||
1685 | pVal = dbTextToObj((char *)sqlite3_column_text(pStmt, i)); | ||
1686 | break; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | if( pScript ){ | ||
1691 | if( pArray==0 ){ | ||
1692 | Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); | ||
1693 | }else{ | ||
1694 | Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); | ||
1695 | } | ||
1696 | }else if( choice==DB_ONECOLUMN ){ | ||
1697 | assert( pRet==0 ); | ||
1698 | if( pRet==0 ){ | ||
1699 | pRet = pVal; | ||
1700 | Tcl_IncrRefCount(pRet); | ||
1701 | } | ||
1702 | rc = TCL_BREAK; | ||
1703 | i = nCol; | ||
1704 | }else if( choice==DB_EXISTS ){ | ||
1705 | Tcl_DecrRefCount(pRet); | ||
1706 | pRet = Tcl_NewBooleanObj(1); | ||
1707 | Tcl_IncrRefCount(pRet); | ||
1708 | rc = TCL_BREAK; | ||
1709 | i = nCol; | ||
1710 | }else{ | ||
1711 | Tcl_ListObjAppendElement(interp, pRet, pVal); | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | if( pScript ){ | ||
1716 | rc = Tcl_EvalObjEx(interp, pScript, 0); | ||
1717 | if( rc==TCL_CONTINUE ){ | ||
1718 | rc = TCL_OK; | ||
1719 | } | ||
1720 | } | ||
1721 | } | ||
1722 | if( rc==TCL_BREAK ){ | ||
1723 | rc = TCL_OK; | ||
1724 | } | ||
1725 | |||
1726 | /* Free the column name objects */ | ||
1727 | if( pScript ){ | ||
1728 | for(i=0; i<nCol; i++){ | ||
1729 | Tcl_DecrRefCount(apColName[i]); | ||
1730 | } | ||
1731 | Tcl_Free((char*)apColName); | ||
1732 | } | ||
1733 | |||
1734 | /* Free the bound string and blob parameters */ | ||
1735 | for(i=0; i<nParm; i++){ | ||
1736 | Tcl_DecrRefCount(apParm[i]); | ||
1737 | } | ||
1738 | if( apParm!=aParm ){ | ||
1739 | Tcl_Free((char*)apParm); | ||
1740 | } | ||
1741 | |||
1742 | /* Reset the statement. If the result code is SQLITE_SCHEMA, then | ||
1743 | ** flush the statement cache and try the statement again. | ||
1744 | */ | ||
1745 | rc2 = sqlite3_reset(pStmt); | ||
1746 | if( SQLITE_SCHEMA==rc2 ){ | ||
1747 | /* After a schema change, flush the cache and try to run the | ||
1748 | ** statement again | ||
1749 | */ | ||
1750 | flushStmtCache( pDb ); | ||
1751 | sqlite3_finalize(pStmt); | ||
1752 | if( pPreStmt ) Tcl_Free((char*)pPreStmt); | ||
1753 | continue; | ||
1754 | }else if( SQLITE_OK!=rc2 ){ | ||
1755 | /* If a run-time error occurs, report the error and stop reading | ||
1756 | ** the SQL | ||
1757 | */ | ||
1758 | Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); | ||
1759 | sqlite3_finalize(pStmt); | ||
1760 | rc = TCL_ERROR; | ||
1761 | if( pPreStmt ) Tcl_Free((char*)pPreStmt); | ||
1762 | break; | ||
1763 | }else if( pDb->maxStmt<=0 ){ | ||
1764 | /* If the cache is turned off, deallocated the statement */ | ||
1765 | if( pPreStmt ) Tcl_Free((char*)pPreStmt); | ||
1766 | sqlite3_finalize(pStmt); | ||
1767 | }else{ | ||
1768 | /* Everything worked and the cache is operational. | ||
1769 | ** Create a new SqlPreparedStmt structure if we need one. | ||
1770 | ** (If we already have one we can just reuse it.) | ||
1771 | */ | ||
1772 | if( pPreStmt==0 ){ | ||
1773 | len = zLeft - zSql; | ||
1774 | pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len ); | ||
1775 | if( pPreStmt==0 ) return TCL_ERROR; | ||
1776 | pPreStmt->pStmt = pStmt; | ||
1777 | pPreStmt->nSql = len; | ||
1778 | memcpy(pPreStmt->zSql, zSql, len); | ||
1779 | pPreStmt->zSql[len] = 0; | ||
1780 | } | ||
1781 | |||
1782 | /* Add the prepared statement to the beginning of the cache list | ||
1783 | */ | ||
1784 | pPreStmt->pNext = pDb->stmtList; | ||
1785 | pPreStmt->pPrev = 0; | ||
1786 | if( pDb->stmtList ){ | ||
1787 | pDb->stmtList->pPrev = pPreStmt; | ||
1788 | } | ||
1789 | pDb->stmtList = pPreStmt; | ||
1790 | if( pDb->stmtLast==0 ){ | ||
1791 | assert( pDb->nStmt==0 ); | ||
1792 | pDb->stmtLast = pPreStmt; | ||
1793 | }else{ | ||
1794 | assert( pDb->nStmt>0 ); | ||
1795 | } | ||
1796 | pDb->nStmt++; | ||
1797 | |||
1798 | /* If we have too many statement in cache, remove the surplus from the | ||
1799 | ** end of the cache list. | ||
1800 | */ | ||
1801 | while( pDb->nStmt>pDb->maxStmt ){ | ||
1802 | sqlite3_finalize(pDb->stmtLast->pStmt); | ||
1803 | pDb->stmtLast = pDb->stmtLast->pPrev; | ||
1804 | Tcl_Free((char*)pDb->stmtLast->pNext); | ||
1805 | pDb->stmtLast->pNext = 0; | ||
1806 | pDb->nStmt--; | ||
1807 | } | ||
1808 | } | ||
1809 | |||
1810 | /* Proceed to the next statement */ | ||
1811 | zSql = zLeft; | ||
1812 | } | ||
1813 | Tcl_DecrRefCount(objv[2]); | ||
1814 | |||
1815 | if( pRet ){ | ||
1816 | if( rc==TCL_OK ){ | ||
1817 | Tcl_SetObjResult(interp, pRet); | ||
1818 | } | ||
1819 | Tcl_DecrRefCount(pRet); | ||
1820 | }else if( rc==TCL_OK ){ | ||
1821 | Tcl_ResetResult(interp); | ||
1822 | } | ||
1823 | break; | ||
1824 | } | ||
1825 | |||
1826 | /* | ||
1827 | ** $db function NAME SCRIPT | ||
1828 | ** | ||
1829 | ** Create a new SQL function called NAME. Whenever that function is | ||
1830 | ** called, invoke SCRIPT to evaluate the function. | ||
1831 | */ | ||
1832 | case DB_FUNCTION: { | ||
1833 | SqlFunc *pFunc; | ||
1834 | Tcl_Obj *pScript; | ||
1835 | char *zName; | ||
1836 | if( objc!=4 ){ | ||
1837 | Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); | ||
1838 | return TCL_ERROR; | ||
1839 | } | ||
1840 | zName = Tcl_GetStringFromObj(objv[2], 0); | ||
1841 | pScript = objv[3]; | ||
1842 | pFunc = findSqlFunc(pDb, zName); | ||
1843 | if( pFunc==0 ) return TCL_ERROR; | ||
1844 | if( pFunc->pScript ){ | ||
1845 | Tcl_DecrRefCount(pFunc->pScript); | ||
1846 | } | ||
1847 | pFunc->pScript = pScript; | ||
1848 | Tcl_IncrRefCount(pScript); | ||
1849 | pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); | ||
1850 | rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, | ||
1851 | pFunc, tclSqlFunc, 0, 0); | ||
1852 | if( rc!=SQLITE_OK ){ | ||
1853 | rc = TCL_ERROR; | ||
1854 | Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); | ||
1855 | }else{ | ||
1856 | /* Must flush any cached statements */ | ||
1857 | flushStmtCache( pDb ); | ||
1858 | } | ||
1859 | break; | ||
1860 | } | ||
1861 | |||
1862 | /* | ||
1863 | ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID | ||
1864 | */ | ||
1865 | case DB_INCRBLOB: { | ||
1866 | #ifdef SQLITE_OMIT_INCRBLOB | ||
1867 | Tcl_AppendResult(interp, "incrblob not available in this build", 0); | ||
1868 | return TCL_ERROR; | ||
1869 | #else | ||
1870 | int isReadonly = 0; | ||
1871 | const char *zDb = "main"; | ||
1872 | const char *zTable; | ||
1873 | const char *zColumn; | ||
1874 | sqlite_int64 iRow; | ||
1875 | |||
1876 | /* Check for the -readonly option */ | ||
1877 | if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){ | ||
1878 | isReadonly = 1; | ||
1879 | } | ||
1880 | |||
1881 | if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ | ||
1882 | Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); | ||
1883 | return TCL_ERROR; | ||
1884 | } | ||
1885 | |||
1886 | if( objc==(6+isReadonly) ){ | ||
1887 | zDb = Tcl_GetString(objv[2]); | ||
1888 | } | ||
1889 | zTable = Tcl_GetString(objv[objc-3]); | ||
1890 | zColumn = Tcl_GetString(objv[objc-2]); | ||
1891 | rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow); | ||
1892 | |||
1893 | if( rc==TCL_OK ){ | ||
1894 | rc = createIncrblobChannel( | ||
1895 | interp, pDb, zDb, zTable, zColumn, iRow, isReadonly | ||
1896 | ); | ||
1897 | } | ||
1898 | #endif | ||
1899 | break; | ||
1900 | } | ||
1901 | |||
1902 | /* | ||
1903 | ** $db interrupt | ||
1904 | ** | ||
1905 | ** Interrupt the execution of the inner-most SQL interpreter. This | ||
1906 | ** causes the SQL statement to return an error of SQLITE_INTERRUPT. | ||
1907 | */ | ||
1908 | case DB_INTERRUPT: { | ||
1909 | sqlite3_interrupt(pDb->db); | ||
1910 | break; | ||
1911 | } | ||
1912 | |||
1913 | /* | ||
1914 | ** $db nullvalue ?STRING? | ||
1915 | ** | ||
1916 | ** Change text used when a NULL comes back from the database. If ?STRING? | ||
1917 | ** is not present, then the current string used for NULL is returned. | ||
1918 | ** If STRING is present, then STRING is returned. | ||
1919 | ** | ||
1920 | */ | ||
1921 | case DB_NULLVALUE: { | ||
1922 | if( objc!=2 && objc!=3 ){ | ||
1923 | Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); | ||
1924 | return TCL_ERROR; | ||
1925 | } | ||
1926 | if( objc==3 ){ | ||
1927 | int len; | ||
1928 | char *zNull = Tcl_GetStringFromObj(objv[2], &len); | ||
1929 | if( pDb->zNull ){ | ||
1930 | Tcl_Free(pDb->zNull); | ||
1931 | } | ||
1932 | if( zNull && len>0 ){ | ||
1933 | pDb->zNull = Tcl_Alloc( len + 1 ); | ||
1934 | strncpy(pDb->zNull, zNull, len); | ||
1935 | pDb->zNull[len] = '\0'; | ||
1936 | }else{ | ||
1937 | pDb->zNull = 0; | ||
1938 | } | ||
1939 | } | ||
1940 | Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull)); | ||
1941 | break; | ||
1942 | } | ||
1943 | |||
1944 | /* | ||
1945 | ** $db last_insert_rowid | ||
1946 | ** | ||
1947 | ** Return an integer which is the ROWID for the most recent insert. | ||
1948 | */ | ||
1949 | case DB_LAST_INSERT_ROWID: { | ||
1950 | Tcl_Obj *pResult; | ||
1951 | Tcl_WideInt rowid; | ||
1952 | if( objc!=2 ){ | ||
1953 | Tcl_WrongNumArgs(interp, 2, objv, ""); | ||
1954 | return TCL_ERROR; | ||
1955 | } | ||
1956 | rowid = sqlite3_last_insert_rowid(pDb->db); | ||
1957 | pResult = Tcl_GetObjResult(interp); | ||
1958 | Tcl_SetWideIntObj(pResult, rowid); | ||
1959 | break; | ||
1960 | } | ||
1961 | |||
1962 | /* | ||
1963 | ** The DB_ONECOLUMN method is implemented together with DB_EVAL. | ||
1964 | */ | ||
1965 | |||
1966 | /* $db progress ?N CALLBACK? | ||
1967 | ** | ||
1968 | ** Invoke the given callback every N virtual machine opcodes while executing | ||
1969 | ** queries. | ||
1970 | */ | ||
1971 | case DB_PROGRESS: { | ||
1972 | if( objc==2 ){ | ||
1973 | if( pDb->zProgress ){ | ||
1974 | Tcl_AppendResult(interp, pDb->zProgress, 0); | ||
1975 | } | ||
1976 | }else if( objc==4 ){ | ||
1977 | char *zProgress; | ||
1978 | int len; | ||
1979 | int N; | ||
1980 | if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ | ||
1981 | return TCL_ERROR; | ||
1982 | }; | ||
1983 | if( pDb->zProgress ){ | ||
1984 | Tcl_Free(pDb->zProgress); | ||
1985 | } | ||
1986 | zProgress = Tcl_GetStringFromObj(objv[3], &len); | ||
1987 | if( zProgress && len>0 ){ | ||
1988 | pDb->zProgress = Tcl_Alloc( len + 1 ); | ||
1989 | memcpy(pDb->zProgress, zProgress, len+1); | ||
1990 | }else{ | ||
1991 | pDb->zProgress = 0; | ||
1992 | } | ||
1993 | #ifndef SQLITE_OMIT_PROGRESS_CALLBACK | ||
1994 | if( pDb->zProgress ){ | ||
1995 | pDb->interp = interp; | ||
1996 | sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); | ||
1997 | }else{ | ||
1998 | sqlite3_progress_handler(pDb->db, 0, 0, 0); | ||
1999 | } | ||
2000 | #endif | ||
2001 | }else{ | ||
2002 | Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); | ||
2003 | return TCL_ERROR; | ||
2004 | } | ||
2005 | break; | ||
2006 | } | ||
2007 | |||
2008 | /* $db profile ?CALLBACK? | ||
2009 | ** | ||
2010 | ** Make arrangements to invoke the CALLBACK routine after each SQL statement | ||
2011 | ** that has run. The text of the SQL and the amount of elapse time are | ||
2012 | ** appended to CALLBACK before the script is run. | ||
2013 | */ | ||
2014 | case DB_PROFILE: { | ||
2015 | if( objc>3 ){ | ||
2016 | Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); | ||
2017 | return TCL_ERROR; | ||
2018 | }else if( objc==2 ){ | ||
2019 | if( pDb->zProfile ){ | ||
2020 | Tcl_AppendResult(interp, pDb->zProfile, 0); | ||
2021 | } | ||
2022 | }else{ | ||
2023 | char *zProfile; | ||
2024 | int len; | ||
2025 | if( pDb->zProfile ){ | ||
2026 | Tcl_Free(pDb->zProfile); | ||
2027 | } | ||
2028 | zProfile = Tcl_GetStringFromObj(objv[2], &len); | ||
2029 | if( zProfile && len>0 ){ | ||
2030 | pDb->zProfile = Tcl_Alloc( len + 1 ); | ||
2031 | memcpy(pDb->zProfile, zProfile, len+1); | ||
2032 | }else{ | ||
2033 | pDb->zProfile = 0; | ||
2034 | } | ||
2035 | #ifndef SQLITE_OMIT_TRACE | ||
2036 | if( pDb->zProfile ){ | ||
2037 | pDb->interp = interp; | ||
2038 | sqlite3_profile(pDb->db, DbProfileHandler, pDb); | ||
2039 | }else{ | ||
2040 | sqlite3_profile(pDb->db, 0, 0); | ||
2041 | } | ||
2042 | #endif | ||
2043 | } | ||
2044 | break; | ||
2045 | } | ||
2046 | |||
2047 | /* | ||
2048 | ** $db rekey KEY | ||
2049 | ** | ||
2050 | ** Change the encryption key on the currently open database. | ||
2051 | */ | ||
2052 | case DB_REKEY: { | ||
2053 | int nKey; | ||
2054 | void *pKey; | ||
2055 | if( objc!=3 ){ | ||
2056 | Tcl_WrongNumArgs(interp, 2, objv, "KEY"); | ||
2057 | return TCL_ERROR; | ||
2058 | } | ||
2059 | pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); | ||
2060 | #ifdef SQLITE_HAS_CODEC | ||
2061 | rc = sqlite3_rekey(pDb->db, pKey, nKey); | ||
2062 | if( rc ){ | ||
2063 | Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); | ||
2064 | rc = TCL_ERROR; | ||
2065 | } | ||
2066 | #endif | ||
2067 | break; | ||
2068 | } | ||
2069 | |||
2070 | /* | ||
2071 | ** $db timeout MILLESECONDS | ||
2072 | ** | ||
2073 | ** Delay for the number of milliseconds specified when a file is locked. | ||
2074 | */ | ||
2075 | case DB_TIMEOUT: { | ||
2076 | int ms; | ||
2077 | if( objc!=3 ){ | ||
2078 | Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); | ||
2079 | return TCL_ERROR; | ||
2080 | } | ||
2081 | if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; | ||
2082 | sqlite3_busy_timeout(pDb->db, ms); | ||
2083 | break; | ||
2084 | } | ||
2085 | |||
2086 | /* | ||
2087 | ** $db total_changes | ||
2088 | ** | ||
2089 | ** Return the number of rows that were modified, inserted, or deleted | ||
2090 | ** since the database handle was created. | ||
2091 | */ | ||
2092 | case DB_TOTAL_CHANGES: { | ||
2093 | Tcl_Obj *pResult; | ||
2094 | if( objc!=2 ){ | ||
2095 | Tcl_WrongNumArgs(interp, 2, objv, ""); | ||
2096 | return TCL_ERROR; | ||
2097 | } | ||
2098 | pResult = Tcl_GetObjResult(interp); | ||
2099 | Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); | ||
2100 | break; | ||
2101 | } | ||
2102 | |||
2103 | /* $db trace ?CALLBACK? | ||
2104 | ** | ||
2105 | ** Make arrangements to invoke the CALLBACK routine for each SQL statement | ||
2106 | ** that is executed. The text of the SQL is appended to CALLBACK before | ||
2107 | ** it is executed. | ||
2108 | */ | ||
2109 | case DB_TRACE: { | ||
2110 | if( objc>3 ){ | ||
2111 | Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); | ||
2112 | return TCL_ERROR; | ||
2113 | }else if( objc==2 ){ | ||
2114 | if( pDb->zTrace ){ | ||
2115 | Tcl_AppendResult(interp, pDb->zTrace, 0); | ||
2116 | } | ||
2117 | }else{ | ||
2118 | char *zTrace; | ||
2119 | int len; | ||
2120 | if( pDb->zTrace ){ | ||
2121 | Tcl_Free(pDb->zTrace); | ||
2122 | } | ||
2123 | zTrace = Tcl_GetStringFromObj(objv[2], &len); | ||
2124 | if( zTrace && len>0 ){ | ||
2125 | pDb->zTrace = Tcl_Alloc( len + 1 ); | ||
2126 | memcpy(pDb->zTrace, zTrace, len+1); | ||
2127 | }else{ | ||
2128 | pDb->zTrace = 0; | ||
2129 | } | ||
2130 | #ifndef SQLITE_OMIT_TRACE | ||
2131 | if( pDb->zTrace ){ | ||
2132 | pDb->interp = interp; | ||
2133 | sqlite3_trace(pDb->db, DbTraceHandler, pDb); | ||
2134 | }else{ | ||
2135 | sqlite3_trace(pDb->db, 0, 0); | ||
2136 | } | ||
2137 | #endif | ||
2138 | } | ||
2139 | break; | ||
2140 | } | ||
2141 | |||
2142 | /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT | ||
2143 | ** | ||
2144 | ** Start a new transaction (if we are not already in the midst of a | ||
2145 | ** transaction) and execute the TCL script SCRIPT. After SCRIPT | ||
2146 | ** completes, either commit the transaction or roll it back if SCRIPT | ||
2147 | ** throws an exception. Or if no new transation was started, do nothing. | ||
2148 | ** pass the exception on up the stack. | ||
2149 | ** | ||
2150 | ** This command was inspired by Dave Thomas's talk on Ruby at the | ||
2151 | ** 2005 O'Reilly Open Source Convention (OSCON). | ||
2152 | */ | ||
2153 | case DB_TRANSACTION: { | ||
2154 | int inTrans; | ||
2155 | Tcl_Obj *pScript; | ||
2156 | const char *zBegin = "BEGIN"; | ||
2157 | if( objc!=3 && objc!=4 ){ | ||
2158 | Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); | ||
2159 | return TCL_ERROR; | ||
2160 | } | ||
2161 | if( objc==3 ){ | ||
2162 | pScript = objv[2]; | ||
2163 | } else { | ||
2164 | static const char *TTYPE_strs[] = { | ||
2165 | "deferred", "exclusive", "immediate", 0 | ||
2166 | }; | ||
2167 | enum TTYPE_enum { | ||
2168 | TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE | ||
2169 | }; | ||
2170 | int ttype; | ||
2171 | if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", | ||
2172 | 0, &ttype) ){ | ||
2173 | return TCL_ERROR; | ||
2174 | } | ||
2175 | switch( (enum TTYPE_enum)ttype ){ | ||
2176 | case TTYPE_DEFERRED: /* no-op */; break; | ||
2177 | case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; | ||
2178 | case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; | ||
2179 | } | ||
2180 | pScript = objv[3]; | ||
2181 | } | ||
2182 | inTrans = !sqlite3_get_autocommit(pDb->db); | ||
2183 | if( !inTrans ){ | ||
2184 | (void)sqlite3_exec(pDb->db, zBegin, 0, 0, 0); | ||
2185 | } | ||
2186 | rc = Tcl_EvalObjEx(interp, pScript, 0); | ||
2187 | if( !inTrans ){ | ||
2188 | const char *zEnd; | ||
2189 | if( rc==TCL_ERROR ){ | ||
2190 | zEnd = "ROLLBACK"; | ||
2191 | } else { | ||
2192 | zEnd = "COMMIT"; | ||
2193 | } | ||
2194 | if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ | ||
2195 | sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); | ||
2196 | } | ||
2197 | } | ||
2198 | break; | ||
2199 | } | ||
2200 | |||
2201 | /* | ||
2202 | ** $db update_hook ?script? | ||
2203 | ** $db rollback_hook ?script? | ||
2204 | */ | ||
2205 | case DB_UPDATE_HOOK: | ||
2206 | case DB_ROLLBACK_HOOK: { | ||
2207 | |||
2208 | /* set ppHook to point at pUpdateHook or pRollbackHook, depending on | ||
2209 | ** whether [$db update_hook] or [$db rollback_hook] was invoked. | ||
2210 | */ | ||
2211 | Tcl_Obj **ppHook; | ||
2212 | if( choice==DB_UPDATE_HOOK ){ | ||
2213 | ppHook = &pDb->pUpdateHook; | ||
2214 | }else{ | ||
2215 | ppHook = &pDb->pRollbackHook; | ||
2216 | } | ||
2217 | |||
2218 | if( objc!=2 && objc!=3 ){ | ||
2219 | Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); | ||
2220 | return TCL_ERROR; | ||
2221 | } | ||
2222 | if( *ppHook ){ | ||
2223 | Tcl_SetObjResult(interp, *ppHook); | ||
2224 | if( objc==3 ){ | ||
2225 | Tcl_DecrRefCount(*ppHook); | ||
2226 | *ppHook = 0; | ||
2227 | } | ||
2228 | } | ||
2229 | if( objc==3 ){ | ||
2230 | assert( !(*ppHook) ); | ||
2231 | if( Tcl_GetCharLength(objv[2])>0 ){ | ||
2232 | *ppHook = objv[2]; | ||
2233 | Tcl_IncrRefCount(*ppHook); | ||
2234 | } | ||
2235 | } | ||
2236 | |||
2237 | sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); | ||
2238 | sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb); | ||
2239 | |||
2240 | break; | ||
2241 | } | ||
2242 | |||
2243 | /* $db version | ||
2244 | ** | ||
2245 | ** Return the version string for this database. | ||
2246 | */ | ||
2247 | case DB_VERSION: { | ||
2248 | Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); | ||
2249 | break; | ||
2250 | } | ||
2251 | |||
2252 | |||
2253 | } /* End of the SWITCH statement */ | ||
2254 | return rc; | ||
2255 | } | ||
2256 | |||
2257 | /* | ||
2258 | ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? | ||
2259 | ** ?-create BOOLEAN? | ||
2260 | ** | ||
2261 | ** This is the main Tcl command. When the "sqlite" Tcl command is | ||
2262 | ** invoked, this routine runs to process that command. | ||
2263 | ** | ||
2264 | ** The first argument, DBNAME, is an arbitrary name for a new | ||
2265 | ** database connection. This command creates a new command named | ||
2266 | ** DBNAME that is used to control that connection. The database | ||
2267 | ** connection is deleted when the DBNAME command is deleted. | ||
2268 | ** | ||
2269 | ** The second argument is the name of the database file. | ||
2270 | ** | ||
2271 | */ | ||
2272 | static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ | ||
2273 | SqliteDb *p; | ||
2274 | void *pKey = 0; | ||
2275 | int nKey = 0; | ||
2276 | const char *zArg; | ||
2277 | char *zErrMsg; | ||
2278 | int i; | ||
2279 | const char *zFile; | ||
2280 | const char *zVfs = 0; | ||
2281 | int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; | ||
2282 | Tcl_DString translatedFilename; | ||
2283 | if( objc==2 ){ | ||
2284 | zArg = Tcl_GetStringFromObj(objv[1], 0); | ||
2285 | if( strcmp(zArg,"-version")==0 ){ | ||
2286 | Tcl_AppendResult(interp,sqlite3_version,0); | ||
2287 | return TCL_OK; | ||
2288 | } | ||
2289 | if( strcmp(zArg,"-has-codec")==0 ){ | ||
2290 | #ifdef SQLITE_HAS_CODEC | ||
2291 | Tcl_AppendResult(interp,"1",0); | ||
2292 | #else | ||
2293 | Tcl_AppendResult(interp,"0",0); | ||
2294 | #endif | ||
2295 | return TCL_OK; | ||
2296 | } | ||
2297 | } | ||
2298 | for(i=3; i+1<objc; i+=2){ | ||
2299 | zArg = Tcl_GetString(objv[i]); | ||
2300 | if( strcmp(zArg,"-key")==0 ){ | ||
2301 | pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey); | ||
2302 | }else if( strcmp(zArg, "-vfs")==0 ){ | ||
2303 | i++; | ||
2304 | zVfs = Tcl_GetString(objv[i]); | ||
2305 | }else if( strcmp(zArg, "-readonly")==0 ){ | ||
2306 | int b; | ||
2307 | if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; | ||
2308 | if( b ){ | ||
2309 | flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); | ||
2310 | flags |= SQLITE_OPEN_READONLY; | ||
2311 | }else{ | ||
2312 | flags &= ~SQLITE_OPEN_READONLY; | ||
2313 | flags |= SQLITE_OPEN_READWRITE; | ||
2314 | } | ||
2315 | }else if( strcmp(zArg, "-create")==0 ){ | ||
2316 | int b; | ||
2317 | if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; | ||
2318 | if( b && (flags & SQLITE_OPEN_READONLY)==0 ){ | ||
2319 | flags |= SQLITE_OPEN_CREATE; | ||
2320 | }else{ | ||
2321 | flags &= ~SQLITE_OPEN_CREATE; | ||
2322 | } | ||
2323 | }else{ | ||
2324 | Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); | ||
2325 | return TCL_ERROR; | ||
2326 | } | ||
2327 | } | ||
2328 | if( objc<3 || (objc&1)!=1 ){ | ||
2329 | Tcl_WrongNumArgs(interp, 1, objv, | ||
2330 | "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" | ||
2331 | #ifdef SQLITE_HAS_CODEC | ||
2332 | " ?-key CODECKEY?" | ||
2333 | #endif | ||
2334 | ); | ||
2335 | return TCL_ERROR; | ||
2336 | } | ||
2337 | zErrMsg = 0; | ||
2338 | p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); | ||
2339 | if( p==0 ){ | ||
2340 | Tcl_SetResult(interp, "malloc failed", TCL_STATIC); | ||
2341 | return TCL_ERROR; | ||
2342 | } | ||
2343 | memset(p, 0, sizeof(*p)); | ||
2344 | zFile = Tcl_GetStringFromObj(objv[2], 0); | ||
2345 | zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); | ||
2346 | sqlite3_open_v2(zFile, &p->db, flags, zVfs); | ||
2347 | Tcl_DStringFree(&translatedFilename); | ||
2348 | if( SQLITE_OK!=sqlite3_errcode(p->db) ){ | ||
2349 | zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); | ||
2350 | sqlite3_close(p->db); | ||
2351 | p->db = 0; | ||
2352 | } | ||
2353 | #ifdef SQLITE_TEST | ||
2354 | if( p->db ){ | ||
2355 | extern int Md5_Register(sqlite3*); | ||
2356 | if( Md5_Register(p->db)==SQLITE_NOMEM ){ | ||
2357 | zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); | ||
2358 | sqlite3_close(p->db); | ||
2359 | p->db = 0; | ||
2360 | } | ||
2361 | } | ||
2362 | #endif | ||
2363 | #ifdef SQLITE_HAS_CODEC | ||
2364 | if( p->db ){ | ||
2365 | sqlite3_key(p->db, pKey, nKey); | ||
2366 | } | ||
2367 | #endif | ||
2368 | if( p->db==0 ){ | ||
2369 | Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); | ||
2370 | Tcl_Free((char*)p); | ||
2371 | sqlite3_free(zErrMsg); | ||
2372 | return TCL_ERROR; | ||
2373 | } | ||
2374 | p->maxStmt = NUM_PREPARED_STMTS; | ||
2375 | p->interp = interp; | ||
2376 | zArg = Tcl_GetStringFromObj(objv[1], 0); | ||
2377 | Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); | ||
2378 | return TCL_OK; | ||
2379 | } | ||
2380 | |||
2381 | /* | ||
2382 | ** Provide a dummy Tcl_InitStubs if we are using this as a static | ||
2383 | ** library. | ||
2384 | */ | ||
2385 | #ifndef USE_TCL_STUBS | ||
2386 | # undef Tcl_InitStubs | ||
2387 | # define Tcl_InitStubs(a,b,c) | ||
2388 | #endif | ||
2389 | |||
2390 | /* | ||
2391 | ** Make sure we have a PACKAGE_VERSION macro defined. This will be | ||
2392 | ** defined automatically by the TEA makefile. But other makefiles | ||
2393 | ** do not define it. | ||
2394 | */ | ||
2395 | #ifndef PACKAGE_VERSION | ||
2396 | # define PACKAGE_VERSION SQLITE_VERSION | ||
2397 | #endif | ||
2398 | |||
2399 | /* | ||
2400 | ** Initialize this module. | ||
2401 | ** | ||
2402 | ** This Tcl module contains only a single new Tcl command named "sqlite". | ||
2403 | ** (Hence there is no namespace. There is no point in using a namespace | ||
2404 | ** if the extension only supplies one new name!) The "sqlite" command is | ||
2405 | ** used to open a new SQLite database. See the DbMain() routine above | ||
2406 | ** for additional information. | ||
2407 | */ | ||
2408 | EXTERN int Sqlite3_Init(Tcl_Interp *interp){ | ||
2409 | Tcl_InitStubs(interp, "8.4", 0); | ||
2410 | Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); | ||
2411 | Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); | ||
2412 | Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); | ||
2413 | Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION); | ||
2414 | return TCL_OK; | ||
2415 | } | ||
2416 | EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } | ||
2417 | EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } | ||
2418 | EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } | ||
2419 | |||
2420 | #ifndef SQLITE_3_SUFFIX_ONLY | ||
2421 | EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } | ||
2422 | EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } | ||
2423 | EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } | ||
2424 | EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } | ||
2425 | #endif | ||
2426 | |||
2427 | #ifdef TCLSH | ||
2428 | /***************************************************************************** | ||
2429 | ** The code that follows is used to build standalone TCL interpreters | ||
2430 | ** that are statically linked with SQLite. | ||
2431 | */ | ||
2432 | |||
2433 | /* | ||
2434 | ** If the macro TCLSH is one, then put in code this for the | ||
2435 | ** "main" routine that will initialize Tcl and take input from | ||
2436 | ** standard input, or if a file is named on the command line | ||
2437 | ** the TCL interpreter reads and evaluates that file. | ||
2438 | */ | ||
2439 | #if TCLSH==1 | ||
2440 | static char zMainloop[] = | ||
2441 | "set line {}\n" | ||
2442 | "while {![eof stdin]} {\n" | ||
2443 | "if {$line!=\"\"} {\n" | ||
2444 | "puts -nonewline \"> \"\n" | ||
2445 | "} else {\n" | ||
2446 | "puts -nonewline \"% \"\n" | ||
2447 | "}\n" | ||
2448 | "flush stdout\n" | ||
2449 | "append line [gets stdin]\n" | ||
2450 | "if {[info complete $line]} {\n" | ||
2451 | "if {[catch {uplevel #0 $line} result]} {\n" | ||
2452 | "puts stderr \"Error: $result\"\n" | ||
2453 | "} elseif {$result!=\"\"} {\n" | ||
2454 | "puts $result\n" | ||
2455 | "}\n" | ||
2456 | "set line {}\n" | ||
2457 | "} else {\n" | ||
2458 | "append line \\n\n" | ||
2459 | "}\n" | ||
2460 | "}\n" | ||
2461 | ; | ||
2462 | #endif | ||
2463 | |||
2464 | /* | ||
2465 | ** If the macro TCLSH is two, then get the main loop code out of | ||
2466 | ** the separate file "spaceanal_tcl.h". | ||
2467 | */ | ||
2468 | #if TCLSH==2 | ||
2469 | static char zMainloop[] = | ||
2470 | #include "spaceanal_tcl.h" | ||
2471 | ; | ||
2472 | #endif | ||
2473 | |||
2474 | #define TCLSH_MAIN main /* Needed to fake out mktclapp */ | ||
2475 | int TCLSH_MAIN(int argc, char **argv){ | ||
2476 | Tcl_Interp *interp; | ||
2477 | Tcl_FindExecutable(argv[0]); | ||
2478 | interp = Tcl_CreateInterp(); | ||
2479 | Sqlite3_Init(interp); | ||
2480 | #ifdef SQLITE_TEST | ||
2481 | { | ||
2482 | extern int Md5_Init(Tcl_Interp*); | ||
2483 | extern int Sqliteconfig_Init(Tcl_Interp*); | ||
2484 | extern int Sqlitetest1_Init(Tcl_Interp*); | ||
2485 | extern int Sqlitetest2_Init(Tcl_Interp*); | ||
2486 | extern int Sqlitetest3_Init(Tcl_Interp*); | ||
2487 | extern int Sqlitetest4_Init(Tcl_Interp*); | ||
2488 | extern int Sqlitetest5_Init(Tcl_Interp*); | ||
2489 | extern int Sqlitetest6_Init(Tcl_Interp*); | ||
2490 | extern int Sqlitetest7_Init(Tcl_Interp*); | ||
2491 | extern int Sqlitetest8_Init(Tcl_Interp*); | ||
2492 | extern int Sqlitetest9_Init(Tcl_Interp*); | ||
2493 | extern int Sqlitetestasync_Init(Tcl_Interp*); | ||
2494 | extern int Sqlitetest_autoext_Init(Tcl_Interp*); | ||
2495 | extern int Sqlitetest_hexio_Init(Tcl_Interp*); | ||
2496 | extern int Sqlitetest_malloc_Init(Tcl_Interp*); | ||
2497 | extern int Sqlitetestschema_Init(Tcl_Interp*); | ||
2498 | extern int Sqlitetestsse_Init(Tcl_Interp*); | ||
2499 | extern int Sqlitetesttclvar_Init(Tcl_Interp*); | ||
2500 | extern int SqlitetestThread_Init(Tcl_Interp*); | ||
2501 | extern int SqlitetestOnefile_Init(); | ||
2502 | |||
2503 | Md5_Init(interp); | ||
2504 | Sqliteconfig_Init(interp); | ||
2505 | Sqlitetest1_Init(interp); | ||
2506 | Sqlitetest2_Init(interp); | ||
2507 | Sqlitetest3_Init(interp); | ||
2508 | Sqlitetest4_Init(interp); | ||
2509 | Sqlitetest5_Init(interp); | ||
2510 | Sqlitetest6_Init(interp); | ||
2511 | Sqlitetest7_Init(interp); | ||
2512 | Sqlitetest8_Init(interp); | ||
2513 | Sqlitetest9_Init(interp); | ||
2514 | Sqlitetestasync_Init(interp); | ||
2515 | Sqlitetest_autoext_Init(interp); | ||
2516 | Sqlitetest_hexio_Init(interp); | ||
2517 | Sqlitetest_malloc_Init(interp); | ||
2518 | Sqlitetestschema_Init(interp); | ||
2519 | Sqlitetesttclvar_Init(interp); | ||
2520 | SqlitetestThread_Init(interp); | ||
2521 | SqlitetestOnefile_Init(interp); | ||
2522 | |||
2523 | #ifdef SQLITE_SSE | ||
2524 | Sqlitetestsse_Init(interp); | ||
2525 | #endif | ||
2526 | } | ||
2527 | #endif | ||
2528 | if( argc>=2 || TCLSH==2 ){ | ||
2529 | int i; | ||
2530 | char zArgc[32]; | ||
2531 | sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH)); | ||
2532 | Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); | ||
2533 | Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); | ||
2534 | Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); | ||
2535 | for(i=3-TCLSH; i<argc; i++){ | ||
2536 | Tcl_SetVar(interp, "argv", argv[i], | ||
2537 | TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); | ||
2538 | } | ||
2539 | if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ | ||
2540 | const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); | ||
2541 | if( zInfo==0 ) zInfo = interp->result; | ||
2542 | fprintf(stderr,"%s: %s\n", *argv, zInfo); | ||
2543 | return 1; | ||
2544 | } | ||
2545 | } | ||
2546 | if( argc<=1 || TCLSH==2 ){ | ||
2547 | Tcl_GlobalEval(interp, zMainloop); | ||
2548 | } | ||
2549 | return 0; | ||
2550 | } | ||
2551 | #endif /* TCLSH */ | ||