OLD | NEW |
| (Empty) |
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 ** Code for testing all sorts of SQLite interfaces. This code | |
13 ** is not included in the SQLite library. It is used for automated | |
14 ** testing of the SQLite library. | |
15 */ | |
16 #include "sqliteInt.h" | |
17 #if SQLITE_OS_WIN | |
18 # include "os_win.h" | |
19 #endif | |
20 | |
21 #include "vdbeInt.h" | |
22 #include "tcl.h" | |
23 #include <stdlib.h> | |
24 #include <string.h> | |
25 | |
26 /* | |
27 ** This is a copy of the first part of the SqliteDb structure in | |
28 ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine | |
29 ** can extract the sqlite3* pointer from an existing Tcl SQLite | |
30 ** connection. | |
31 */ | |
32 struct SqliteDb { | |
33 sqlite3 *db; | |
34 }; | |
35 | |
36 /* | |
37 ** Convert text generated by the "%p" conversion format back into | |
38 ** a pointer. | |
39 */ | |
40 static int testHexToInt(int h){ | |
41 if( h>='0' && h<='9' ){ | |
42 return h - '0'; | |
43 }else if( h>='a' && h<='f' ){ | |
44 return h - 'a' + 10; | |
45 }else{ | |
46 assert( h>='A' && h<='F' ); | |
47 return h - 'A' + 10; | |
48 } | |
49 } | |
50 void *sqlite3TestTextToPtr(const char *z){ | |
51 void *p; | |
52 u64 v; | |
53 u32 v2; | |
54 if( z[0]=='0' && z[1]=='x' ){ | |
55 z += 2; | |
56 } | |
57 v = 0; | |
58 while( *z ){ | |
59 v = (v<<4) + testHexToInt(*z); | |
60 z++; | |
61 } | |
62 if( sizeof(p)==sizeof(v) ){ | |
63 memcpy(&p, &v, sizeof(p)); | |
64 }else{ | |
65 assert( sizeof(p)==sizeof(v2) ); | |
66 v2 = (u32)v; | |
67 memcpy(&p, &v2, sizeof(p)); | |
68 } | |
69 return p; | |
70 } | |
71 | |
72 | |
73 /* | |
74 ** A TCL command that returns the address of the sqlite* pointer | |
75 ** for an sqlite connection instance. Bad things happen if the | |
76 ** input is not an sqlite connection. | |
77 */ | |
78 static int get_sqlite_pointer( | |
79 void * clientData, | |
80 Tcl_Interp *interp, | |
81 int objc, | |
82 Tcl_Obj *CONST objv[] | |
83 ){ | |
84 struct SqliteDb *p; | |
85 Tcl_CmdInfo cmdInfo; | |
86 char zBuf[100]; | |
87 if( objc!=2 ){ | |
88 Tcl_WrongNumArgs(interp, 1, objv, "SQLITE-CONNECTION"); | |
89 return TCL_ERROR; | |
90 } | |
91 if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ | |
92 Tcl_AppendResult(interp, "command not found: ", | |
93 Tcl_GetString(objv[1]), (char*)0); | |
94 return TCL_ERROR; | |
95 } | |
96 p = (struct SqliteDb*)cmdInfo.objClientData; | |
97 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p->db); | |
98 Tcl_AppendResult(interp, zBuf, 0); | |
99 return TCL_OK; | |
100 } | |
101 | |
102 /* | |
103 ** Decode a pointer to an sqlite3 object. | |
104 */ | |
105 int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ | |
106 struct SqliteDb *p; | |
107 Tcl_CmdInfo cmdInfo; | |
108 if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){ | |
109 p = (struct SqliteDb*)cmdInfo.objClientData; | |
110 *ppDb = p->db; | |
111 }else{ | |
112 *ppDb = (sqlite3*)sqlite3TestTextToPtr(zA); | |
113 } | |
114 return TCL_OK; | |
115 } | |
116 | |
117 #if SQLITE_OS_WIN | |
118 /* | |
119 ** Decode a Win32 HANDLE object. | |
120 */ | |
121 int getWin32Handle(Tcl_Interp *interp, const char *zA, LPHANDLE phFile){ | |
122 *phFile = (HANDLE)sqlite3TestTextToPtr(zA); | |
123 return TCL_OK; | |
124 } | |
125 #endif | |
126 | |
127 extern const char *sqlite3ErrName(int); | |
128 #define t1ErrorName sqlite3ErrName | |
129 | |
130 /* | |
131 ** Convert an sqlite3_stmt* into an sqlite3*. This depends on the | |
132 ** fact that the sqlite3* is the first field in the Vdbe structure. | |
133 */ | |
134 #define StmtToDb(X) sqlite3_db_handle(X) | |
135 | |
136 /* | |
137 ** Check a return value to make sure it agrees with the results | |
138 ** from sqlite3_errcode. | |
139 */ | |
140 int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){ | |
141 if( sqlite3_threadsafe()==0 && rc!=SQLITE_MISUSE && rc!=SQLITE_OK | |
142 && sqlite3_errcode(db)!=rc ){ | |
143 char zBuf[200]; | |
144 int r2 = sqlite3_errcode(db); | |
145 sqlite3_snprintf(sizeof(zBuf), zBuf, | |
146 "error code %s (%d) does not match sqlite3_errcode %s (%d)", | |
147 t1ErrorName(rc), rc, t1ErrorName(r2), r2); | |
148 Tcl_ResetResult(interp); | |
149 Tcl_AppendResult(interp, zBuf, 0); | |
150 return 1; | |
151 } | |
152 return 0; | |
153 } | |
154 | |
155 /* | |
156 ** Decode a pointer to an sqlite3_stmt object. | |
157 */ | |
158 static int getStmtPointer( | |
159 Tcl_Interp *interp, | |
160 const char *zArg, | |
161 sqlite3_stmt **ppStmt | |
162 ){ | |
163 *ppStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(zArg); | |
164 return TCL_OK; | |
165 } | |
166 | |
167 /* | |
168 ** Generate a text representation of a pointer that can be understood | |
169 ** by the getDbPointer and getVmPointer routines above. | |
170 ** | |
171 ** The problem is, on some machines (Solaris) if you do a printf with | |
172 ** "%p" you cannot turn around and do a scanf with the same "%p" and | |
173 ** get your pointer back. You have to prepend a "0x" before it will | |
174 ** work. Or at least that is what is reported to me (drh). But this | |
175 ** behavior varies from machine to machine. The solution used her is | |
176 ** to test the string right after it is generated to see if it can be | |
177 ** understood by scanf, and if not, try prepending an "0x" to see if | |
178 ** that helps. If nothing works, a fatal error is generated. | |
179 */ | |
180 int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ | |
181 sqlite3_snprintf(100, zPtr, "%p", p); | |
182 return TCL_OK; | |
183 } | |
184 | |
185 /* | |
186 ** The callback routine for sqlite3_exec_printf(). | |
187 */ | |
188 static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ | |
189 Tcl_DString *str = (Tcl_DString*)pArg; | |
190 int i; | |
191 | |
192 if( Tcl_DStringLength(str)==0 ){ | |
193 for(i=0; i<argc; i++){ | |
194 Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); | |
195 } | |
196 } | |
197 for(i=0; i<argc; i++){ | |
198 Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); | |
199 } | |
200 return 0; | |
201 } | |
202 | |
203 /* | |
204 ** The I/O tracing callback. | |
205 */ | |
206 #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) | |
207 static FILE *iotrace_file = 0; | |
208 static void io_trace_callback(const char *zFormat, ...){ | |
209 va_list ap; | |
210 va_start(ap, zFormat); | |
211 vfprintf(iotrace_file, zFormat, ap); | |
212 va_end(ap); | |
213 fflush(iotrace_file); | |
214 } | |
215 #endif | |
216 | |
217 /* | |
218 ** Usage: io_trace FILENAME | |
219 ** | |
220 ** Turn I/O tracing on or off. If FILENAME is not an empty string, | |
221 ** I/O tracing begins going into FILENAME. If FILENAME is an empty | |
222 ** string, I/O tracing is turned off. | |
223 */ | |
224 static int test_io_trace( | |
225 void *NotUsed, | |
226 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
227 int argc, /* Number of arguments */ | |
228 char **argv /* Text of each argument */ | |
229 ){ | |
230 #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) | |
231 if( argc!=2 ){ | |
232 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
233 " FILENAME\"", 0); | |
234 return TCL_ERROR; | |
235 } | |
236 if( iotrace_file ){ | |
237 if( iotrace_file!=stdout && iotrace_file!=stderr ){ | |
238 fclose(iotrace_file); | |
239 } | |
240 iotrace_file = 0; | |
241 sqlite3IoTrace = 0; | |
242 } | |
243 if( argv[1][0] ){ | |
244 if( strcmp(argv[1],"stdout")==0 ){ | |
245 iotrace_file = stdout; | |
246 }else if( strcmp(argv[1],"stderr")==0 ){ | |
247 iotrace_file = stderr; | |
248 }else{ | |
249 iotrace_file = fopen(argv[1], "w"); | |
250 } | |
251 sqlite3IoTrace = io_trace_callback; | |
252 } | |
253 #endif | |
254 return TCL_OK; | |
255 } | |
256 | |
257 /* | |
258 ** Usage: clang_sanitize_address | |
259 ** | |
260 ** Returns true if the program was compiled using clang with the | |
261 ** -fsanitize=address switch on the command line. False otherwise. | |
262 ** | |
263 ** Also return true if the OMIT_MISUSE environment variable exists. | |
264 */ | |
265 static int clang_sanitize_address( | |
266 void *NotUsed, | |
267 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
268 int argc, /* Number of arguments */ | |
269 char **argv /* Text of each argument */ | |
270 ){ | |
271 int res = 0; | |
272 #if defined(__has_feature) | |
273 # if __has_feature(address_sanitizer) | |
274 res = 1; | |
275 # endif | |
276 #endif | |
277 #ifdef __SANITIZE_ADDRESS__ | |
278 res = 1; | |
279 #endif | |
280 if( res==0 && getenv("OMIT_MISUSE")!=0 ) res = 1; | |
281 Tcl_SetObjResult(interp, Tcl_NewIntObj(res)); | |
282 return TCL_OK; | |
283 } | |
284 | |
285 /* | |
286 ** Usage: sqlite3_exec_printf DB FORMAT STRING | |
287 ** | |
288 ** Invoke the sqlite3_exec_printf() interface using the open database | |
289 ** DB. The SQL is the string FORMAT. The format string should contain | |
290 ** one %s or %q. STRING is the value inserted into %s or %q. | |
291 */ | |
292 static int test_exec_printf( | |
293 void *NotUsed, | |
294 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
295 int argc, /* Number of arguments */ | |
296 char **argv /* Text of each argument */ | |
297 ){ | |
298 sqlite3 *db; | |
299 Tcl_DString str; | |
300 int rc; | |
301 char *zErr = 0; | |
302 char *zSql; | |
303 char zBuf[30]; | |
304 if( argc!=4 ){ | |
305 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
306 " DB FORMAT STRING", 0); | |
307 return TCL_ERROR; | |
308 } | |
309 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
310 Tcl_DStringInit(&str); | |
311 zSql = sqlite3_mprintf(argv[2], argv[3]); | |
312 rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); | |
313 sqlite3_free(zSql); | |
314 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); | |
315 Tcl_AppendElement(interp, zBuf); | |
316 Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); | |
317 Tcl_DStringFree(&str); | |
318 if( zErr ) sqlite3_free(zErr); | |
319 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
320 return TCL_OK; | |
321 } | |
322 | |
323 /* | |
324 ** Usage: sqlite3_exec_hex DB HEX | |
325 ** | |
326 ** Invoke the sqlite3_exec() on a string that is obtained by translating | |
327 ** HEX into ASCII. Most characters are translated as is. %HH becomes | |
328 ** a hex character. | |
329 */ | |
330 static int test_exec_hex( | |
331 void *NotUsed, | |
332 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
333 int argc, /* Number of arguments */ | |
334 char **argv /* Text of each argument */ | |
335 ){ | |
336 sqlite3 *db; | |
337 Tcl_DString str; | |
338 int rc, i, j; | |
339 char *zErr = 0; | |
340 char *zHex; | |
341 char zSql[501]; | |
342 char zBuf[30]; | |
343 if( argc!=3 ){ | |
344 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
345 " DB HEX", 0); | |
346 return TCL_ERROR; | |
347 } | |
348 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
349 zHex = argv[2]; | |
350 for(i=j=0; i<(sizeof(zSql)-1) && zHex[j]; i++, j++){ | |
351 if( zHex[j]=='%' && zHex[j+2] && zHex[j+2] ){ | |
352 zSql[i] = (testHexToInt(zHex[j+1])<<4) + testHexToInt(zHex[j+2]); | |
353 j += 2; | |
354 }else{ | |
355 zSql[i] = zHex[j]; | |
356 } | |
357 } | |
358 zSql[i] = 0; | |
359 Tcl_DStringInit(&str); | |
360 rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); | |
361 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); | |
362 Tcl_AppendElement(interp, zBuf); | |
363 Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); | |
364 Tcl_DStringFree(&str); | |
365 if( zErr ) sqlite3_free(zErr); | |
366 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
367 return TCL_OK; | |
368 } | |
369 | |
370 /* | |
371 ** Usage: db_enter DB | |
372 ** db_leave DB | |
373 ** | |
374 ** Enter or leave the mutex on a database connection. | |
375 */ | |
376 static int db_enter( | |
377 void *NotUsed, | |
378 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
379 int argc, /* Number of arguments */ | |
380 char **argv /* Text of each argument */ | |
381 ){ | |
382 sqlite3 *db; | |
383 if( argc!=2 ){ | |
384 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
385 " DB", 0); | |
386 return TCL_ERROR; | |
387 } | |
388 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
389 sqlite3_mutex_enter(db->mutex); | |
390 return TCL_OK; | |
391 } | |
392 static int db_leave( | |
393 void *NotUsed, | |
394 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
395 int argc, /* Number of arguments */ | |
396 char **argv /* Text of each argument */ | |
397 ){ | |
398 sqlite3 *db; | |
399 if( argc!=2 ){ | |
400 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
401 " DB", 0); | |
402 return TCL_ERROR; | |
403 } | |
404 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
405 sqlite3_mutex_leave(db->mutex); | |
406 return TCL_OK; | |
407 } | |
408 | |
409 /* | |
410 ** Usage: sqlite3_exec DB SQL | |
411 ** | |
412 ** Invoke the sqlite3_exec interface using the open database DB | |
413 */ | |
414 static int test_exec( | |
415 void *NotUsed, | |
416 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
417 int argc, /* Number of arguments */ | |
418 char **argv /* Text of each argument */ | |
419 ){ | |
420 sqlite3 *db; | |
421 Tcl_DString str; | |
422 int rc; | |
423 char *zErr = 0; | |
424 char *zSql; | |
425 int i, j; | |
426 char zBuf[30]; | |
427 if( argc!=3 ){ | |
428 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
429 " DB SQL", 0); | |
430 return TCL_ERROR; | |
431 } | |
432 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
433 Tcl_DStringInit(&str); | |
434 zSql = sqlite3_mprintf("%s", argv[2]); | |
435 for(i=j=0; zSql[i];){ | |
436 if( zSql[i]=='%' ){ | |
437 zSql[j++] = (testHexToInt(zSql[i+1])<<4) + testHexToInt(zSql[i+2]); | |
438 i += 3; | |
439 }else{ | |
440 zSql[j++] = zSql[i++]; | |
441 } | |
442 } | |
443 zSql[j] = 0; | |
444 rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); | |
445 sqlite3_free(zSql); | |
446 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); | |
447 Tcl_AppendElement(interp, zBuf); | |
448 Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); | |
449 Tcl_DStringFree(&str); | |
450 if( zErr ) sqlite3_free(zErr); | |
451 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
452 return TCL_OK; | |
453 } | |
454 | |
455 /* | |
456 ** Usage: sqlite3_exec_nr DB SQL | |
457 ** | |
458 ** Invoke the sqlite3_exec interface using the open database DB. Discard | |
459 ** all results | |
460 */ | |
461 static int test_exec_nr( | |
462 void *NotUsed, | |
463 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
464 int argc, /* Number of arguments */ | |
465 char **argv /* Text of each argument */ | |
466 ){ | |
467 sqlite3 *db; | |
468 int rc; | |
469 char *zErr = 0; | |
470 if( argc!=3 ){ | |
471 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
472 " DB SQL", 0); | |
473 return TCL_ERROR; | |
474 } | |
475 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
476 rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); | |
477 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
478 return TCL_OK; | |
479 } | |
480 | |
481 /* | |
482 ** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ... | |
483 ** | |
484 ** Test the %z format of sqlite_mprintf(). Use multiple mprintf() calls to | |
485 ** concatenate arg0 through argn using separator as the separator. | |
486 ** Return the result. | |
487 */ | |
488 static int test_mprintf_z( | |
489 void *NotUsed, | |
490 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
491 int argc, /* Number of arguments */ | |
492 char **argv /* Text of each argument */ | |
493 ){ | |
494 char *zResult = 0; | |
495 int i; | |
496 | |
497 for(i=2; i<argc && (i==2 || zResult); i++){ | |
498 zResult = sqlite3_mprintf("%z%s%s", zResult, argv[1], argv[i]); | |
499 } | |
500 Tcl_AppendResult(interp, zResult, 0); | |
501 sqlite3_free(zResult); | |
502 return TCL_OK; | |
503 } | |
504 | |
505 /* | |
506 ** Usage: sqlite3_mprintf_n_test STRING | |
507 ** | |
508 ** Test the %n format of sqlite_mprintf(). Return the length of the | |
509 ** input string. | |
510 */ | |
511 static int test_mprintf_n( | |
512 void *NotUsed, | |
513 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
514 int argc, /* Number of arguments */ | |
515 char **argv /* Text of each argument */ | |
516 ){ | |
517 char *zStr; | |
518 int n = 0; | |
519 zStr = sqlite3_mprintf("%s%n", argv[1], &n); | |
520 sqlite3_free(zStr); | |
521 Tcl_SetObjResult(interp, Tcl_NewIntObj(n)); | |
522 return TCL_OK; | |
523 } | |
524 | |
525 /* | |
526 ** Usage: sqlite3_snprintf_int SIZE FORMAT INT | |
527 ** | |
528 ** Test the of sqlite3_snprintf() routine. SIZE is the size of the | |
529 ** output buffer in bytes. The maximum size is 100. FORMAT is the | |
530 ** format string. INT is a single integer argument. The FORMAT | |
531 ** string must require no more than this one integer argument. If | |
532 ** You pass in a format string that requires more than one argument, | |
533 ** bad things will happen. | |
534 */ | |
535 static int test_snprintf_int( | |
536 void *NotUsed, | |
537 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
538 int argc, /* Number of arguments */ | |
539 char **argv /* Text of each argument */ | |
540 ){ | |
541 char zStr[100]; | |
542 int n = atoi(argv[1]); | |
543 const char *zFormat = argv[2]; | |
544 int a1 = atoi(argv[3]); | |
545 if( n>sizeof(zStr) ) n = sizeof(zStr); | |
546 sqlite3_snprintf(sizeof(zStr), zStr, "abcdefghijklmnopqrstuvwxyz"); | |
547 sqlite3_snprintf(n, zStr, zFormat, a1); | |
548 Tcl_AppendResult(interp, zStr, 0); | |
549 return TCL_OK; | |
550 } | |
551 | |
552 #ifndef SQLITE_OMIT_GET_TABLE | |
553 | |
554 /* | |
555 ** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts? | |
556 ** | |
557 ** Invoke the sqlite3_get_table_printf() interface using the open database | |
558 ** DB. The SQL is the string FORMAT. The format string should contain | |
559 ** one %s or %q. STRING is the value inserted into %s or %q. | |
560 */ | |
561 static int test_get_table_printf( | |
562 void *NotUsed, | |
563 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
564 int argc, /* Number of arguments */ | |
565 char **argv /* Text of each argument */ | |
566 ){ | |
567 sqlite3 *db; | |
568 Tcl_DString str; | |
569 int rc; | |
570 char *zErr = 0; | |
571 int nRow = 0, nCol = 0; | |
572 char **aResult; | |
573 int i; | |
574 char zBuf[30]; | |
575 char *zSql; | |
576 int resCount = -1; | |
577 if( argc==5 ){ | |
578 if( Tcl_GetInt(interp, argv[4], &resCount) ) return TCL_ERROR; | |
579 } | |
580 if( argc!=4 && argc!=5 ){ | |
581 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
582 " DB FORMAT STRING ?COUNT?", 0); | |
583 return TCL_ERROR; | |
584 } | |
585 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
586 Tcl_DStringInit(&str); | |
587 zSql = sqlite3_mprintf(argv[2],argv[3]); | |
588 if( argc==5 ){ | |
589 rc = sqlite3_get_table(db, zSql, &aResult, 0, 0, &zErr); | |
590 }else{ | |
591 rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr); | |
592 resCount = (nRow+1)*nCol; | |
593 } | |
594 sqlite3_free(zSql); | |
595 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); | |
596 Tcl_AppendElement(interp, zBuf); | |
597 if( rc==SQLITE_OK ){ | |
598 if( argc==4 ){ | |
599 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nRow); | |
600 Tcl_AppendElement(interp, zBuf); | |
601 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nCol); | |
602 Tcl_AppendElement(interp, zBuf); | |
603 } | |
604 for(i=0; i<resCount; i++){ | |
605 Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); | |
606 } | |
607 }else{ | |
608 Tcl_AppendElement(interp, zErr); | |
609 } | |
610 sqlite3_free_table(aResult); | |
611 if( zErr ) sqlite3_free(zErr); | |
612 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
613 return TCL_OK; | |
614 } | |
615 | |
616 #endif /* SQLITE_OMIT_GET_TABLE */ | |
617 | |
618 | |
619 /* | |
620 ** Usage: sqlite3_last_insert_rowid DB | |
621 ** | |
622 ** Returns the integer ROWID of the most recent insert. | |
623 */ | |
624 static int test_last_rowid( | |
625 void *NotUsed, | |
626 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
627 int argc, /* Number of arguments */ | |
628 char **argv /* Text of each argument */ | |
629 ){ | |
630 sqlite3 *db; | |
631 char zBuf[30]; | |
632 | |
633 if( argc!=2 ){ | |
634 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); | |
635 return TCL_ERROR; | |
636 } | |
637 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
638 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", sqlite3_last_insert_rowid(db)); | |
639 Tcl_AppendResult(interp, zBuf, 0); | |
640 return SQLITE_OK; | |
641 } | |
642 | |
643 /* | |
644 ** Usage: sqlite3_key DB KEY | |
645 ** | |
646 ** Set the codec key. | |
647 */ | |
648 static int test_key( | |
649 void *NotUsed, | |
650 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
651 int argc, /* Number of arguments */ | |
652 char **argv /* Text of each argument */ | |
653 ){ | |
654 #ifdef SQLITE_HAS_CODEC | |
655 sqlite3 *db; | |
656 const char *zKey; | |
657 int nKey; | |
658 if( argc!=3 ){ | |
659 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
660 " FILENAME\"", 0); | |
661 return TCL_ERROR; | |
662 } | |
663 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
664 zKey = argv[2]; | |
665 nKey = strlen(zKey); | |
666 sqlite3_key(db, zKey, nKey); | |
667 #endif | |
668 return TCL_OK; | |
669 } | |
670 | |
671 /* | |
672 ** Usage: sqlite3_rekey DB KEY | |
673 ** | |
674 ** Change the codec key. | |
675 */ | |
676 static int test_rekey( | |
677 void *NotUsed, | |
678 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
679 int argc, /* Number of arguments */ | |
680 char **argv /* Text of each argument */ | |
681 ){ | |
682 #ifdef SQLITE_HAS_CODEC | |
683 sqlite3 *db; | |
684 const char *zKey; | |
685 int nKey; | |
686 if( argc!=3 ){ | |
687 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
688 " FILENAME\"", 0); | |
689 return TCL_ERROR; | |
690 } | |
691 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
692 zKey = argv[2]; | |
693 nKey = strlen(zKey); | |
694 sqlite3_rekey(db, zKey, nKey); | |
695 #endif | |
696 return TCL_OK; | |
697 } | |
698 | |
699 /* | |
700 ** Usage: sqlite3_close DB | |
701 ** | |
702 ** Closes the database opened by sqlite3_open. | |
703 */ | |
704 static int sqlite_test_close( | |
705 void *NotUsed, | |
706 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
707 int argc, /* Number of arguments */ | |
708 char **argv /* Text of each argument */ | |
709 ){ | |
710 sqlite3 *db; | |
711 int rc; | |
712 if( argc!=2 ){ | |
713 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
714 " FILENAME\"", 0); | |
715 return TCL_ERROR; | |
716 } | |
717 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
718 rc = sqlite3_close(db); | |
719 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
720 return TCL_OK; | |
721 } | |
722 | |
723 /* | |
724 ** Usage: sqlite3_close_v2 DB | |
725 ** | |
726 ** Closes the database opened by sqlite3_open. | |
727 */ | |
728 static int sqlite_test_close_v2( | |
729 void *NotUsed, | |
730 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
731 int argc, /* Number of arguments */ | |
732 char **argv /* Text of each argument */ | |
733 ){ | |
734 sqlite3 *db; | |
735 int rc; | |
736 if( argc!=2 ){ | |
737 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
738 " FILENAME\"", 0); | |
739 return TCL_ERROR; | |
740 } | |
741 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
742 rc = sqlite3_close_v2(db); | |
743 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
744 return TCL_OK; | |
745 } | |
746 | |
747 /* | |
748 ** Implementation of the x_coalesce() function. | |
749 ** Return the first argument non-NULL argument. | |
750 */ | |
751 static void t1_ifnullFunc( | |
752 sqlite3_context *context, | |
753 int argc, | |
754 sqlite3_value **argv | |
755 ){ | |
756 int i; | |
757 for(i=0; i<argc; i++){ | |
758 if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ | |
759 int n = sqlite3_value_bytes(argv[i]); | |
760 sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]), | |
761 n, SQLITE_TRANSIENT); | |
762 break; | |
763 } | |
764 } | |
765 } | |
766 | |
767 /* | |
768 ** These are test functions. hex8() interprets its argument as | |
769 ** UTF8 and returns a hex encoding. hex16le() interprets its argument | |
770 ** as UTF16le and returns a hex encoding. | |
771 */ | |
772 static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){ | |
773 const unsigned char *z; | |
774 int i; | |
775 char zBuf[200]; | |
776 z = sqlite3_value_text(argv[0]); | |
777 for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){ | |
778 sqlite3_snprintf(sizeof(zBuf)-i*2, &zBuf[i*2], "%02x", z[i]); | |
779 } | |
780 zBuf[i*2] = 0; | |
781 sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT); | |
782 } | |
783 #ifndef SQLITE_OMIT_UTF16 | |
784 static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){ | |
785 const unsigned short int *z; | |
786 int i; | |
787 char zBuf[400]; | |
788 z = sqlite3_value_text16(argv[0]); | |
789 for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){ | |
790 sqlite3_snprintf(sizeof(zBuf)-i*4, &zBuf[i*4],"%04x", z[i]&0xff); | |
791 } | |
792 zBuf[i*4] = 0; | |
793 sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT); | |
794 } | |
795 #endif | |
796 | |
797 /* | |
798 ** A structure into which to accumulate text. | |
799 */ | |
800 struct dstr { | |
801 int nAlloc; /* Space allocated */ | |
802 int nUsed; /* Space used */ | |
803 char *z; /* The space */ | |
804 }; | |
805 | |
806 /* | |
807 ** Append text to a dstr | |
808 */ | |
809 static void dstrAppend(struct dstr *p, const char *z, int divider){ | |
810 int n = (int)strlen(z); | |
811 if( p->nUsed + n + 2 > p->nAlloc ){ | |
812 char *zNew; | |
813 p->nAlloc = p->nAlloc*2 + n + 200; | |
814 zNew = sqlite3_realloc(p->z, p->nAlloc); | |
815 if( zNew==0 ){ | |
816 sqlite3_free(p->z); | |
817 memset(p, 0, sizeof(*p)); | |
818 return; | |
819 } | |
820 p->z = zNew; | |
821 } | |
822 if( divider && p->nUsed>0 ){ | |
823 p->z[p->nUsed++] = divider; | |
824 } | |
825 memcpy(&p->z[p->nUsed], z, n+1); | |
826 p->nUsed += n; | |
827 } | |
828 | |
829 /* | |
830 ** Invoked for each callback from sqlite3ExecFunc | |
831 */ | |
832 static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){ | |
833 struct dstr *p = (struct dstr*)pData; | |
834 int i; | |
835 for(i=0; i<argc; i++){ | |
836 if( argv[i]==0 ){ | |
837 dstrAppend(p, "NULL", ' '); | |
838 }else{ | |
839 dstrAppend(p, argv[i], ' '); | |
840 } | |
841 } | |
842 return 0; | |
843 } | |
844 | |
845 /* | |
846 ** Implementation of the x_sqlite_exec() function. This function takes | |
847 ** a single argument and attempts to execute that argument as SQL code. | |
848 ** This is illegal and should set the SQLITE_MISUSE flag on the database. | |
849 ** | |
850 ** 2004-Jan-07: We have changed this to make it legal to call sqlite3_exec() | |
851 ** from within a function call. | |
852 ** | |
853 ** This routine simulates the effect of having two threads attempt to | |
854 ** use the same database at the same time. | |
855 */ | |
856 static void sqlite3ExecFunc( | |
857 sqlite3_context *context, | |
858 int argc, | |
859 sqlite3_value **argv | |
860 ){ | |
861 struct dstr x; | |
862 memset(&x, 0, sizeof(x)); | |
863 (void)sqlite3_exec((sqlite3*)sqlite3_user_data(context), | |
864 (char*)sqlite3_value_text(argv[0]), | |
865 execFuncCallback, &x, 0); | |
866 sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT); | |
867 sqlite3_free(x.z); | |
868 } | |
869 | |
870 /* | |
871 ** Implementation of tkt2213func(), a scalar function that takes exactly | |
872 ** one argument. It has two interesting features: | |
873 ** | |
874 ** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*. | |
875 ** If the three pointers returned are not the same an SQL error is raised. | |
876 ** | |
877 ** * Otherwise it returns a copy of the text representation of its | |
878 ** argument in such a way as the VDBE representation is a Mem* cell | |
879 ** with the MEM_Term flag clear. | |
880 ** | |
881 ** Ticket #2213 can therefore be tested by evaluating the following | |
882 ** SQL expression: | |
883 ** | |
884 ** tkt2213func(tkt2213func('a string')); | |
885 */ | |
886 static void tkt2213Function( | |
887 sqlite3_context *context, | |
888 int argc, | |
889 sqlite3_value **argv | |
890 ){ | |
891 int nText; | |
892 unsigned char const *zText1; | |
893 unsigned char const *zText2; | |
894 unsigned char const *zText3; | |
895 | |
896 nText = sqlite3_value_bytes(argv[0]); | |
897 zText1 = sqlite3_value_text(argv[0]); | |
898 zText2 = sqlite3_value_text(argv[0]); | |
899 zText3 = sqlite3_value_text(argv[0]); | |
900 | |
901 if( zText1!=zText2 || zText2!=zText3 ){ | |
902 sqlite3_result_error(context, "tkt2213 is not fixed", -1); | |
903 }else{ | |
904 char *zCopy = (char *)sqlite3_malloc(nText); | |
905 memcpy(zCopy, zText1, nText); | |
906 sqlite3_result_text(context, zCopy, nText, sqlite3_free); | |
907 } | |
908 } | |
909 | |
910 /* | |
911 ** The following SQL function takes 4 arguments. The 2nd and | |
912 ** 4th argument must be one of these strings: 'text', 'text16', | |
913 ** or 'blob' corresponding to API functions | |
914 ** | |
915 ** sqlite3_value_text() | |
916 ** sqlite3_value_text16() | |
917 ** sqlite3_value_blob() | |
918 ** | |
919 ** The third argument is a string, either 'bytes' or 'bytes16' or 'noop', | |
920 ** corresponding to APIs: | |
921 ** | |
922 ** sqlite3_value_bytes() | |
923 ** sqlite3_value_bytes16() | |
924 ** noop | |
925 ** | |
926 ** The APIs designated by the 2nd through 4th arguments are applied | |
927 ** to the first argument in order. If the pointers returned by the | |
928 ** second and fourth are different, this routine returns 1. Otherwise, | |
929 ** this routine returns 0. | |
930 ** | |
931 ** This function is used to test to see when returned pointers from | |
932 ** the _text(), _text16() and _blob() APIs become invalidated. | |
933 */ | |
934 static void ptrChngFunction( | |
935 sqlite3_context *context, | |
936 int argc, | |
937 sqlite3_value **argv | |
938 ){ | |
939 const void *p1, *p2; | |
940 const char *zCmd; | |
941 if( argc!=4 ) return; | |
942 zCmd = (const char*)sqlite3_value_text(argv[1]); | |
943 if( zCmd==0 ) return; | |
944 if( strcmp(zCmd,"text")==0 ){ | |
945 p1 = (const void*)sqlite3_value_text(argv[0]); | |
946 #ifndef SQLITE_OMIT_UTF16 | |
947 }else if( strcmp(zCmd, "text16")==0 ){ | |
948 p1 = (const void*)sqlite3_value_text16(argv[0]); | |
949 #endif | |
950 }else if( strcmp(zCmd, "blob")==0 ){ | |
951 p1 = (const void*)sqlite3_value_blob(argv[0]); | |
952 }else{ | |
953 return; | |
954 } | |
955 zCmd = (const char*)sqlite3_value_text(argv[2]); | |
956 if( zCmd==0 ) return; | |
957 if( strcmp(zCmd,"bytes")==0 ){ | |
958 sqlite3_value_bytes(argv[0]); | |
959 #ifndef SQLITE_OMIT_UTF16 | |
960 }else if( strcmp(zCmd, "bytes16")==0 ){ | |
961 sqlite3_value_bytes16(argv[0]); | |
962 #endif | |
963 }else if( strcmp(zCmd, "noop")==0 ){ | |
964 /* do nothing */ | |
965 }else{ | |
966 return; | |
967 } | |
968 zCmd = (const char*)sqlite3_value_text(argv[3]); | |
969 if( zCmd==0 ) return; | |
970 if( strcmp(zCmd,"text")==0 ){ | |
971 p2 = (const void*)sqlite3_value_text(argv[0]); | |
972 #ifndef SQLITE_OMIT_UTF16 | |
973 }else if( strcmp(zCmd, "text16")==0 ){ | |
974 p2 = (const void*)sqlite3_value_text16(argv[0]); | |
975 #endif | |
976 }else if( strcmp(zCmd, "blob")==0 ){ | |
977 p2 = (const void*)sqlite3_value_blob(argv[0]); | |
978 }else{ | |
979 return; | |
980 } | |
981 sqlite3_result_int(context, p1!=p2); | |
982 } | |
983 | |
984 /* | |
985 ** This SQL function returns a different answer each time it is called, even if | |
986 ** the arguments are the same. | |
987 */ | |
988 static void nondeterministicFunction( | |
989 sqlite3_context *context, | |
990 int argc, | |
991 sqlite3_value **argv | |
992 ){ | |
993 static int cnt = 0; | |
994 sqlite3_result_int(context, cnt++); | |
995 } | |
996 | |
997 /* | |
998 ** Usage: sqlite3_create_function DB | |
999 ** | |
1000 ** Call the sqlite3_create_function API on the given database in order | |
1001 ** to create a function named "x_coalesce". This function does the same thing | |
1002 ** as the "coalesce" function. This function also registers an SQL function | |
1003 ** named "x_sqlite_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec() | |
1004 ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. | |
1005 ** The effect is similar to trying to use the same database connection from | |
1006 ** two threads at the same time. | |
1007 ** | |
1008 ** The original motivation for this routine was to be able to call the | |
1009 ** sqlite3_create_function function while a query is in progress in order | |
1010 ** to test the SQLITE_MISUSE detection logic. | |
1011 */ | |
1012 static int test_create_function( | |
1013 void *NotUsed, | |
1014 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1015 int argc, /* Number of arguments */ | |
1016 char **argv /* Text of each argument */ | |
1017 ){ | |
1018 int rc; | |
1019 sqlite3 *db; | |
1020 | |
1021 if( argc!=2 ){ | |
1022 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1023 " DB\"", 0); | |
1024 return TCL_ERROR; | |
1025 } | |
1026 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
1027 rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, | |
1028 t1_ifnullFunc, 0, 0); | |
1029 if( rc==SQLITE_OK ){ | |
1030 rc = sqlite3_create_function(db, "hex8", 1, SQLITE_UTF8 | SQLITE_DETERMINIST
IC, | |
1031 0, hex8Func, 0, 0); | |
1032 } | |
1033 #ifndef SQLITE_OMIT_UTF16 | |
1034 if( rc==SQLITE_OK ){ | |
1035 rc = sqlite3_create_function(db, "hex16", 1, SQLITE_UTF16 | SQLITE_DETERMINI
STIC, | |
1036 0, hex16Func, 0, 0); | |
1037 } | |
1038 #endif | |
1039 if( rc==SQLITE_OK ){ | |
1040 rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0, | |
1041 tkt2213Function, 0, 0); | |
1042 } | |
1043 if( rc==SQLITE_OK ){ | |
1044 rc = sqlite3_create_function(db, "pointer_change", 4, SQLITE_ANY, 0, | |
1045 ptrChngFunction, 0, 0); | |
1046 } | |
1047 | |
1048 /* Functions counter1() and counter2() have the same implementation - they | |
1049 ** both return an ascending integer with each call. But counter1() is marked | |
1050 ** as non-deterministic and counter2() is marked as deterministic. | |
1051 */ | |
1052 if( rc==SQLITE_OK ){ | |
1053 rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8, | |
1054 0, nondeterministicFunction, 0, 0); | |
1055 } | |
1056 if( rc==SQLITE_OK ){ | |
1057 rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMIN
ISTIC, | |
1058 0, nondeterministicFunction, 0, 0); | |
1059 } | |
1060 | |
1061 #ifndef SQLITE_OMIT_UTF16 | |
1062 /* Use the sqlite3_create_function16() API here. Mainly for fun, but also | |
1063 ** because it is not tested anywhere else. */ | |
1064 if( rc==SQLITE_OK ){ | |
1065 const void *zUtf16; | |
1066 sqlite3_value *pVal; | |
1067 sqlite3_mutex_enter(db->mutex); | |
1068 pVal = sqlite3ValueNew(db); | |
1069 sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC); | |
1070 zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); | |
1071 if( db->mallocFailed ){ | |
1072 rc = SQLITE_NOMEM; | |
1073 }else{ | |
1074 rc = sqlite3_create_function16(db, zUtf16, | |
1075 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0); | |
1076 } | |
1077 sqlite3ValueFree(pVal); | |
1078 sqlite3_mutex_leave(db->mutex); | |
1079 } | |
1080 #endif | |
1081 | |
1082 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
1083 Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); | |
1084 return TCL_OK; | |
1085 } | |
1086 | |
1087 /* | |
1088 ** Routines to implement the x_count() aggregate function. | |
1089 ** | |
1090 ** x_count() counts the number of non-null arguments. But there are | |
1091 ** some twists for testing purposes. | |
1092 ** | |
1093 ** If the argument to x_count() is 40 then a UTF-8 error is reported | |
1094 ** on the step function. If x_count(41) is seen, then a UTF-16 error | |
1095 ** is reported on the step function. If the total count is 42, then | |
1096 ** a UTF-8 error is reported on the finalize function. | |
1097 */ | |
1098 typedef struct t1CountCtx t1CountCtx; | |
1099 struct t1CountCtx { | |
1100 int n; | |
1101 }; | |
1102 static void t1CountStep( | |
1103 sqlite3_context *context, | |
1104 int argc, | |
1105 sqlite3_value **argv | |
1106 ){ | |
1107 t1CountCtx *p; | |
1108 p = sqlite3_aggregate_context(context, sizeof(*p)); | |
1109 if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){ | |
1110 p->n++; | |
1111 } | |
1112 if( argc>0 ){ | |
1113 int v = sqlite3_value_int(argv[0]); | |
1114 if( v==40 ){ | |
1115 sqlite3_result_error(context, "value of 40 handed to x_count", -1); | |
1116 #ifndef SQLITE_OMIT_UTF16 | |
1117 }else if( v==41 ){ | |
1118 const char zUtf16ErrMsg[] = { 0, 0x61, 0, 0x62, 0, 0x63, 0, 0, 0}; | |
1119 sqlite3_result_error16(context, &zUtf16ErrMsg[1-SQLITE_BIGENDIAN], -1); | |
1120 #endif | |
1121 } | |
1122 } | |
1123 } | |
1124 static void t1CountFinalize(sqlite3_context *context){ | |
1125 t1CountCtx *p; | |
1126 p = sqlite3_aggregate_context(context, sizeof(*p)); | |
1127 if( p ){ | |
1128 if( p->n==42 ){ | |
1129 sqlite3_result_error(context, "x_count totals to 42", -1); | |
1130 }else{ | |
1131 sqlite3_result_int(context, p ? p->n : 0); | |
1132 } | |
1133 } | |
1134 } | |
1135 | |
1136 #ifndef SQLITE_OMIT_DEPRECATED | |
1137 static void legacyCountStep( | |
1138 sqlite3_context *context, | |
1139 int argc, | |
1140 sqlite3_value **argv | |
1141 ){ | |
1142 /* no-op */ | |
1143 } | |
1144 | |
1145 static void legacyCountFinalize(sqlite3_context *context){ | |
1146 sqlite3_result_int(context, sqlite3_aggregate_count(context)); | |
1147 } | |
1148 #endif | |
1149 | |
1150 /* | |
1151 ** Usage: sqlite3_create_aggregate DB | |
1152 ** | |
1153 ** Call the sqlite3_create_function API on the given database in order | |
1154 ** to create a function named "x_count". This function is similar | |
1155 ** to the built-in count() function, with a few special quirks | |
1156 ** for testing the sqlite3_result_error() APIs. | |
1157 ** | |
1158 ** The original motivation for this routine was to be able to call the | |
1159 ** sqlite3_create_aggregate function while a query is in progress in order | |
1160 ** to test the SQLITE_MISUSE detection logic. See misuse.test. | |
1161 ** | |
1162 ** This routine was later extended to test the use of sqlite3_result_error() | |
1163 ** within aggregate functions. | |
1164 ** | |
1165 ** Later: It is now also extended to register the aggregate function | |
1166 ** "legacy_count()" with the supplied database handle. This is used | |
1167 ** to test the deprecated sqlite3_aggregate_count() API. | |
1168 */ | |
1169 static int test_create_aggregate( | |
1170 void *NotUsed, | |
1171 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1172 int argc, /* Number of arguments */ | |
1173 char **argv /* Text of each argument */ | |
1174 ){ | |
1175 sqlite3 *db; | |
1176 int rc; | |
1177 if( argc!=2 ){ | |
1178 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1179 " FILENAME\"", 0); | |
1180 return TCL_ERROR; | |
1181 } | |
1182 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
1183 rc = sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0, | |
1184 t1CountStep,t1CountFinalize); | |
1185 if( rc==SQLITE_OK ){ | |
1186 rc = sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0, | |
1187 t1CountStep,t1CountFinalize); | |
1188 } | |
1189 #ifndef SQLITE_OMIT_DEPRECATED | |
1190 if( rc==SQLITE_OK ){ | |
1191 rc = sqlite3_create_function(db, "legacy_count", 0, SQLITE_ANY, 0, 0, | |
1192 legacyCountStep, legacyCountFinalize | |
1193 ); | |
1194 } | |
1195 #endif | |
1196 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
1197 Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); | |
1198 return TCL_OK; | |
1199 } | |
1200 | |
1201 | |
1202 /* | |
1203 ** Usage: printf TEXT | |
1204 ** | |
1205 ** Send output to printf. Use this rather than puts to merge the output | |
1206 ** in the correct sequence with debugging printfs inserted into C code. | |
1207 ** Puts uses a separate buffer and debugging statements will be out of | |
1208 ** sequence if it is used. | |
1209 */ | |
1210 static int test_printf( | |
1211 void *NotUsed, | |
1212 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1213 int argc, /* Number of arguments */ | |
1214 char **argv /* Text of each argument */ | |
1215 ){ | |
1216 if( argc!=2 ){ | |
1217 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1218 " TEXT\"", 0); | |
1219 return TCL_ERROR; | |
1220 } | |
1221 printf("%s\n", argv[1]); | |
1222 return TCL_OK; | |
1223 } | |
1224 | |
1225 | |
1226 | |
1227 /* | |
1228 ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER | |
1229 ** | |
1230 ** Call mprintf with three integer arguments | |
1231 */ | |
1232 static int sqlite3_mprintf_int( | |
1233 void *NotUsed, | |
1234 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1235 int argc, /* Number of arguments */ | |
1236 char **argv /* Text of each argument */ | |
1237 ){ | |
1238 int a[3], i; | |
1239 char *z; | |
1240 if( argc!=5 ){ | |
1241 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1242 " FORMAT INT INT INT\"", 0); | |
1243 return TCL_ERROR; | |
1244 } | |
1245 for(i=2; i<5; i++){ | |
1246 if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; | |
1247 } | |
1248 z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); | |
1249 Tcl_AppendResult(interp, z, 0); | |
1250 sqlite3_free(z); | |
1251 return TCL_OK; | |
1252 } | |
1253 | |
1254 /* | |
1255 ** Usage: sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER | |
1256 ** | |
1257 ** Call mprintf with three 64-bit integer arguments | |
1258 */ | |
1259 static int sqlite3_mprintf_int64( | |
1260 void *NotUsed, | |
1261 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1262 int argc, /* Number of arguments */ | |
1263 char **argv /* Text of each argument */ | |
1264 ){ | |
1265 int i; | |
1266 sqlite_int64 a[3]; | |
1267 char *z; | |
1268 if( argc!=5 ){ | |
1269 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1270 " FORMAT INT INT INT\"", 0); | |
1271 return TCL_ERROR; | |
1272 } | |
1273 for(i=2; i<5; i++){ | |
1274 if( sqlite3Atoi64(argv[i], &a[i-2], 1000000, SQLITE_UTF8) ){ | |
1275 Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0); | |
1276 return TCL_ERROR; | |
1277 } | |
1278 } | |
1279 z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); | |
1280 Tcl_AppendResult(interp, z, 0); | |
1281 sqlite3_free(z); | |
1282 return TCL_OK; | |
1283 } | |
1284 | |
1285 /* | |
1286 ** Usage: sqlite3_mprintf_long FORMAT INTEGER INTEGER INTEGER | |
1287 ** | |
1288 ** Call mprintf with three long integer arguments. This might be the | |
1289 ** same as sqlite3_mprintf_int or sqlite3_mprintf_int64, depending on | |
1290 ** platform. | |
1291 */ | |
1292 static int sqlite3_mprintf_long( | |
1293 void *NotUsed, | |
1294 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1295 int argc, /* Number of arguments */ | |
1296 char **argv /* Text of each argument */ | |
1297 ){ | |
1298 int i; | |
1299 long int a[3]; | |
1300 int b[3]; | |
1301 char *z; | |
1302 if( argc!=5 ){ | |
1303 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1304 " FORMAT INT INT INT\"", 0); | |
1305 return TCL_ERROR; | |
1306 } | |
1307 for(i=2; i<5; i++){ | |
1308 if( Tcl_GetInt(interp, argv[i], &b[i-2]) ) return TCL_ERROR; | |
1309 a[i-2] = (long int)b[i-2]; | |
1310 a[i-2] &= (((u64)1)<<(sizeof(int)*8))-1; | |
1311 } | |
1312 z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); | |
1313 Tcl_AppendResult(interp, z, 0); | |
1314 sqlite3_free(z); | |
1315 return TCL_OK; | |
1316 } | |
1317 | |
1318 /* | |
1319 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING | |
1320 ** | |
1321 ** Call mprintf with two integer arguments and one string argument | |
1322 */ | |
1323 static int sqlite3_mprintf_str( | |
1324 void *NotUsed, | |
1325 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1326 int argc, /* Number of arguments */ | |
1327 char **argv /* Text of each argument */ | |
1328 ){ | |
1329 int a[3], i; | |
1330 char *z; | |
1331 if( argc<4 || argc>5 ){ | |
1332 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1333 " FORMAT INT INT ?STRING?\"", 0); | |
1334 return TCL_ERROR; | |
1335 } | |
1336 for(i=2; i<4; i++){ | |
1337 if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; | |
1338 } | |
1339 z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); | |
1340 Tcl_AppendResult(interp, z, 0); | |
1341 sqlite3_free(z); | |
1342 return TCL_OK; | |
1343 } | |
1344 | |
1345 /* | |
1346 ** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING | |
1347 ** | |
1348 ** Call mprintf with two integer arguments and one string argument | |
1349 */ | |
1350 static int sqlite3_snprintf_str( | |
1351 void *NotUsed, | |
1352 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1353 int argc, /* Number of arguments */ | |
1354 char **argv /* Text of each argument */ | |
1355 ){ | |
1356 int a[3], i; | |
1357 int n; | |
1358 char *z; | |
1359 if( argc<5 || argc>6 ){ | |
1360 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1361 " INT FORMAT INT INT ?STRING?\"", 0); | |
1362 return TCL_ERROR; | |
1363 } | |
1364 if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; | |
1365 if( n<0 ){ | |
1366 Tcl_AppendResult(interp, "N must be non-negative", 0); | |
1367 return TCL_ERROR; | |
1368 } | |
1369 for(i=3; i<5; i++){ | |
1370 if( Tcl_GetInt(interp, argv[i], &a[i-3]) ) return TCL_ERROR; | |
1371 } | |
1372 z = sqlite3_malloc( n+1 ); | |
1373 sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL); | |
1374 Tcl_AppendResult(interp, z, 0); | |
1375 sqlite3_free(z); | |
1376 return TCL_OK; | |
1377 } | |
1378 | |
1379 /* | |
1380 ** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE | |
1381 ** | |
1382 ** Call mprintf with two integer arguments and one double argument | |
1383 */ | |
1384 static int sqlite3_mprintf_double( | |
1385 void *NotUsed, | |
1386 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1387 int argc, /* Number of arguments */ | |
1388 char **argv /* Text of each argument */ | |
1389 ){ | |
1390 int a[3], i; | |
1391 double r; | |
1392 char *z; | |
1393 if( argc!=5 ){ | |
1394 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1395 " FORMAT INT INT DOUBLE\"", 0); | |
1396 return TCL_ERROR; | |
1397 } | |
1398 for(i=2; i<4; i++){ | |
1399 if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; | |
1400 } | |
1401 if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; | |
1402 z = sqlite3_mprintf(argv[1], a[0], a[1], r); | |
1403 Tcl_AppendResult(interp, z, 0); | |
1404 sqlite3_free(z); | |
1405 return TCL_OK; | |
1406 } | |
1407 | |
1408 /* | |
1409 ** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE | |
1410 ** | |
1411 ** Call mprintf with a single double argument which is the product of the | |
1412 ** two arguments given above. This is used to generate overflow and underflow | |
1413 ** doubles to test that they are converted properly. | |
1414 */ | |
1415 static int sqlite3_mprintf_scaled( | |
1416 void *NotUsed, | |
1417 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1418 int argc, /* Number of arguments */ | |
1419 char **argv /* Text of each argument */ | |
1420 ){ | |
1421 int i; | |
1422 double r[2]; | |
1423 char *z; | |
1424 if( argc!=4 ){ | |
1425 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1426 " FORMAT DOUBLE DOUBLE\"", 0); | |
1427 return TCL_ERROR; | |
1428 } | |
1429 for(i=2; i<4; i++){ | |
1430 if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR; | |
1431 } | |
1432 z = sqlite3_mprintf(argv[1], r[0]*r[1]); | |
1433 Tcl_AppendResult(interp, z, 0); | |
1434 sqlite3_free(z); | |
1435 return TCL_OK; | |
1436 } | |
1437 | |
1438 /* | |
1439 ** Usage: sqlite3_mprintf_stronly FORMAT STRING | |
1440 ** | |
1441 ** Call mprintf with a single double argument which is the product of the | |
1442 ** two arguments given above. This is used to generate overflow and underflow | |
1443 ** doubles to test that they are converted properly. | |
1444 */ | |
1445 static int sqlite3_mprintf_stronly( | |
1446 void *NotUsed, | |
1447 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1448 int argc, /* Number of arguments */ | |
1449 char **argv /* Text of each argument */ | |
1450 ){ | |
1451 char *z; | |
1452 if( argc!=3 ){ | |
1453 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1454 " FORMAT STRING\"", 0); | |
1455 return TCL_ERROR; | |
1456 } | |
1457 z = sqlite3_mprintf(argv[1], argv[2]); | |
1458 Tcl_AppendResult(interp, z, 0); | |
1459 sqlite3_free(z); | |
1460 return TCL_OK; | |
1461 } | |
1462 | |
1463 /* | |
1464 ** Usage: sqlite3_mprintf_hexdouble FORMAT HEX | |
1465 ** | |
1466 ** Call mprintf with a single double argument which is derived from the | |
1467 ** hexadecimal encoding of an IEEE double. | |
1468 */ | |
1469 static int sqlite3_mprintf_hexdouble( | |
1470 void *NotUsed, | |
1471 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1472 int argc, /* Number of arguments */ | |
1473 char **argv /* Text of each argument */ | |
1474 ){ | |
1475 char *z; | |
1476 double r; | |
1477 unsigned int x1, x2; | |
1478 sqlite_uint64 d; | |
1479 if( argc!=3 ){ | |
1480 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
1481 " FORMAT STRING\"", 0); | |
1482 return TCL_ERROR; | |
1483 } | |
1484 if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){ | |
1485 Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0); | |
1486 return TCL_ERROR; | |
1487 } | |
1488 d = x2; | |
1489 d = (d<<32) + x1; | |
1490 memcpy(&r, &d, sizeof(r)); | |
1491 z = sqlite3_mprintf(argv[1], r); | |
1492 Tcl_AppendResult(interp, z, 0); | |
1493 sqlite3_free(z); | |
1494 return TCL_OK; | |
1495 } | |
1496 | |
1497 /* | |
1498 ** Usage: sqlite3_enable_shared_cache ?BOOLEAN? | |
1499 ** | |
1500 */ | |
1501 #if !defined(SQLITE_OMIT_SHARED_CACHE) | |
1502 static int test_enable_shared( | |
1503 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
1504 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1505 int objc, /* Number of arguments */ | |
1506 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1507 ){ | |
1508 int rc; | |
1509 int enable; | |
1510 int ret = 0; | |
1511 | |
1512 if( objc!=2 && objc!=1 ){ | |
1513 Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?"); | |
1514 return TCL_ERROR; | |
1515 } | |
1516 ret = sqlite3GlobalConfig.sharedCacheEnabled; | |
1517 | |
1518 if( objc==2 ){ | |
1519 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){ | |
1520 return TCL_ERROR; | |
1521 } | |
1522 rc = sqlite3_enable_shared_cache(enable); | |
1523 if( rc!=SQLITE_OK ){ | |
1524 Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC); | |
1525 return TCL_ERROR; | |
1526 } | |
1527 } | |
1528 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ret)); | |
1529 return TCL_OK; | |
1530 } | |
1531 #endif | |
1532 | |
1533 | |
1534 | |
1535 /* | |
1536 ** Usage: sqlite3_extended_result_codes DB BOOLEAN | |
1537 ** | |
1538 */ | |
1539 static int test_extended_result_codes( | |
1540 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
1541 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1542 int objc, /* Number of arguments */ | |
1543 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1544 ){ | |
1545 int enable; | |
1546 sqlite3 *db; | |
1547 | |
1548 if( objc!=3 ){ | |
1549 Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN"); | |
1550 return TCL_ERROR; | |
1551 } | |
1552 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
1553 if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR; | |
1554 sqlite3_extended_result_codes(db, enable); | |
1555 return TCL_OK; | |
1556 } | |
1557 | |
1558 /* | |
1559 ** Usage: sqlite3_libversion_number | |
1560 ** | |
1561 */ | |
1562 static int test_libversion_number( | |
1563 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
1564 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1565 int objc, /* Number of arguments */ | |
1566 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1567 ){ | |
1568 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_libversion_number())); | |
1569 return TCL_OK; | |
1570 } | |
1571 | |
1572 /* | |
1573 ** Usage: sqlite3_table_column_metadata DB dbname tblname colname | |
1574 ** | |
1575 */ | |
1576 static int test_table_column_metadata( | |
1577 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
1578 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1579 int objc, /* Number of arguments */ | |
1580 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1581 ){ | |
1582 sqlite3 *db; | |
1583 const char *zDb; | |
1584 const char *zTbl; | |
1585 const char *zCol; | |
1586 int rc; | |
1587 Tcl_Obj *pRet; | |
1588 | |
1589 const char *zDatatype; | |
1590 const char *zCollseq; | |
1591 int notnull; | |
1592 int primarykey; | |
1593 int autoincrement; | |
1594 | |
1595 if( objc!=5 && objc!=4 ){ | |
1596 Tcl_WrongNumArgs(interp, 1, objv, "DB dbname tblname colname"); | |
1597 return TCL_ERROR; | |
1598 } | |
1599 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
1600 zDb = Tcl_GetString(objv[2]); | |
1601 zTbl = Tcl_GetString(objv[3]); | |
1602 zCol = objc==5 ? Tcl_GetString(objv[4]) : 0; | |
1603 | |
1604 if( strlen(zDb)==0 ) zDb = 0; | |
1605 | |
1606 rc = sqlite3_table_column_metadata(db, zDb, zTbl, zCol, | |
1607 &zDatatype, &zCollseq, ¬null, &primarykey, &autoincrement); | |
1608 | |
1609 if( rc!=SQLITE_OK ){ | |
1610 Tcl_AppendResult(interp, sqlite3_errmsg(db), 0); | |
1611 return TCL_ERROR; | |
1612 } | |
1613 | |
1614 pRet = Tcl_NewObj(); | |
1615 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zDatatype, -1)); | |
1616 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zCollseq, -1)); | |
1617 Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(notnull)); | |
1618 Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(primarykey)); | |
1619 Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(autoincrement)); | |
1620 Tcl_SetObjResult(interp, pRet); | |
1621 | |
1622 return TCL_OK; | |
1623 } | |
1624 | |
1625 #ifndef SQLITE_OMIT_INCRBLOB | |
1626 | |
1627 static int blobHandleFromObj( | |
1628 Tcl_Interp *interp, | |
1629 Tcl_Obj *pObj, | |
1630 sqlite3_blob **ppBlob | |
1631 ){ | |
1632 char *z; | |
1633 int n; | |
1634 | |
1635 z = Tcl_GetStringFromObj(pObj, &n); | |
1636 if( n==0 ){ | |
1637 *ppBlob = 0; | |
1638 }else{ | |
1639 int notUsed; | |
1640 Tcl_Channel channel; | |
1641 ClientData instanceData; | |
1642 | |
1643 channel = Tcl_GetChannel(interp, z, ¬Used); | |
1644 if( !channel ) return TCL_ERROR; | |
1645 | |
1646 Tcl_Flush(channel); | |
1647 Tcl_Seek(channel, 0, SEEK_SET); | |
1648 | |
1649 instanceData = Tcl_GetChannelInstanceData(channel); | |
1650 *ppBlob = *((sqlite3_blob **)instanceData); | |
1651 } | |
1652 | |
1653 return TCL_OK; | |
1654 } | |
1655 | |
1656 static int test_blob_reopen( | |
1657 ClientData clientData, /* Not used */ | |
1658 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1659 int objc, /* Number of arguments */ | |
1660 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1661 ){ | |
1662 Tcl_WideInt iRowid; | |
1663 sqlite3_blob *pBlob; | |
1664 int rc; | |
1665 | |
1666 if( objc!=3 ){ | |
1667 Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL ROWID"); | |
1668 return TCL_ERROR; | |
1669 } | |
1670 | |
1671 if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; | |
1672 if( Tcl_GetWideIntFromObj(interp, objv[2], &iRowid) ) return TCL_ERROR; | |
1673 | |
1674 rc = sqlite3_blob_reopen(pBlob, iRowid); | |
1675 if( rc!=SQLITE_OK ){ | |
1676 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); | |
1677 } | |
1678 | |
1679 return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); | |
1680 } | |
1681 | |
1682 #endif | |
1683 | |
1684 /* | |
1685 ** Usage: sqlite3_create_collation_v2 DB-HANDLE NAME CMP-PROC DEL-PROC | |
1686 ** | |
1687 ** This Tcl proc is used for testing the experimental | |
1688 ** sqlite3_create_collation_v2() interface. | |
1689 */ | |
1690 struct TestCollationX { | |
1691 Tcl_Interp *interp; | |
1692 Tcl_Obj *pCmp; | |
1693 Tcl_Obj *pDel; | |
1694 }; | |
1695 typedef struct TestCollationX TestCollationX; | |
1696 static void testCreateCollationDel(void *pCtx){ | |
1697 TestCollationX *p = (TestCollationX *)pCtx; | |
1698 | |
1699 int rc = Tcl_EvalObjEx(p->interp, p->pDel, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); | |
1700 if( rc!=TCL_OK ){ | |
1701 Tcl_BackgroundError(p->interp); | |
1702 } | |
1703 | |
1704 Tcl_DecrRefCount(p->pCmp); | |
1705 Tcl_DecrRefCount(p->pDel); | |
1706 sqlite3_free((void *)p); | |
1707 } | |
1708 static int testCreateCollationCmp( | |
1709 void *pCtx, | |
1710 int nLeft, | |
1711 const void *zLeft, | |
1712 int nRight, | |
1713 const void *zRight | |
1714 ){ | |
1715 TestCollationX *p = (TestCollationX *)pCtx; | |
1716 Tcl_Obj *pScript = Tcl_DuplicateObj(p->pCmp); | |
1717 int iRes = 0; | |
1718 | |
1719 Tcl_IncrRefCount(pScript); | |
1720 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zLeft, nLeft)); | |
1721 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zRight,nRight)); | |
1722 | |
1723 if( TCL_OK!=Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL) | |
1724 || TCL_OK!=Tcl_GetIntFromObj(p->interp, Tcl_GetObjResult(p->interp), &iRes) | |
1725 ){ | |
1726 Tcl_BackgroundError(p->interp); | |
1727 } | |
1728 Tcl_DecrRefCount(pScript); | |
1729 | |
1730 return iRes; | |
1731 } | |
1732 static int test_create_collation_v2( | |
1733 ClientData clientData, /* Not used */ | |
1734 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1735 int objc, /* Number of arguments */ | |
1736 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1737 ){ | |
1738 TestCollationX *p; | |
1739 sqlite3 *db; | |
1740 int rc; | |
1741 | |
1742 if( objc!=5 ){ | |
1743 Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE NAME CMP-PROC DEL-PROC"); | |
1744 return TCL_ERROR; | |
1745 } | |
1746 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
1747 | |
1748 p = (TestCollationX *)sqlite3_malloc(sizeof(TestCollationX)); | |
1749 p->pCmp = objv[3]; | |
1750 p->pDel = objv[4]; | |
1751 p->interp = interp; | |
1752 Tcl_IncrRefCount(p->pCmp); | |
1753 Tcl_IncrRefCount(p->pDel); | |
1754 | |
1755 rc = sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), 16, | |
1756 (void *)p, testCreateCollationCmp, testCreateCollationDel | |
1757 ); | |
1758 if( rc!=SQLITE_MISUSE ){ | |
1759 Tcl_AppendResult(interp, "sqlite3_create_collate_v2() failed to detect " | |
1760 "an invalid encoding", (char*)0); | |
1761 return TCL_ERROR; | |
1762 } | |
1763 rc = sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), SQLITE_UTF8, | |
1764 (void *)p, testCreateCollationCmp, testCreateCollationDel | |
1765 ); | |
1766 return TCL_OK; | |
1767 } | |
1768 | |
1769 /* | |
1770 ** USAGE: sqlite3_create_function_v2 DB NAME NARG ENC ?SWITCHES? | |
1771 ** | |
1772 ** Available switches are: | |
1773 ** | |
1774 ** -func SCRIPT | |
1775 ** -step SCRIPT | |
1776 ** -final SCRIPT | |
1777 ** -destroy SCRIPT | |
1778 */ | |
1779 typedef struct CreateFunctionV2 CreateFunctionV2; | |
1780 struct CreateFunctionV2 { | |
1781 Tcl_Interp *interp; | |
1782 Tcl_Obj *pFunc; /* Script for function invocation */ | |
1783 Tcl_Obj *pStep; /* Script for agg. step invocation */ | |
1784 Tcl_Obj *pFinal; /* Script for agg. finalization invocation */ | |
1785 Tcl_Obj *pDestroy; /* Destructor script */ | |
1786 }; | |
1787 static void cf2Func(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ | |
1788 } | |
1789 static void cf2Step(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ | |
1790 } | |
1791 static void cf2Final(sqlite3_context *ctx){ | |
1792 } | |
1793 static void cf2Destroy(void *pUser){ | |
1794 CreateFunctionV2 *p = (CreateFunctionV2 *)pUser; | |
1795 | |
1796 if( p->interp && p->pDestroy ){ | |
1797 int rc = Tcl_EvalObjEx(p->interp, p->pDestroy, 0); | |
1798 if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp); | |
1799 } | |
1800 | |
1801 if( p->pFunc ) Tcl_DecrRefCount(p->pFunc); | |
1802 if( p->pStep ) Tcl_DecrRefCount(p->pStep); | |
1803 if( p->pFinal ) Tcl_DecrRefCount(p->pFinal); | |
1804 if( p->pDestroy ) Tcl_DecrRefCount(p->pDestroy); | |
1805 sqlite3_free(p); | |
1806 } | |
1807 static int test_create_function_v2( | |
1808 ClientData clientData, /* Not used */ | |
1809 Tcl_Interp *interp, /* The invoking TCL interpreter */ | |
1810 int objc, /* Number of arguments */ | |
1811 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1812 ){ | |
1813 sqlite3 *db; | |
1814 const char *zFunc; | |
1815 int nArg; | |
1816 int enc; | |
1817 CreateFunctionV2 *p; | |
1818 int i; | |
1819 int rc; | |
1820 | |
1821 struct EncTable { | |
1822 const char *zEnc; | |
1823 int enc; | |
1824 } aEnc[] = { | |
1825 {"utf8", SQLITE_UTF8 }, | |
1826 {"utf16", SQLITE_UTF16 }, | |
1827 {"utf16le", SQLITE_UTF16LE }, | |
1828 {"utf16be", SQLITE_UTF16BE }, | |
1829 {"any", SQLITE_ANY }, | |
1830 {"0", 0 } | |
1831 }; | |
1832 | |
1833 if( objc<5 || (objc%2)==0 ){ | |
1834 Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG ENC SWITCHES..."); | |
1835 return TCL_ERROR; | |
1836 } | |
1837 | |
1838 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
1839 zFunc = Tcl_GetString(objv[2]); | |
1840 if( Tcl_GetIntFromObj(interp, objv[3], &nArg) ) return TCL_ERROR; | |
1841 if( Tcl_GetIndexFromObjStruct(interp, objv[4], aEnc, sizeof(aEnc[0]), | |
1842 "encoding", 0, &enc) | |
1843 ){ | |
1844 return TCL_ERROR; | |
1845 } | |
1846 enc = aEnc[enc].enc; | |
1847 | |
1848 p = sqlite3_malloc(sizeof(CreateFunctionV2)); | |
1849 assert( p ); | |
1850 memset(p, 0, sizeof(CreateFunctionV2)); | |
1851 p->interp = interp; | |
1852 | |
1853 for(i=5; i<objc; i+=2){ | |
1854 int iSwitch; | |
1855 const char *azSwitch[] = {"-func", "-step", "-final", "-destroy", 0}; | |
1856 if( Tcl_GetIndexFromObj(interp, objv[i], azSwitch, "switch", 0, &iSwitch) ){ | |
1857 sqlite3_free(p); | |
1858 return TCL_ERROR; | |
1859 } | |
1860 | |
1861 switch( iSwitch ){ | |
1862 case 0: p->pFunc = objv[i+1]; break; | |
1863 case 1: p->pStep = objv[i+1]; break; | |
1864 case 2: p->pFinal = objv[i+1]; break; | |
1865 case 3: p->pDestroy = objv[i+1]; break; | |
1866 } | |
1867 } | |
1868 if( p->pFunc ) p->pFunc = Tcl_DuplicateObj(p->pFunc); | |
1869 if( p->pStep ) p->pStep = Tcl_DuplicateObj(p->pStep); | |
1870 if( p->pFinal ) p->pFinal = Tcl_DuplicateObj(p->pFinal); | |
1871 if( p->pDestroy ) p->pDestroy = Tcl_DuplicateObj(p->pDestroy); | |
1872 | |
1873 if( p->pFunc ) Tcl_IncrRefCount(p->pFunc); | |
1874 if( p->pStep ) Tcl_IncrRefCount(p->pStep); | |
1875 if( p->pFinal ) Tcl_IncrRefCount(p->pFinal); | |
1876 if( p->pDestroy ) Tcl_IncrRefCount(p->pDestroy); | |
1877 | |
1878 rc = sqlite3_create_function_v2(db, zFunc, nArg, enc, (void *)p, | |
1879 (p->pFunc ? cf2Func : 0), | |
1880 (p->pStep ? cf2Step : 0), | |
1881 (p->pFinal ? cf2Final : 0), | |
1882 cf2Destroy | |
1883 ); | |
1884 if( rc!=SQLITE_OK ){ | |
1885 Tcl_ResetResult(interp); | |
1886 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
1887 return TCL_ERROR; | |
1888 } | |
1889 return TCL_OK; | |
1890 } | |
1891 | |
1892 /* | |
1893 ** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC? | |
1894 */ | |
1895 static int test_load_extension( | |
1896 ClientData clientData, /* Not used */ | |
1897 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1898 int objc, /* Number of arguments */ | |
1899 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1900 ){ | |
1901 Tcl_CmdInfo cmdInfo; | |
1902 sqlite3 *db; | |
1903 int rc; | |
1904 char *zDb; | |
1905 char *zFile; | |
1906 char *zProc = 0; | |
1907 char *zErr = 0; | |
1908 | |
1909 if( objc!=4 && objc!=3 ){ | |
1910 Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE FILE ?PROC?"); | |
1911 return TCL_ERROR; | |
1912 } | |
1913 zDb = Tcl_GetString(objv[1]); | |
1914 zFile = Tcl_GetString(objv[2]); | |
1915 if( objc==4 ){ | |
1916 zProc = Tcl_GetString(objv[3]); | |
1917 } | |
1918 | |
1919 /* Extract the C database handle from the Tcl command name */ | |
1920 if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ | |
1921 Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0); | |
1922 return TCL_ERROR; | |
1923 } | |
1924 db = ((struct SqliteDb*)cmdInfo.objClientData)->db; | |
1925 assert(db); | |
1926 | |
1927 /* Call the underlying C function. If an error occurs, set rc to | |
1928 ** TCL_ERROR and load any error string into the interpreter. If no | |
1929 ** error occurs, set rc to TCL_OK. | |
1930 */ | |
1931 #ifdef SQLITE_OMIT_LOAD_EXTENSION | |
1932 rc = SQLITE_ERROR; | |
1933 zErr = sqlite3_mprintf("this build omits sqlite3_load_extension()"); | |
1934 #else | |
1935 rc = sqlite3_load_extension(db, zFile, zProc, &zErr); | |
1936 #endif | |
1937 if( rc!=SQLITE_OK ){ | |
1938 Tcl_SetResult(interp, zErr ? zErr : "", TCL_VOLATILE); | |
1939 rc = TCL_ERROR; | |
1940 }else{ | |
1941 rc = TCL_OK; | |
1942 } | |
1943 sqlite3_free(zErr); | |
1944 | |
1945 return rc; | |
1946 } | |
1947 | |
1948 /* | |
1949 ** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF | |
1950 */ | |
1951 static int test_enable_load( | |
1952 ClientData clientData, /* Not used */ | |
1953 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
1954 int objc, /* Number of arguments */ | |
1955 Tcl_Obj *CONST objv[] /* Command arguments */ | |
1956 ){ | |
1957 Tcl_CmdInfo cmdInfo; | |
1958 sqlite3 *db; | |
1959 char *zDb; | |
1960 int onoff; | |
1961 | |
1962 if( objc!=3 ){ | |
1963 Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE ONOFF"); | |
1964 return TCL_ERROR; | |
1965 } | |
1966 zDb = Tcl_GetString(objv[1]); | |
1967 | |
1968 /* Extract the C database handle from the Tcl command name */ | |
1969 if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ | |
1970 Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0); | |
1971 return TCL_ERROR; | |
1972 } | |
1973 db = ((struct SqliteDb*)cmdInfo.objClientData)->db; | |
1974 assert(db); | |
1975 | |
1976 /* Get the onoff parameter */ | |
1977 if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){ | |
1978 return TCL_ERROR; | |
1979 } | |
1980 | |
1981 #ifdef SQLITE_OMIT_LOAD_EXTENSION | |
1982 Tcl_AppendResult(interp, "this build omits sqlite3_load_extension()"); | |
1983 return TCL_ERROR; | |
1984 #else | |
1985 sqlite3_enable_load_extension(db, onoff); | |
1986 return TCL_OK; | |
1987 #endif | |
1988 } | |
1989 | |
1990 /* | |
1991 ** Usage: sqlite_abort | |
1992 ** | |
1993 ** Shutdown the process immediately. This is not a clean shutdown. | |
1994 ** This command is used to test the recoverability of a database in | |
1995 ** the event of a program crash. | |
1996 */ | |
1997 static int sqlite_abort( | |
1998 void *NotUsed, | |
1999 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
2000 int argc, /* Number of arguments */ | |
2001 char **argv /* Text of each argument */ | |
2002 ){ | |
2003 #if defined(_MSC_VER) | |
2004 /* We do this, otherwise the test will halt with a popup message | |
2005 * that we have to click away before the test will continue. | |
2006 */ | |
2007 _set_abort_behavior( 0, _CALL_REPORTFAULT ); | |
2008 #endif | |
2009 exit(255); | |
2010 assert( interp==0 ); /* This will always fail */ | |
2011 return TCL_OK; | |
2012 } | |
2013 | |
2014 /* | |
2015 ** The following routine is a user-defined SQL function whose purpose | |
2016 ** is to test the sqlite_set_result() API. | |
2017 */ | |
2018 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ | |
2019 while( argc>=2 ){ | |
2020 const char *zArg0 = (char*)sqlite3_value_text(argv[0]); | |
2021 if( zArg0 ){ | |
2022 if( 0==sqlite3StrICmp(zArg0, "int") ){ | |
2023 sqlite3_result_int(context, sqlite3_value_int(argv[1])); | |
2024 }else if( sqlite3StrICmp(zArg0,"int64")==0 ){ | |
2025 sqlite3_result_int64(context, sqlite3_value_int64(argv[1])); | |
2026 }else if( sqlite3StrICmp(zArg0,"string")==0 ){ | |
2027 sqlite3_result_text(context, (char*)sqlite3_value_text(argv[1]), -1, | |
2028 SQLITE_TRANSIENT); | |
2029 }else if( sqlite3StrICmp(zArg0,"double")==0 ){ | |
2030 sqlite3_result_double(context, sqlite3_value_double(argv[1])); | |
2031 }else if( sqlite3StrICmp(zArg0,"null")==0 ){ | |
2032 sqlite3_result_null(context); | |
2033 }else if( sqlite3StrICmp(zArg0,"value")==0 ){ | |
2034 sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]); | |
2035 }else{ | |
2036 goto error_out; | |
2037 } | |
2038 }else{ | |
2039 goto error_out; | |
2040 } | |
2041 argc -= 2; | |
2042 argv += 2; | |
2043 } | |
2044 return; | |
2045 | |
2046 error_out: | |
2047 sqlite3_result_error(context,"first argument should be one of: " | |
2048 "int int64 string double null value", -1); | |
2049 } | |
2050 | |
2051 /* | |
2052 ** Usage: sqlite_register_test_function DB NAME | |
2053 ** | |
2054 ** Register the test SQL function on the database DB under the name NAME. | |
2055 */ | |
2056 static int test_register_func( | |
2057 void *NotUsed, | |
2058 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
2059 int argc, /* Number of arguments */ | |
2060 char **argv /* Text of each argument */ | |
2061 ){ | |
2062 sqlite3 *db; | |
2063 int rc; | |
2064 if( argc!=3 ){ | |
2065 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
2066 " DB FUNCTION-NAME", 0); | |
2067 return TCL_ERROR; | |
2068 } | |
2069 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
2070 rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, | |
2071 testFunc, 0, 0); | |
2072 if( rc!=0 ){ | |
2073 Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); | |
2074 return TCL_ERROR; | |
2075 } | |
2076 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
2077 return TCL_OK; | |
2078 } | |
2079 | |
2080 /* | |
2081 ** Usage: sqlite3_finalize STMT | |
2082 ** | |
2083 ** Finalize a statement handle. | |
2084 */ | |
2085 static int test_finalize( | |
2086 void * clientData, | |
2087 Tcl_Interp *interp, | |
2088 int objc, | |
2089 Tcl_Obj *CONST objv[] | |
2090 ){ | |
2091 sqlite3_stmt *pStmt; | |
2092 int rc; | |
2093 sqlite3 *db = 0; | |
2094 | |
2095 if( objc!=2 ){ | |
2096 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2097 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); | |
2098 return TCL_ERROR; | |
2099 } | |
2100 | |
2101 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2102 | |
2103 if( pStmt ){ | |
2104 db = StmtToDb(pStmt); | |
2105 } | |
2106 rc = sqlite3_finalize(pStmt); | |
2107 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
2108 if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
2109 return TCL_OK; | |
2110 } | |
2111 | |
2112 /* | |
2113 ** Usage: sqlite3_stmt_status STMT CODE RESETFLAG | |
2114 ** | |
2115 ** Get the value of a status counter from a statement. | |
2116 */ | |
2117 static int test_stmt_status( | |
2118 void * clientData, | |
2119 Tcl_Interp *interp, | |
2120 int objc, | |
2121 Tcl_Obj *CONST objv[] | |
2122 ){ | |
2123 int iValue; | |
2124 int i, op = 0, resetFlag; | |
2125 const char *zOpName; | |
2126 sqlite3_stmt *pStmt; | |
2127 | |
2128 static const struct { | |
2129 const char *zName; | |
2130 int op; | |
2131 } aOp[] = { | |
2132 { "SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP }, | |
2133 { "SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT }, | |
2134 { "SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX }, | |
2135 { "SQLITE_STMTSTATUS_VM_STEP", SQLITE_STMTSTATUS_VM_STEP }, | |
2136 }; | |
2137 if( objc!=4 ){ | |
2138 Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG"); | |
2139 return TCL_ERROR; | |
2140 } | |
2141 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2142 zOpName = Tcl_GetString(objv[2]); | |
2143 for(i=0; i<ArraySize(aOp); i++){ | |
2144 if( strcmp(aOp[i].zName, zOpName)==0 ){ | |
2145 op = aOp[i].op; | |
2146 break; | |
2147 } | |
2148 } | |
2149 if( i>=ArraySize(aOp) ){ | |
2150 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR; | |
2151 } | |
2152 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR; | |
2153 iValue = sqlite3_stmt_status(pStmt, op, resetFlag); | |
2154 Tcl_SetObjResult(interp, Tcl_NewIntObj(iValue)); | |
2155 return TCL_OK; | |
2156 } | |
2157 | |
2158 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS | |
2159 /* | |
2160 ** Usage: sqlite3_stmt_scanstatus STMT IDX | |
2161 */ | |
2162 static int test_stmt_scanstatus( | |
2163 void * clientData, | |
2164 Tcl_Interp *interp, | |
2165 int objc, | |
2166 Tcl_Obj *CONST objv[] | |
2167 ){ | |
2168 sqlite3_stmt *pStmt; /* First argument */ | |
2169 int idx; /* Second argument */ | |
2170 | |
2171 const char *zName; | |
2172 const char *zExplain; | |
2173 sqlite3_int64 nLoop; | |
2174 sqlite3_int64 nVisit; | |
2175 double rEst; | |
2176 int res; | |
2177 | |
2178 if( objc!=3 ){ | |
2179 Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX"); | |
2180 return TCL_ERROR; | |
2181 } | |
2182 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2183 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
2184 | |
2185 res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop
); | |
2186 if( res==0 ){ | |
2187 Tcl_Obj *pRet = Tcl_NewObj(); | |
2188 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1)); | |
2189 Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop)); | |
2190 sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); | |
2191 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); | |
2192 Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); | |
2193 sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst); | |
2194 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); | |
2195 Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst)); | |
2196 sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); | |
2197 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); | |
2198 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); | |
2199 sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplai
n); | |
2200 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1)); | |
2201 Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1)); | |
2202 Tcl_SetObjResult(interp, pRet); | |
2203 }else{ | |
2204 Tcl_ResetResult(interp); | |
2205 } | |
2206 return TCL_OK; | |
2207 } | |
2208 | |
2209 /* | |
2210 ** Usage: sqlite3_stmt_scanstatus_reset STMT | |
2211 */ | |
2212 static int test_stmt_scanstatus_reset( | |
2213 void * clientData, | |
2214 Tcl_Interp *interp, | |
2215 int objc, | |
2216 Tcl_Obj *CONST objv[] | |
2217 ){ | |
2218 sqlite3_stmt *pStmt; /* First argument */ | |
2219 if( objc!=2 ){ | |
2220 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); | |
2221 return TCL_ERROR; | |
2222 } | |
2223 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2224 sqlite3_stmt_scanstatus_reset(pStmt); | |
2225 return TCL_OK; | |
2226 } | |
2227 #endif | |
2228 | |
2229 #ifdef SQLITE_ENABLE_SQLLOG | |
2230 /* | |
2231 ** Usage: sqlite3_config_sqllog | |
2232 ** | |
2233 ** Zero the SQLITE_CONFIG_SQLLOG configuration | |
2234 */ | |
2235 static int test_config_sqllog( | |
2236 void * clientData, | |
2237 Tcl_Interp *interp, | |
2238 int objc, | |
2239 Tcl_Obj *CONST objv[] | |
2240 ){ | |
2241 if( objc!=1 ){ | |
2242 Tcl_WrongNumArgs(interp, 1, objv, ""); | |
2243 return TCL_ERROR; | |
2244 } | |
2245 sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0); | |
2246 return TCL_OK; | |
2247 } | |
2248 #endif | |
2249 | |
2250 /* | |
2251 ** Usage: vfs_current_time_int64 | |
2252 ** | |
2253 ** Return the value returned by the default VFS's xCurrentTimeInt64 method. | |
2254 */ | |
2255 static int vfsCurrentTimeInt64( | |
2256 void * clientData, | |
2257 Tcl_Interp *interp, | |
2258 int objc, | |
2259 Tcl_Obj *CONST objv[] | |
2260 ){ | |
2261 i64 t; | |
2262 sqlite3_vfs *pVfs = sqlite3_vfs_find(0); | |
2263 if( objc!=1 ){ | |
2264 Tcl_WrongNumArgs(interp, 1, objv, ""); | |
2265 return TCL_ERROR; | |
2266 } | |
2267 pVfs->xCurrentTimeInt64(pVfs, &t); | |
2268 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t)); | |
2269 return TCL_OK; | |
2270 } | |
2271 | |
2272 #ifdef SQLITE_ENABLE_SNAPSHOT | |
2273 /* | |
2274 ** Usage: sqlite3_snapshot_get DB DBNAME | |
2275 */ | |
2276 static int test_snapshot_get( | |
2277 void * clientData, | |
2278 Tcl_Interp *interp, | |
2279 int objc, | |
2280 Tcl_Obj *CONST objv[] | |
2281 ){ | |
2282 int rc; | |
2283 sqlite3 *db; | |
2284 char *zName; | |
2285 sqlite3_snapshot *pSnapshot = 0; | |
2286 | |
2287 if( objc!=3 ){ | |
2288 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); | |
2289 return TCL_ERROR; | |
2290 } | |
2291 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2292 zName = Tcl_GetString(objv[2]); | |
2293 | |
2294 rc = sqlite3_snapshot_get(db, zName, &pSnapshot); | |
2295 if( rc!=SQLITE_OK ){ | |
2296 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); | |
2297 return TCL_ERROR; | |
2298 }else{ | |
2299 char zBuf[100]; | |
2300 if( sqlite3TestMakePointerStr(interp, zBuf, pSnapshot) ) return TCL_ERROR; | |
2301 Tcl_SetObjResult(interp, Tcl_NewStringObj(zBuf, -1)); | |
2302 } | |
2303 return TCL_OK; | |
2304 } | |
2305 #endif /* SQLITE_ENABLE_SNAPSHOT */ | |
2306 | |
2307 #ifdef SQLITE_ENABLE_SNAPSHOT | |
2308 /* | |
2309 ** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT | |
2310 */ | |
2311 static int test_snapshot_open( | |
2312 void * clientData, | |
2313 Tcl_Interp *interp, | |
2314 int objc, | |
2315 Tcl_Obj *CONST objv[] | |
2316 ){ | |
2317 int rc; | |
2318 sqlite3 *db; | |
2319 char *zName; | |
2320 sqlite3_snapshot *pSnapshot; | |
2321 | |
2322 if( objc!=4 ){ | |
2323 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT"); | |
2324 return TCL_ERROR; | |
2325 } | |
2326 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2327 zName = Tcl_GetString(objv[2]); | |
2328 pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[3])); | |
2329 | |
2330 rc = sqlite3_snapshot_open(db, zName, pSnapshot); | |
2331 if( rc!=SQLITE_OK ){ | |
2332 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); | |
2333 return TCL_ERROR; | |
2334 } | |
2335 return TCL_OK; | |
2336 } | |
2337 #endif /* SQLITE_ENABLE_SNAPSHOT */ | |
2338 | |
2339 #ifdef SQLITE_ENABLE_SNAPSHOT | |
2340 /* | |
2341 ** Usage: sqlite3_snapshot_free SNAPSHOT | |
2342 */ | |
2343 static int test_snapshot_free( | |
2344 void * clientData, | |
2345 Tcl_Interp *interp, | |
2346 int objc, | |
2347 Tcl_Obj *CONST objv[] | |
2348 ){ | |
2349 sqlite3_snapshot *pSnapshot; | |
2350 if( objc!=2 ){ | |
2351 Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT"); | |
2352 return TCL_ERROR; | |
2353 } | |
2354 pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); | |
2355 sqlite3_snapshot_free(pSnapshot); | |
2356 return TCL_OK; | |
2357 } | |
2358 #endif /* SQLITE_ENABLE_SNAPSHOT */ | |
2359 | |
2360 /* | |
2361 ** Usage: sqlite3_next_stmt DB STMT | |
2362 ** | |
2363 ** Return the next statment in sequence after STMT. | |
2364 */ | |
2365 static int test_next_stmt( | |
2366 void * clientData, | |
2367 Tcl_Interp *interp, | |
2368 int objc, | |
2369 Tcl_Obj *CONST objv[] | |
2370 ){ | |
2371 sqlite3_stmt *pStmt; | |
2372 sqlite3 *db = 0; | |
2373 char zBuf[50]; | |
2374 | |
2375 if( objc!=3 ){ | |
2376 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2377 Tcl_GetStringFromObj(objv[0], 0), " DB STMT", 0); | |
2378 return TCL_ERROR; | |
2379 } | |
2380 | |
2381 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2382 if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt) ) return TCL_ERROR; | |
2383 pStmt = sqlite3_next_stmt(db, pStmt); | |
2384 if( pStmt ){ | |
2385 if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; | |
2386 Tcl_AppendResult(interp, zBuf, 0); | |
2387 } | |
2388 return TCL_OK; | |
2389 } | |
2390 | |
2391 /* | |
2392 ** Usage: sqlite3_stmt_readonly STMT | |
2393 ** | |
2394 ** Return true if STMT is a NULL pointer or a pointer to a statement | |
2395 ** that is guaranteed to leave the database unmodified. | |
2396 */ | |
2397 static int test_stmt_readonly( | |
2398 void * clientData, | |
2399 Tcl_Interp *interp, | |
2400 int objc, | |
2401 Tcl_Obj *CONST objv[] | |
2402 ){ | |
2403 sqlite3_stmt *pStmt; | |
2404 int rc; | |
2405 | |
2406 if( objc!=2 ){ | |
2407 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2408 Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); | |
2409 return TCL_ERROR; | |
2410 } | |
2411 | |
2412 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2413 rc = sqlite3_stmt_readonly(pStmt); | |
2414 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); | |
2415 return TCL_OK; | |
2416 } | |
2417 | |
2418 /* | |
2419 ** Usage: sqlite3_stmt_busy STMT | |
2420 ** | |
2421 ** Return true if STMT is a non-NULL pointer to a statement | |
2422 ** that has been stepped but not to completion. | |
2423 */ | |
2424 static int test_stmt_busy( | |
2425 void * clientData, | |
2426 Tcl_Interp *interp, | |
2427 int objc, | |
2428 Tcl_Obj *CONST objv[] | |
2429 ){ | |
2430 sqlite3_stmt *pStmt; | |
2431 int rc; | |
2432 | |
2433 if( objc!=2 ){ | |
2434 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2435 Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); | |
2436 return TCL_ERROR; | |
2437 } | |
2438 | |
2439 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2440 rc = sqlite3_stmt_busy(pStmt); | |
2441 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); | |
2442 return TCL_OK; | |
2443 } | |
2444 | |
2445 /* | |
2446 ** Usage: uses_stmt_journal STMT | |
2447 ** | |
2448 ** Return true if STMT uses a statement journal. | |
2449 */ | |
2450 static int uses_stmt_journal( | |
2451 void * clientData, | |
2452 Tcl_Interp *interp, | |
2453 int objc, | |
2454 Tcl_Obj *CONST objv[] | |
2455 ){ | |
2456 sqlite3_stmt *pStmt; | |
2457 | |
2458 if( objc!=2 ){ | |
2459 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2460 Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); | |
2461 return TCL_ERROR; | |
2462 } | |
2463 | |
2464 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2465 sqlite3_stmt_readonly(pStmt); | |
2466 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal)); | |
2467 return TCL_OK; | |
2468 } | |
2469 | |
2470 | |
2471 /* | |
2472 ** Usage: sqlite3_reset STMT | |
2473 ** | |
2474 ** Reset a statement handle. | |
2475 */ | |
2476 static int test_reset( | |
2477 void * clientData, | |
2478 Tcl_Interp *interp, | |
2479 int objc, | |
2480 Tcl_Obj *CONST objv[] | |
2481 ){ | |
2482 sqlite3_stmt *pStmt; | |
2483 int rc; | |
2484 | |
2485 if( objc!=2 ){ | |
2486 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2487 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); | |
2488 return TCL_ERROR; | |
2489 } | |
2490 | |
2491 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2492 | |
2493 rc = sqlite3_reset(pStmt); | |
2494 if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){ | |
2495 return TCL_ERROR; | |
2496 } | |
2497 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
2498 /* | |
2499 if( rc ){ | |
2500 return TCL_ERROR; | |
2501 } | |
2502 */ | |
2503 return TCL_OK; | |
2504 } | |
2505 | |
2506 /* | |
2507 ** Usage: sqlite3_expired STMT | |
2508 ** | |
2509 ** Return TRUE if a recompilation of the statement is recommended. | |
2510 */ | |
2511 static int test_expired( | |
2512 void * clientData, | |
2513 Tcl_Interp *interp, | |
2514 int objc, | |
2515 Tcl_Obj *CONST objv[] | |
2516 ){ | |
2517 #ifndef SQLITE_OMIT_DEPRECATED | |
2518 sqlite3_stmt *pStmt; | |
2519 if( objc!=2 ){ | |
2520 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2521 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); | |
2522 return TCL_ERROR; | |
2523 } | |
2524 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
2525 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(sqlite3_expired(pStmt))); | |
2526 #endif | |
2527 return TCL_OK; | |
2528 } | |
2529 | |
2530 /* | |
2531 ** Usage: sqlite3_transfer_bindings FROMSTMT TOSTMT | |
2532 ** | |
2533 ** Transfer all bindings from FROMSTMT over to TOSTMT | |
2534 */ | |
2535 static int test_transfer_bind( | |
2536 void * clientData, | |
2537 Tcl_Interp *interp, | |
2538 int objc, | |
2539 Tcl_Obj *CONST objv[] | |
2540 ){ | |
2541 #ifndef SQLITE_OMIT_DEPRECATED | |
2542 sqlite3_stmt *pStmt1, *pStmt2; | |
2543 if( objc!=3 ){ | |
2544 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2545 Tcl_GetStringFromObj(objv[0], 0), " FROM-STMT TO-STMT", 0); | |
2546 return TCL_ERROR; | |
2547 } | |
2548 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt1)) return TCL_ERROR; | |
2549 if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt2)) return TCL_ERROR; | |
2550 Tcl_SetObjResult(interp, | |
2551 Tcl_NewIntObj(sqlite3_transfer_bindings(pStmt1,pStmt2))); | |
2552 #endif | |
2553 return TCL_OK; | |
2554 } | |
2555 | |
2556 /* | |
2557 ** Usage: sqlite3_changes DB | |
2558 ** | |
2559 ** Return the number of changes made to the database by the last SQL | |
2560 ** execution. | |
2561 */ | |
2562 static int test_changes( | |
2563 void * clientData, | |
2564 Tcl_Interp *interp, | |
2565 int objc, | |
2566 Tcl_Obj *CONST objv[] | |
2567 ){ | |
2568 sqlite3 *db; | |
2569 if( objc!=2 ){ | |
2570 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2571 Tcl_GetString(objv[0]), " DB", 0); | |
2572 return TCL_ERROR; | |
2573 } | |
2574 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2575 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db))); | |
2576 return TCL_OK; | |
2577 } | |
2578 | |
2579 /* | |
2580 ** This is the "static_bind_value" that variables are bound to when | |
2581 ** the FLAG option of sqlite3_bind is "static" | |
2582 */ | |
2583 static char *sqlite_static_bind_value = 0; | |
2584 static int sqlite_static_bind_nbyte = 0; | |
2585 | |
2586 /* | |
2587 ** Usage: sqlite3_bind VM IDX VALUE FLAGS | |
2588 ** | |
2589 ** Sets the value of the IDX-th occurrence of "?" in the original SQL | |
2590 ** string. VALUE is the new value. If FLAGS=="null" then VALUE is | |
2591 ** ignored and the value is set to NULL. If FLAGS=="static" then | |
2592 ** the value is set to the value of a static variable named | |
2593 ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy | |
2594 ** of the VALUE is made. If FLAGS=="blob10" then a VALUE is ignored | |
2595 ** an a 10-byte blob "abc\000xyz\000pq" is inserted. | |
2596 */ | |
2597 static int test_bind( | |
2598 void *NotUsed, | |
2599 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
2600 int argc, /* Number of arguments */ | |
2601 char **argv /* Text of each argument */ | |
2602 ){ | |
2603 sqlite3_stmt *pStmt; | |
2604 int rc; | |
2605 int idx; | |
2606 if( argc!=5 ){ | |
2607 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
2608 " VM IDX VALUE (null|static|normal)\"", 0); | |
2609 return TCL_ERROR; | |
2610 } | |
2611 if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR; | |
2612 if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; | |
2613 if( strcmp(argv[4],"null")==0 ){ | |
2614 rc = sqlite3_bind_null(pStmt, idx); | |
2615 }else if( strcmp(argv[4],"static")==0 ){ | |
2616 rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); | |
2617 }else if( strcmp(argv[4],"static-nbytes")==0 ){ | |
2618 rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, | |
2619 sqlite_static_bind_nbyte, 0); | |
2620 }else if( strcmp(argv[4],"normal")==0 ){ | |
2621 rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT); | |
2622 }else if( strcmp(argv[4],"blob10")==0 ){ | |
2623 rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC); | |
2624 }else{ | |
2625 Tcl_AppendResult(interp, "4th argument should be " | |
2626 "\"null\" or \"static\" or \"normal\"", 0); | |
2627 return TCL_ERROR; | |
2628 } | |
2629 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
2630 if( rc ){ | |
2631 char zBuf[50]; | |
2632 sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc); | |
2633 Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0); | |
2634 return TCL_ERROR; | |
2635 } | |
2636 return TCL_OK; | |
2637 } | |
2638 | |
2639 #ifndef SQLITE_OMIT_UTF16 | |
2640 /* | |
2641 ** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be> | |
2642 ** | |
2643 ** This function is used to test that SQLite selects the correct collation | |
2644 ** sequence callback when multiple versions (for different text encodings) | |
2645 ** are available. | |
2646 ** | |
2647 ** Calling this routine registers the collation sequence "test_collate" | |
2648 ** with database handle <db>. The second argument must be a list of three | |
2649 ** boolean values. If the first is true, then a version of test_collate is | |
2650 ** registered for UTF-8, if the second is true, a version is registered for | |
2651 ** UTF-16le, if the third is true, a UTF-16be version is available. | |
2652 ** Previous versions of test_collate are deleted. | |
2653 ** | |
2654 ** The collation sequence test_collate is implemented by calling the | |
2655 ** following TCL script: | |
2656 ** | |
2657 ** "test_collate <enc> <lhs> <rhs>" | |
2658 ** | |
2659 ** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8. | |
2660 ** The <enc> parameter is the encoding of the collation function that | |
2661 ** SQLite selected to call. The TCL test script implements the | |
2662 ** "test_collate" proc. | |
2663 ** | |
2664 ** Note that this will only work with one interpreter at a time, as the | |
2665 ** interp pointer to use when evaluating the TCL script is stored in | |
2666 ** pTestCollateInterp. | |
2667 */ | |
2668 static Tcl_Interp* pTestCollateInterp; | |
2669 static int test_collate_func( | |
2670 void *pCtx, | |
2671 int nA, const void *zA, | |
2672 int nB, const void *zB | |
2673 ){ | |
2674 Tcl_Interp *i = pTestCollateInterp; | |
2675 int encin = SQLITE_PTR_TO_INT(pCtx); | |
2676 int res; | |
2677 int n; | |
2678 | |
2679 sqlite3_value *pVal; | |
2680 Tcl_Obj *pX; | |
2681 | |
2682 pX = Tcl_NewStringObj("test_collate", -1); | |
2683 Tcl_IncrRefCount(pX); | |
2684 | |
2685 switch( encin ){ | |
2686 case SQLITE_UTF8: | |
2687 Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1)); | |
2688 break; | |
2689 case SQLITE_UTF16LE: | |
2690 Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1)); | |
2691 break; | |
2692 case SQLITE_UTF16BE: | |
2693 Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1)); | |
2694 break; | |
2695 default: | |
2696 assert(0); | |
2697 } | |
2698 | |
2699 sqlite3BeginBenignMalloc(); | |
2700 pVal = sqlite3ValueNew(0); | |
2701 if( pVal ){ | |
2702 sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC); | |
2703 n = sqlite3_value_bytes(pVal); | |
2704 Tcl_ListObjAppendElement(i,pX, | |
2705 Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n)); | |
2706 sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC); | |
2707 n = sqlite3_value_bytes(pVal); | |
2708 Tcl_ListObjAppendElement(i,pX, | |
2709 Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n)); | |
2710 sqlite3ValueFree(pVal); | |
2711 } | |
2712 sqlite3EndBenignMalloc(); | |
2713 | |
2714 Tcl_EvalObjEx(i, pX, 0); | |
2715 Tcl_DecrRefCount(pX); | |
2716 Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res); | |
2717 return res; | |
2718 } | |
2719 static int test_collate( | |
2720 void * clientData, | |
2721 Tcl_Interp *interp, | |
2722 int objc, | |
2723 Tcl_Obj *CONST objv[] | |
2724 ){ | |
2725 sqlite3 *db; | |
2726 int val; | |
2727 sqlite3_value *pVal; | |
2728 int rc; | |
2729 | |
2730 if( objc!=5 ) goto bad_args; | |
2731 pTestCollateInterp = interp; | |
2732 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2733 | |
2734 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; | |
2735 rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8, | |
2736 (void *)SQLITE_UTF8, val?test_collate_func:0); | |
2737 if( rc==SQLITE_OK ){ | |
2738 const void *zUtf16; | |
2739 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; | |
2740 rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE, | |
2741 (void *)SQLITE_UTF16LE, val?test_collate_func:0); | |
2742 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; | |
2743 | |
2744 #if 0 | |
2745 if( sqlite3_iMallocFail>0 ){ | |
2746 sqlite3_iMallocFail++; | |
2747 } | |
2748 #endif | |
2749 sqlite3_mutex_enter(db->mutex); | |
2750 pVal = sqlite3ValueNew(db); | |
2751 sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC); | |
2752 zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); | |
2753 if( db->mallocFailed ){ | |
2754 rc = SQLITE_NOMEM; | |
2755 }else{ | |
2756 rc = sqlite3_create_collation16(db, zUtf16, SQLITE_UTF16BE, | |
2757 (void *)SQLITE_UTF16BE, val?test_collate_func:0); | |
2758 } | |
2759 sqlite3ValueFree(pVal); | |
2760 sqlite3_mutex_leave(db->mutex); | |
2761 } | |
2762 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
2763 | |
2764 if( rc!=SQLITE_OK ){ | |
2765 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
2766 return TCL_ERROR; | |
2767 } | |
2768 return TCL_OK; | |
2769 | |
2770 bad_args: | |
2771 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
2772 Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0); | |
2773 return TCL_ERROR; | |
2774 } | |
2775 | |
2776 /* | |
2777 ** Usage: add_test_utf16bin_collate <db ptr> | |
2778 ** | |
2779 ** Add a utf-16 collation sequence named "utf16bin" to the database | |
2780 ** handle. This collation sequence compares arguments in the same way as the | |
2781 ** built-in collation "binary". | |
2782 */ | |
2783 static int test_utf16bin_collate_func( | |
2784 void *pCtx, | |
2785 int nA, const void *zA, | |
2786 int nB, const void *zB | |
2787 ){ | |
2788 int nCmp = (nA>nB ? nB : nA); | |
2789 int res = memcmp(zA, zB, nCmp); | |
2790 if( res==0 ) res = nA - nB; | |
2791 return res; | |
2792 } | |
2793 static int test_utf16bin_collate( | |
2794 void * clientData, | |
2795 Tcl_Interp *interp, | |
2796 int objc, | |
2797 Tcl_Obj *CONST objv[] | |
2798 ){ | |
2799 sqlite3 *db; | |
2800 int rc; | |
2801 | |
2802 if( objc!=2 ) goto bad_args; | |
2803 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2804 | |
2805 rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0, | |
2806 test_utf16bin_collate_func | |
2807 ); | |
2808 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
2809 return TCL_OK; | |
2810 | |
2811 bad_args: | |
2812 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | |
2813 return TCL_ERROR; | |
2814 } | |
2815 | |
2816 /* | |
2817 ** When the collation needed callback is invoked, record the name of | |
2818 ** the requested collating function here. The recorded name is linked | |
2819 ** to a TCL variable and used to make sure that the requested collation | |
2820 ** name is correct. | |
2821 */ | |
2822 static char zNeededCollation[200]; | |
2823 static char *pzNeededCollation = zNeededCollation; | |
2824 | |
2825 | |
2826 /* | |
2827 ** Called when a collating sequence is needed. Registered using | |
2828 ** sqlite3_collation_needed16(). | |
2829 */ | |
2830 static void test_collate_needed_cb( | |
2831 void *pCtx, | |
2832 sqlite3 *db, | |
2833 int eTextRep, | |
2834 const void *pName | |
2835 ){ | |
2836 int enc = ENC(db); | |
2837 int i; | |
2838 char *z; | |
2839 for(z = (char*)pName, i=0; *z || z[1]; z++){ | |
2840 if( *z ) zNeededCollation[i++] = *z; | |
2841 } | |
2842 zNeededCollation[i] = 0; | |
2843 sqlite3_create_collation( | |
2844 db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func); | |
2845 } | |
2846 | |
2847 /* | |
2848 ** Usage: add_test_collate_needed DB | |
2849 */ | |
2850 static int test_collate_needed( | |
2851 void * clientData, | |
2852 Tcl_Interp *interp, | |
2853 int objc, | |
2854 Tcl_Obj *CONST objv[] | |
2855 ){ | |
2856 sqlite3 *db; | |
2857 int rc; | |
2858 | |
2859 if( objc!=2 ) goto bad_args; | |
2860 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2861 rc = sqlite3_collation_needed16(db, 0, test_collate_needed_cb); | |
2862 zNeededCollation[0] = 0; | |
2863 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
2864 return TCL_OK; | |
2865 | |
2866 bad_args: | |
2867 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | |
2868 return TCL_ERROR; | |
2869 } | |
2870 | |
2871 /* | |
2872 ** tclcmd: add_alignment_test_collations DB | |
2873 ** | |
2874 ** Add two new collating sequences to the database DB | |
2875 ** | |
2876 ** utf16_aligned | |
2877 ** utf16_unaligned | |
2878 ** | |
2879 ** Both collating sequences use the same sort order as BINARY. | |
2880 ** The only difference is that the utf16_aligned collating | |
2881 ** sequence is declared with the SQLITE_UTF16_ALIGNED flag. | |
2882 ** Both collating functions increment the unaligned utf16 counter | |
2883 ** whenever they see a string that begins on an odd byte boundary. | |
2884 */ | |
2885 static int unaligned_string_counter = 0; | |
2886 static int alignmentCollFunc( | |
2887 void *NotUsed, | |
2888 int nKey1, const void *pKey1, | |
2889 int nKey2, const void *pKey2 | |
2890 ){ | |
2891 int rc, n; | |
2892 n = nKey1<nKey2 ? nKey1 : nKey2; | |
2893 if( nKey1>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey1))) ) unaligned_string_counter++; | |
2894 if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++; | |
2895 rc = memcmp(pKey1, pKey2, n); | |
2896 if( rc==0 ){ | |
2897 rc = nKey1 - nKey2; | |
2898 } | |
2899 return rc; | |
2900 } | |
2901 static int add_alignment_test_collations( | |
2902 void * clientData, | |
2903 Tcl_Interp *interp, | |
2904 int objc, | |
2905 Tcl_Obj *CONST objv[] | |
2906 ){ | |
2907 sqlite3 *db; | |
2908 if( objc>=2 ){ | |
2909 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
2910 sqlite3_create_collation(db, "utf16_unaligned", SQLITE_UTF16, | |
2911 0, alignmentCollFunc); | |
2912 sqlite3_create_collation(db, "utf16_aligned", SQLITE_UTF16_ALIGNED, | |
2913 0, alignmentCollFunc); | |
2914 } | |
2915 return SQLITE_OK; | |
2916 } | |
2917 #endif /* !defined(SQLITE_OMIT_UTF16) */ | |
2918 | |
2919 /* | |
2920 ** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be> | |
2921 ** | |
2922 ** This function is used to test that SQLite selects the correct user | |
2923 ** function callback when multiple versions (for different text encodings) | |
2924 ** are available. | |
2925 ** | |
2926 ** Calling this routine registers up to three versions of the user function | |
2927 ** "test_function" with database handle <db>. If the second argument is | |
2928 ** true, then a version of test_function is registered for UTF-8, if the | |
2929 ** third is true, a version is registered for UTF-16le, if the fourth is | |
2930 ** true, a UTF-16be version is available. Previous versions of | |
2931 ** test_function are deleted. | |
2932 ** | |
2933 ** The user function is implemented by calling the following TCL script: | |
2934 ** | |
2935 ** "test_function <enc> <arg>" | |
2936 ** | |
2937 ** Where <enc> is one of UTF-8, UTF-16LE or UTF16BE, and <arg> is the | |
2938 ** single argument passed to the SQL function. The value returned by | |
2939 ** the TCL script is used as the return value of the SQL function. It | |
2940 ** is passed to SQLite using UTF-16BE for a UTF-8 test_function(), UTF-8 | |
2941 ** for a UTF-16LE test_function(), and UTF-16LE for an implementation that | |
2942 ** prefers UTF-16BE. | |
2943 */ | |
2944 #ifndef SQLITE_OMIT_UTF16 | |
2945 static void test_function_utf8( | |
2946 sqlite3_context *pCtx, | |
2947 int nArg, | |
2948 sqlite3_value **argv | |
2949 ){ | |
2950 Tcl_Interp *interp; | |
2951 Tcl_Obj *pX; | |
2952 sqlite3_value *pVal; | |
2953 interp = (Tcl_Interp *)sqlite3_user_data(pCtx); | |
2954 pX = Tcl_NewStringObj("test_function", -1); | |
2955 Tcl_IncrRefCount(pX); | |
2956 Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-8", -1)); | |
2957 Tcl_ListObjAppendElement(interp, pX, | |
2958 Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1)); | |
2959 Tcl_EvalObjEx(interp, pX, 0); | |
2960 Tcl_DecrRefCount(pX); | |
2961 sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT); | |
2962 pVal = sqlite3ValueNew(0); | |
2963 sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp), | |
2964 SQLITE_UTF8, SQLITE_STATIC); | |
2965 sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal), | |
2966 -1, SQLITE_TRANSIENT); | |
2967 sqlite3ValueFree(pVal); | |
2968 } | |
2969 static void test_function_utf16le( | |
2970 sqlite3_context *pCtx, | |
2971 int nArg, | |
2972 sqlite3_value **argv | |
2973 ){ | |
2974 Tcl_Interp *interp; | |
2975 Tcl_Obj *pX; | |
2976 sqlite3_value *pVal; | |
2977 interp = (Tcl_Interp *)sqlite3_user_data(pCtx); | |
2978 pX = Tcl_NewStringObj("test_function", -1); | |
2979 Tcl_IncrRefCount(pX); | |
2980 Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16LE", -1)); | |
2981 Tcl_ListObjAppendElement(interp, pX, | |
2982 Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1)); | |
2983 Tcl_EvalObjEx(interp, pX, 0); | |
2984 Tcl_DecrRefCount(pX); | |
2985 pVal = sqlite3ValueNew(0); | |
2986 sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp), | |
2987 SQLITE_UTF8, SQLITE_STATIC); | |
2988 sqlite3_result_text(pCtx,(char*)sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT); | |
2989 sqlite3ValueFree(pVal); | |
2990 } | |
2991 static void test_function_utf16be( | |
2992 sqlite3_context *pCtx, | |
2993 int nArg, | |
2994 sqlite3_value **argv | |
2995 ){ | |
2996 Tcl_Interp *interp; | |
2997 Tcl_Obj *pX; | |
2998 sqlite3_value *pVal; | |
2999 interp = (Tcl_Interp *)sqlite3_user_data(pCtx); | |
3000 pX = Tcl_NewStringObj("test_function", -1); | |
3001 Tcl_IncrRefCount(pX); | |
3002 Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16BE", -1)); | |
3003 Tcl_ListObjAppendElement(interp, pX, | |
3004 Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1)); | |
3005 Tcl_EvalObjEx(interp, pX, 0); | |
3006 Tcl_DecrRefCount(pX); | |
3007 pVal = sqlite3ValueNew(0); | |
3008 sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp), | |
3009 SQLITE_UTF8, SQLITE_STATIC); | |
3010 sqlite3_result_text16(pCtx, sqlite3_value_text16le(pVal), | |
3011 -1, SQLITE_TRANSIENT); | |
3012 sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal), | |
3013 -1, SQLITE_TRANSIENT); | |
3014 sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal), | |
3015 -1, SQLITE_TRANSIENT); | |
3016 sqlite3ValueFree(pVal); | |
3017 } | |
3018 #endif /* SQLITE_OMIT_UTF16 */ | |
3019 static int test_function( | |
3020 void * clientData, | |
3021 Tcl_Interp *interp, | |
3022 int objc, | |
3023 Tcl_Obj *CONST objv[] | |
3024 ){ | |
3025 #ifndef SQLITE_OMIT_UTF16 | |
3026 sqlite3 *db; | |
3027 int val; | |
3028 | |
3029 if( objc!=5 ) goto bad_args; | |
3030 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3031 | |
3032 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; | |
3033 if( val ){ | |
3034 sqlite3_create_function(db, "test_function", 1, SQLITE_UTF8, | |
3035 interp, test_function_utf8, 0, 0); | |
3036 } | |
3037 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; | |
3038 if( val ){ | |
3039 sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16LE, | |
3040 interp, test_function_utf16le, 0, 0); | |
3041 } | |
3042 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; | |
3043 if( val ){ | |
3044 sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16BE, | |
3045 interp, test_function_utf16be, 0, 0); | |
3046 } | |
3047 | |
3048 return TCL_OK; | |
3049 bad_args: | |
3050 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3051 Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0); | |
3052 #endif /* SQLITE_OMIT_UTF16 */ | |
3053 return TCL_ERROR; | |
3054 } | |
3055 | |
3056 /* | |
3057 ** Usage: sqlite3_test_errstr <err code> | |
3058 ** | |
3059 ** Test that the english language string equivalents for sqlite error codes | |
3060 ** are sane. The parameter is an integer representing an sqlite error code. | |
3061 ** The result is a list of two elements, the string representation of the | |
3062 ** error code and the english language explanation. | |
3063 */ | |
3064 static int test_errstr( | |
3065 void * clientData, | |
3066 Tcl_Interp *interp, | |
3067 int objc, | |
3068 Tcl_Obj *CONST objv[] | |
3069 ){ | |
3070 char *zCode; | |
3071 int i; | |
3072 if( objc!=1 ){ | |
3073 Tcl_WrongNumArgs(interp, 1, objv, "<error code>"); | |
3074 } | |
3075 | |
3076 zCode = Tcl_GetString(objv[1]); | |
3077 for(i=0; i<200; i++){ | |
3078 if( 0==strcmp(t1ErrorName(i), zCode) ) break; | |
3079 } | |
3080 Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0); | |
3081 return TCL_OK; | |
3082 } | |
3083 | |
3084 /* | |
3085 ** Usage: breakpoint | |
3086 ** | |
3087 ** This routine exists for one purpose - to provide a place to put a | |
3088 ** breakpoint with GDB that can be triggered using TCL code. The use | |
3089 ** for this is when a particular test fails on (say) the 1485th iteration. | |
3090 ** In the TCL test script, we can add code like this: | |
3091 ** | |
3092 ** if {$i==1485} breakpoint | |
3093 ** | |
3094 ** Then run testfixture in the debugger and wait for the breakpoint to | |
3095 ** fire. Then additional breakpoints can be set to trace down the bug. | |
3096 */ | |
3097 static int test_breakpoint( | |
3098 void *NotUsed, | |
3099 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
3100 int argc, /* Number of arguments */ | |
3101 char **argv /* Text of each argument */ | |
3102 ){ | |
3103 return TCL_OK; /* Do nothing */ | |
3104 } | |
3105 | |
3106 /* | |
3107 ** Usage: sqlite3_bind_zeroblob STMT IDX N | |
3108 ** | |
3109 ** Test the sqlite3_bind_zeroblob interface. STMT is a prepared statement. | |
3110 ** IDX is the index of a wildcard in the prepared statement. This command | |
3111 ** binds a N-byte zero-filled BLOB to the wildcard. | |
3112 */ | |
3113 static int test_bind_zeroblob( | |
3114 void * clientData, | |
3115 Tcl_Interp *interp, | |
3116 int objc, | |
3117 Tcl_Obj *CONST objv[] | |
3118 ){ | |
3119 sqlite3_stmt *pStmt; | |
3120 int idx; | |
3121 int n; | |
3122 int rc; | |
3123 | |
3124 if( objc!=4 ){ | |
3125 Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N"); | |
3126 return TCL_ERROR; | |
3127 } | |
3128 | |
3129 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3130 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3131 if( Tcl_GetIntFromObj(interp, objv[3], &n) ) return TCL_ERROR; | |
3132 | |
3133 rc = sqlite3_bind_zeroblob(pStmt, idx, n); | |
3134 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3135 if( rc!=SQLITE_OK ){ | |
3136 return TCL_ERROR; | |
3137 } | |
3138 | |
3139 return TCL_OK; | |
3140 } | |
3141 | |
3142 /* | |
3143 ** Usage: sqlite3_bind_zeroblob64 STMT IDX N | |
3144 ** | |
3145 ** Test the sqlite3_bind_zeroblob64 interface. STMT is a prepared statement. | |
3146 ** IDX is the index of a wildcard in the prepared statement. This command | |
3147 ** binds a N-byte zero-filled BLOB to the wildcard. | |
3148 */ | |
3149 static int test_bind_zeroblob64( | |
3150 void * clientData, | |
3151 Tcl_Interp *interp, | |
3152 int objc, | |
3153 Tcl_Obj *CONST objv[] | |
3154 ){ | |
3155 sqlite3_stmt *pStmt; | |
3156 int idx; | |
3157 i64 n; | |
3158 int rc; | |
3159 | |
3160 if( objc!=4 ){ | |
3161 Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N"); | |
3162 return TCL_ERROR; | |
3163 } | |
3164 | |
3165 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3166 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3167 if( Tcl_GetWideIntFromObj(interp, objv[3], &n) ) return TCL_ERROR; | |
3168 | |
3169 rc = sqlite3_bind_zeroblob64(pStmt, idx, n); | |
3170 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3171 if( rc!=SQLITE_OK ){ | |
3172 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
3173 return TCL_ERROR; | |
3174 } | |
3175 | |
3176 return TCL_OK; | |
3177 } | |
3178 | |
3179 /* | |
3180 ** Usage: sqlite3_bind_int STMT N VALUE | |
3181 ** | |
3182 ** Test the sqlite3_bind_int interface. STMT is a prepared statement. | |
3183 ** N is the index of a wildcard in the prepared statement. This command | |
3184 ** binds a 32-bit integer VALUE to that wildcard. | |
3185 */ | |
3186 static int test_bind_int( | |
3187 void * clientData, | |
3188 Tcl_Interp *interp, | |
3189 int objc, | |
3190 Tcl_Obj *CONST objv[] | |
3191 ){ | |
3192 sqlite3_stmt *pStmt; | |
3193 int idx; | |
3194 int value; | |
3195 int rc; | |
3196 | |
3197 if( objc!=4 ){ | |
3198 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3199 Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); | |
3200 return TCL_ERROR; | |
3201 } | |
3202 | |
3203 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3204 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3205 if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; | |
3206 | |
3207 rc = sqlite3_bind_int(pStmt, idx, value); | |
3208 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3209 if( rc!=SQLITE_OK ){ | |
3210 return TCL_ERROR; | |
3211 } | |
3212 | |
3213 return TCL_OK; | |
3214 } | |
3215 | |
3216 | |
3217 /* | |
3218 ** Usage: sqlite3_bind_int64 STMT N VALUE | |
3219 ** | |
3220 ** Test the sqlite3_bind_int64 interface. STMT is a prepared statement. | |
3221 ** N is the index of a wildcard in the prepared statement. This command | |
3222 ** binds a 64-bit integer VALUE to that wildcard. | |
3223 */ | |
3224 static int test_bind_int64( | |
3225 void * clientData, | |
3226 Tcl_Interp *interp, | |
3227 int objc, | |
3228 Tcl_Obj *CONST objv[] | |
3229 ){ | |
3230 sqlite3_stmt *pStmt; | |
3231 int idx; | |
3232 Tcl_WideInt value; | |
3233 int rc; | |
3234 | |
3235 if( objc!=4 ){ | |
3236 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3237 Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); | |
3238 return TCL_ERROR; | |
3239 } | |
3240 | |
3241 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3242 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3243 if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; | |
3244 | |
3245 rc = sqlite3_bind_int64(pStmt, idx, value); | |
3246 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3247 if( rc!=SQLITE_OK ){ | |
3248 return TCL_ERROR; | |
3249 } | |
3250 | |
3251 return TCL_OK; | |
3252 } | |
3253 | |
3254 | |
3255 /* | |
3256 ** Usage: sqlite3_bind_double STMT N VALUE | |
3257 ** | |
3258 ** Test the sqlite3_bind_double interface. STMT is a prepared statement. | |
3259 ** N is the index of a wildcard in the prepared statement. This command | |
3260 ** binds a 64-bit integer VALUE to that wildcard. | |
3261 */ | |
3262 static int test_bind_double( | |
3263 void * clientData, | |
3264 Tcl_Interp *interp, | |
3265 int objc, | |
3266 Tcl_Obj *CONST objv[] | |
3267 ){ | |
3268 sqlite3_stmt *pStmt; | |
3269 int idx; | |
3270 double value = 0; | |
3271 int rc; | |
3272 const char *zVal; | |
3273 int i; | |
3274 static const struct { | |
3275 const char *zName; /* Name of the special floating point value */ | |
3276 unsigned int iUpper; /* Upper 32 bits */ | |
3277 unsigned int iLower; /* Lower 32 bits */ | |
3278 } aSpecialFp[] = { | |
3279 { "NaN", 0x7fffffff, 0xffffffff }, | |
3280 { "SNaN", 0x7ff7ffff, 0xffffffff }, | |
3281 { "-NaN", 0xffffffff, 0xffffffff }, | |
3282 { "-SNaN", 0xfff7ffff, 0xffffffff }, | |
3283 { "+Inf", 0x7ff00000, 0x00000000 }, | |
3284 { "-Inf", 0xfff00000, 0x00000000 }, | |
3285 { "Epsilon", 0x00000000, 0x00000001 }, | |
3286 { "-Epsilon", 0x80000000, 0x00000001 }, | |
3287 { "NaN0", 0x7ff80000, 0x00000000 }, | |
3288 { "-NaN0", 0xfff80000, 0x00000000 }, | |
3289 }; | |
3290 | |
3291 if( objc!=4 ){ | |
3292 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3293 Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); | |
3294 return TCL_ERROR; | |
3295 } | |
3296 | |
3297 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3298 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3299 | |
3300 /* Intercept the string "NaN" and generate a NaN value for it. | |
3301 ** All other strings are passed through to Tcl_GetDoubleFromObj(). | |
3302 ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions | |
3303 ** contain a bug. | |
3304 */ | |
3305 zVal = Tcl_GetString(objv[3]); | |
3306 for(i=0; i<sizeof(aSpecialFp)/sizeof(aSpecialFp[0]); i++){ | |
3307 if( strcmp(aSpecialFp[i].zName, zVal)==0 ){ | |
3308 sqlite3_uint64 x; | |
3309 x = aSpecialFp[i].iUpper; | |
3310 x <<= 32; | |
3311 x |= aSpecialFp[i].iLower; | |
3312 assert( sizeof(value)==8 ); | |
3313 assert( sizeof(x)==8 ); | |
3314 memcpy(&value, &x, 8); | |
3315 break; | |
3316 } | |
3317 } | |
3318 if( i>=sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) && | |
3319 Tcl_GetDoubleFromObj(interp, objv[3], &value) ){ | |
3320 return TCL_ERROR; | |
3321 } | |
3322 rc = sqlite3_bind_double(pStmt, idx, value); | |
3323 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3324 if( rc!=SQLITE_OK ){ | |
3325 return TCL_ERROR; | |
3326 } | |
3327 | |
3328 return TCL_OK; | |
3329 } | |
3330 | |
3331 /* | |
3332 ** Usage: sqlite3_bind_null STMT N | |
3333 ** | |
3334 ** Test the sqlite3_bind_null interface. STMT is a prepared statement. | |
3335 ** N is the index of a wildcard in the prepared statement. This command | |
3336 ** binds a NULL to the wildcard. | |
3337 */ | |
3338 static int test_bind_null( | |
3339 void * clientData, | |
3340 Tcl_Interp *interp, | |
3341 int objc, | |
3342 Tcl_Obj *CONST objv[] | |
3343 ){ | |
3344 sqlite3_stmt *pStmt; | |
3345 int idx; | |
3346 int rc; | |
3347 | |
3348 if( objc!=3 ){ | |
3349 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3350 Tcl_GetStringFromObj(objv[0], 0), " STMT N", 0); | |
3351 return TCL_ERROR; | |
3352 } | |
3353 | |
3354 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3355 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3356 | |
3357 rc = sqlite3_bind_null(pStmt, idx); | |
3358 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3359 if( rc!=SQLITE_OK ){ | |
3360 return TCL_ERROR; | |
3361 } | |
3362 | |
3363 return TCL_OK; | |
3364 } | |
3365 | |
3366 /* | |
3367 ** Usage: sqlite3_bind_text STMT N STRING BYTES | |
3368 ** | |
3369 ** Test the sqlite3_bind_text interface. STMT is a prepared statement. | |
3370 ** N is the index of a wildcard in the prepared statement. This command | |
3371 ** binds a UTF-8 string STRING to the wildcard. The string is BYTES bytes | |
3372 ** long. | |
3373 */ | |
3374 static int test_bind_text( | |
3375 void * clientData, | |
3376 Tcl_Interp *interp, | |
3377 int objc, | |
3378 Tcl_Obj *CONST objv[] | |
3379 ){ | |
3380 sqlite3_stmt *pStmt; | |
3381 int idx; | |
3382 int bytes; | |
3383 char *value; | |
3384 int rc; | |
3385 | |
3386 if( objc!=5 ){ | |
3387 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3388 Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); | |
3389 return TCL_ERROR; | |
3390 } | |
3391 | |
3392 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3393 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3394 value = (char*)Tcl_GetByteArrayFromObj(objv[3], &bytes); | |
3395 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; | |
3396 | |
3397 rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); | |
3398 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3399 if( rc!=SQLITE_OK ){ | |
3400 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
3401 return TCL_ERROR; | |
3402 } | |
3403 | |
3404 return TCL_OK; | |
3405 } | |
3406 | |
3407 /* | |
3408 ** Usage: sqlite3_bind_text16 ?-static? STMT N STRING BYTES | |
3409 ** | |
3410 ** Test the sqlite3_bind_text16 interface. STMT is a prepared statement. | |
3411 ** N is the index of a wildcard in the prepared statement. This command | |
3412 ** binds a UTF-16 string STRING to the wildcard. The string is BYTES bytes | |
3413 ** long. | |
3414 */ | |
3415 static int test_bind_text16( | |
3416 void * clientData, | |
3417 Tcl_Interp *interp, | |
3418 int objc, | |
3419 Tcl_Obj *CONST objv[] | |
3420 ){ | |
3421 #ifndef SQLITE_OMIT_UTF16 | |
3422 sqlite3_stmt *pStmt; | |
3423 int idx; | |
3424 int bytes; | |
3425 char *value; | |
3426 int rc; | |
3427 | |
3428 void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT); | |
3429 Tcl_Obj *oStmt = objv[objc-4]; | |
3430 Tcl_Obj *oN = objv[objc-3]; | |
3431 Tcl_Obj *oString = objv[objc-2]; | |
3432 Tcl_Obj *oBytes = objv[objc-1]; | |
3433 | |
3434 if( objc!=5 && objc!=6){ | |
3435 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3436 Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); | |
3437 return TCL_ERROR; | |
3438 } | |
3439 | |
3440 if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR; | |
3441 if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR; | |
3442 value = (char*)Tcl_GetByteArrayFromObj(oString, 0); | |
3443 if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR; | |
3444 | |
3445 rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); | |
3446 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3447 if( rc!=SQLITE_OK ){ | |
3448 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
3449 return TCL_ERROR; | |
3450 } | |
3451 | |
3452 #endif /* SQLITE_OMIT_UTF16 */ | |
3453 return TCL_OK; | |
3454 } | |
3455 | |
3456 /* | |
3457 ** Usage: sqlite3_bind_blob ?-static? STMT N DATA BYTES | |
3458 ** | |
3459 ** Test the sqlite3_bind_blob interface. STMT is a prepared statement. | |
3460 ** N is the index of a wildcard in the prepared statement. This command | |
3461 ** binds a BLOB to the wildcard. The BLOB is BYTES bytes in size. | |
3462 */ | |
3463 static int test_bind_blob( | |
3464 void * clientData, | |
3465 Tcl_Interp *interp, | |
3466 int objc, | |
3467 Tcl_Obj *CONST objv[] | |
3468 ){ | |
3469 sqlite3_stmt *pStmt; | |
3470 int idx; | |
3471 int bytes; | |
3472 char *value; | |
3473 int rc; | |
3474 sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT; | |
3475 | |
3476 if( objc!=5 && objc!=6 ){ | |
3477 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3478 Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0); | |
3479 return TCL_ERROR; | |
3480 } | |
3481 | |
3482 if( objc==6 ){ | |
3483 xDestructor = SQLITE_STATIC; | |
3484 objv++; | |
3485 } | |
3486 | |
3487 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3488 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | |
3489 value = Tcl_GetString(objv[3]); | |
3490 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; | |
3491 | |
3492 rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor); | |
3493 if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; | |
3494 if( rc!=SQLITE_OK ){ | |
3495 return TCL_ERROR; | |
3496 } | |
3497 | |
3498 return TCL_OK; | |
3499 } | |
3500 | |
3501 /* | |
3502 ** Usage: sqlite3_bind_parameter_count STMT | |
3503 ** | |
3504 ** Return the number of wildcards in the given statement. | |
3505 */ | |
3506 static int test_bind_parameter_count( | |
3507 void * clientData, | |
3508 Tcl_Interp *interp, | |
3509 int objc, | |
3510 Tcl_Obj *CONST objv[] | |
3511 ){ | |
3512 sqlite3_stmt *pStmt; | |
3513 | |
3514 if( objc!=2 ){ | |
3515 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); | |
3516 return TCL_ERROR; | |
3517 } | |
3518 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3519 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_bind_parameter_count(pStmt))); | |
3520 return TCL_OK; | |
3521 } | |
3522 | |
3523 /* | |
3524 ** Usage: sqlite3_bind_parameter_name STMT N | |
3525 ** | |
3526 ** Return the name of the Nth wildcard. The first wildcard is 1. | |
3527 ** An empty string is returned if N is out of range or if the wildcard | |
3528 ** is nameless. | |
3529 */ | |
3530 static int test_bind_parameter_name( | |
3531 void * clientData, | |
3532 Tcl_Interp *interp, | |
3533 int objc, | |
3534 Tcl_Obj *CONST objv[] | |
3535 ){ | |
3536 sqlite3_stmt *pStmt; | |
3537 int i; | |
3538 | |
3539 if( objc!=3 ){ | |
3540 Tcl_WrongNumArgs(interp, 1, objv, "STMT N"); | |
3541 return TCL_ERROR; | |
3542 } | |
3543 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3544 if( Tcl_GetIntFromObj(interp, objv[2], &i) ) return TCL_ERROR; | |
3545 Tcl_SetObjResult(interp, | |
3546 Tcl_NewStringObj(sqlite3_bind_parameter_name(pStmt,i),-1) | |
3547 ); | |
3548 return TCL_OK; | |
3549 } | |
3550 | |
3551 /* | |
3552 ** Usage: sqlite3_bind_parameter_index STMT NAME | |
3553 ** | |
3554 ** Return the index of the wildcard called NAME. Return 0 if there is | |
3555 ** no such wildcard. | |
3556 */ | |
3557 static int test_bind_parameter_index( | |
3558 void * clientData, | |
3559 Tcl_Interp *interp, | |
3560 int objc, | |
3561 Tcl_Obj *CONST objv[] | |
3562 ){ | |
3563 sqlite3_stmt *pStmt; | |
3564 | |
3565 if( objc!=3 ){ | |
3566 Tcl_WrongNumArgs(interp, 1, objv, "STMT NAME"); | |
3567 return TCL_ERROR; | |
3568 } | |
3569 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3570 Tcl_SetObjResult(interp, | |
3571 Tcl_NewIntObj( | |
3572 sqlite3_bind_parameter_index(pStmt,Tcl_GetString(objv[2])) | |
3573 ) | |
3574 ); | |
3575 return TCL_OK; | |
3576 } | |
3577 | |
3578 /* | |
3579 ** Usage: sqlite3_clear_bindings STMT | |
3580 ** | |
3581 */ | |
3582 static int test_clear_bindings( | |
3583 void * clientData, | |
3584 Tcl_Interp *interp, | |
3585 int objc, | |
3586 Tcl_Obj *CONST objv[] | |
3587 ){ | |
3588 sqlite3_stmt *pStmt; | |
3589 | |
3590 if( objc!=2 ){ | |
3591 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); | |
3592 return TCL_ERROR; | |
3593 } | |
3594 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
3595 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt))); | |
3596 return TCL_OK; | |
3597 } | |
3598 | |
3599 /* | |
3600 ** Usage: sqlite3_sleep MILLISECONDS | |
3601 */ | |
3602 static int test_sleep( | |
3603 void * clientData, | |
3604 Tcl_Interp *interp, | |
3605 int objc, | |
3606 Tcl_Obj *CONST objv[] | |
3607 ){ | |
3608 int ms; | |
3609 | |
3610 if( objc!=2 ){ | |
3611 Tcl_WrongNumArgs(interp, 1, objv, "MILLISECONDS"); | |
3612 return TCL_ERROR; | |
3613 } | |
3614 if( Tcl_GetIntFromObj(interp, objv[1], &ms) ){ | |
3615 return TCL_ERROR; | |
3616 } | |
3617 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(ms))); | |
3618 return TCL_OK; | |
3619 } | |
3620 | |
3621 /* | |
3622 ** Usage: sqlite3_extended_errcode DB | |
3623 ** | |
3624 ** Return the string representation of the most recent sqlite3_* API | |
3625 ** error code. e.g. "SQLITE_ERROR". | |
3626 */ | |
3627 static int test_ex_errcode( | |
3628 void * clientData, | |
3629 Tcl_Interp *interp, | |
3630 int objc, | |
3631 Tcl_Obj *CONST objv[] | |
3632 ){ | |
3633 sqlite3 *db; | |
3634 int rc; | |
3635 | |
3636 if( objc!=2 ){ | |
3637 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3638 Tcl_GetString(objv[0]), " DB", 0); | |
3639 return TCL_ERROR; | |
3640 } | |
3641 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3642 rc = sqlite3_extended_errcode(db); | |
3643 Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0); | |
3644 return TCL_OK; | |
3645 } | |
3646 | |
3647 | |
3648 /* | |
3649 ** Usage: sqlite3_errcode DB | |
3650 ** | |
3651 ** Return the string representation of the most recent sqlite3_* API | |
3652 ** error code. e.g. "SQLITE_ERROR". | |
3653 */ | |
3654 static int test_errcode( | |
3655 void * clientData, | |
3656 Tcl_Interp *interp, | |
3657 int objc, | |
3658 Tcl_Obj *CONST objv[] | |
3659 ){ | |
3660 sqlite3 *db; | |
3661 int rc; | |
3662 | |
3663 if( objc!=2 ){ | |
3664 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3665 Tcl_GetString(objv[0]), " DB", 0); | |
3666 return TCL_ERROR; | |
3667 } | |
3668 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3669 rc = sqlite3_errcode(db); | |
3670 Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0); | |
3671 return TCL_OK; | |
3672 } | |
3673 | |
3674 /* | |
3675 ** Usage: sqlite3_errmsg DB | |
3676 ** | |
3677 ** Returns the UTF-8 representation of the error message string for the | |
3678 ** most recent sqlite3_* API call. | |
3679 */ | |
3680 static int test_errmsg( | |
3681 void * clientData, | |
3682 Tcl_Interp *interp, | |
3683 int objc, | |
3684 Tcl_Obj *CONST objv[] | |
3685 ){ | |
3686 sqlite3 *db; | |
3687 const char *zErr; | |
3688 | |
3689 if( objc!=2 ){ | |
3690 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3691 Tcl_GetString(objv[0]), " DB", 0); | |
3692 return TCL_ERROR; | |
3693 } | |
3694 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3695 | |
3696 zErr = sqlite3_errmsg(db); | |
3697 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); | |
3698 return TCL_OK; | |
3699 } | |
3700 | |
3701 /* | |
3702 ** Usage: test_errmsg16 DB | |
3703 ** | |
3704 ** Returns the UTF-16 representation of the error message string for the | |
3705 ** most recent sqlite3_* API call. This is a byte array object at the TCL | |
3706 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the | |
3707 ** UTF-16 string. | |
3708 */ | |
3709 static int test_errmsg16( | |
3710 void * clientData, | |
3711 Tcl_Interp *interp, | |
3712 int objc, | |
3713 Tcl_Obj *CONST objv[] | |
3714 ){ | |
3715 #ifndef SQLITE_OMIT_UTF16 | |
3716 sqlite3 *db; | |
3717 const void *zErr; | |
3718 const char *z; | |
3719 int bytes = 0; | |
3720 | |
3721 if( objc!=2 ){ | |
3722 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3723 Tcl_GetString(objv[0]), " DB", 0); | |
3724 return TCL_ERROR; | |
3725 } | |
3726 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3727 | |
3728 zErr = sqlite3_errmsg16(db); | |
3729 if( zErr ){ | |
3730 z = zErr; | |
3731 for(bytes=0; z[bytes] || z[bytes+1]; bytes+=2){} | |
3732 } | |
3733 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); | |
3734 #endif /* SQLITE_OMIT_UTF16 */ | |
3735 return TCL_OK; | |
3736 } | |
3737 | |
3738 /* | |
3739 ** Usage: sqlite3_prepare DB sql bytes ?tailvar? | |
3740 ** | |
3741 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using | |
3742 ** database handle <DB>. The parameter <tailval> is the name of a global | |
3743 ** variable that is set to the unused portion of <sql> (if any). A | |
3744 ** STMT handle is returned. | |
3745 */ | |
3746 static int test_prepare( | |
3747 void * clientData, | |
3748 Tcl_Interp *interp, | |
3749 int objc, | |
3750 Tcl_Obj *CONST objv[] | |
3751 ){ | |
3752 sqlite3 *db; | |
3753 const char *zSql; | |
3754 int bytes; | |
3755 const char *zTail = 0; | |
3756 sqlite3_stmt *pStmt = 0; | |
3757 char zBuf[50]; | |
3758 int rc; | |
3759 | |
3760 if( objc!=5 && objc!=4 ){ | |
3761 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3762 Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0); | |
3763 return TCL_ERROR; | |
3764 } | |
3765 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3766 zSql = Tcl_GetString(objv[2]); | |
3767 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; | |
3768 | |
3769 rc = sqlite3_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); | |
3770 Tcl_ResetResult(interp); | |
3771 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
3772 if( zTail && objc>=5 ){ | |
3773 if( bytes>=0 ){ | |
3774 bytes = bytes - (int)(zTail-zSql); | |
3775 } | |
3776 if( (int)strlen(zTail)<bytes ){ | |
3777 bytes = (int)strlen(zTail); | |
3778 } | |
3779 Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); | |
3780 } | |
3781 if( rc!=SQLITE_OK ){ | |
3782 assert( pStmt==0 ); | |
3783 sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc); | |
3784 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); | |
3785 return TCL_ERROR; | |
3786 } | |
3787 | |
3788 if( pStmt ){ | |
3789 if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; | |
3790 Tcl_AppendResult(interp, zBuf, 0); | |
3791 } | |
3792 return TCL_OK; | |
3793 } | |
3794 | |
3795 /* | |
3796 ** Usage: sqlite3_prepare_v2 DB sql bytes ?tailvar? | |
3797 ** | |
3798 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using | |
3799 ** database handle <DB>. The parameter <tailval> is the name of a global | |
3800 ** variable that is set to the unused portion of <sql> (if any). A | |
3801 ** STMT handle is returned. | |
3802 */ | |
3803 static int test_prepare_v2( | |
3804 void * clientData, | |
3805 Tcl_Interp *interp, | |
3806 int objc, | |
3807 Tcl_Obj *CONST objv[] | |
3808 ){ | |
3809 sqlite3 *db; | |
3810 const char *zSql; | |
3811 char *zCopy = 0; /* malloc() copy of zSql */ | |
3812 int bytes; | |
3813 const char *zTail = 0; | |
3814 sqlite3_stmt *pStmt = 0; | |
3815 char zBuf[50]; | |
3816 int rc; | |
3817 | |
3818 if( objc!=5 && objc!=4 ){ | |
3819 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3820 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); | |
3821 return TCL_ERROR; | |
3822 } | |
3823 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3824 zSql = Tcl_GetString(objv[2]); | |
3825 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; | |
3826 | |
3827 /* Instead of using zSql directly, make a copy into a buffer obtained | |
3828 ** directly from malloc(). The idea is to make it easier for valgrind | |
3829 ** to spot buffer overreads. */ | |
3830 if( bytes>=0 ){ | |
3831 zCopy = malloc(bytes); | |
3832 memcpy(zCopy, zSql, bytes); | |
3833 }else{ | |
3834 int n = (int)strlen(zSql) + 1; | |
3835 zCopy = malloc(n); | |
3836 memcpy(zCopy, zSql, n); | |
3837 } | |
3838 rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0); | |
3839 free(zCopy); | |
3840 zTail = &zSql[(zTail - zCopy)]; | |
3841 | |
3842 assert(rc==SQLITE_OK || pStmt==0); | |
3843 Tcl_ResetResult(interp); | |
3844 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
3845 if( rc==SQLITE_OK && zTail && objc>=5 ){ | |
3846 if( bytes>=0 ){ | |
3847 bytes = bytes - (int)(zTail-zSql); | |
3848 } | |
3849 Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); | |
3850 } | |
3851 if( rc!=SQLITE_OK ){ | |
3852 assert( pStmt==0 ); | |
3853 sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc); | |
3854 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); | |
3855 return TCL_ERROR; | |
3856 } | |
3857 | |
3858 if( pStmt ){ | |
3859 if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; | |
3860 Tcl_AppendResult(interp, zBuf, 0); | |
3861 } | |
3862 return TCL_OK; | |
3863 } | |
3864 | |
3865 /* | |
3866 ** Usage: sqlite3_prepare_tkt3134 DB | |
3867 ** | |
3868 ** Generate a prepared statement for a zero-byte string as a test | |
3869 ** for ticket #3134. The string should be preceded by a zero byte. | |
3870 */ | |
3871 static int test_prepare_tkt3134( | |
3872 void * clientData, | |
3873 Tcl_Interp *interp, | |
3874 int objc, | |
3875 Tcl_Obj *CONST objv[] | |
3876 ){ | |
3877 sqlite3 *db; | |
3878 static const char zSql[] = "\000SELECT 1"; | |
3879 sqlite3_stmt *pStmt = 0; | |
3880 char zBuf[50]; | |
3881 int rc; | |
3882 | |
3883 if( objc!=2 ){ | |
3884 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3885 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); | |
3886 return TCL_ERROR; | |
3887 } | |
3888 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3889 rc = sqlite3_prepare_v2(db, &zSql[1], 0, &pStmt, 0); | |
3890 assert(rc==SQLITE_OK || pStmt==0); | |
3891 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
3892 if( rc!=SQLITE_OK ){ | |
3893 assert( pStmt==0 ); | |
3894 sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc); | |
3895 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); | |
3896 return TCL_ERROR; | |
3897 } | |
3898 | |
3899 if( pStmt ){ | |
3900 if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; | |
3901 Tcl_AppendResult(interp, zBuf, 0); | |
3902 } | |
3903 return TCL_OK; | |
3904 } | |
3905 | |
3906 /* | |
3907 ** Usage: sqlite3_prepare16 DB sql bytes tailvar | |
3908 ** | |
3909 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using | |
3910 ** database handle <DB>. The parameter <tailval> is the name of a global | |
3911 ** variable that is set to the unused portion of <sql> (if any). A | |
3912 ** STMT handle is returned. | |
3913 */ | |
3914 static int test_prepare16( | |
3915 void * clientData, | |
3916 Tcl_Interp *interp, | |
3917 int objc, | |
3918 Tcl_Obj *CONST objv[] | |
3919 ){ | |
3920 #ifndef SQLITE_OMIT_UTF16 | |
3921 sqlite3 *db; | |
3922 const void *zSql; | |
3923 const void *zTail = 0; | |
3924 Tcl_Obj *pTail = 0; | |
3925 sqlite3_stmt *pStmt = 0; | |
3926 char zBuf[50]; | |
3927 int rc; | |
3928 int bytes; /* The integer specified as arg 3 */ | |
3929 int objlen; /* The byte-array length of arg 2 */ | |
3930 | |
3931 if( objc!=5 && objc!=4 ){ | |
3932 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3933 Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0); | |
3934 return TCL_ERROR; | |
3935 } | |
3936 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3937 zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); | |
3938 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; | |
3939 | |
3940 rc = sqlite3_prepare16(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); | |
3941 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
3942 if( rc ){ | |
3943 return TCL_ERROR; | |
3944 } | |
3945 | |
3946 if( objc>=5 ){ | |
3947 if( zTail ){ | |
3948 objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql); | |
3949 }else{ | |
3950 objlen = 0; | |
3951 } | |
3952 pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); | |
3953 Tcl_IncrRefCount(pTail); | |
3954 Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); | |
3955 Tcl_DecrRefCount(pTail); | |
3956 } | |
3957 | |
3958 if( pStmt ){ | |
3959 if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; | |
3960 } | |
3961 Tcl_AppendResult(interp, zBuf, 0); | |
3962 #endif /* SQLITE_OMIT_UTF16 */ | |
3963 return TCL_OK; | |
3964 } | |
3965 | |
3966 /* | |
3967 ** Usage: sqlite3_prepare16_v2 DB sql bytes ?tailvar? | |
3968 ** | |
3969 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using | |
3970 ** database handle <DB>. The parameter <tailval> is the name of a global | |
3971 ** variable that is set to the unused portion of <sql> (if any). A | |
3972 ** STMT handle is returned. | |
3973 */ | |
3974 static int test_prepare16_v2( | |
3975 void * clientData, | |
3976 Tcl_Interp *interp, | |
3977 int objc, | |
3978 Tcl_Obj *CONST objv[] | |
3979 ){ | |
3980 #ifndef SQLITE_OMIT_UTF16 | |
3981 sqlite3 *db; | |
3982 const void *zSql; | |
3983 const void *zTail = 0; | |
3984 Tcl_Obj *pTail = 0; | |
3985 sqlite3_stmt *pStmt = 0; | |
3986 char zBuf[50]; | |
3987 int rc; | |
3988 int bytes; /* The integer specified as arg 3 */ | |
3989 int objlen; /* The byte-array length of arg 2 */ | |
3990 | |
3991 if( objc!=5 && objc!=4 ){ | |
3992 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
3993 Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0); | |
3994 return TCL_ERROR; | |
3995 } | |
3996 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
3997 zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); | |
3998 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; | |
3999 | |
4000 rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); | |
4001 if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; | |
4002 if( rc ){ | |
4003 return TCL_ERROR; | |
4004 } | |
4005 | |
4006 if( objc>=5 ){ | |
4007 if( zTail ){ | |
4008 objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql); | |
4009 }else{ | |
4010 objlen = 0; | |
4011 } | |
4012 pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); | |
4013 Tcl_IncrRefCount(pTail); | |
4014 Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); | |
4015 Tcl_DecrRefCount(pTail); | |
4016 } | |
4017 | |
4018 if( pStmt ){ | |
4019 if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; | |
4020 } | |
4021 Tcl_AppendResult(interp, zBuf, 0); | |
4022 #endif /* SQLITE_OMIT_UTF16 */ | |
4023 return TCL_OK; | |
4024 } | |
4025 | |
4026 /* | |
4027 ** Usage: sqlite3_open filename ?options-list? | |
4028 */ | |
4029 static int test_open( | |
4030 void * clientData, | |
4031 Tcl_Interp *interp, | |
4032 int objc, | |
4033 Tcl_Obj *CONST objv[] | |
4034 ){ | |
4035 const char *zFilename; | |
4036 sqlite3 *db; | |
4037 char zBuf[100]; | |
4038 | |
4039 if( objc!=3 && objc!=2 && objc!=1 ){ | |
4040 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4041 Tcl_GetString(objv[0]), " filename options-list", 0); | |
4042 return TCL_ERROR; | |
4043 } | |
4044 | |
4045 zFilename = objc>1 ? Tcl_GetString(objv[1]) : 0; | |
4046 sqlite3_open(zFilename, &db); | |
4047 | |
4048 if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; | |
4049 Tcl_AppendResult(interp, zBuf, 0); | |
4050 return TCL_OK; | |
4051 } | |
4052 | |
4053 /* | |
4054 ** Usage: sqlite3_open_v2 FILENAME FLAGS VFS | |
4055 */ | |
4056 static int test_open_v2( | |
4057 void * clientData, | |
4058 Tcl_Interp *interp, | |
4059 int objc, | |
4060 Tcl_Obj *CONST objv[] | |
4061 ){ | |
4062 const char *zFilename; | |
4063 const char *zVfs; | |
4064 int flags = 0; | |
4065 sqlite3 *db; | |
4066 int rc; | |
4067 char zBuf[100]; | |
4068 | |
4069 int nFlag; | |
4070 Tcl_Obj **apFlag; | |
4071 int i; | |
4072 | |
4073 if( objc!=4 ){ | |
4074 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS"); | |
4075 return TCL_ERROR; | |
4076 } | |
4077 zFilename = Tcl_GetString(objv[1]); | |
4078 zVfs = Tcl_GetString(objv[3]); | |
4079 if( zVfs[0]==0x00 ) zVfs = 0; | |
4080 | |
4081 rc = Tcl_ListObjGetElements(interp, objv[2], &nFlag, &apFlag); | |
4082 if( rc!=TCL_OK ) return rc; | |
4083 for(i=0; i<nFlag; i++){ | |
4084 int iFlag; | |
4085 struct OpenFlag { | |
4086 const char *zFlag; | |
4087 int flag; | |
4088 } aFlag[] = { | |
4089 { "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY }, | |
4090 { "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE }, | |
4091 { "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE }, | |
4092 { "SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE }, | |
4093 { "SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE }, | |
4094 { "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY }, | |
4095 { "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB }, | |
4096 { "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB }, | |
4097 { "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB }, | |
4098 { "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL }, | |
4099 { "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL }, | |
4100 { "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL }, | |
4101 { "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL }, | |
4102 { "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX }, | |
4103 { "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX }, | |
4104 { "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE }, | |
4105 { "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE }, | |
4106 { "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL }, | |
4107 { "SQLITE_OPEN_URI", SQLITE_OPEN_URI }, | |
4108 { 0, 0 } | |
4109 }; | |
4110 rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]), | |
4111 "flag", 0, &iFlag | |
4112 ); | |
4113 if( rc!=TCL_OK ) return rc; | |
4114 flags |= aFlag[iFlag].flag; | |
4115 } | |
4116 | |
4117 rc = sqlite3_open_v2(zFilename, &db, flags, zVfs); | |
4118 if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; | |
4119 Tcl_AppendResult(interp, zBuf, 0); | |
4120 return TCL_OK; | |
4121 } | |
4122 | |
4123 /* | |
4124 ** Usage: sqlite3_open16 filename options | |
4125 */ | |
4126 static int test_open16( | |
4127 void * clientData, | |
4128 Tcl_Interp *interp, | |
4129 int objc, | |
4130 Tcl_Obj *CONST objv[] | |
4131 ){ | |
4132 #ifndef SQLITE_OMIT_UTF16 | |
4133 const void *zFilename; | |
4134 sqlite3 *db; | |
4135 char zBuf[100]; | |
4136 | |
4137 if( objc!=3 ){ | |
4138 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4139 Tcl_GetString(objv[0]), " filename options-list", 0); | |
4140 return TCL_ERROR; | |
4141 } | |
4142 | |
4143 zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); | |
4144 sqlite3_open16(zFilename, &db); | |
4145 | |
4146 if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; | |
4147 Tcl_AppendResult(interp, zBuf, 0); | |
4148 #endif /* SQLITE_OMIT_UTF16 */ | |
4149 return TCL_OK; | |
4150 } | |
4151 | |
4152 /* | |
4153 ** Usage: sqlite3_complete16 <UTF-16 string> | |
4154 ** | |
4155 ** Return 1 if the supplied argument is a complete SQL statement, or zero | |
4156 ** otherwise. | |
4157 */ | |
4158 static int test_complete16( | |
4159 void * clientData, | |
4160 Tcl_Interp *interp, | |
4161 int objc, | |
4162 Tcl_Obj *CONST objv[] | |
4163 ){ | |
4164 #if !defined(SQLITE_OMIT_COMPLETE) && !defined(SQLITE_OMIT_UTF16) | |
4165 char *zBuf; | |
4166 | |
4167 if( objc!=2 ){ | |
4168 Tcl_WrongNumArgs(interp, 1, objv, "<utf-16 sql>"); | |
4169 return TCL_ERROR; | |
4170 } | |
4171 | |
4172 zBuf = (char*)Tcl_GetByteArrayFromObj(objv[1], 0); | |
4173 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf))); | |
4174 #endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */ | |
4175 return TCL_OK; | |
4176 } | |
4177 | |
4178 /* | |
4179 ** Usage: sqlite3_step STMT | |
4180 ** | |
4181 ** Advance the statement to the next row. | |
4182 */ | |
4183 static int test_step( | |
4184 void * clientData, | |
4185 Tcl_Interp *interp, | |
4186 int objc, | |
4187 Tcl_Obj *CONST objv[] | |
4188 ){ | |
4189 sqlite3_stmt *pStmt; | |
4190 int rc; | |
4191 | |
4192 if( objc!=2 ){ | |
4193 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4194 Tcl_GetString(objv[0]), " STMT", 0); | |
4195 return TCL_ERROR; | |
4196 } | |
4197 | |
4198 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4199 rc = sqlite3_step(pStmt); | |
4200 | |
4201 /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */ | |
4202 Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); | |
4203 return TCL_OK; | |
4204 } | |
4205 | |
4206 static int test_sql( | |
4207 void * clientData, | |
4208 Tcl_Interp *interp, | |
4209 int objc, | |
4210 Tcl_Obj *CONST objv[] | |
4211 ){ | |
4212 sqlite3_stmt *pStmt; | |
4213 | |
4214 if( objc!=2 ){ | |
4215 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); | |
4216 return TCL_ERROR; | |
4217 } | |
4218 | |
4219 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4220 Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE); | |
4221 return TCL_OK; | |
4222 } | |
4223 | |
4224 /* | |
4225 ** Usage: sqlite3_column_count STMT | |
4226 ** | |
4227 ** Return the number of columns returned by the sql statement STMT. | |
4228 */ | |
4229 static int test_column_count( | |
4230 void * clientData, | |
4231 Tcl_Interp *interp, | |
4232 int objc, | |
4233 Tcl_Obj *CONST objv[] | |
4234 ){ | |
4235 sqlite3_stmt *pStmt; | |
4236 | |
4237 if( objc!=2 ){ | |
4238 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4239 Tcl_GetString(objv[0]), " STMT column", 0); | |
4240 return TCL_ERROR; | |
4241 } | |
4242 | |
4243 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4244 | |
4245 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt))); | |
4246 return TCL_OK; | |
4247 } | |
4248 | |
4249 /* | |
4250 ** Usage: sqlite3_column_type STMT column | |
4251 ** | |
4252 ** Return the type of the data in column 'column' of the current row. | |
4253 */ | |
4254 static int test_column_type( | |
4255 void * clientData, | |
4256 Tcl_Interp *interp, | |
4257 int objc, | |
4258 Tcl_Obj *CONST objv[] | |
4259 ){ | |
4260 sqlite3_stmt *pStmt; | |
4261 int col; | |
4262 int tp; | |
4263 | |
4264 if( objc!=3 ){ | |
4265 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4266 Tcl_GetString(objv[0]), " STMT column", 0); | |
4267 return TCL_ERROR; | |
4268 } | |
4269 | |
4270 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4271 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4272 | |
4273 tp = sqlite3_column_type(pStmt, col); | |
4274 switch( tp ){ | |
4275 case SQLITE_INTEGER: | |
4276 Tcl_SetResult(interp, "INTEGER", TCL_STATIC); | |
4277 break; | |
4278 case SQLITE_NULL: | |
4279 Tcl_SetResult(interp, "NULL", TCL_STATIC); | |
4280 break; | |
4281 case SQLITE_FLOAT: | |
4282 Tcl_SetResult(interp, "FLOAT", TCL_STATIC); | |
4283 break; | |
4284 case SQLITE_TEXT: | |
4285 Tcl_SetResult(interp, "TEXT", TCL_STATIC); | |
4286 break; | |
4287 case SQLITE_BLOB: | |
4288 Tcl_SetResult(interp, "BLOB", TCL_STATIC); | |
4289 break; | |
4290 default: | |
4291 assert(0); | |
4292 } | |
4293 | |
4294 return TCL_OK; | |
4295 } | |
4296 | |
4297 /* | |
4298 ** Usage: sqlite3_column_int64 STMT column | |
4299 ** | |
4300 ** Return the data in column 'column' of the current row cast as an | |
4301 ** wide (64-bit) integer. | |
4302 */ | |
4303 static int test_column_int64( | |
4304 void * clientData, | |
4305 Tcl_Interp *interp, | |
4306 int objc, | |
4307 Tcl_Obj *CONST objv[] | |
4308 ){ | |
4309 sqlite3_stmt *pStmt; | |
4310 int col; | |
4311 i64 iVal; | |
4312 | |
4313 if( objc!=3 ){ | |
4314 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4315 Tcl_GetString(objv[0]), " STMT column", 0); | |
4316 return TCL_ERROR; | |
4317 } | |
4318 | |
4319 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4320 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4321 | |
4322 iVal = sqlite3_column_int64(pStmt, col); | |
4323 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal)); | |
4324 return TCL_OK; | |
4325 } | |
4326 | |
4327 /* | |
4328 ** Usage: sqlite3_column_blob STMT column | |
4329 */ | |
4330 static int test_column_blob( | |
4331 void * clientData, | |
4332 Tcl_Interp *interp, | |
4333 int objc, | |
4334 Tcl_Obj *CONST objv[] | |
4335 ){ | |
4336 sqlite3_stmt *pStmt; | |
4337 int col; | |
4338 | |
4339 int len; | |
4340 const void *pBlob; | |
4341 | |
4342 if( objc!=3 ){ | |
4343 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4344 Tcl_GetString(objv[0]), " STMT column", 0); | |
4345 return TCL_ERROR; | |
4346 } | |
4347 | |
4348 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4349 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4350 | |
4351 len = sqlite3_column_bytes(pStmt, col); | |
4352 pBlob = sqlite3_column_blob(pStmt, col); | |
4353 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len)); | |
4354 return TCL_OK; | |
4355 } | |
4356 | |
4357 /* | |
4358 ** Usage: sqlite3_column_double STMT column | |
4359 ** | |
4360 ** Return the data in column 'column' of the current row cast as a double. | |
4361 */ | |
4362 static int test_column_double( | |
4363 void * clientData, | |
4364 Tcl_Interp *interp, | |
4365 int objc, | |
4366 Tcl_Obj *CONST objv[] | |
4367 ){ | |
4368 sqlite3_stmt *pStmt; | |
4369 int col; | |
4370 double rVal; | |
4371 | |
4372 if( objc!=3 ){ | |
4373 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4374 Tcl_GetString(objv[0]), " STMT column", 0); | |
4375 return TCL_ERROR; | |
4376 } | |
4377 | |
4378 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4379 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4380 | |
4381 rVal = sqlite3_column_double(pStmt, col); | |
4382 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal)); | |
4383 return TCL_OK; | |
4384 } | |
4385 | |
4386 /* | |
4387 ** Usage: sqlite3_data_count STMT | |
4388 ** | |
4389 ** Return the number of columns returned by the sql statement STMT. | |
4390 */ | |
4391 static int test_data_count( | |
4392 void * clientData, | |
4393 Tcl_Interp *interp, | |
4394 int objc, | |
4395 Tcl_Obj *CONST objv[] | |
4396 ){ | |
4397 sqlite3_stmt *pStmt; | |
4398 | |
4399 if( objc!=2 ){ | |
4400 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4401 Tcl_GetString(objv[0]), " STMT column", 0); | |
4402 return TCL_ERROR; | |
4403 } | |
4404 | |
4405 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4406 | |
4407 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt))); | |
4408 return TCL_OK; | |
4409 } | |
4410 | |
4411 /* | |
4412 ** Usage: sqlite3_column_text STMT column | |
4413 ** | |
4414 ** Usage: sqlite3_column_decltype STMT column | |
4415 ** | |
4416 ** Usage: sqlite3_column_name STMT column | |
4417 */ | |
4418 static int test_stmt_utf8( | |
4419 void * clientData, /* Pointer to SQLite API function to be invoke */ | |
4420 Tcl_Interp *interp, | |
4421 int objc, | |
4422 Tcl_Obj *CONST objv[] | |
4423 ){ | |
4424 sqlite3_stmt *pStmt; | |
4425 int col; | |
4426 const char *(*xFunc)(sqlite3_stmt*, int); | |
4427 const char *zRet; | |
4428 | |
4429 xFunc = (const char *(*)(sqlite3_stmt*, int))clientData; | |
4430 if( objc!=3 ){ | |
4431 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4432 Tcl_GetString(objv[0]), " STMT column", 0); | |
4433 return TCL_ERROR; | |
4434 } | |
4435 | |
4436 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4437 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4438 zRet = xFunc(pStmt, col); | |
4439 if( zRet ){ | |
4440 Tcl_SetResult(interp, (char *)zRet, 0); | |
4441 } | |
4442 return TCL_OK; | |
4443 } | |
4444 | |
4445 static int test_global_recover( | |
4446 void * clientData, | |
4447 Tcl_Interp *interp, | |
4448 int objc, | |
4449 Tcl_Obj *CONST objv[] | |
4450 ){ | |
4451 #ifndef SQLITE_OMIT_DEPRECATED | |
4452 int rc; | |
4453 if( objc!=1 ){ | |
4454 Tcl_WrongNumArgs(interp, 1, objv, ""); | |
4455 return TCL_ERROR; | |
4456 } | |
4457 rc = sqlite3_global_recover(); | |
4458 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
4459 #endif | |
4460 return TCL_OK; | |
4461 } | |
4462 | |
4463 /* | |
4464 ** Usage: sqlite3_column_text STMT column | |
4465 ** | |
4466 ** Usage: sqlite3_column_decltype STMT column | |
4467 ** | |
4468 ** Usage: sqlite3_column_name STMT column | |
4469 */ | |
4470 static int test_stmt_utf16( | |
4471 void * clientData, /* Pointer to SQLite API function to be invoked */ | |
4472 Tcl_Interp *interp, | |
4473 int objc, | |
4474 Tcl_Obj *CONST objv[] | |
4475 ){ | |
4476 #ifndef SQLITE_OMIT_UTF16 | |
4477 sqlite3_stmt *pStmt; | |
4478 int col; | |
4479 Tcl_Obj *pRet; | |
4480 const void *zName16; | |
4481 const void *(*xFunc)(sqlite3_stmt*, int); | |
4482 | |
4483 xFunc = (const void *(*)(sqlite3_stmt*, int))clientData; | |
4484 if( objc!=3 ){ | |
4485 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4486 Tcl_GetString(objv[0]), " STMT column", 0); | |
4487 return TCL_ERROR; | |
4488 } | |
4489 | |
4490 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4491 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4492 | |
4493 zName16 = xFunc(pStmt, col); | |
4494 if( zName16 ){ | |
4495 int n; | |
4496 const char *z = zName16; | |
4497 for(n=0; z[n] || z[n+1]; n+=2){} | |
4498 pRet = Tcl_NewByteArrayObj(zName16, n+2); | |
4499 Tcl_SetObjResult(interp, pRet); | |
4500 } | |
4501 #endif /* SQLITE_OMIT_UTF16 */ | |
4502 | |
4503 return TCL_OK; | |
4504 } | |
4505 | |
4506 /* | |
4507 ** Usage: sqlite3_column_int STMT column | |
4508 ** | |
4509 ** Usage: sqlite3_column_bytes STMT column | |
4510 ** | |
4511 ** Usage: sqlite3_column_bytes16 STMT column | |
4512 ** | |
4513 */ | |
4514 static int test_stmt_int( | |
4515 void * clientData, /* Pointer to SQLite API function to be invoked */ | |
4516 Tcl_Interp *interp, | |
4517 int objc, | |
4518 Tcl_Obj *CONST objv[] | |
4519 ){ | |
4520 sqlite3_stmt *pStmt; | |
4521 int col; | |
4522 int (*xFunc)(sqlite3_stmt*, int); | |
4523 | |
4524 xFunc = (int (*)(sqlite3_stmt*, int))clientData; | |
4525 if( objc!=3 ){ | |
4526 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4527 Tcl_GetString(objv[0]), " STMT column", 0); | |
4528 return TCL_ERROR; | |
4529 } | |
4530 | |
4531 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
4532 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | |
4533 | |
4534 Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col))); | |
4535 return TCL_OK; | |
4536 } | |
4537 | |
4538 /* | |
4539 ** Usage: sqlite_set_magic DB MAGIC-NUMBER | |
4540 ** | |
4541 ** Set the db->magic value. This is used to test error recovery logic. | |
4542 */ | |
4543 static int sqlite_set_magic( | |
4544 void * clientData, | |
4545 Tcl_Interp *interp, | |
4546 int argc, | |
4547 char **argv | |
4548 ){ | |
4549 sqlite3 *db; | |
4550 if( argc!=3 ){ | |
4551 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
4552 " DB MAGIC", 0); | |
4553 return TCL_ERROR; | |
4554 } | |
4555 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4556 if( strcmp(argv[2], "SQLITE_MAGIC_OPEN")==0 ){ | |
4557 db->magic = SQLITE_MAGIC_OPEN; | |
4558 }else if( strcmp(argv[2], "SQLITE_MAGIC_CLOSED")==0 ){ | |
4559 db->magic = SQLITE_MAGIC_CLOSED; | |
4560 }else if( strcmp(argv[2], "SQLITE_MAGIC_BUSY")==0 ){ | |
4561 db->magic = SQLITE_MAGIC_BUSY; | |
4562 }else if( strcmp(argv[2], "SQLITE_MAGIC_ERROR")==0 ){ | |
4563 db->magic = SQLITE_MAGIC_ERROR; | |
4564 }else if( Tcl_GetInt(interp, argv[2], (int*)&db->magic) ){ | |
4565 return TCL_ERROR; | |
4566 } | |
4567 return TCL_OK; | |
4568 } | |
4569 | |
4570 /* | |
4571 ** Usage: sqlite3_interrupt DB | |
4572 ** | |
4573 ** Trigger an interrupt on DB | |
4574 */ | |
4575 static int test_interrupt( | |
4576 void * clientData, | |
4577 Tcl_Interp *interp, | |
4578 int argc, | |
4579 char **argv | |
4580 ){ | |
4581 sqlite3 *db; | |
4582 if( argc!=2 ){ | |
4583 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0); | |
4584 return TCL_ERROR; | |
4585 } | |
4586 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4587 sqlite3_interrupt(db); | |
4588 return TCL_OK; | |
4589 } | |
4590 | |
4591 static u8 *sqlite3_stack_baseline = 0; | |
4592 | |
4593 /* | |
4594 ** Fill the stack with a known bitpattern. | |
4595 */ | |
4596 static void prepStack(void){ | |
4597 int i; | |
4598 u32 bigBuf[65536]; | |
4599 for(i=0; i<sizeof(bigBuf)/sizeof(bigBuf[0]); i++) bigBuf[i] = 0xdeadbeef; | |
4600 sqlite3_stack_baseline = (u8*)&bigBuf[65536]; | |
4601 } | |
4602 | |
4603 /* | |
4604 ** Get the current stack depth. Used for debugging only. | |
4605 */ | |
4606 u64 sqlite3StackDepth(void){ | |
4607 u8 x; | |
4608 return (u64)(sqlite3_stack_baseline - &x); | |
4609 } | |
4610 | |
4611 /* | |
4612 ** Usage: sqlite3_stack_used DB SQL | |
4613 ** | |
4614 ** Try to measure the amount of stack space used by a call to sqlite3_exec | |
4615 */ | |
4616 static int test_stack_used( | |
4617 void * clientData, | |
4618 Tcl_Interp *interp, | |
4619 int argc, | |
4620 char **argv | |
4621 ){ | |
4622 sqlite3 *db; | |
4623 int i; | |
4624 if( argc!=3 ){ | |
4625 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
4626 " DB SQL", 0); | |
4627 return TCL_ERROR; | |
4628 } | |
4629 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4630 prepStack(); | |
4631 (void)sqlite3_exec(db, argv[2], 0, 0, 0); | |
4632 for(i=65535; i>=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){} | |
4633 Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4)); | |
4634 return TCL_OK; | |
4635 } | |
4636 | |
4637 /* | |
4638 ** Usage: sqlite_delete_function DB function-name | |
4639 ** | |
4640 ** Delete the user function 'function-name' from database handle DB. It | |
4641 ** is assumed that the user function was created as UTF8, any number of | |
4642 ** arguments (the way the TCL interface does it). | |
4643 */ | |
4644 static int delete_function( | |
4645 void * clientData, | |
4646 Tcl_Interp *interp, | |
4647 int argc, | |
4648 char **argv | |
4649 ){ | |
4650 int rc; | |
4651 sqlite3 *db; | |
4652 if( argc!=3 ){ | |
4653 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
4654 " DB function-name", 0); | |
4655 return TCL_ERROR; | |
4656 } | |
4657 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4658 rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0); | |
4659 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
4660 return TCL_OK; | |
4661 } | |
4662 | |
4663 /* | |
4664 ** Usage: sqlite_delete_collation DB collation-name | |
4665 ** | |
4666 ** Delete the collation sequence 'collation-name' from database handle | |
4667 ** DB. It is assumed that the collation sequence was created as UTF8 (the | |
4668 ** way the TCL interface does it). | |
4669 */ | |
4670 static int delete_collation( | |
4671 void * clientData, | |
4672 Tcl_Interp *interp, | |
4673 int argc, | |
4674 char **argv | |
4675 ){ | |
4676 int rc; | |
4677 sqlite3 *db; | |
4678 if( argc!=3 ){ | |
4679 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
4680 " DB function-name", 0); | |
4681 return TCL_ERROR; | |
4682 } | |
4683 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4684 rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0); | |
4685 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
4686 return TCL_OK; | |
4687 } | |
4688 | |
4689 /* | |
4690 ** Usage: sqlite3_get_autocommit DB | |
4691 ** | |
4692 ** Return true if the database DB is currently in auto-commit mode. | |
4693 ** Return false if not. | |
4694 */ | |
4695 static int get_autocommit( | |
4696 void * clientData, | |
4697 Tcl_Interp *interp, | |
4698 int argc, | |
4699 char **argv | |
4700 ){ | |
4701 char zBuf[30]; | |
4702 sqlite3 *db; | |
4703 if( argc!=2 ){ | |
4704 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
4705 " DB", 0); | |
4706 return TCL_ERROR; | |
4707 } | |
4708 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4709 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3_get_autocommit(db)); | |
4710 Tcl_AppendResult(interp, zBuf, 0); | |
4711 return TCL_OK; | |
4712 } | |
4713 | |
4714 /* | |
4715 ** Usage: sqlite3_busy_timeout DB MS | |
4716 ** | |
4717 ** Set the busy timeout. This is more easily done using the timeout | |
4718 ** method of the TCL interface. But we need a way to test the case | |
4719 ** where it returns SQLITE_MISUSE. | |
4720 */ | |
4721 static int test_busy_timeout( | |
4722 void * clientData, | |
4723 Tcl_Interp *interp, | |
4724 int argc, | |
4725 char **argv | |
4726 ){ | |
4727 int rc, ms; | |
4728 sqlite3 *db; | |
4729 if( argc!=3 ){ | |
4730 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
4731 " DB", 0); | |
4732 return TCL_ERROR; | |
4733 } | |
4734 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; | |
4735 if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR; | |
4736 rc = sqlite3_busy_timeout(db, ms); | |
4737 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
4738 return TCL_OK; | |
4739 } | |
4740 | |
4741 /* | |
4742 ** Usage: tcl_variable_type VARIABLENAME | |
4743 ** | |
4744 ** Return the name of the internal representation for the | |
4745 ** value of the given variable. | |
4746 */ | |
4747 static int tcl_variable_type( | |
4748 void * clientData, | |
4749 Tcl_Interp *interp, | |
4750 int objc, | |
4751 Tcl_Obj *CONST objv[] | |
4752 ){ | |
4753 Tcl_Obj *pVar; | |
4754 if( objc!=2 ){ | |
4755 Tcl_WrongNumArgs(interp, 1, objv, "VARIABLE"); | |
4756 return TCL_ERROR; | |
4757 } | |
4758 pVar = Tcl_GetVar2Ex(interp, Tcl_GetString(objv[1]), 0, TCL_LEAVE_ERR_MSG); | |
4759 if( pVar==0 ) return TCL_ERROR; | |
4760 if( pVar->typePtr ){ | |
4761 Tcl_SetObjResult(interp, Tcl_NewStringObj(pVar->typePtr->name, -1)); | |
4762 } | |
4763 return TCL_OK; | |
4764 } | |
4765 | |
4766 /* | |
4767 ** Usage: sqlite3_release_memory ?N? | |
4768 ** | |
4769 ** Attempt to release memory currently held but not actually required. | |
4770 ** The integer N is the number of bytes we are trying to release. The | |
4771 ** return value is the amount of memory actually released. | |
4772 */ | |
4773 static int test_release_memory( | |
4774 void * clientData, | |
4775 Tcl_Interp *interp, | |
4776 int objc, | |
4777 Tcl_Obj *CONST objv[] | |
4778 ){ | |
4779 #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) | |
4780 int N; | |
4781 int amt; | |
4782 if( objc!=1 && objc!=2 ){ | |
4783 Tcl_WrongNumArgs(interp, 1, objv, "?N?"); | |
4784 return TCL_ERROR; | |
4785 } | |
4786 if( objc==2 ){ | |
4787 if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; | |
4788 }else{ | |
4789 N = -1; | |
4790 } | |
4791 amt = sqlite3_release_memory(N); | |
4792 Tcl_SetObjResult(interp, Tcl_NewIntObj(amt)); | |
4793 #endif | |
4794 return TCL_OK; | |
4795 } | |
4796 | |
4797 | |
4798 /* | |
4799 ** Usage: sqlite3_db_release_memory DB | |
4800 ** | |
4801 ** Attempt to release memory currently held by database DB. Return the | |
4802 ** result code (which in the current implementation is always zero). | |
4803 */ | |
4804 static int test_db_release_memory( | |
4805 void * clientData, | |
4806 Tcl_Interp *interp, | |
4807 int objc, | |
4808 Tcl_Obj *CONST objv[] | |
4809 ){ | |
4810 sqlite3 *db; | |
4811 int rc; | |
4812 if( objc!=2 ){ | |
4813 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | |
4814 return TCL_ERROR; | |
4815 } | |
4816 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
4817 rc = sqlite3_db_release_memory(db); | |
4818 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
4819 return TCL_OK; | |
4820 } | |
4821 | |
4822 /* | |
4823 ** Usage: sqlite3_db_cacheflush DB | |
4824 ** | |
4825 ** Attempt to flush any dirty pages to disk. | |
4826 */ | |
4827 static int test_db_cacheflush( | |
4828 void * clientData, | |
4829 Tcl_Interp *interp, | |
4830 int objc, | |
4831 Tcl_Obj *CONST objv[] | |
4832 ){ | |
4833 sqlite3 *db; | |
4834 int rc; | |
4835 if( objc!=2 ){ | |
4836 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | |
4837 return TCL_ERROR; | |
4838 } | |
4839 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
4840 rc = sqlite3_db_cacheflush(db); | |
4841 if( rc ){ | |
4842 Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC); | |
4843 return TCL_ERROR; | |
4844 } | |
4845 | |
4846 Tcl_ResetResult(interp); | |
4847 return TCL_OK; | |
4848 } | |
4849 | |
4850 /* | |
4851 ** Usage: sqlite3_db_filename DB DBNAME | |
4852 ** | |
4853 ** Return the name of a file associated with a database. | |
4854 */ | |
4855 static int test_db_filename( | |
4856 void * clientData, | |
4857 Tcl_Interp *interp, | |
4858 int objc, | |
4859 Tcl_Obj *CONST objv[] | |
4860 ){ | |
4861 sqlite3 *db; | |
4862 const char *zDbName; | |
4863 if( objc!=3 ){ | |
4864 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); | |
4865 return TCL_ERROR; | |
4866 } | |
4867 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
4868 zDbName = Tcl_GetString(objv[2]); | |
4869 Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0); | |
4870 return TCL_OK; | |
4871 } | |
4872 | |
4873 /* | |
4874 ** Usage: sqlite3_db_readonly DB DBNAME | |
4875 ** | |
4876 ** Return 1 or 0 if DBNAME is readonly or not. Return -1 if DBNAME does | |
4877 ** not exist. | |
4878 */ | |
4879 static int test_db_readonly( | |
4880 void * clientData, | |
4881 Tcl_Interp *interp, | |
4882 int objc, | |
4883 Tcl_Obj *CONST objv[] | |
4884 ){ | |
4885 sqlite3 *db; | |
4886 const char *zDbName; | |
4887 if( objc!=3 ){ | |
4888 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); | |
4889 return TCL_ERROR; | |
4890 } | |
4891 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
4892 zDbName = Tcl_GetString(objv[2]); | |
4893 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_db_readonly(db, zDbName))); | |
4894 return TCL_OK; | |
4895 } | |
4896 | |
4897 /* | |
4898 ** Usage: sqlite3_soft_heap_limit ?N? | |
4899 ** | |
4900 ** Query or set the soft heap limit for the current thread. The | |
4901 ** limit is only changed if the N is present. The previous limit | |
4902 ** is returned. | |
4903 */ | |
4904 static int test_soft_heap_limit( | |
4905 void * clientData, | |
4906 Tcl_Interp *interp, | |
4907 int objc, | |
4908 Tcl_Obj *CONST objv[] | |
4909 ){ | |
4910 sqlite3_int64 amt; | |
4911 Tcl_WideInt N = -1; | |
4912 if( objc!=1 && objc!=2 ){ | |
4913 Tcl_WrongNumArgs(interp, 1, objv, "?N?"); | |
4914 return TCL_ERROR; | |
4915 } | |
4916 if( objc==2 ){ | |
4917 if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; | |
4918 } | |
4919 amt = sqlite3_soft_heap_limit64(N); | |
4920 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt)); | |
4921 return TCL_OK; | |
4922 } | |
4923 | |
4924 /* | |
4925 ** Usage: sqlite3_thread_cleanup | |
4926 ** | |
4927 ** Call the sqlite3_thread_cleanup API. | |
4928 */ | |
4929 static int test_thread_cleanup( | |
4930 void * clientData, | |
4931 Tcl_Interp *interp, | |
4932 int objc, | |
4933 Tcl_Obj *CONST objv[] | |
4934 ){ | |
4935 #ifndef SQLITE_OMIT_DEPRECATED | |
4936 sqlite3_thread_cleanup(); | |
4937 #endif | |
4938 return TCL_OK; | |
4939 } | |
4940 | |
4941 /* | |
4942 ** Usage: sqlite3_pager_refcounts DB | |
4943 ** | |
4944 ** Return a list of numbers which are the PagerRefcount for all | |
4945 ** pagers on each database connection. | |
4946 */ | |
4947 static int test_pager_refcounts( | |
4948 void * clientData, | |
4949 Tcl_Interp *interp, | |
4950 int objc, | |
4951 Tcl_Obj *CONST objv[] | |
4952 ){ | |
4953 sqlite3 *db; | |
4954 int i; | |
4955 int v, *a; | |
4956 Tcl_Obj *pResult; | |
4957 | |
4958 if( objc!=2 ){ | |
4959 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
4960 Tcl_GetStringFromObj(objv[0], 0), " DB", 0); | |
4961 return TCL_ERROR; | |
4962 } | |
4963 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
4964 pResult = Tcl_NewObj(); | |
4965 for(i=0; i<db->nDb; i++){ | |
4966 if( db->aDb[i].pBt==0 ){ | |
4967 v = -1; | |
4968 }else{ | |
4969 sqlite3_mutex_enter(db->mutex); | |
4970 a = sqlite3PagerStats(sqlite3BtreePager(db->aDb[i].pBt)); | |
4971 v = a[0]; | |
4972 sqlite3_mutex_leave(db->mutex); | |
4973 } | |
4974 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(v)); | |
4975 } | |
4976 Tcl_SetObjResult(interp, pResult); | |
4977 return TCL_OK; | |
4978 } | |
4979 | |
4980 | |
4981 /* | |
4982 ** tclcmd: working_64bit_int | |
4983 ** | |
4984 ** Some TCL builds (ex: cygwin) do not support 64-bit integers. This | |
4985 ** leads to a number of test failures. The present command checks the | |
4986 ** TCL build to see whether or not it supports 64-bit integers. It | |
4987 ** returns TRUE if it does and FALSE if not. | |
4988 ** | |
4989 ** This command is used to warn users that their TCL build is defective | |
4990 ** and that the errors they are seeing in the test scripts might be | |
4991 ** a result of their defective TCL rather than problems in SQLite. | |
4992 */ | |
4993 static int working_64bit_int( | |
4994 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
4995 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
4996 int objc, /* Number of arguments */ | |
4997 Tcl_Obj *CONST objv[] /* Command arguments */ | |
4998 ){ | |
4999 Tcl_Obj *pTestObj; | |
5000 int working = 0; | |
5001 | |
5002 pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890); | |
5003 working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0; | |
5004 Tcl_DecrRefCount(pTestObj); | |
5005 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working)); | |
5006 return TCL_OK; | |
5007 } | |
5008 | |
5009 | |
5010 /* | |
5011 ** tclcmd: vfs_unlink_test | |
5012 ** | |
5013 ** This TCL command unregisters the primary VFS and then registers | |
5014 ** it back again. This is used to test the ability to register a | |
5015 ** VFS when none are previously registered, and the ability to | |
5016 ** unregister the only available VFS. Ticket #2738 | |
5017 */ | |
5018 static int vfs_unlink_test( | |
5019 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5020 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5021 int objc, /* Number of arguments */ | |
5022 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5023 ){ | |
5024 int i; | |
5025 sqlite3_vfs *pMain; | |
5026 sqlite3_vfs *apVfs[20]; | |
5027 sqlite3_vfs one, two; | |
5028 | |
5029 sqlite3_vfs_unregister(0); /* Unregister of NULL is harmless */ | |
5030 one.zName = "__one"; | |
5031 two.zName = "__two"; | |
5032 | |
5033 /* Calling sqlite3_vfs_register with 2nd argument of 0 does not | |
5034 ** change the default VFS | |
5035 */ | |
5036 pMain = sqlite3_vfs_find(0); | |
5037 sqlite3_vfs_register(&one, 0); | |
5038 assert( pMain==0 || pMain==sqlite3_vfs_find(0) ); | |
5039 sqlite3_vfs_register(&two, 0); | |
5040 assert( pMain==0 || pMain==sqlite3_vfs_find(0) ); | |
5041 | |
5042 /* We can find a VFS by its name */ | |
5043 assert( sqlite3_vfs_find("__one")==&one ); | |
5044 assert( sqlite3_vfs_find("__two")==&two ); | |
5045 | |
5046 /* Calling sqlite_vfs_register with non-zero second parameter changes the | |
5047 ** default VFS, even if the 1st parameter is an existig VFS that is | |
5048 ** previously registered as the non-default. | |
5049 */ | |
5050 sqlite3_vfs_register(&one, 1); | |
5051 assert( sqlite3_vfs_find("__one")==&one ); | |
5052 assert( sqlite3_vfs_find("__two")==&two ); | |
5053 assert( sqlite3_vfs_find(0)==&one ); | |
5054 sqlite3_vfs_register(&two, 1); | |
5055 assert( sqlite3_vfs_find("__one")==&one ); | |
5056 assert( sqlite3_vfs_find("__two")==&two ); | |
5057 assert( sqlite3_vfs_find(0)==&two ); | |
5058 if( pMain ){ | |
5059 sqlite3_vfs_register(pMain, 1); | |
5060 assert( sqlite3_vfs_find("__one")==&one ); | |
5061 assert( sqlite3_vfs_find("__two")==&two ); | |
5062 assert( sqlite3_vfs_find(0)==pMain ); | |
5063 } | |
5064 | |
5065 /* Unlink the default VFS. Repeat until there are no more VFSes | |
5066 ** registered. | |
5067 */ | |
5068 for(i=0; i<sizeof(apVfs)/sizeof(apVfs[0]); i++){ | |
5069 apVfs[i] = sqlite3_vfs_find(0); | |
5070 if( apVfs[i] ){ | |
5071 assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) ); | |
5072 sqlite3_vfs_unregister(apVfs[i]); | |
5073 assert( 0==sqlite3_vfs_find(apVfs[i]->zName) ); | |
5074 } | |
5075 } | |
5076 assert( 0==sqlite3_vfs_find(0) ); | |
5077 | |
5078 /* Register the main VFS as non-default (will be made default, since | |
5079 ** it'll be the only one in existence). | |
5080 */ | |
5081 sqlite3_vfs_register(pMain, 0); | |
5082 assert( sqlite3_vfs_find(0)==pMain ); | |
5083 | |
5084 /* Un-register the main VFS again to restore an empty VFS list */ | |
5085 sqlite3_vfs_unregister(pMain); | |
5086 assert( 0==sqlite3_vfs_find(0) ); | |
5087 | |
5088 /* Relink all VFSes in reverse order. */ | |
5089 for(i=sizeof(apVfs)/sizeof(apVfs[0])-1; i>=0; i--){ | |
5090 if( apVfs[i] ){ | |
5091 sqlite3_vfs_register(apVfs[i], 1); | |
5092 assert( apVfs[i]==sqlite3_vfs_find(0) ); | |
5093 assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) ); | |
5094 } | |
5095 } | |
5096 | |
5097 /* Unregister out sample VFSes. */ | |
5098 sqlite3_vfs_unregister(&one); | |
5099 sqlite3_vfs_unregister(&two); | |
5100 | |
5101 /* Unregistering a VFS that is not currently registered is harmless */ | |
5102 sqlite3_vfs_unregister(&one); | |
5103 sqlite3_vfs_unregister(&two); | |
5104 assert( sqlite3_vfs_find("__one")==0 ); | |
5105 assert( sqlite3_vfs_find("__two")==0 ); | |
5106 | |
5107 /* We should be left with the original default VFS back as the | |
5108 ** original */ | |
5109 assert( sqlite3_vfs_find(0)==pMain ); | |
5110 | |
5111 return TCL_OK; | |
5112 } | |
5113 | |
5114 /* | |
5115 ** tclcmd: vfs_initfail_test | |
5116 ** | |
5117 ** This TCL command attempts to vfs_find and vfs_register when the | |
5118 ** sqlite3_initialize() interface is failing. All calls should fail. | |
5119 */ | |
5120 static int vfs_initfail_test( | |
5121 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5122 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5123 int objc, /* Number of arguments */ | |
5124 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5125 ){ | |
5126 sqlite3_vfs one; | |
5127 one.zName = "__one"; | |
5128 | |
5129 if( sqlite3_vfs_find(0) ) return TCL_ERROR; | |
5130 sqlite3_vfs_register(&one, 0); | |
5131 if( sqlite3_vfs_find(0) ) return TCL_ERROR; | |
5132 sqlite3_vfs_register(&one, 1); | |
5133 if( sqlite3_vfs_find(0) ) return TCL_ERROR; | |
5134 return TCL_OK; | |
5135 } | |
5136 | |
5137 /* | |
5138 ** Saved VFSes | |
5139 */ | |
5140 static sqlite3_vfs *apVfs[20]; | |
5141 static int nVfs = 0; | |
5142 | |
5143 /* | |
5144 ** tclcmd: vfs_unregister_all | |
5145 ** | |
5146 ** Unregister all VFSes. | |
5147 */ | |
5148 static int vfs_unregister_all( | |
5149 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5150 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5151 int objc, /* Number of arguments */ | |
5152 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5153 ){ | |
5154 int i; | |
5155 for(i=0; i<ArraySize(apVfs); i++){ | |
5156 apVfs[i] = sqlite3_vfs_find(0); | |
5157 if( apVfs[i]==0 ) break; | |
5158 sqlite3_vfs_unregister(apVfs[i]); | |
5159 } | |
5160 nVfs = i; | |
5161 return TCL_OK; | |
5162 } | |
5163 /* | |
5164 ** tclcmd: vfs_reregister_all | |
5165 ** | |
5166 ** Restore all VFSes that were removed using vfs_unregister_all | |
5167 */ | |
5168 static int vfs_reregister_all( | |
5169 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5170 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5171 int objc, /* Number of arguments */ | |
5172 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5173 ){ | |
5174 int i; | |
5175 for(i=0; i<nVfs; i++){ | |
5176 sqlite3_vfs_register(apVfs[i], i==0); | |
5177 } | |
5178 return TCL_OK; | |
5179 } | |
5180 | |
5181 | |
5182 /* | |
5183 ** tclcmd: file_control_test DB | |
5184 ** | |
5185 ** This TCL command runs the sqlite3_file_control interface and | |
5186 ** verifies correct operation of the same. | |
5187 */ | |
5188 static int file_control_test( | |
5189 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5190 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5191 int objc, /* Number of arguments */ | |
5192 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5193 ){ | |
5194 int iArg = 0; | |
5195 sqlite3 *db; | |
5196 int rc; | |
5197 | |
5198 if( objc!=2 ){ | |
5199 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5200 Tcl_GetStringFromObj(objv[0], 0), " DB", 0); | |
5201 return TCL_ERROR; | |
5202 } | |
5203 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
5204 rc = sqlite3_file_control(db, 0, 0, &iArg); | |
5205 assert( rc==SQLITE_NOTFOUND ); | |
5206 rc = sqlite3_file_control(db, "notadatabase", SQLITE_FCNTL_LOCKSTATE, &iArg); | |
5207 assert( rc==SQLITE_ERROR ); | |
5208 rc = sqlite3_file_control(db, "main", -1, &iArg); | |
5209 assert( rc==SQLITE_NOTFOUND ); | |
5210 rc = sqlite3_file_control(db, "temp", -1, &iArg); | |
5211 assert( rc==SQLITE_NOTFOUND || rc==SQLITE_ERROR ); | |
5212 | |
5213 return TCL_OK; | |
5214 } | |
5215 | |
5216 | |
5217 /* | |
5218 ** tclcmd: file_control_lasterrno_test DB | |
5219 ** | |
5220 ** This TCL command runs the sqlite3_file_control interface and | |
5221 ** verifies correct operation of the SQLITE_LAST_ERRNO verb. | |
5222 */ | |
5223 static int file_control_lasterrno_test( | |
5224 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5225 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5226 int objc, /* Number of arguments */ | |
5227 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5228 ){ | |
5229 int iArg = 0; | |
5230 sqlite3 *db; | |
5231 int rc; | |
5232 | |
5233 if( objc!=2 ){ | |
5234 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5235 Tcl_GetStringFromObj(objv[0], 0), " DB", 0); | |
5236 return TCL_ERROR; | |
5237 } | |
5238 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5239 return TCL_ERROR; | |
5240 } | |
5241 rc = sqlite3_file_control(db, NULL, SQLITE_LAST_ERRNO, &iArg); | |
5242 if( rc ){ | |
5243 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
5244 return TCL_ERROR; | |
5245 } | |
5246 if( iArg!=0 ) { | |
5247 Tcl_AppendResult(interp, "Unexpected non-zero errno: ", | |
5248 Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0); | |
5249 return TCL_ERROR; | |
5250 } | |
5251 return TCL_OK; | |
5252 } | |
5253 | |
5254 /* | |
5255 ** tclcmd: file_control_chunksize_test DB DBNAME SIZE | |
5256 ** | |
5257 ** This TCL command runs the sqlite3_file_control interface and | |
5258 ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and | |
5259 ** SQLITE_SET_LOCKPROXYFILE verbs. | |
5260 */ | |
5261 static int file_control_chunksize_test( | |
5262 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5263 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5264 int objc, /* Number of arguments */ | |
5265 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5266 ){ | |
5267 int nSize; /* New chunk size */ | |
5268 char *zDb; /* Db name ("main", "temp" etc.) */ | |
5269 sqlite3 *db; /* Database handle */ | |
5270 int rc; /* file_control() return code */ | |
5271 | |
5272 if( objc!=4 ){ | |
5273 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE"); | |
5274 return TCL_ERROR; | |
5275 } | |
5276 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) | |
5277 || Tcl_GetIntFromObj(interp, objv[3], &nSize) | |
5278 ){ | |
5279 return TCL_ERROR; | |
5280 } | |
5281 zDb = Tcl_GetString(objv[2]); | |
5282 if( zDb[0]=='\0' ) zDb = NULL; | |
5283 | |
5284 rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize); | |
5285 if( rc ){ | |
5286 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); | |
5287 return TCL_ERROR; | |
5288 } | |
5289 return TCL_OK; | |
5290 } | |
5291 | |
5292 /* | |
5293 ** tclcmd: file_control_sizehint_test DB DBNAME SIZE | |
5294 ** | |
5295 ** This TCL command runs the sqlite3_file_control interface | |
5296 ** with SQLITE_FCNTL_SIZE_HINT | |
5297 */ | |
5298 static int file_control_sizehint_test( | |
5299 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5300 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5301 int objc, /* Number of arguments */ | |
5302 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5303 ){ | |
5304 Tcl_WideInt nSize; /* Hinted size */ | |
5305 char *zDb; /* Db name ("main", "temp" etc.) */ | |
5306 sqlite3 *db; /* Database handle */ | |
5307 int rc; /* file_control() return code */ | |
5308 | |
5309 if( objc!=4 ){ | |
5310 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE"); | |
5311 return TCL_ERROR; | |
5312 } | |
5313 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) | |
5314 || Tcl_GetWideIntFromObj(interp, objv[3], &nSize) | |
5315 ){ | |
5316 return TCL_ERROR; | |
5317 } | |
5318 zDb = Tcl_GetString(objv[2]); | |
5319 if( zDb[0]=='\0' ) zDb = NULL; | |
5320 | |
5321 rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize); | |
5322 if( rc ){ | |
5323 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); | |
5324 return TCL_ERROR; | |
5325 } | |
5326 return TCL_OK; | |
5327 } | |
5328 | |
5329 /* | |
5330 ** tclcmd: file_control_lockproxy_test DB PWD | |
5331 ** | |
5332 ** This TCL command runs the sqlite3_file_control interface and | |
5333 ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and | |
5334 ** SQLITE_SET_LOCKPROXYFILE verbs. | |
5335 */ | |
5336 static int file_control_lockproxy_test( | |
5337 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5338 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5339 int objc, /* Number of arguments */ | |
5340 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5341 ){ | |
5342 sqlite3 *db; | |
5343 | |
5344 if( objc!=3 ){ | |
5345 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5346 Tcl_GetStringFromObj(objv[0], 0), " DB PWD", 0); | |
5347 return TCL_ERROR; | |
5348 } | |
5349 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5350 return TCL_ERROR; | |
5351 } | |
5352 | |
5353 #if !defined(SQLITE_ENABLE_LOCKING_STYLE) | |
5354 # if defined(__APPLE__) | |
5355 # define SQLITE_ENABLE_LOCKING_STYLE 1 | |
5356 # else | |
5357 # define SQLITE_ENABLE_LOCKING_STYLE 0 | |
5358 # endif | |
5359 #endif | |
5360 #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) | |
5361 { | |
5362 char *testPath; | |
5363 int rc; | |
5364 int nPwd; | |
5365 const char *zPwd; | |
5366 char proxyPath[400]; | |
5367 | |
5368 zPwd = Tcl_GetStringFromObj(objv[2], &nPwd); | |
5369 if( sizeof(proxyPath)<nPwd+20 ){ | |
5370 Tcl_AppendResult(interp, "PWD too big", (void*)0); | |
5371 return TCL_ERROR; | |
5372 } | |
5373 sqlite3_snprintf(sizeof(proxyPath), proxyPath, "%s/test.proxy", zPwd); | |
5374 rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath); | |
5375 if( rc ){ | |
5376 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
5377 return TCL_ERROR; | |
5378 } | |
5379 rc = sqlite3_file_control(db, NULL, SQLITE_GET_LOCKPROXYFILE, &testPath); | |
5380 if( strncmp(proxyPath,testPath,11) ){ | |
5381 Tcl_AppendResult(interp, "Lock proxy file did not match the " | |
5382 "previously assigned value", 0); | |
5383 return TCL_ERROR; | |
5384 } | |
5385 if( rc ){ | |
5386 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
5387 return TCL_ERROR; | |
5388 } | |
5389 rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath); | |
5390 if( rc ){ | |
5391 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
5392 return TCL_ERROR; | |
5393 } | |
5394 } | |
5395 #endif | |
5396 return TCL_OK; | |
5397 } | |
5398 | |
5399 #if SQLITE_OS_WIN | |
5400 /* | |
5401 ** tclcmd: file_control_win32_av_retry DB NRETRY DELAY | |
5402 ** | |
5403 ** This TCL command runs the sqlite3_file_control interface with | |
5404 ** the SQLITE_FCNTL_WIN32_AV_RETRY opcode. | |
5405 */ | |
5406 static int file_control_win32_av_retry( | |
5407 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5408 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5409 int objc, /* Number of arguments */ | |
5410 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5411 ){ | |
5412 sqlite3 *db; | |
5413 int rc; | |
5414 int a[2]; | |
5415 char z[100]; | |
5416 | |
5417 if( objc!=4 ){ | |
5418 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5419 Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0); | |
5420 return TCL_ERROR; | |
5421 } | |
5422 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5423 return TCL_ERROR; | |
5424 } | |
5425 if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR; | |
5426 if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR; | |
5427 rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a); | |
5428 sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]); | |
5429 Tcl_AppendResult(interp, z, (char*)0); | |
5430 return TCL_OK; | |
5431 } | |
5432 | |
5433 /* | |
5434 ** tclcmd: file_control_win32_set_handle DB HANDLE | |
5435 ** | |
5436 ** This TCL command runs the sqlite3_file_control interface with | |
5437 ** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode. | |
5438 */ | |
5439 static int file_control_win32_set_handle( | |
5440 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5441 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5442 int objc, /* Number of arguments */ | |
5443 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5444 ){ | |
5445 sqlite3 *db; | |
5446 int rc; | |
5447 HANDLE hFile = NULL; | |
5448 char z[100]; | |
5449 | |
5450 if( objc!=3 ){ | |
5451 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5452 Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0); | |
5453 return TCL_ERROR; | |
5454 } | |
5455 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5456 return TCL_ERROR; | |
5457 } | |
5458 if( getWin32Handle(interp, Tcl_GetString(objv[2]), &hFile) ){ | |
5459 return TCL_ERROR; | |
5460 } | |
5461 rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_SET_HANDLE, | |
5462 (void*)&hFile); | |
5463 sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile); | |
5464 Tcl_AppendResult(interp, z, (char*)0); | |
5465 return TCL_OK; | |
5466 } | |
5467 #endif | |
5468 | |
5469 /* | |
5470 ** tclcmd: file_control_persist_wal DB PERSIST-FLAG | |
5471 ** | |
5472 ** This TCL command runs the sqlite3_file_control interface with | |
5473 ** the SQLITE_FCNTL_PERSIST_WAL opcode. | |
5474 */ | |
5475 static int file_control_persist_wal( | |
5476 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5477 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5478 int objc, /* Number of arguments */ | |
5479 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5480 ){ | |
5481 sqlite3 *db; | |
5482 int rc; | |
5483 int bPersist; | |
5484 char z[100]; | |
5485 | |
5486 if( objc!=3 ){ | |
5487 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5488 Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0); | |
5489 return TCL_ERROR; | |
5490 } | |
5491 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5492 return TCL_ERROR; | |
5493 } | |
5494 if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR; | |
5495 rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist
); | |
5496 sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist); | |
5497 Tcl_AppendResult(interp, z, (char*)0); | |
5498 return TCL_OK; | |
5499 } | |
5500 | |
5501 /* | |
5502 ** tclcmd: file_control_powersafe_overwrite DB PSOW-FLAG | |
5503 ** | |
5504 ** This TCL command runs the sqlite3_file_control interface with | |
5505 ** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode. | |
5506 */ | |
5507 static int file_control_powersafe_overwrite( | |
5508 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5509 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5510 int objc, /* Number of arguments */ | |
5511 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5512 ){ | |
5513 sqlite3 *db; | |
5514 int rc; | |
5515 int b; | |
5516 char z[100]; | |
5517 | |
5518 if( objc!=3 ){ | |
5519 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5520 Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0); | |
5521 return TCL_ERROR; | |
5522 } | |
5523 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5524 return TCL_ERROR; | |
5525 } | |
5526 if( Tcl_GetIntFromObj(interp, objv[2], &b) ) return TCL_ERROR; | |
5527 rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_POWERSAFE_OVERWRITE,(void*)&b); | |
5528 sqlite3_snprintf(sizeof(z), z, "%d %d", rc, b); | |
5529 Tcl_AppendResult(interp, z, (char*)0); | |
5530 return TCL_OK; | |
5531 } | |
5532 | |
5533 | |
5534 /* | |
5535 ** tclcmd: file_control_vfsname DB ?AUXDB? | |
5536 ** | |
5537 ** Return a string that describes the stack of VFSes. | |
5538 */ | |
5539 static int file_control_vfsname( | |
5540 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5541 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5542 int objc, /* Number of arguments */ | |
5543 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5544 ){ | |
5545 sqlite3 *db; | |
5546 const char *zDbName = "main"; | |
5547 char *zVfsName = 0; | |
5548 | |
5549 if( objc!=2 && objc!=3 ){ | |
5550 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5551 Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0); | |
5552 return TCL_ERROR; | |
5553 } | |
5554 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5555 return TCL_ERROR; | |
5556 } | |
5557 if( objc==3 ){ | |
5558 zDbName = Tcl_GetString(objv[2]); | |
5559 } | |
5560 sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName); | |
5561 Tcl_AppendResult(interp, zVfsName, (char*)0); | |
5562 sqlite3_free(zVfsName); | |
5563 return TCL_OK; | |
5564 } | |
5565 | |
5566 /* | |
5567 ** tclcmd: file_control_tempfilename DB ?AUXDB? | |
5568 ** | |
5569 ** Return a string that is a temporary filename | |
5570 */ | |
5571 static int file_control_tempfilename( | |
5572 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5573 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5574 int objc, /* Number of arguments */ | |
5575 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5576 ){ | |
5577 sqlite3 *db; | |
5578 const char *zDbName = "main"; | |
5579 char *zTName = 0; | |
5580 | |
5581 if( objc!=2 && objc!=3 ){ | |
5582 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5583 Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0); | |
5584 return TCL_ERROR; | |
5585 } | |
5586 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5587 return TCL_ERROR; | |
5588 } | |
5589 if( objc==3 ){ | |
5590 zDbName = Tcl_GetString(objv[2]); | |
5591 } | |
5592 sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName); | |
5593 Tcl_AppendResult(interp, zTName, (char*)0); | |
5594 sqlite3_free(zTName); | |
5595 return TCL_OK; | |
5596 } | |
5597 | |
5598 | |
5599 /* | |
5600 ** tclcmd: sqlite3_vfs_list | |
5601 ** | |
5602 ** Return a tcl list containing the names of all registered vfs's. | |
5603 */ | |
5604 static int vfs_list( | |
5605 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5606 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5607 int objc, /* Number of arguments */ | |
5608 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5609 ){ | |
5610 sqlite3_vfs *pVfs; | |
5611 Tcl_Obj *pRet = Tcl_NewObj(); | |
5612 if( objc!=1 ){ | |
5613 Tcl_WrongNumArgs(interp, 1, objv, ""); | |
5614 return TCL_ERROR; | |
5615 } | |
5616 for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ | |
5617 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(pVfs->zName, -1)); | |
5618 } | |
5619 Tcl_SetObjResult(interp, pRet); | |
5620 return TCL_OK; | |
5621 } | |
5622 | |
5623 /* | |
5624 ** tclcmd: sqlite3_limit DB ID VALUE | |
5625 ** | |
5626 ** This TCL command runs the sqlite3_limit interface and | |
5627 ** verifies correct operation of the same. | |
5628 */ | |
5629 static int test_limit( | |
5630 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5631 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5632 int objc, /* Number of arguments */ | |
5633 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5634 ){ | |
5635 sqlite3 *db; | |
5636 int rc; | |
5637 static const struct { | |
5638 char *zName; | |
5639 int id; | |
5640 } aId[] = { | |
5641 { "SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH }, | |
5642 { "SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH }, | |
5643 { "SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN }, | |
5644 { "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, | |
5645 { "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, | |
5646 { "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, | |
5647 { "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, | |
5648 { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, | |
5649 { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, | |
5650 { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, | |
5651 { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, | |
5652 { "SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS }, | |
5653 | |
5654 /* Out of range test cases */ | |
5655 { "SQLITE_LIMIT_TOOSMALL", -1, }, | |
5656 { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_WORKER_THREADS+1 }, | |
5657 }; | |
5658 int i, id = 0; | |
5659 int val; | |
5660 const char *zId; | |
5661 | |
5662 if( objc!=4 ){ | |
5663 Tcl_AppendResult(interp, "wrong # args: should be \"", | |
5664 Tcl_GetStringFromObj(objv[0], 0), " DB ID VALUE", 0); | |
5665 return TCL_ERROR; | |
5666 } | |
5667 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
5668 zId = Tcl_GetString(objv[2]); | |
5669 for(i=0; i<sizeof(aId)/sizeof(aId[0]); i++){ | |
5670 if( strcmp(zId, aId[i].zName)==0 ){ | |
5671 id = aId[i].id; | |
5672 break; | |
5673 } | |
5674 } | |
5675 if( i>=sizeof(aId)/sizeof(aId[0]) ){ | |
5676 Tcl_AppendResult(interp, "unknown limit type: ", zId, (char*)0); | |
5677 return TCL_ERROR; | |
5678 } | |
5679 if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR; | |
5680 rc = sqlite3_limit(db, id, val); | |
5681 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
5682 return TCL_OK; | |
5683 } | |
5684 | |
5685 /* | |
5686 ** tclcmd: save_prng_state | |
5687 ** | |
5688 ** Save the state of the pseudo-random number generator. | |
5689 ** At the same time, verify that sqlite3_test_control works even when | |
5690 ** called with an out-of-range opcode. | |
5691 */ | |
5692 static int save_prng_state( | |
5693 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5694 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5695 int objc, /* Number of arguments */ | |
5696 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5697 ){ | |
5698 int rc = sqlite3_test_control(9999); | |
5699 assert( rc==0 ); | |
5700 rc = sqlite3_test_control(-1); | |
5701 assert( rc==0 ); | |
5702 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SAVE); | |
5703 return TCL_OK; | |
5704 } | |
5705 /* | |
5706 ** tclcmd: restore_prng_state | |
5707 */ | |
5708 static int restore_prng_state( | |
5709 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5710 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5711 int objc, /* Number of arguments */ | |
5712 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5713 ){ | |
5714 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESTORE); | |
5715 return TCL_OK; | |
5716 } | |
5717 /* | |
5718 ** tclcmd: reset_prng_state | |
5719 */ | |
5720 static int reset_prng_state( | |
5721 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5722 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5723 int objc, /* Number of arguments */ | |
5724 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5725 ){ | |
5726 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET); | |
5727 return TCL_OK; | |
5728 } | |
5729 | |
5730 /* | |
5731 ** tclcmd: database_may_be_corrupt | |
5732 ** | |
5733 ** Indicate that database files might be corrupt. In other words, set the norma
l | |
5734 ** state of operation. | |
5735 */ | |
5736 static int database_may_be_corrupt( | |
5737 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5738 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5739 int objc, /* Number of arguments */ | |
5740 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5741 ){ | |
5742 sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0); | |
5743 return TCL_OK; | |
5744 } | |
5745 /* | |
5746 ** tclcmd: database_never_corrupt | |
5747 ** | |
5748 ** Indicate that database files are always well-formed. This enables extra asse
rt() | |
5749 ** statements that test conditions that are always true for well-formed database
s. | |
5750 */ | |
5751 static int database_never_corrupt( | |
5752 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5753 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5754 int objc, /* Number of arguments */ | |
5755 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5756 ){ | |
5757 sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1); | |
5758 return TCL_OK; | |
5759 } | |
5760 | |
5761 /* | |
5762 ** tclcmd: pcache_stats | |
5763 */ | |
5764 static int test_pcache_stats( | |
5765 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | |
5766 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5767 int objc, /* Number of arguments */ | |
5768 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5769 ){ | |
5770 int nMin; | |
5771 int nMax; | |
5772 int nCurrent; | |
5773 int nRecyclable; | |
5774 Tcl_Obj *pRet; | |
5775 | |
5776 sqlite3PcacheStats(&nCurrent, &nMax, &nMin, &nRecyclable); | |
5777 | |
5778 pRet = Tcl_NewObj(); | |
5779 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("current", -1)); | |
5780 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCurrent)); | |
5781 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("max", -1)); | |
5782 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMax)); | |
5783 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("min", -1)); | |
5784 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMin)); | |
5785 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("recyclable", -1)); | |
5786 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nRecyclable)); | |
5787 | |
5788 Tcl_SetObjResult(interp, pRet); | |
5789 | |
5790 return TCL_OK; | |
5791 } | |
5792 | |
5793 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | |
5794 static void test_unlock_notify_cb(void **aArg, int nArg){ | |
5795 int ii; | |
5796 for(ii=0; ii<nArg; ii++){ | |
5797 Tcl_EvalEx((Tcl_Interp *)aArg[ii], "unlock_notify", -1, TCL_EVAL_GLOBAL); | |
5798 } | |
5799 } | |
5800 #endif /* SQLITE_ENABLE_UNLOCK_NOTIFY */ | |
5801 | |
5802 /* | |
5803 ** tclcmd: sqlite3_unlock_notify db | |
5804 */ | |
5805 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | |
5806 static int test_unlock_notify( | |
5807 ClientData clientData, /* Unused */ | |
5808 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5809 int objc, /* Number of arguments */ | |
5810 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5811 ){ | |
5812 sqlite3 *db; | |
5813 int rc; | |
5814 | |
5815 if( objc!=2 ){ | |
5816 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | |
5817 return TCL_ERROR; | |
5818 } | |
5819 | |
5820 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5821 return TCL_ERROR; | |
5822 } | |
5823 rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp); | |
5824 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
5825 return TCL_OK; | |
5826 } | |
5827 #endif | |
5828 | |
5829 /* | |
5830 ** tclcmd: sqlite3_wal_checkpoint db ?NAME? | |
5831 */ | |
5832 static int test_wal_checkpoint( | |
5833 ClientData clientData, /* Unused */ | |
5834 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5835 int objc, /* Number of arguments */ | |
5836 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5837 ){ | |
5838 char *zDb = 0; | |
5839 sqlite3 *db; | |
5840 int rc; | |
5841 | |
5842 if( objc!=3 && objc!=2 ){ | |
5843 Tcl_WrongNumArgs(interp, 1, objv, "DB ?NAME?"); | |
5844 return TCL_ERROR; | |
5845 } | |
5846 | |
5847 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
5848 return TCL_ERROR; | |
5849 } | |
5850 if( objc==3 ){ | |
5851 zDb = Tcl_GetString(objv[2]); | |
5852 } | |
5853 rc = sqlite3_wal_checkpoint(db, zDb); | |
5854 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
5855 return TCL_OK; | |
5856 } | |
5857 | |
5858 /* | |
5859 ** tclcmd: sqlite3_wal_checkpoint_v2 db MODE ?NAME? | |
5860 ** | |
5861 ** This command calls the wal_checkpoint_v2() function with the specified | |
5862 ** mode argument (passive, full or restart). If present, the database name | |
5863 ** NAME is passed as the second argument to wal_checkpoint_v2(). If it the | |
5864 ** NAME argument is not present, a NULL pointer is passed instead. | |
5865 ** | |
5866 ** If wal_checkpoint_v2() returns any value other than SQLITE_BUSY or | |
5867 ** SQLITE_OK, then this command returns TCL_ERROR. The Tcl result is set | |
5868 ** to the error message obtained from sqlite3_errmsg(). | |
5869 ** | |
5870 ** Otherwise, this command returns a list of three integers. The first integer | |
5871 ** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers | |
5872 ** are the values returned via the output parameters by wal_checkpoint_v2() - | |
5873 ** the number of frames in the log and the number of frames in the log | |
5874 ** that have been checkpointed. | |
5875 */ | |
5876 static int test_wal_checkpoint_v2( | |
5877 ClientData clientData, /* Unused */ | |
5878 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5879 int objc, /* Number of arguments */ | |
5880 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5881 ){ | |
5882 char *zDb = 0; | |
5883 sqlite3 *db; | |
5884 int rc; | |
5885 | |
5886 int eMode; | |
5887 int nLog = -555; | |
5888 int nCkpt = -555; | |
5889 Tcl_Obj *pRet; | |
5890 | |
5891 const char * aMode[] = { "passive", "full", "restart", "truncate", 0 }; | |
5892 assert( SQLITE_CHECKPOINT_PASSIVE==0 ); | |
5893 assert( SQLITE_CHECKPOINT_FULL==1 ); | |
5894 assert( SQLITE_CHECKPOINT_RESTART==2 ); | |
5895 assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); | |
5896 | |
5897 if( objc!=3 && objc!=4 ){ | |
5898 Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?"); | |
5899 return TCL_ERROR; | |
5900 } | |
5901 | |
5902 if( objc==4 ){ | |
5903 zDb = Tcl_GetString(objv[3]); | |
5904 } | |
5905 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || ( | |
5906 TCL_OK!=Tcl_GetIntFromObj(0, objv[2], &eMode) | |
5907 && TCL_OK!=Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode) | |
5908 )){ | |
5909 return TCL_ERROR; | |
5910 } | |
5911 | |
5912 rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt); | |
5913 if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ | |
5914 const char *zErrCode = sqlite3ErrName(rc); | |
5915 Tcl_ResetResult(interp); | |
5916 Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), 0); | |
5917 return TCL_ERROR; | |
5918 } | |
5919 | |
5920 pRet = Tcl_NewObj(); | |
5921 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(rc==SQLITE_BUSY?1:0)); | |
5922 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nLog)); | |
5923 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCkpt)); | |
5924 Tcl_SetObjResult(interp, pRet); | |
5925 | |
5926 return TCL_OK; | |
5927 } | |
5928 | |
5929 /* | |
5930 ** tclcmd: sqlite3_wal_autocheckpoint db VALUE | |
5931 */ | |
5932 static int test_wal_autocheckpoint( | |
5933 ClientData clientData, /* Unused */ | |
5934 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5935 int objc, /* Number of arguments */ | |
5936 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5937 ){ | |
5938 sqlite3 *db; | |
5939 int rc; | |
5940 int iVal; | |
5941 | |
5942 | |
5943 if( objc!=3 ){ | |
5944 Tcl_WrongNumArgs(interp, 1, objv, "DB VALUE"); | |
5945 return TCL_ERROR; | |
5946 } | |
5947 | |
5948 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) | |
5949 || Tcl_GetIntFromObj(0, objv[2], &iVal) | |
5950 ){ | |
5951 return TCL_ERROR; | |
5952 } | |
5953 | |
5954 rc = sqlite3_wal_autocheckpoint(db, iVal); | |
5955 Tcl_ResetResult(interp); | |
5956 if( rc!=SQLITE_OK ){ | |
5957 const char *zErrCode = sqlite3ErrName(rc); | |
5958 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErrCode, -1)); | |
5959 return TCL_ERROR; | |
5960 } | |
5961 | |
5962 return TCL_OK; | |
5963 } | |
5964 | |
5965 | |
5966 /* | |
5967 ** tclcmd: test_sqlite3_log ?SCRIPT? | |
5968 */ | |
5969 static struct LogCallback { | |
5970 Tcl_Interp *pInterp; | |
5971 Tcl_Obj *pObj; | |
5972 } logcallback = {0, 0}; | |
5973 static void xLogcallback(void *unused, int err, char *zMsg){ | |
5974 Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj); | |
5975 Tcl_IncrRefCount(pNew); | |
5976 Tcl_ListObjAppendElement( | |
5977 0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1) | |
5978 ); | |
5979 Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1)); | |
5980 Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); | |
5981 Tcl_DecrRefCount(pNew); | |
5982 } | |
5983 static int test_sqlite3_log( | |
5984 ClientData clientData, | |
5985 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
5986 int objc, /* Number of arguments */ | |
5987 Tcl_Obj *CONST objv[] /* Command arguments */ | |
5988 ){ | |
5989 if( objc>2 ){ | |
5990 Tcl_WrongNumArgs(interp, 1, objv, "SCRIPT"); | |
5991 return TCL_ERROR; | |
5992 } | |
5993 if( logcallback.pObj ){ | |
5994 Tcl_DecrRefCount(logcallback.pObj); | |
5995 logcallback.pObj = 0; | |
5996 logcallback.pInterp = 0; | |
5997 sqlite3_config(SQLITE_CONFIG_LOG, (void*)0, (void*)0); | |
5998 } | |
5999 if( objc>1 ){ | |
6000 logcallback.pObj = objv[1]; | |
6001 Tcl_IncrRefCount(logcallback.pObj); | |
6002 logcallback.pInterp = interp; | |
6003 sqlite3_config(SQLITE_CONFIG_LOG, xLogcallback, (void*)0); | |
6004 } | |
6005 return TCL_OK; | |
6006 } | |
6007 | |
6008 /* | |
6009 ** tcl_objproc COMMANDNAME ARGS... | |
6010 ** | |
6011 ** Run a TCL command using its objProc interface. Throw an error if | |
6012 ** the command has no objProc interface. | |
6013 */ | |
6014 static int runAsObjProc( | |
6015 void * clientData, | |
6016 Tcl_Interp *interp, | |
6017 int objc, | |
6018 Tcl_Obj *CONST objv[] | |
6019 ){ | |
6020 Tcl_CmdInfo cmdInfo; | |
6021 if( objc<2 ){ | |
6022 Tcl_WrongNumArgs(interp, 1, objv, "COMMAND ..."); | |
6023 return TCL_ERROR; | |
6024 } | |
6025 if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ | |
6026 Tcl_AppendResult(interp, "command not found: ", | |
6027 Tcl_GetString(objv[1]), (char*)0); | |
6028 return TCL_ERROR; | |
6029 } | |
6030 if( cmdInfo.objProc==0 ){ | |
6031 Tcl_AppendResult(interp, "command has no objProc: ", | |
6032 Tcl_GetString(objv[1]), (char*)0); | |
6033 return TCL_ERROR; | |
6034 } | |
6035 return cmdInfo.objProc(cmdInfo.objClientData, interp, objc-1, objv+1); | |
6036 } | |
6037 | |
6038 #ifndef SQLITE_OMIT_EXPLAIN | |
6039 /* | |
6040 ** WARNING: The following function, printExplainQueryPlan() is an exact | |
6041 ** copy of example code from eqp.in (eqp.html). If this code is modified, | |
6042 ** then the documentation copy needs to be modified as well. | |
6043 */ | |
6044 /* | |
6045 ** Argument pStmt is a prepared SQL statement. This function compiles | |
6046 ** an EXPLAIN QUERY PLAN command to report on the prepared statement, | |
6047 ** and prints the report to stdout using printf(). | |
6048 */ | |
6049 int printExplainQueryPlan(sqlite3_stmt *pStmt){ | |
6050 const char *zSql; /* Input SQL */ | |
6051 char *zExplain; /* SQL with EXPLAIN QUERY PLAN prepended */ | |
6052 sqlite3_stmt *pExplain; /* Compiled EXPLAIN QUERY PLAN command */ | |
6053 int rc; /* Return code from sqlite3_prepare_v2() */ | |
6054 | |
6055 zSql = sqlite3_sql(pStmt); | |
6056 if( zSql==0 ) return SQLITE_ERROR; | |
6057 | |
6058 zExplain = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zSql); | |
6059 if( zExplain==0 ) return SQLITE_NOMEM; | |
6060 | |
6061 rc = sqlite3_prepare_v2(sqlite3_db_handle(pStmt), zExplain, -1, &pExplain, 0); | |
6062 sqlite3_free(zExplain); | |
6063 if( rc!=SQLITE_OK ) return rc; | |
6064 | |
6065 while( SQLITE_ROW==sqlite3_step(pExplain) ){ | |
6066 int iSelectid = sqlite3_column_int(pExplain, 0); | |
6067 int iOrder = sqlite3_column_int(pExplain, 1); | |
6068 int iFrom = sqlite3_column_int(pExplain, 2); | |
6069 const char *zDetail = (const char *)sqlite3_column_text(pExplain, 3); | |
6070 | |
6071 printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail); | |
6072 } | |
6073 | |
6074 return sqlite3_finalize(pExplain); | |
6075 } | |
6076 | |
6077 static int test_print_eqp( | |
6078 void * clientData, | |
6079 Tcl_Interp *interp, | |
6080 int objc, | |
6081 Tcl_Obj *CONST objv[] | |
6082 ){ | |
6083 int rc; | |
6084 sqlite3_stmt *pStmt; | |
6085 | |
6086 if( objc!=2 ){ | |
6087 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); | |
6088 return TCL_ERROR; | |
6089 } | |
6090 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; | |
6091 rc = printExplainQueryPlan(pStmt); | |
6092 /* This is needed on Windows so that a test case using this | |
6093 ** function can open a read pipe and get the output of | |
6094 ** printExplainQueryPlan() immediately. | |
6095 */ | |
6096 fflush(stdout); | |
6097 Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); | |
6098 return TCL_OK; | |
6099 } | |
6100 #endif /* SQLITE_OMIT_EXPLAIN */ | |
6101 | |
6102 /* | |
6103 ** sqlite3_test_control VERB ARGS... | |
6104 */ | |
6105 static int test_test_control( | |
6106 void * clientData, | |
6107 Tcl_Interp *interp, | |
6108 int objc, | |
6109 Tcl_Obj *CONST objv[] | |
6110 ){ | |
6111 struct Verb { | |
6112 const char *zName; | |
6113 int i; | |
6114 } aVerb[] = { | |
6115 { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, | |
6116 { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP }, | |
6117 { "SQLITE_TESTCTRL_IMPOSTER", SQLITE_TESTCTRL_IMPOSTER }, | |
6118 }; | |
6119 int iVerb; | |
6120 int iFlag; | |
6121 int rc; | |
6122 | |
6123 if( objc<2 ){ | |
6124 Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS..."); | |
6125 return TCL_ERROR; | |
6126 } | |
6127 | |
6128 rc = Tcl_GetIndexFromObjStruct( | |
6129 interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb | |
6130 ); | |
6131 if( rc!=TCL_OK ) return rc; | |
6132 | |
6133 iFlag = aVerb[iVerb].i; | |
6134 switch( iFlag ){ | |
6135 case SQLITE_TESTCTRL_LOCALTIME_FAULT: { | |
6136 int val; | |
6137 if( objc!=3 ){ | |
6138 Tcl_WrongNumArgs(interp, 2, objv, "ONOFF"); | |
6139 return TCL_ERROR; | |
6140 } | |
6141 if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; | |
6142 sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val); | |
6143 break; | |
6144 } | |
6145 | |
6146 case SQLITE_TESTCTRL_SORTER_MMAP: { | |
6147 int val; | |
6148 sqlite3 *db; | |
6149 if( objc!=4 ){ | |
6150 Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT"); | |
6151 return TCL_ERROR; | |
6152 } | |
6153 if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR; | |
6154 if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR; | |
6155 sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val); | |
6156 break; | |
6157 } | |
6158 | |
6159 case SQLITE_TESTCTRL_IMPOSTER: { | |
6160 int onOff, tnum; | |
6161 const char *zDbName; | |
6162 sqlite3 *db; | |
6163 if( objc!=6 ){ | |
6164 Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum"); | |
6165 return TCL_ERROR; | |
6166 } | |
6167 if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR; | |
6168 zDbName = Tcl_GetString(objv[3]); | |
6169 if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR; | |
6170 if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR; | |
6171 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum); | |
6172 break; | |
6173 } | |
6174 } | |
6175 | |
6176 Tcl_ResetResult(interp); | |
6177 return TCL_OK; | |
6178 } | |
6179 | |
6180 #if SQLITE_OS_UNIX | |
6181 #include <sys/time.h> | |
6182 #include <sys/resource.h> | |
6183 | |
6184 static int test_getrusage( | |
6185 void * clientData, | |
6186 Tcl_Interp *interp, | |
6187 int objc, | |
6188 Tcl_Obj *CONST objv[] | |
6189 ){ | |
6190 char buf[1024]; | |
6191 struct rusage r; | |
6192 memset(&r, 0, sizeof(r)); | |
6193 getrusage(RUSAGE_SELF, &r); | |
6194 | |
6195 sqlite3_snprintf(sizeof(buf), buf, | |
6196 "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d", | |
6197 (int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec, | |
6198 (int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec, | |
6199 (int)r.ru_minflt, (int)r.ru_majflt | |
6200 ); | |
6201 Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1)); | |
6202 return TCL_OK; | |
6203 } | |
6204 #endif | |
6205 | |
6206 #if SQLITE_OS_WIN | |
6207 /* | |
6208 ** Information passed from the main thread into the windows file locker | |
6209 ** background thread. | |
6210 */ | |
6211 struct win32FileLocker { | |
6212 char *evName; /* Name of event to signal thread startup */ | |
6213 HANDLE h; /* Handle of the file to be locked */ | |
6214 int delay1; /* Delay before locking */ | |
6215 int delay2; /* Delay before unlocking */ | |
6216 int ok; /* Finished ok */ | |
6217 int err; /* True if an error occurs */ | |
6218 }; | |
6219 #endif | |
6220 | |
6221 | |
6222 #if SQLITE_OS_WIN | |
6223 #include <process.h> | |
6224 /* | |
6225 ** The background thread that does file locking. | |
6226 */ | |
6227 static void win32_file_locker(void *pAppData){ | |
6228 struct win32FileLocker *p = (struct win32FileLocker*)pAppData; | |
6229 if( p->evName ){ | |
6230 HANDLE ev = OpenEvent(EVENT_MODIFY_STATE, FALSE, p->evName); | |
6231 if ( ev ){ | |
6232 SetEvent(ev); | |
6233 CloseHandle(ev); | |
6234 } | |
6235 } | |
6236 if( p->delay1 ) Sleep(p->delay1); | |
6237 if( LockFile(p->h, 0, 0, 100000000, 0) ){ | |
6238 Sleep(p->delay2); | |
6239 UnlockFile(p->h, 0, 0, 100000000, 0); | |
6240 p->ok = 1; | |
6241 }else{ | |
6242 p->err = 1; | |
6243 } | |
6244 CloseHandle(p->h); | |
6245 p->h = 0; | |
6246 p->delay1 = 0; | |
6247 p->delay2 = 0; | |
6248 } | |
6249 #endif | |
6250 | |
6251 #if SQLITE_OS_WIN | |
6252 /* | |
6253 ** lock_win32_file FILENAME DELAY1 DELAY2 | |
6254 ** | |
6255 ** Get an exclusive manditory lock on file for DELAY2 milliseconds. | |
6256 ** Wait DELAY1 milliseconds before acquiring the lock. | |
6257 */ | |
6258 static int win32_file_lock( | |
6259 void * clientData, | |
6260 Tcl_Interp *interp, | |
6261 int objc, | |
6262 Tcl_Obj *CONST objv[] | |
6263 ){ | |
6264 static struct win32FileLocker x = { "win32_file_lock", 0, 0, 0, 0, 0 }; | |
6265 const char *zFilename; | |
6266 char zBuf[200]; | |
6267 int retry = 0; | |
6268 HANDLE ev; | |
6269 DWORD wResult; | |
6270 | |
6271 if( objc!=4 && objc!=1 ){ | |
6272 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME DELAY1 DELAY2"); | |
6273 return TCL_ERROR; | |
6274 } | |
6275 if( objc==1 ){ | |
6276 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d", | |
6277 x.ok, x.err, x.delay1, x.delay2, x.h); | |
6278 Tcl_AppendResult(interp, zBuf, (char*)0); | |
6279 return TCL_OK; | |
6280 } | |
6281 while( x.h && retry<30 ){ | |
6282 retry++; | |
6283 Sleep(100); | |
6284 } | |
6285 if( x.h ){ | |
6286 Tcl_AppendResult(interp, "busy", (char*)0); | |
6287 return TCL_ERROR; | |
6288 } | |
6289 if( Tcl_GetIntFromObj(interp, objv[2], &x.delay1) ) return TCL_ERROR; | |
6290 if( Tcl_GetIntFromObj(interp, objv[3], &x.delay2) ) return TCL_ERROR; | |
6291 zFilename = Tcl_GetString(objv[1]); | |
6292 x.h = CreateFile(zFilename, GENERIC_READ|GENERIC_WRITE, | |
6293 FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_ALWAYS, | |
6294 FILE_ATTRIBUTE_NORMAL, 0); | |
6295 if( !x.h ){ | |
6296 Tcl_AppendResult(interp, "cannot open file: ", zFilename, (char*)0); | |
6297 return TCL_ERROR; | |
6298 } | |
6299 ev = CreateEvent(NULL, TRUE, FALSE, x.evName); | |
6300 if ( !ev ){ | |
6301 Tcl_AppendResult(interp, "cannot create event: ", x.evName, (char*)0); | |
6302 return TCL_ERROR; | |
6303 } | |
6304 _beginthread(win32_file_locker, 0, (void*)&x); | |
6305 Sleep(0); | |
6306 if ( (wResult = WaitForSingleObject(ev, 10000))!=WAIT_OBJECT_0 ){ | |
6307 sqlite3_snprintf(sizeof(zBuf), zBuf, "0x%x", wResult); | |
6308 Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0); | |
6309 CloseHandle(ev); | |
6310 return TCL_ERROR; | |
6311 } | |
6312 CloseHandle(ev); | |
6313 return TCL_OK; | |
6314 } | |
6315 | |
6316 /* | |
6317 ** exists_win32_path PATH | |
6318 ** | |
6319 ** Returns non-zero if the specified path exists, whose fully qualified name | |
6320 ** may exceed 260 characters if it is prefixed with "\\?\". | |
6321 */ | |
6322 static int win32_exists_path( | |
6323 void *clientData, | |
6324 Tcl_Interp *interp, | |
6325 int objc, | |
6326 Tcl_Obj *CONST objv[] | |
6327 ){ | |
6328 if( objc!=2 ){ | |
6329 Tcl_WrongNumArgs(interp, 1, objv, "PATH"); | |
6330 return TCL_ERROR; | |
6331 } | |
6332 Tcl_SetObjResult(interp, Tcl_NewBooleanObj( | |
6333 GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES )); | |
6334 return TCL_OK; | |
6335 } | |
6336 | |
6337 /* | |
6338 ** find_win32_file PATTERN | |
6339 ** | |
6340 ** Returns a list of entries in a directory that match the specified pattern, | |
6341 ** whose fully qualified name may exceed 248 characters if it is prefixed with | |
6342 ** "\\?\". | |
6343 */ | |
6344 static int win32_find_file( | |
6345 void *clientData, | |
6346 Tcl_Interp *interp, | |
6347 int objc, | |
6348 Tcl_Obj *CONST objv[] | |
6349 ){ | |
6350 HANDLE hFindFile = INVALID_HANDLE_VALUE; | |
6351 WIN32_FIND_DATAW findData; | |
6352 Tcl_Obj *listObj; | |
6353 DWORD lastErrno; | |
6354 if( objc!=2 ){ | |
6355 Tcl_WrongNumArgs(interp, 1, objv, "PATTERN"); | |
6356 return TCL_ERROR; | |
6357 } | |
6358 hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData); | |
6359 if( hFindFile==INVALID_HANDLE_VALUE ){ | |
6360 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); | |
6361 return TCL_ERROR; | |
6362 } | |
6363 listObj = Tcl_NewObj(); | |
6364 Tcl_IncrRefCount(listObj); | |
6365 do { | |
6366 Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj( | |
6367 findData.cFileName, -1)); | |
6368 Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj( | |
6369 findData.dwFileAttributes)); | |
6370 } while( FindNextFileW(hFindFile, &findData) ); | |
6371 lastErrno = GetLastError(); | |
6372 if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){ | |
6373 FindClose(hFindFile); | |
6374 Tcl_DecrRefCount(listObj); | |
6375 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); | |
6376 return TCL_ERROR; | |
6377 } | |
6378 FindClose(hFindFile); | |
6379 Tcl_SetObjResult(interp, listObj); | |
6380 return TCL_OK; | |
6381 } | |
6382 | |
6383 /* | |
6384 ** delete_win32_file FILENAME | |
6385 ** | |
6386 ** Deletes the specified file, whose fully qualified name may exceed 260 | |
6387 ** characters if it is prefixed with "\\?\". | |
6388 */ | |
6389 static int win32_delete_file( | |
6390 void *clientData, | |
6391 Tcl_Interp *interp, | |
6392 int objc, | |
6393 Tcl_Obj *CONST objv[] | |
6394 ){ | |
6395 if( objc!=2 ){ | |
6396 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); | |
6397 return TCL_ERROR; | |
6398 } | |
6399 if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){ | |
6400 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); | |
6401 return TCL_ERROR; | |
6402 } | |
6403 Tcl_ResetResult(interp); | |
6404 return TCL_OK; | |
6405 } | |
6406 | |
6407 /* | |
6408 ** make_win32_dir DIRECTORY | |
6409 ** | |
6410 ** Creates the specified directory, whose fully qualified name may exceed 248 | |
6411 ** characters if it is prefixed with "\\?\". | |
6412 */ | |
6413 static int win32_mkdir( | |
6414 void *clientData, | |
6415 Tcl_Interp *interp, | |
6416 int objc, | |
6417 Tcl_Obj *CONST objv[] | |
6418 ){ | |
6419 if( objc!=2 ){ | |
6420 Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY"); | |
6421 return TCL_ERROR; | |
6422 } | |
6423 if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){ | |
6424 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); | |
6425 return TCL_ERROR; | |
6426 } | |
6427 Tcl_ResetResult(interp); | |
6428 return TCL_OK; | |
6429 } | |
6430 | |
6431 /* | |
6432 ** remove_win32_dir DIRECTORY | |
6433 ** | |
6434 ** Removes the specified directory, whose fully qualified name may exceed 248 | |
6435 ** characters if it is prefixed with "\\?\". | |
6436 */ | |
6437 static int win32_rmdir( | |
6438 void *clientData, | |
6439 Tcl_Interp *interp, | |
6440 int objc, | |
6441 Tcl_Obj *CONST objv[] | |
6442 ){ | |
6443 if( objc!=2 ){ | |
6444 Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY"); | |
6445 return TCL_ERROR; | |
6446 } | |
6447 if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){ | |
6448 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); | |
6449 return TCL_ERROR; | |
6450 } | |
6451 Tcl_ResetResult(interp); | |
6452 return TCL_OK; | |
6453 } | |
6454 #endif | |
6455 | |
6456 | |
6457 /* | |
6458 ** optimization_control DB OPT BOOLEAN | |
6459 ** | |
6460 ** Enable or disable query optimizations using the sqlite3_test_control() | |
6461 ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. | |
6462 ** OPT is the name of the optimization to be disabled. | |
6463 */ | |
6464 static int optimization_control( | |
6465 void * clientData, | |
6466 Tcl_Interp *interp, | |
6467 int objc, | |
6468 Tcl_Obj *CONST objv[] | |
6469 ){ | |
6470 int i; | |
6471 sqlite3 *db; | |
6472 const char *zOpt; | |
6473 int onoff; | |
6474 int mask = 0; | |
6475 static const struct { | |
6476 const char *zOptName; | |
6477 int mask; | |
6478 } aOpt[] = { | |
6479 { "all", SQLITE_AllOpts }, | |
6480 { "none", 0 }, | |
6481 { "query-flattener", SQLITE_QueryFlattener }, | |
6482 { "column-cache", SQLITE_ColumnCache }, | |
6483 { "groupby-order", SQLITE_GroupByOrder }, | |
6484 { "factor-constants", SQLITE_FactorOutConst }, | |
6485 { "distinct-opt", SQLITE_DistinctOpt }, | |
6486 { "cover-idx-scan", SQLITE_CoverIdxScan }, | |
6487 { "order-by-idx-join", SQLITE_OrderByIdxJoin }, | |
6488 { "transitive", SQLITE_Transitive }, | |
6489 { "subquery-coroutine", SQLITE_SubqCoroutine }, | |
6490 { "omit-noop-join", SQLITE_OmitNoopJoin }, | |
6491 { "stat3", SQLITE_Stat34 }, | |
6492 { "stat4", SQLITE_Stat34 }, | |
6493 }; | |
6494 | |
6495 if( objc!=4 ){ | |
6496 Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); | |
6497 return TCL_ERROR; | |
6498 } | |
6499 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
6500 if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR; | |
6501 zOpt = Tcl_GetString(objv[2]); | |
6502 for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ | |
6503 if( strcmp(zOpt, aOpt[i].zOptName)==0 ){ | |
6504 mask = aOpt[i].mask; | |
6505 break; | |
6506 } | |
6507 } | |
6508 if( onoff ) mask = ~mask; | |
6509 if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){ | |
6510 Tcl_AppendResult(interp, "unknown optimization - should be one of:", | |
6511 (char*)0); | |
6512 for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ | |
6513 Tcl_AppendResult(interp, " ", aOpt[i].zOptName, (char*)0); | |
6514 } | |
6515 return TCL_ERROR; | |
6516 } | |
6517 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); | |
6518 return TCL_OK; | |
6519 } | |
6520 | |
6521 typedef struct sqlite3_api_routines sqlite3_api_routines; | |
6522 /* | |
6523 ** load_static_extension DB NAME ... | |
6524 ** | |
6525 ** Load one or more statically linked extensions. | |
6526 */ | |
6527 static int tclLoadStaticExtensionCmd( | |
6528 void * clientData, | |
6529 Tcl_Interp *interp, | |
6530 int objc, | |
6531 Tcl_Obj *CONST objv[] | |
6532 ){ | |
6533 extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6534 extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6535 extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6536 extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6537 extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6538 extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6539 extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6540 extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*
); | |
6541 extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6542 extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6543 extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6544 extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); | |
6545 extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines
*); | |
6546 static const struct { | |
6547 const char *zExtName; | |
6548 int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); | |
6549 } aExtension[] = { | |
6550 { "amatch", sqlite3_amatch_init }, | |
6551 { "closure", sqlite3_closure_init }, | |
6552 { "eval", sqlite3_eval_init }, | |
6553 { "fileio", sqlite3_fileio_init }, | |
6554 { "fuzzer", sqlite3_fuzzer_init }, | |
6555 { "ieee754", sqlite3_ieee_init }, | |
6556 { "nextchar", sqlite3_nextchar_init }, | |
6557 { "percentile", sqlite3_percentile_init }, | |
6558 { "regexp", sqlite3_regexp_init }, | |
6559 { "series", sqlite3_series_init }, | |
6560 { "spellfix", sqlite3_spellfix_init }, | |
6561 { "totype", sqlite3_totype_init }, | |
6562 { "wholenumber", sqlite3_wholenumber_init }, | |
6563 }; | |
6564 sqlite3 *db; | |
6565 const char *zName; | |
6566 int i, j, rc; | |
6567 char *zErrMsg = 0; | |
6568 if( objc<3 ){ | |
6569 Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ..."); | |
6570 return TCL_ERROR; | |
6571 } | |
6572 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
6573 for(j=2; j<objc; j++){ | |
6574 zName = Tcl_GetString(objv[j]); | |
6575 for(i=0; i<ArraySize(aExtension); i++){ | |
6576 if( strcmp(zName, aExtension[i].zExtName)==0 ) break; | |
6577 } | |
6578 if( i>=ArraySize(aExtension) ){ | |
6579 Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0); | |
6580 return TCL_ERROR; | |
6581 } | |
6582 if( aExtension[i].pInit ){ | |
6583 rc = aExtension[i].pInit(db, &zErrMsg, 0); | |
6584 }else{ | |
6585 rc = SQLITE_OK; | |
6586 } | |
6587 if( rc!=SQLITE_OK || zErrMsg ){ | |
6588 Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg
, | |
6589 (char*)0); | |
6590 sqlite3_free(zErrMsg); | |
6591 return TCL_ERROR; | |
6592 } | |
6593 } | |
6594 return TCL_OK; | |
6595 } | |
6596 | |
6597 /* | |
6598 ** sorter_test_fakeheap BOOL | |
6599 ** | |
6600 */ | |
6601 static int sorter_test_fakeheap( | |
6602 void * clientData, | |
6603 Tcl_Interp *interp, | |
6604 int objc, | |
6605 Tcl_Obj *CONST objv[] | |
6606 ){ | |
6607 int bArg; | |
6608 if( objc!=2 ){ | |
6609 Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); | |
6610 return TCL_ERROR; | |
6611 } | |
6612 | |
6613 if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){ | |
6614 return TCL_ERROR; | |
6615 } | |
6616 | |
6617 if( bArg ){ | |
6618 if( sqlite3GlobalConfig.pHeap==0 ){ | |
6619 sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1); | |
6620 } | |
6621 }else{ | |
6622 if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){ | |
6623 sqlite3GlobalConfig.pHeap = 0; | |
6624 } | |
6625 } | |
6626 | |
6627 Tcl_ResetResult(interp); | |
6628 return TCL_OK; | |
6629 } | |
6630 | |
6631 /* | |
6632 ** sorter_test_sort4_helper DB SQL1 NSTEP SQL2 | |
6633 ** | |
6634 ** Compile SQL statement $SQL1 and step it $NSTEP times. For each row, | |
6635 ** check that the leftmost and rightmost columns returned are both integers, | |
6636 ** and that both contain the same value. | |
6637 ** | |
6638 ** Then execute statement $SQL2. Check that the statement returns the same | |
6639 ** set of integers in the same order as in the previous step (using $SQL1). | |
6640 */ | |
6641 static int sorter_test_sort4_helper( | |
6642 void * clientData, | |
6643 Tcl_Interp *interp, | |
6644 int objc, | |
6645 Tcl_Obj *CONST objv[] | |
6646 ){ | |
6647 const char *zSql1; | |
6648 const char *zSql2; | |
6649 int nStep; | |
6650 int iStep; | |
6651 int iCksum1 = 0; | |
6652 int iCksum2 = 0; | |
6653 int rc; | |
6654 int iB; | |
6655 sqlite3 *db; | |
6656 sqlite3_stmt *pStmt; | |
6657 | |
6658 if( objc!=5 ){ | |
6659 Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2"); | |
6660 return TCL_ERROR; | |
6661 } | |
6662 | |
6663 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | |
6664 zSql1 = Tcl_GetString(objv[2]); | |
6665 if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR; | |
6666 zSql2 = Tcl_GetString(objv[4]); | |
6667 | |
6668 rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0); | |
6669 if( rc!=SQLITE_OK ) goto sql_error; | |
6670 | |
6671 iB = sqlite3_column_count(pStmt)-1; | |
6672 for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){ | |
6673 int a = sqlite3_column_int(pStmt, 0); | |
6674 if( a!=sqlite3_column_int(pStmt, iB) ){ | |
6675 Tcl_AppendResult(interp, "data error: (a!=b)", 0); | |
6676 return TCL_ERROR; | |
6677 } | |
6678 | |
6679 iCksum1 += (iCksum1 << 3) + a; | |
6680 } | |
6681 rc = sqlite3_finalize(pStmt); | |
6682 if( rc!=SQLITE_OK ) goto sql_error; | |
6683 | |
6684 rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0); | |
6685 if( rc!=SQLITE_OK ) goto sql_error; | |
6686 for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){ | |
6687 int a = sqlite3_column_int(pStmt, 0); | |
6688 iCksum2 += (iCksum2 << 3) + a; | |
6689 } | |
6690 rc = sqlite3_finalize(pStmt); | |
6691 if( rc!=SQLITE_OK ) goto sql_error; | |
6692 | |
6693 if( iCksum1!=iCksum2 ){ | |
6694 Tcl_AppendResult(interp, "checksum mismatch", 0); | |
6695 return TCL_ERROR; | |
6696 } | |
6697 | |
6698 return TCL_OK; | |
6699 sql_error: | |
6700 Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0); | |
6701 return TCL_ERROR; | |
6702 } | |
6703 | |
6704 | |
6705 #ifdef SQLITE_USER_AUTHENTICATION | |
6706 #include "sqlite3userauth.h" | |
6707 /* | |
6708 ** tclcmd: sqlite3_user_authenticate DB USERNAME PASSWORD | |
6709 */ | |
6710 static int test_user_authenticate( | |
6711 ClientData clientData, /* Unused */ | |
6712 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
6713 int objc, /* Number of arguments */ | |
6714 Tcl_Obj *CONST objv[] /* Command arguments */ | |
6715 ){ | |
6716 char *zUser = 0; | |
6717 char *zPasswd = 0; | |
6718 int nPasswd = 0; | |
6719 sqlite3 *db; | |
6720 int rc; | |
6721 | |
6722 if( objc!=4 ){ | |
6723 Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD"); | |
6724 return TCL_ERROR; | |
6725 } | |
6726 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
6727 return TCL_ERROR; | |
6728 } | |
6729 zUser = Tcl_GetString(objv[2]); | |
6730 zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd); | |
6731 rc = sqlite3_user_authenticate(db, zUser, zPasswd, nPasswd); | |
6732 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
6733 return TCL_OK; | |
6734 } | |
6735 #endif /* SQLITE_USER_AUTHENTICATION */ | |
6736 | |
6737 #ifdef SQLITE_USER_AUTHENTICATION | |
6738 /* | |
6739 ** tclcmd: sqlite3_user_add DB USERNAME PASSWORD ISADMIN | |
6740 */ | |
6741 static int test_user_add( | |
6742 ClientData clientData, /* Unused */ | |
6743 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
6744 int objc, /* Number of arguments */ | |
6745 Tcl_Obj *CONST objv[] /* Command arguments */ | |
6746 ){ | |
6747 char *zUser = 0; | |
6748 char *zPasswd = 0; | |
6749 int nPasswd = 0; | |
6750 int isAdmin = 0; | |
6751 sqlite3 *db; | |
6752 int rc; | |
6753 | |
6754 if( objc!=5 ){ | |
6755 Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN"); | |
6756 return TCL_ERROR; | |
6757 } | |
6758 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
6759 return TCL_ERROR; | |
6760 } | |
6761 zUser = Tcl_GetString(objv[2]); | |
6762 zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd); | |
6763 Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin); | |
6764 rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin); | |
6765 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
6766 return TCL_OK; | |
6767 } | |
6768 #endif /* SQLITE_USER_AUTHENTICATION */ | |
6769 | |
6770 #ifdef SQLITE_USER_AUTHENTICATION | |
6771 /* | |
6772 ** tclcmd: sqlite3_user_change DB USERNAME PASSWORD ISADMIN | |
6773 */ | |
6774 static int test_user_change( | |
6775 ClientData clientData, /* Unused */ | |
6776 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
6777 int objc, /* Number of arguments */ | |
6778 Tcl_Obj *CONST objv[] /* Command arguments */ | |
6779 ){ | |
6780 char *zUser = 0; | |
6781 char *zPasswd = 0; | |
6782 int nPasswd = 0; | |
6783 int isAdmin = 0; | |
6784 sqlite3 *db; | |
6785 int rc; | |
6786 | |
6787 if( objc!=5 ){ | |
6788 Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN"); | |
6789 return TCL_ERROR; | |
6790 } | |
6791 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
6792 return TCL_ERROR; | |
6793 } | |
6794 zUser = Tcl_GetString(objv[2]); | |
6795 zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd); | |
6796 Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin); | |
6797 rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin); | |
6798 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
6799 return TCL_OK; | |
6800 } | |
6801 #endif /* SQLITE_USER_AUTHENTICATION */ | |
6802 | |
6803 #ifdef SQLITE_USER_AUTHENTICATION | |
6804 /* | |
6805 ** tclcmd: sqlite3_user_delete DB USERNAME | |
6806 */ | |
6807 static int test_user_delete( | |
6808 ClientData clientData, /* Unused */ | |
6809 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
6810 int objc, /* Number of arguments */ | |
6811 Tcl_Obj *CONST objv[] /* Command arguments */ | |
6812 ){ | |
6813 char *zUser = 0; | |
6814 sqlite3 *db; | |
6815 int rc; | |
6816 | |
6817 if( objc!=3 ){ | |
6818 Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME"); | |
6819 return TCL_ERROR; | |
6820 } | |
6821 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ | |
6822 return TCL_ERROR; | |
6823 } | |
6824 zUser = Tcl_GetString(objv[2]); | |
6825 rc = sqlite3_user_delete(db, zUser); | |
6826 Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); | |
6827 return TCL_OK; | |
6828 } | |
6829 #endif /* SQLITE_USER_AUTHENTICATION */ | |
6830 | |
6831 /* | |
6832 ** tclcmd: bad_behavior TYPE | |
6833 ** | |
6834 ** Do some things that should trigger a valgrind or -fsanitize=undefined | |
6835 ** warning. This is used to verify that errors and warnings output by those | |
6836 ** tools are detected by the test scripts. | |
6837 ** | |
6838 ** TYPE BEHAVIOR | |
6839 ** 1 Overflow a signed integer | |
6840 ** 2 Jump based on an uninitialized variable | |
6841 ** 3 Read after free | |
6842 ** 4 Panic | |
6843 */ | |
6844 static int test_bad_behavior( | |
6845 ClientData clientData, /* Pointer to an integer containing zero */ | |
6846 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
6847 int objc, /* Number of arguments */ | |
6848 Tcl_Obj *CONST objv[] /* Command arguments */ | |
6849 ){ | |
6850 int iType; | |
6851 int xyz; | |
6852 int i = *(int*)clientData; | |
6853 int j; | |
6854 int w[10]; | |
6855 int *a; | |
6856 if( objc!=2 ){ | |
6857 Tcl_WrongNumArgs(interp, 1, objv, "TYPE"); | |
6858 return TCL_ERROR; | |
6859 } | |
6860 if( Tcl_GetIntFromObj(interp, objv[1], &iType) ) return TCL_ERROR; | |
6861 switch( iType ){ | |
6862 case 1: { | |
6863 xyz = 0x7fffff00 - i; | |
6864 xyz += 0x100; | |
6865 Tcl_SetObjResult(interp, Tcl_NewIntObj(xyz)); | |
6866 break; | |
6867 } | |
6868 case 2: { | |
6869 w[1] = 5; | |
6870 if( w[i]>0 ) w[1]++; | |
6871 Tcl_SetObjResult(interp, Tcl_NewIntObj(w[1])); | |
6872 break; | |
6873 } | |
6874 case 3: { | |
6875 a = malloc( sizeof(int)*10 ); | |
6876 for(j=0; j<10; j++) a[j] = j; | |
6877 free(a); | |
6878 Tcl_SetObjResult(interp, Tcl_NewIntObj(a[i])); | |
6879 break; | |
6880 } | |
6881 case 4: { | |
6882 Tcl_Panic("Deliberate panic"); | |
6883 break; | |
6884 } | |
6885 } | |
6886 return TCL_OK; | |
6887 } | |
6888 | |
6889 /* | |
6890 ** tclcmd: register_dbstat_vtab DB | |
6891 ** | |
6892 ** Cause the dbstat virtual table to be available on the connection DB | |
6893 */ | |
6894 static int test_register_dbstat_vtab( | |
6895 void *clientData, | |
6896 Tcl_Interp *interp, | |
6897 int objc, | |
6898 Tcl_Obj *CONST objv[] | |
6899 ){ | |
6900 #ifdef SQLITE_OMIT_VIRTUALTABLE | |
6901 Tcl_AppendResult(interp, "dbstat not available because of " | |
6902 "SQLITE_OMIT_VIRTUALTABLE", (void*)0); | |
6903 return TCL_ERROR; | |
6904 #else | |
6905 struct SqliteDb { sqlite3 *db; }; | |
6906 char *zDb; | |
6907 Tcl_CmdInfo cmdInfo; | |
6908 | |
6909 if( objc!=2 ){ | |
6910 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | |
6911 return TCL_ERROR; | |
6912 } | |
6913 | |
6914 zDb = Tcl_GetString(objv[1]); | |
6915 if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ | |
6916 sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db; | |
6917 sqlite3DbstatRegister(db); | |
6918 } | |
6919 return TCL_OK; | |
6920 #endif /* SQLITE_OMIT_VIRTUALTABLE */ | |
6921 } | |
6922 | |
6923 /* | |
6924 ** Register commands with the TCL interpreter. | |
6925 */ | |
6926 int Sqlitetest1_Init(Tcl_Interp *interp){ | |
6927 extern int sqlite3_search_count; | |
6928 extern int sqlite3_found_count; | |
6929 extern int sqlite3_interrupt_count; | |
6930 extern int sqlite3_open_file_count; | |
6931 extern int sqlite3_sort_count; | |
6932 extern int sqlite3_current_time; | |
6933 #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE | |
6934 extern int sqlite3_hostid_num; | |
6935 #endif | |
6936 extern int sqlite3_max_blobsize; | |
6937 extern int sqlite3BtreeSharedCacheReport(void*, | |
6938 Tcl_Interp*,int,Tcl_Obj*CONST*); | |
6939 static int iZero = 0; | |
6940 static struct { | |
6941 char *zName; | |
6942 Tcl_CmdProc *xProc; | |
6943 } aCmd[] = { | |
6944 { "db_enter", (Tcl_CmdProc*)db_enter }, | |
6945 { "db_leave", (Tcl_CmdProc*)db_leave }, | |
6946 { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, | |
6947 { "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 }, | |
6948 { "sqlite3_mprintf_long", (Tcl_CmdProc*)sqlite3_mprintf_long }, | |
6949 { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, | |
6950 { "sqlite3_snprintf_str", (Tcl_CmdProc*)sqlite3_snprintf_str }, | |
6951 { "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly}, | |
6952 { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, | |
6953 { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, | |
6954 { "sqlite3_mprintf_hexdouble", (Tcl_CmdProc*)sqlite3_mprintf_hexdouble}, | |
6955 { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, | |
6956 { "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n }, | |
6957 { "sqlite3_snprintf_int", (Tcl_CmdProc*)test_snprintf_int }, | |
6958 { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, | |
6959 { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, | |
6960 { "sqlite3_exec_hex", (Tcl_CmdProc*)test_exec_hex }, | |
6961 { "sqlite3_exec", (Tcl_CmdProc*)test_exec }, | |
6962 { "sqlite3_exec_nr", (Tcl_CmdProc*)test_exec_nr }, | |
6963 #ifndef SQLITE_OMIT_GET_TABLE | |
6964 { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, | |
6965 #endif | |
6966 { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, | |
6967 { "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 }, | |
6968 { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, | |
6969 { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, | |
6970 { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, | |
6971 { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, | |
6972 { "sqlite_bind", (Tcl_CmdProc*)test_bind }, | |
6973 { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, | |
6974 { "sqlite3_key", (Tcl_CmdProc*)test_key }, | |
6975 { "sqlite3_rekey", (Tcl_CmdProc*)test_rekey }, | |
6976 { "sqlite_set_magic", (Tcl_CmdProc*)sqlite_set_magic }, | |
6977 { "sqlite3_interrupt", (Tcl_CmdProc*)test_interrupt }, | |
6978 { "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, | |
6979 { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }, | |
6980 { "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit }, | |
6981 { "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used }, | |
6982 { "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout }, | |
6983 { "printf", (Tcl_CmdProc*)test_printf }, | |
6984 { "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace }, | |
6985 { "clang_sanitize_address", (Tcl_CmdProc*)clang_sanitize_address }, | |
6986 }; | |
6987 static struct { | |
6988 char *zName; | |
6989 Tcl_ObjCmdProc *xProc; | |
6990 void *clientData; | |
6991 } aObjCmd[] = { | |
6992 { "bad_behavior", test_bad_behavior, (void*)&iZero }, | |
6993 { "register_dbstat_vtab", test_register_dbstat_vtab }, | |
6994 { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, | |
6995 { "sqlite3_bind_int", test_bind_int, 0 }, | |
6996 { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, | |
6997 { "sqlite3_bind_zeroblob64", test_bind_zeroblob64, 0 }, | |
6998 { "sqlite3_bind_int64", test_bind_int64, 0 }, | |
6999 { "sqlite3_bind_double", test_bind_double, 0 }, | |
7000 { "sqlite3_bind_null", test_bind_null ,0 }, | |
7001 { "sqlite3_bind_text", test_bind_text ,0 }, | |
7002 { "sqlite3_bind_text16", test_bind_text16 ,0 }, | |
7003 { "sqlite3_bind_blob", test_bind_blob ,0 }, | |
7004 { "sqlite3_bind_parameter_count", test_bind_parameter_count, 0}, | |
7005 { "sqlite3_bind_parameter_name", test_bind_parameter_name, 0}, | |
7006 { "sqlite3_bind_parameter_index", test_bind_parameter_index, 0}, | |
7007 { "sqlite3_clear_bindings", test_clear_bindings, 0}, | |
7008 { "sqlite3_sleep", test_sleep, 0}, | |
7009 { "sqlite3_errcode", test_errcode ,0 }, | |
7010 { "sqlite3_extended_errcode", test_ex_errcode ,0 }, | |
7011 { "sqlite3_errmsg", test_errmsg ,0 }, | |
7012 { "sqlite3_errmsg16", test_errmsg16 ,0 }, | |
7013 { "sqlite3_open", test_open ,0 }, | |
7014 { "sqlite3_open16", test_open16 ,0 }, | |
7015 { "sqlite3_open_v2", test_open_v2 ,0 }, | |
7016 { "sqlite3_complete16", test_complete16 ,0 }, | |
7017 | |
7018 { "sqlite3_prepare", test_prepare ,0 }, | |
7019 { "sqlite3_prepare16", test_prepare16 ,0 }, | |
7020 { "sqlite3_prepare_v2", test_prepare_v2 ,0 }, | |
7021 { "sqlite3_prepare_tkt3134", test_prepare_tkt3134, 0}, | |
7022 { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 }, | |
7023 { "sqlite3_finalize", test_finalize ,0 }, | |
7024 { "sqlite3_stmt_status", test_stmt_status ,0 }, | |
7025 { "sqlite3_reset", test_reset ,0 }, | |
7026 { "sqlite3_expired", test_expired ,0 }, | |
7027 { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, | |
7028 { "sqlite3_changes", test_changes ,0 }, | |
7029 { "sqlite3_step", test_step ,0 }, | |
7030 { "sqlite3_sql", test_sql ,0 }, | |
7031 { "sqlite3_next_stmt", test_next_stmt ,0 }, | |
7032 { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, | |
7033 { "sqlite3_stmt_busy", test_stmt_busy ,0 }, | |
7034 { "uses_stmt_journal", uses_stmt_journal ,0 }, | |
7035 | |
7036 { "sqlite3_release_memory", test_release_memory, 0}, | |
7037 { "sqlite3_db_release_memory", test_db_release_memory, 0}, | |
7038 { "sqlite3_db_cacheflush", test_db_cacheflush, 0}, | |
7039 { "sqlite3_db_filename", test_db_filename, 0}, | |
7040 { "sqlite3_db_readonly", test_db_readonly, 0}, | |
7041 { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, | |
7042 { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, | |
7043 { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, | |
7044 | |
7045 { "sqlite3_load_extension", test_load_extension, 0}, | |
7046 { "sqlite3_enable_load_extension", test_enable_load, 0}, | |
7047 { "sqlite3_extended_result_codes", test_extended_result_codes, 0}, | |
7048 { "sqlite3_limit", test_limit, 0}, | |
7049 | |
7050 { "save_prng_state", save_prng_state, 0 }, | |
7051 { "restore_prng_state", restore_prng_state, 0 }, | |
7052 { "reset_prng_state", reset_prng_state, 0 }, | |
7053 { "database_never_corrupt", database_never_corrupt, 0}, | |
7054 { "database_may_be_corrupt", database_may_be_corrupt, 0}, | |
7055 { "optimization_control", optimization_control,0}, | |
7056 #if SQLITE_OS_WIN | |
7057 { "lock_win32_file", win32_file_lock, 0 }, | |
7058 { "exists_win32_path", win32_exists_path, 0 }, | |
7059 { "find_win32_file", win32_find_file, 0 }, | |
7060 { "delete_win32_file", win32_delete_file, 0 }, | |
7061 { "make_win32_dir", win32_mkdir, 0 }, | |
7062 { "remove_win32_dir", win32_rmdir, 0 }, | |
7063 #endif | |
7064 { "tcl_objproc", runAsObjProc, 0 }, | |
7065 | |
7066 /* sqlite3_column_*() API */ | |
7067 { "sqlite3_column_count", test_column_count ,0 }, | |
7068 { "sqlite3_data_count", test_data_count ,0 }, | |
7069 { "sqlite3_column_type", test_column_type ,0 }, | |
7070 { "sqlite3_column_blob", test_column_blob ,0 }, | |
7071 { "sqlite3_column_double", test_column_double ,0 }, | |
7072 { "sqlite3_column_int64", test_column_int64 ,0 }, | |
7073 { "sqlite3_column_text", test_stmt_utf8, (void*)sqlite3_column_text }, | |
7074 { "sqlite3_column_name", test_stmt_utf8, (void*)sqlite3_column_name }, | |
7075 { "sqlite3_column_int", test_stmt_int, (void*)sqlite3_column_int }, | |
7076 { "sqlite3_column_bytes", test_stmt_int, (void*)sqlite3_column_bytes}, | |
7077 #ifndef SQLITE_OMIT_DECLTYPE | |
7078 { "sqlite3_column_decltype",test_stmt_utf8,(void*)sqlite3_column_decltype}, | |
7079 #endif | |
7080 #ifdef SQLITE_ENABLE_COLUMN_METADATA | |
7081 { "sqlite3_column_database_name",test_stmt_utf8,(void*)sqlite3_column_database_n
ame}, | |
7082 { "sqlite3_column_table_name",test_stmt_utf8,(void*)sqlite3_column_table_name}, | |
7083 { "sqlite3_column_origin_name",test_stmt_utf8,(void*)sqlite3_column_origin_name}
, | |
7084 #endif | |
7085 | |
7086 #ifndef SQLITE_OMIT_UTF16 | |
7087 { "sqlite3_column_bytes16", test_stmt_int, (void*)sqlite3_column_bytes16 }, | |
7088 { "sqlite3_column_text16", test_stmt_utf16, (void*)sqlite3_column_text16}, | |
7089 { "sqlite3_column_name16", test_stmt_utf16, (void*)sqlite3_column_name16}, | |
7090 { "add_alignment_test_collations", add_alignment_test_collations, 0 }, | |
7091 #ifndef SQLITE_OMIT_DECLTYPE | |
7092 { "sqlite3_column_decltype16",test_stmt_utf16,(void*)sqlite3_column_decltyp
e16}, | |
7093 #endif | |
7094 #ifdef SQLITE_ENABLE_COLUMN_METADATA | |
7095 {"sqlite3_column_database_name16", | |
7096 test_stmt_utf16, (void*)sqlite3_column_database_name16}, | |
7097 {"sqlite3_column_table_name16", test_stmt_utf16, (void*)sqlite3_column_table_nam
e16}, | |
7098 {"sqlite3_column_origin_name16", test_stmt_utf16, (void*)sqlite3_column_origin_n
ame16}, | |
7099 #endif | |
7100 #endif | |
7101 { "sqlite3_create_collation_v2", test_create_collation_v2, 0 }, | |
7102 { "sqlite3_global_recover", test_global_recover, 0 }, | |
7103 { "working_64bit_int", working_64bit_int, 0 }, | |
7104 { "vfs_unlink_test", vfs_unlink_test, 0 }, | |
7105 { "vfs_initfail_test", vfs_initfail_test, 0 }, | |
7106 { "vfs_unregister_all", vfs_unregister_all, 0 }, | |
7107 { "vfs_reregister_all", vfs_reregister_all, 0 }, | |
7108 { "file_control_test", file_control_test, 0 }, | |
7109 { "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, | |
7110 { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, | |
7111 { "file_control_chunksize_test", file_control_chunksize_test, 0 }, | |
7112 { "file_control_sizehint_test", file_control_sizehint_test, 0 }, | |
7113 #if SQLITE_OS_WIN | |
7114 { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, | |
7115 { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, | |
7116 #endif | |
7117 { "file_control_persist_wal", file_control_persist_wal, 0 }, | |
7118 { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, | |
7119 { "file_control_vfsname", file_control_vfsname, 0 }, | |
7120 { "file_control_tempfilename", file_control_tempfilename, 0 }, | |
7121 { "sqlite3_vfs_list", vfs_list, 0 }, | |
7122 { "sqlite3_create_function_v2", test_create_function_v2, 0 }, | |
7123 | |
7124 /* Functions from os.h */ | |
7125 #ifndef SQLITE_OMIT_UTF16 | |
7126 { "add_test_collate", test_collate, 0 }, | |
7127 { "add_test_collate_needed", test_collate_needed, 0 }, | |
7128 { "add_test_function", test_function, 0 }, | |
7129 { "add_test_utf16bin_collate", test_utf16bin_collate, 0 }, | |
7130 #endif | |
7131 { "sqlite3_test_errstr", test_errstr, 0 }, | |
7132 { "tcl_variable_type", tcl_variable_type, 0 }, | |
7133 #ifndef SQLITE_OMIT_SHARED_CACHE | |
7134 { "sqlite3_enable_shared_cache", test_enable_shared, 0 }, | |
7135 { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, | |
7136 #endif | |
7137 { "sqlite3_libversion_number", test_libversion_number, 0 }, | |
7138 { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, | |
7139 #ifndef SQLITE_OMIT_INCRBLOB | |
7140 { "sqlite3_blob_reopen", test_blob_reopen, 0 }, | |
7141 #endif | |
7142 { "pcache_stats", test_pcache_stats, 0 }, | |
7143 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | |
7144 { "sqlite3_unlock_notify", test_unlock_notify, 0 }, | |
7145 #endif | |
7146 { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, | |
7147 { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, | |
7148 { "sqlite3_wal_autocheckpoint",test_wal_autocheckpoint, 0 }, | |
7149 { "test_sqlite3_log", test_sqlite3_log, 0 }, | |
7150 #ifndef SQLITE_OMIT_EXPLAIN | |
7151 { "print_explain_query_plan", test_print_eqp, 0 }, | |
7152 #endif | |
7153 { "sqlite3_test_control", test_test_control }, | |
7154 #if SQLITE_OS_UNIX | |
7155 { "getrusage", test_getrusage }, | |
7156 #endif | |
7157 { "load_static_extension", tclLoadStaticExtensionCmd }, | |
7158 { "sorter_test_fakeheap", sorter_test_fakeheap }, | |
7159 { "sorter_test_sort4_helper", sorter_test_sort4_helper }, | |
7160 #ifdef SQLITE_USER_AUTHENTICATION | |
7161 { "sqlite3_user_authenticate", test_user_authenticate, 0 }, | |
7162 { "sqlite3_user_add", test_user_add, 0 }, | |
7163 { "sqlite3_user_change", test_user_change, 0 }, | |
7164 { "sqlite3_user_delete", test_user_delete, 0 }, | |
7165 #endif | |
7166 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS | |
7167 { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, | |
7168 { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, | |
7169 #endif | |
7170 #ifdef SQLITE_ENABLE_SQLLOG | |
7171 { "sqlite3_config_sqllog", test_config_sqllog, 0 }, | |
7172 #endif | |
7173 { "vfs_current_time_int64", vfsCurrentTimeInt64, 0 }, | |
7174 #ifdef SQLITE_ENABLE_SNAPSHOT | |
7175 { "sqlite3_snapshot_get", test_snapshot_get, 0 }, | |
7176 { "sqlite3_snapshot_open", test_snapshot_open, 0 }, | |
7177 { "sqlite3_snapshot_free", test_snapshot_free, 0 }, | |
7178 #endif | |
7179 }; | |
7180 static int bitmask_size = sizeof(Bitmask)*8; | |
7181 static int longdouble_size = sizeof(LONGDOUBLE_TYPE); | |
7182 int i; | |
7183 extern int sqlite3_sync_count, sqlite3_fullsync_count; | |
7184 extern int sqlite3_opentemp_count; | |
7185 extern int sqlite3_like_count; | |
7186 extern int sqlite3_xferopt_count; | |
7187 extern int sqlite3_pager_readdb_count; | |
7188 extern int sqlite3_pager_writedb_count; | |
7189 extern int sqlite3_pager_writej_count; | |
7190 #if SQLITE_OS_WIN | |
7191 extern LONG volatile sqlite3_os_type; | |
7192 #endif | |
7193 #ifdef SQLITE_DEBUG | |
7194 extern int sqlite3WhereTrace; | |
7195 extern int sqlite3OSTrace; | |
7196 extern int sqlite3WalTrace; | |
7197 #endif | |
7198 #ifdef SQLITE_TEST | |
7199 #ifdef SQLITE_ENABLE_FTS3 | |
7200 extern int sqlite3_fts3_enable_parentheses; | |
7201 #endif | |
7202 #endif | |
7203 | |
7204 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | |
7205 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | |
7206 } | |
7207 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ | |
7208 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, | |
7209 aObjCmd[i].xProc, aObjCmd[i].clientData, 0); | |
7210 } | |
7211 Tcl_LinkVar(interp, "sqlite_search_count", | |
7212 (char*)&sqlite3_search_count, TCL_LINK_INT); | |
7213 Tcl_LinkVar(interp, "sqlite_found_count", | |
7214 (char*)&sqlite3_found_count, TCL_LINK_INT); | |
7215 Tcl_LinkVar(interp, "sqlite_sort_count", | |
7216 (char*)&sqlite3_sort_count, TCL_LINK_INT); | |
7217 Tcl_LinkVar(interp, "sqlite3_max_blobsize", | |
7218 (char*)&sqlite3_max_blobsize, TCL_LINK_INT); | |
7219 Tcl_LinkVar(interp, "sqlite_like_count", | |
7220 (char*)&sqlite3_like_count, TCL_LINK_INT); | |
7221 Tcl_LinkVar(interp, "sqlite_interrupt_count", | |
7222 (char*)&sqlite3_interrupt_count, TCL_LINK_INT); | |
7223 Tcl_LinkVar(interp, "sqlite_open_file_count", | |
7224 (char*)&sqlite3_open_file_count, TCL_LINK_INT); | |
7225 Tcl_LinkVar(interp, "sqlite_current_time", | |
7226 (char*)&sqlite3_current_time, TCL_LINK_INT); | |
7227 #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE | |
7228 Tcl_LinkVar(interp, "sqlite_hostid_num", | |
7229 (char*)&sqlite3_hostid_num, TCL_LINK_INT); | |
7230 #endif | |
7231 Tcl_LinkVar(interp, "sqlite3_xferopt_count", | |
7232 (char*)&sqlite3_xferopt_count, TCL_LINK_INT); | |
7233 Tcl_LinkVar(interp, "sqlite3_pager_readdb_count", | |
7234 (char*)&sqlite3_pager_readdb_count, TCL_LINK_INT); | |
7235 Tcl_LinkVar(interp, "sqlite3_pager_writedb_count", | |
7236 (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT); | |
7237 Tcl_LinkVar(interp, "sqlite3_pager_writej_count", | |
7238 (char*)&sqlite3_pager_writej_count, TCL_LINK_INT); | |
7239 #ifndef SQLITE_OMIT_UTF16 | |
7240 Tcl_LinkVar(interp, "unaligned_string_counter", | |
7241 (char*)&unaligned_string_counter, TCL_LINK_INT); | |
7242 #endif | |
7243 #ifndef SQLITE_OMIT_UTF16 | |
7244 Tcl_LinkVar(interp, "sqlite_last_needed_collation", | |
7245 (char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY); | |
7246 #endif | |
7247 #if SQLITE_OS_WIN | |
7248 Tcl_LinkVar(interp, "sqlite_os_type", | |
7249 (char*)&sqlite3_os_type, TCL_LINK_LONG); | |
7250 #endif | |
7251 #ifdef SQLITE_TEST | |
7252 { | |
7253 static const char *query_plan = "*** OBSOLETE VARIABLE ***"; | |
7254 Tcl_LinkVar(interp, "sqlite_query_plan", | |
7255 (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); | |
7256 } | |
7257 #endif | |
7258 #ifdef SQLITE_DEBUG | |
7259 Tcl_LinkVar(interp, "sqlite_where_trace", | |
7260 (char*)&sqlite3WhereTrace, TCL_LINK_INT); | |
7261 Tcl_LinkVar(interp, "sqlite_os_trace", | |
7262 (char*)&sqlite3OSTrace, TCL_LINK_INT); | |
7263 #ifndef SQLITE_OMIT_WAL | |
7264 Tcl_LinkVar(interp, "sqlite_wal_trace", | |
7265 (char*)&sqlite3WalTrace, TCL_LINK_INT); | |
7266 #endif | |
7267 #endif | |
7268 #ifndef SQLITE_OMIT_DISKIO | |
7269 Tcl_LinkVar(interp, "sqlite_opentemp_count", | |
7270 (char*)&sqlite3_opentemp_count, TCL_LINK_INT); | |
7271 #endif | |
7272 Tcl_LinkVar(interp, "sqlite_static_bind_value", | |
7273 (char*)&sqlite_static_bind_value, TCL_LINK_STRING); | |
7274 Tcl_LinkVar(interp, "sqlite_static_bind_nbyte", | |
7275 (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT); | |
7276 Tcl_LinkVar(interp, "sqlite_temp_directory", | |
7277 (char*)&sqlite3_temp_directory, TCL_LINK_STRING); | |
7278 Tcl_LinkVar(interp, "sqlite_data_directory", | |
7279 (char*)&sqlite3_data_directory, TCL_LINK_STRING); | |
7280 Tcl_LinkVar(interp, "bitmask_size", | |
7281 (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); | |
7282 Tcl_LinkVar(interp, "longdouble_size", | |
7283 (char*)&longdouble_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); | |
7284 Tcl_LinkVar(interp, "sqlite_sync_count", | |
7285 (char*)&sqlite3_sync_count, TCL_LINK_INT); | |
7286 Tcl_LinkVar(interp, "sqlite_fullsync_count", | |
7287 (char*)&sqlite3_fullsync_count, TCL_LINK_INT); | |
7288 #if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST) | |
7289 Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses", | |
7290 (char*)&sqlite3_fts3_enable_parentheses, TCL_LINK_INT); | |
7291 #endif | |
7292 return TCL_OK; | |
7293 } | |
OLD | NEW |