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