00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef NO_TCL
00017
00018 #include "sqliteInt.h"
00019 #include "tcl.h"
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <assert.h>
00023
00024
00025
00026
00027
00028
00029
00030 #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)
00031 # define UTF_TRANSLATION_NEEDED 1
00032 #endif
00033
00034
00035
00036
00037
00038 typedef struct SqlFunc SqlFunc;
00039 struct SqlFunc {
00040 Tcl_Interp *interp;
00041 char *zScript;
00042 SqlFunc *pNext;
00043 };
00044
00045
00046
00047
00048
00049 typedef struct SqliteDb SqliteDb;
00050 struct SqliteDb {
00051 sqlite *db;
00052 Tcl_Interp *interp;
00053 char *zBusy;
00054 char *zCommit;
00055 char *zTrace;
00056 char *zProgress;
00057 char *zAuth;
00058 SqlFunc *pFunc;
00059 int rc;
00060 };
00061
00062
00063
00064
00065
00066 typedef struct CallbackData CallbackData;
00067 struct CallbackData {
00068 Tcl_Interp *interp;
00069 char *zArray;
00070 Tcl_Obj *pCode;
00071 int once;
00072 int tcl_rc;
00073 int nColName;
00074 char **azColName;
00075 };
00076
00077 #ifdef UTF_TRANSLATION_NEEDED
00078
00079
00080
00081
00082
00083
00084
00085 static int DbEvalCallback(
00086 void *clientData,
00087 int nCol,
00088 char ** azCol,
00089 char ** azN
00090 ){
00091 CallbackData *cbData = (CallbackData*)clientData;
00092 int i, rc;
00093 Tcl_DString dCol;
00094 Tcl_DStringInit(&dCol);
00095 if( cbData->azColName==0 ){
00096 assert( cbData->once );
00097 cbData->once = 0;
00098 if( cbData->zArray[0] ){
00099 Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
00100 }
00101 cbData->azColName = malloc( nCol*sizeof(char*) );
00102 if( cbData->azColName==0 ){ return 1; }
00103 cbData->nColName = nCol;
00104 for(i=0; i<nCol; i++){
00105 Tcl_ExternalToUtfDString(NULL, azN[i], -1, &dCol);
00106 cbData->azColName[i] = malloc( Tcl_DStringLength(&dCol) + 1 );
00107 if( cbData->azColName[i] ){
00108 strcpy(cbData->azColName[i], Tcl_DStringValue(&dCol));
00109 }else{
00110 return 1;
00111 }
00112 if( cbData->zArray[0] ){
00113 Tcl_SetVar2(cbData->interp, cbData->zArray, "*",
00114 Tcl_DStringValue(&dCol), TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
00115 if( azN[nCol]!=0 ){
00116 Tcl_DString dType;
00117 Tcl_DStringInit(&dType);
00118 Tcl_DStringAppend(&dType, "typeof:", -1);
00119 Tcl_DStringAppend(&dType, Tcl_DStringValue(&dCol), -1);
00120 Tcl_DStringFree(&dCol);
00121 Tcl_ExternalToUtfDString(NULL, azN[i+nCol], -1, &dCol);
00122 Tcl_SetVar2(cbData->interp, cbData->zArray,
00123 Tcl_DStringValue(&dType), Tcl_DStringValue(&dCol),
00124 TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
00125 Tcl_DStringFree(&dType);
00126 }
00127 }
00128
00129 Tcl_DStringFree(&dCol);
00130 }
00131 }
00132 if( azCol!=0 ){
00133 if( cbData->zArray[0] ){
00134 for(i=0; i<nCol; i++){
00135 char *z = azCol[i];
00136 if( z==0 ) z = "";
00137 Tcl_DStringInit(&dCol);
00138 Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
00139 Tcl_SetVar2(cbData->interp, cbData->zArray, cbData->azColName[i],
00140 Tcl_DStringValue(&dCol), 0);
00141 Tcl_DStringFree(&dCol);
00142 }
00143 }else{
00144 for(i=0; i<nCol; i++){
00145 char *z = azCol[i];
00146 if( z==0 ) z = "";
00147 Tcl_DStringInit(&dCol);
00148 Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
00149 Tcl_SetVar(cbData->interp, cbData->azColName[i],
00150 Tcl_DStringValue(&dCol), 0);
00151 Tcl_DStringFree(&dCol);
00152 }
00153 }
00154 }
00155 rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
00156 if( rc==TCL_CONTINUE ) rc = TCL_OK;
00157 cbData->tcl_rc = rc;
00158 return rc!=TCL_OK;
00159 }
00160 #endif
00161
00162 #ifndef UTF_TRANSLATION_NEEDED
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 static int DbEvalCallback(
00175 void *clientData,
00176 int nCol,
00177 char ** azCol,
00178 char ** azN
00179 ){
00180 CallbackData *cbData = (CallbackData*)clientData;
00181 int i, rc;
00182 if( azCol==0 || (cbData->once && cbData->zArray[0]) ){
00183 Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
00184 for(i=0; i<nCol; i++){
00185 Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
00186 TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
00187 if( azN[nCol] ){
00188 char *z = sqlite_mprintf("typeof:%s", azN[i]);
00189 Tcl_SetVar2(cbData->interp, cbData->zArray, z, azN[i+nCol],
00190 TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
00191 sqlite_freemem(z);
00192 }
00193 }
00194 cbData->once = 0;
00195 }
00196 if( azCol!=0 ){
00197 if( cbData->zArray[0] ){
00198 for(i=0; i<nCol; i++){
00199 char *z = azCol[i];
00200 if( z==0 ) z = "";
00201 Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0);
00202 }
00203 }else{
00204 for(i=0; i<nCol; i++){
00205 char *z = azCol[i];
00206 if( z==0 ) z = "";
00207 Tcl_SetVar(cbData->interp, azN[i], z, 0);
00208 }
00209 }
00210 }
00211 rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
00212 if( rc==TCL_CONTINUE ) rc = TCL_OK;
00213 cbData->tcl_rc = rc;
00214 return rc!=TCL_OK;
00215 }
00216 #endif
00217
00218
00219
00220
00221
00222
00223
00224 static int DbEvalCallback2(
00225 void *clientData,
00226 int nCol,
00227 char ** azCol,
00228 char ** azN
00229 ){
00230 Tcl_Obj *pList = (Tcl_Obj*)clientData;
00231 int i;
00232 if( azCol==0 ) return 0;
00233 for(i=0; i<nCol; i++){
00234 Tcl_Obj *pElem;
00235 if( azCol[i] && *azCol[i] ){
00236 #ifdef UTF_TRANSLATION_NEEDED
00237 Tcl_DString dCol;
00238 Tcl_DStringInit(&dCol);
00239 Tcl_ExternalToUtfDString(NULL, azCol[i], -1, &dCol);
00240 pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
00241 Tcl_DStringFree(&dCol);
00242 #else
00243 pElem = Tcl_NewStringObj(azCol[i], -1);
00244 #endif
00245 }else{
00246 pElem = Tcl_NewObj();
00247 }
00248 Tcl_ListObjAppendElement(0, pList, pElem);
00249 }
00250 return 0;
00251 }
00252
00253
00254
00255
00256
00257 static int DbEvalCallback3(
00258 void *clientData,
00259 int nCol,
00260 char ** azCol,
00261 char ** azN
00262 ){
00263 Tcl_Interp *interp = (Tcl_Interp*)clientData;
00264 Tcl_Obj *pElem;
00265 if( azCol==0 ) return 1;
00266 if( nCol==0 ) return 1;
00267 #ifdef UTF_TRANSLATION_NEEDED
00268 {
00269 Tcl_DString dCol;
00270 Tcl_DStringInit(&dCol);
00271 Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
00272 pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
00273 Tcl_DStringFree(&dCol);
00274 }
00275 #else
00276 pElem = Tcl_NewStringObj(azCol[0], -1);
00277 #endif
00278 Tcl_SetObjResult(interp, pElem);
00279 return 1;
00280 }
00281
00282
00283
00284
00285 static void DbDeleteCmd(void *db){
00286 SqliteDb *pDb = (SqliteDb*)db;
00287 sqlite_close(pDb->db);
00288 while( pDb->pFunc ){
00289 SqlFunc *pFunc = pDb->pFunc;
00290 pDb->pFunc = pFunc->pNext;
00291 Tcl_Free((char*)pFunc);
00292 }
00293 if( pDb->zBusy ){
00294 Tcl_Free(pDb->zBusy);
00295 }
00296 if( pDb->zTrace ){
00297 Tcl_Free(pDb->zTrace);
00298 }
00299 if( pDb->zAuth ){
00300 Tcl_Free(pDb->zAuth);
00301 }
00302 Tcl_Free((char*)pDb);
00303 }
00304
00305
00306
00307
00308
00309 static int DbBusyHandler(void *cd, const char *zTable, int nTries){
00310 SqliteDb *pDb = (SqliteDb*)cd;
00311 int rc;
00312 char zVal[30];
00313 char *zCmd;
00314 Tcl_DString cmd;
00315
00316 Tcl_DStringInit(&cmd);
00317 Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
00318 Tcl_DStringAppendElement(&cmd, zTable);
00319 sprintf(zVal, " %d", nTries);
00320 Tcl_DStringAppend(&cmd, zVal, -1);
00321 zCmd = Tcl_DStringValue(&cmd);
00322 rc = Tcl_Eval(pDb->interp, zCmd);
00323 Tcl_DStringFree(&cmd);
00324 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
00325 return 0;
00326 }
00327 return 1;
00328 }
00329
00330
00331
00332
00333 static int DbProgressHandler(void *cd){
00334 SqliteDb *pDb = (SqliteDb*)cd;
00335 int rc;
00336
00337 assert( pDb->zProgress );
00338 rc = Tcl_Eval(pDb->interp, pDb->zProgress);
00339 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
00340 return 1;
00341 }
00342 return 0;
00343 }
00344
00345
00346
00347
00348
00349 static void DbTraceHandler(void *cd, const char *zSql){
00350 SqliteDb *pDb = (SqliteDb*)cd;
00351 Tcl_DString str;
00352
00353 Tcl_DStringInit(&str);
00354 Tcl_DStringAppend(&str, pDb->zTrace, -1);
00355 Tcl_DStringAppendElement(&str, zSql);
00356 Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
00357 Tcl_DStringFree(&str);
00358 Tcl_ResetResult(pDb->interp);
00359 }
00360
00361
00362
00363
00364
00365
00366
00367 static int DbCommitHandler(void *cd){
00368 SqliteDb *pDb = (SqliteDb*)cd;
00369 int rc;
00370
00371 rc = Tcl_Eval(pDb->interp, pDb->zCommit);
00372 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
00373 return 1;
00374 }
00375 return 0;
00376 }
00377
00378
00379
00380
00381
00382 static void tclSqlFunc(sqlite_func *context, int argc, const char **argv){
00383 SqlFunc *p = sqlite_user_data(context);
00384 Tcl_DString cmd;
00385 int i;
00386 int rc;
00387
00388 Tcl_DStringInit(&cmd);
00389 Tcl_DStringAppend(&cmd, p->zScript, -1);
00390 for(i=0; i<argc; i++){
00391 Tcl_DStringAppendElement(&cmd, argv[i] ? argv[i] : "");
00392 }
00393 rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
00394 if( rc ){
00395 sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1);
00396 }else{
00397 sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
00398 }
00399 }
00400 #ifndef SQLITE_OMIT_AUTHORIZATION
00401
00402
00403
00404
00405
00406
00407 static int auth_callback(
00408 void *pArg,
00409 int code,
00410 const char *zArg1,
00411 const char *zArg2,
00412 const char *zArg3,
00413 const char *zArg4
00414 ){
00415 char *zCode;
00416 Tcl_DString str;
00417 int rc;
00418 const char *zReply;
00419 SqliteDb *pDb = (SqliteDb*)pArg;
00420
00421 switch( code ){
00422 case SQLITE_COPY : zCode="SQLITE_COPY"; break;
00423 case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
00424 case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break;
00425 case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
00426 case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
00427 case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
00428 case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
00429 case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break;
00430 case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break;
00431 case SQLITE_DELETE : zCode="SQLITE_DELETE"; break;
00432 case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break;
00433 case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break;
00434 case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break;
00435 case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break;
00436 case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
00437 case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break;
00438 case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break;
00439 case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break;
00440 case SQLITE_INSERT : zCode="SQLITE_INSERT"; break;
00441 case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break;
00442 case SQLITE_READ : zCode="SQLITE_READ"; break;
00443 case SQLITE_SELECT : zCode="SQLITE_SELECT"; break;
00444 case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break;
00445 case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
00446 case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
00447 case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
00448 default : zCode="????"; break;
00449 }
00450 Tcl_DStringInit(&str);
00451 Tcl_DStringAppend(&str, pDb->zAuth, -1);
00452 Tcl_DStringAppendElement(&str, zCode);
00453 Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
00454 Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
00455 Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
00456 Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
00457 rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
00458 Tcl_DStringFree(&str);
00459 zReply = Tcl_GetStringResult(pDb->interp);
00460 if( strcmp(zReply,"SQLITE_OK")==0 ){
00461 rc = SQLITE_OK;
00462 }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
00463 rc = SQLITE_DENY;
00464 }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
00465 rc = SQLITE_IGNORE;
00466 }else{
00467 rc = 999;
00468 }
00469 return rc;
00470 }
00471 #endif
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
00487 SqliteDb *pDb = (SqliteDb*)cd;
00488 int choice;
00489 int rc = TCL_OK;
00490 static const char *DB_strs[] = {
00491 "authorizer", "busy", "changes",
00492 "close", "commit_hook", "complete",
00493 "errorcode", "eval", "function",
00494 "last_insert_rowid", "last_statement_changes", "onecolumn",
00495 "progress", "rekey", "timeout",
00496 "trace",
00497 0
00498 };
00499 enum DB_enum {
00500 DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
00501 DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE,
00502 DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
00503 DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
00504 DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
00505 DB_TRACE
00506 };
00507
00508 if( objc<2 ){
00509 Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
00510 return TCL_ERROR;
00511 }
00512 if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
00513 return TCL_ERROR;
00514 }
00515
00516 switch( (enum DB_enum)choice ){
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 case DB_AUTHORIZER: {
00537 if( objc>3 ){
00538 Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
00539 }else if( objc==2 ){
00540 if( pDb->zAuth ){
00541 Tcl_AppendResult(interp, pDb->zAuth, 0);
00542 }
00543 }else{
00544 char *zAuth;
00545 int len;
00546 if( pDb->zAuth ){
00547 Tcl_Free(pDb->zAuth);
00548 }
00549 zAuth = Tcl_GetStringFromObj(objv[2], &len);
00550 if( zAuth && len>0 ){
00551 pDb->zAuth = Tcl_Alloc( len + 1 );
00552 strcpy(pDb->zAuth, zAuth);
00553 }else{
00554 pDb->zAuth = 0;
00555 }
00556 #ifndef SQLITE_OMIT_AUTHORIZATION
00557 if( pDb->zAuth ){
00558 pDb->interp = interp;
00559 sqlite_set_authorizer(pDb->db, auth_callback, pDb);
00560 }else{
00561 sqlite_set_authorizer(pDb->db, 0, 0);
00562 }
00563 #endif
00564 }
00565 break;
00566 }
00567
00568
00569
00570
00571
00572
00573 case DB_BUSY: {
00574 if( objc>3 ){
00575 Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
00576 return TCL_ERROR;
00577 }else if( objc==2 ){
00578 if( pDb->zBusy ){
00579 Tcl_AppendResult(interp, pDb->zBusy, 0);
00580 }
00581 }else{
00582 char *zBusy;
00583 int len;
00584 if( pDb->zBusy ){
00585 Tcl_Free(pDb->zBusy);
00586 }
00587 zBusy = Tcl_GetStringFromObj(objv[2], &len);
00588 if( zBusy && len>0 ){
00589 pDb->zBusy = Tcl_Alloc( len + 1 );
00590 strcpy(pDb->zBusy, zBusy);
00591 }else{
00592 pDb->zBusy = 0;
00593 }
00594 if( pDb->zBusy ){
00595 pDb->interp = interp;
00596 sqlite_busy_handler(pDb->db, DbBusyHandler, pDb);
00597 }else{
00598 sqlite_busy_handler(pDb->db, 0, 0);
00599 }
00600 }
00601 break;
00602 }
00603
00604
00605
00606
00607
00608
00609 case DB_PROGRESS: {
00610 if( objc==2 ){
00611 if( pDb->zProgress ){
00612 Tcl_AppendResult(interp, pDb->zProgress, 0);
00613 }
00614 }else if( objc==4 ){
00615 char *zProgress;
00616 int len;
00617 int N;
00618 if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
00619 return TCL_ERROR;
00620 };
00621 if( pDb->zProgress ){
00622 Tcl_Free(pDb->zProgress);
00623 }
00624 zProgress = Tcl_GetStringFromObj(objv[3], &len);
00625 if( zProgress && len>0 ){
00626 pDb->zProgress = Tcl_Alloc( len + 1 );
00627 strcpy(pDb->zProgress, zProgress);
00628 }else{
00629 pDb->zProgress = 0;
00630 }
00631 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
00632 if( pDb->zProgress ){
00633 pDb->interp = interp;
00634 sqlite_progress_handler(pDb->db, N, DbProgressHandler, pDb);
00635 }else{
00636 sqlite_progress_handler(pDb->db, 0, 0, 0);
00637 }
00638 #endif
00639 }else{
00640 Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
00641 return TCL_ERROR;
00642 }
00643 break;
00644 }
00645
00646
00647
00648
00649
00650
00651
00652 case DB_CHANGES: {
00653 Tcl_Obj *pResult;
00654 int nChange;
00655 if( objc!=2 ){
00656 Tcl_WrongNumArgs(interp, 2, objv, "");
00657 return TCL_ERROR;
00658 }
00659 nChange = sqlite_changes(pDb->db);
00660 pResult = Tcl_GetObjResult(interp);
00661 Tcl_SetIntObj(pResult, nChange);
00662 break;
00663 }
00664
00665
00666
00667
00668
00669
00670
00671
00672 case DB_LAST_STATEMENT_CHANGES: {
00673 Tcl_Obj *pResult;
00674 int lsChange;
00675 if( objc!=2 ){
00676 Tcl_WrongNumArgs(interp, 2, objv, "");
00677 return TCL_ERROR;
00678 }
00679 lsChange = sqlite_last_statement_changes(pDb->db);
00680 pResult = Tcl_GetObjResult(interp);
00681 Tcl_SetIntObj(pResult, lsChange);
00682 break;
00683 }
00684
00685
00686
00687
00688
00689 case DB_CLOSE: {
00690 Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
00691 break;
00692 }
00693
00694
00695
00696
00697
00698
00699
00700
00701 case DB_COMMIT_HOOK: {
00702 if( objc>3 ){
00703 Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
00704 }else if( objc==2 ){
00705 if( pDb->zCommit ){
00706 Tcl_AppendResult(interp, pDb->zCommit, 0);
00707 }
00708 }else{
00709 char *zCommit;
00710 int len;
00711 if( pDb->zCommit ){
00712 Tcl_Free(pDb->zCommit);
00713 }
00714 zCommit = Tcl_GetStringFromObj(objv[2], &len);
00715 if( zCommit && len>0 ){
00716 pDb->zCommit = Tcl_Alloc( len + 1 );
00717 strcpy(pDb->zCommit, zCommit);
00718 }else{
00719 pDb->zCommit = 0;
00720 }
00721 if( pDb->zCommit ){
00722 pDb->interp = interp;
00723 sqlite_commit_hook(pDb->db, DbCommitHandler, pDb);
00724 }else{
00725 sqlite_commit_hook(pDb->db, 0, 0);
00726 }
00727 }
00728 break;
00729 }
00730
00731
00732
00733
00734
00735
00736
00737 case DB_COMPLETE: {
00738 Tcl_Obj *pResult;
00739 int isComplete;
00740 if( objc!=3 ){
00741 Tcl_WrongNumArgs(interp, 2, objv, "SQL");
00742 return TCL_ERROR;
00743 }
00744 isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) );
00745 pResult = Tcl_GetObjResult(interp);
00746 Tcl_SetBooleanObj(pResult, isComplete);
00747 break;
00748 }
00749
00750
00751
00752
00753
00754
00755
00756 case DB_ERRORCODE: {
00757 Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
00758 break;
00759 }
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 case DB_EVAL: {
00771 CallbackData cbData;
00772 char *zErrMsg;
00773 char *zSql;
00774 #ifdef UTF_TRANSLATION_NEEDED
00775 Tcl_DString dSql;
00776 int i;
00777 #endif
00778
00779 if( objc!=5 && objc!=3 ){
00780 Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
00781 return TCL_ERROR;
00782 }
00783 pDb->interp = interp;
00784 zSql = Tcl_GetStringFromObj(objv[2], 0);
00785 #ifdef UTF_TRANSLATION_NEEDED
00786 Tcl_DStringInit(&dSql);
00787 Tcl_UtfToExternalDString(NULL, zSql, -1, &dSql);
00788 zSql = Tcl_DStringValue(&dSql);
00789 #endif
00790 Tcl_IncrRefCount(objv[2]);
00791 if( objc==5 ){
00792 cbData.interp = interp;
00793 cbData.once = 1;
00794 cbData.zArray = Tcl_GetStringFromObj(objv[3], 0);
00795 cbData.pCode = objv[4];
00796 cbData.tcl_rc = TCL_OK;
00797 cbData.nColName = 0;
00798 cbData.azColName = 0;
00799 zErrMsg = 0;
00800 Tcl_IncrRefCount(objv[3]);
00801 Tcl_IncrRefCount(objv[4]);
00802 rc = sqlite_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg);
00803 Tcl_DecrRefCount(objv[4]);
00804 Tcl_DecrRefCount(objv[3]);
00805 if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
00806 }else{
00807 Tcl_Obj *pList = Tcl_NewObj();
00808 cbData.tcl_rc = TCL_OK;
00809 rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
00810 Tcl_SetObjResult(interp, pList);
00811 }
00812 pDb->rc = rc;
00813 if( rc==SQLITE_ABORT ){
00814 if( zErrMsg ) free(zErrMsg);
00815 rc = cbData.tcl_rc;
00816 }else if( zErrMsg ){
00817 Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
00818 free(zErrMsg);
00819 rc = TCL_ERROR;
00820 }else if( rc!=SQLITE_OK ){
00821 Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
00822 rc = TCL_ERROR;
00823 }else{
00824 }
00825 Tcl_DecrRefCount(objv[2]);
00826 #ifdef UTF_TRANSLATION_NEEDED
00827 Tcl_DStringFree(&dSql);
00828 if( objc==5 && cbData.azColName ){
00829 for(i=0; i<cbData.nColName; i++){
00830 if( cbData.azColName[i] ) free(cbData.azColName[i]);
00831 }
00832 free(cbData.azColName);
00833 cbData.azColName = 0;
00834 }
00835 #endif
00836 return rc;
00837 }
00838
00839
00840
00841
00842
00843
00844
00845 case DB_FUNCTION: {
00846 SqlFunc *pFunc;
00847 char *zName;
00848 char *zScript;
00849 int nScript;
00850 if( objc!=4 ){
00851 Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
00852 return TCL_ERROR;
00853 }
00854 zName = Tcl_GetStringFromObj(objv[2], 0);
00855 zScript = Tcl_GetStringFromObj(objv[3], &nScript);
00856 pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
00857 if( pFunc==0 ) return TCL_ERROR;
00858 pFunc->interp = interp;
00859 pFunc->pNext = pDb->pFunc;
00860 pFunc->zScript = (char*)&pFunc[1];
00861 strcpy(pFunc->zScript, zScript);
00862 sqlite_create_function(pDb->db, zName, -1, tclSqlFunc, pFunc);
00863 sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC);
00864 break;
00865 }
00866
00867
00868
00869
00870
00871
00872 case DB_LAST_INSERT_ROWID: {
00873 Tcl_Obj *pResult;
00874 int rowid;
00875 if( objc!=2 ){
00876 Tcl_WrongNumArgs(interp, 2, objv, "");
00877 return TCL_ERROR;
00878 }
00879 rowid = sqlite_last_insert_rowid(pDb->db);
00880 pResult = Tcl_GetObjResult(interp);
00881 Tcl_SetIntObj(pResult, rowid);
00882 break;
00883 }
00884
00885
00886
00887
00888
00889
00890 case DB_ONECOLUMN: {
00891 char *zSql;
00892 char *zErrMsg = 0;
00893 if( objc!=3 ){
00894 Tcl_WrongNumArgs(interp, 2, objv, "SQL");
00895 return TCL_ERROR;
00896 }
00897 zSql = Tcl_GetStringFromObj(objv[2], 0);
00898 rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
00899 if( rc==SQLITE_ABORT ){
00900 rc = SQLITE_OK;
00901 }else if( zErrMsg ){
00902 Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
00903 free(zErrMsg);
00904 rc = TCL_ERROR;
00905 }else if( rc!=SQLITE_OK ){
00906 Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
00907 rc = TCL_ERROR;
00908 }
00909 break;
00910 }
00911
00912
00913
00914
00915
00916
00917 case DB_REKEY: {
00918 int nKey;
00919 void *pKey;
00920 if( objc!=3 ){
00921 Tcl_WrongNumArgs(interp, 2, objv, "KEY");
00922 return TCL_ERROR;
00923 }
00924 pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
00925 #ifdef SQLITE_HAS_CODEC
00926 rc = sqlite_rekey(pDb->db, pKey, nKey);
00927 if( rc ){
00928 Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
00929 rc = TCL_ERROR;
00930 }
00931 #endif
00932 break;
00933 }
00934
00935
00936
00937
00938
00939
00940 case DB_TIMEOUT: {
00941 int ms;
00942 if( objc!=3 ){
00943 Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
00944 return TCL_ERROR;
00945 }
00946 if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
00947 sqlite_busy_timeout(pDb->db, ms);
00948 break;
00949 }
00950
00951
00952
00953
00954
00955
00956
00957 case DB_TRACE: {
00958 if( objc>3 ){
00959 Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
00960 }else if( objc==2 ){
00961 if( pDb->zTrace ){
00962 Tcl_AppendResult(interp, pDb->zTrace, 0);
00963 }
00964 }else{
00965 char *zTrace;
00966 int len;
00967 if( pDb->zTrace ){
00968 Tcl_Free(pDb->zTrace);
00969 }
00970 zTrace = Tcl_GetStringFromObj(objv[2], &len);
00971 if( zTrace && len>0 ){
00972 pDb->zTrace = Tcl_Alloc( len + 1 );
00973 strcpy(pDb->zTrace, zTrace);
00974 }else{
00975 pDb->zTrace = 0;
00976 }
00977 if( pDb->zTrace ){
00978 pDb->interp = interp;
00979 sqlite_trace(pDb->db, DbTraceHandler, pDb);
00980 }else{
00981 sqlite_trace(pDb->db, 0, 0);
00982 }
00983 }
00984 break;
00985 }
00986
00987 }
00988 return rc;
00989 }
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
01023 int mode;
01024 SqliteDb *p;
01025 void *pKey = 0;
01026 int nKey = 0;
01027 const char *zArg;
01028 char *zErrMsg;
01029 const char *zFile;
01030 char zBuf[80];
01031 if( objc==2 ){
01032 zArg = Tcl_GetStringFromObj(objv[1], 0);
01033 if( strcmp(zArg,"-encoding")==0 ){
01034 Tcl_AppendResult(interp,sqlite_encoding,0);
01035 return TCL_OK;
01036 }
01037 if( strcmp(zArg,"-version")==0 ){
01038 Tcl_AppendResult(interp,sqlite_version,0);
01039 return TCL_OK;
01040 }
01041 if( strcmp(zArg,"-has-codec")==0 ){
01042 #ifdef SQLITE_HAS_CODEC
01043 Tcl_AppendResult(interp,"1",0);
01044 #else
01045 Tcl_AppendResult(interp,"0",0);
01046 #endif
01047 return TCL_OK;
01048 }
01049 if( strcmp(zArg,"-tcl-uses-utf")==0 ){
01050 #ifdef TCL_UTF_MAX
01051 Tcl_AppendResult(interp,"1",0);
01052 #else
01053 Tcl_AppendResult(interp,"0",0);
01054 #endif
01055 return TCL_OK;
01056 }
01057 }
01058 if( objc==5 || objc==6 ){
01059 zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
01060 if( strcmp(zArg,"-key")==0 ){
01061 pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
01062 objc -= 2;
01063 }
01064 }
01065 if( objc!=3 && objc!=4 ){
01066 Tcl_WrongNumArgs(interp, 1, objv,
01067 #ifdef SQLITE_HAS_CODEC
01068 "HANDLE FILENAME ?-key CODEC-KEY?"
01069 #else
01070 "HANDLE FILENAME ?MODE?"
01071 #endif
01072 );
01073 return TCL_ERROR;
01074 }
01075 if( objc==3 ){
01076 mode = 0666;
01077 }else if( Tcl_GetIntFromObj(interp, objv[3], &mode)!=TCL_OK ){
01078 return TCL_ERROR;
01079 }
01080 zErrMsg = 0;
01081 p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
01082 if( p==0 ){
01083 Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
01084 return TCL_ERROR;
01085 }
01086 memset(p, 0, sizeof(*p));
01087 zFile = Tcl_GetStringFromObj(objv[2], 0);
01088 #ifdef SQLITE_HAS_CODEC
01089 p->db = sqlite_open_encrypted(zFile, pKey, nKey, 0, &zErrMsg);
01090 #else
01091 p->db = sqlite_open(zFile, mode, &zErrMsg);
01092 #endif
01093 if( p->db==0 ){
01094 Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
01095 Tcl_Free((char*)p);
01096 free(zErrMsg);
01097 return TCL_ERROR;
01098 }
01099 zArg = Tcl_GetStringFromObj(objv[1], 0);
01100 Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
01101
01102
01103
01104 sprintf(zBuf, "%p", p->db);
01105 if( strncmp(zBuf,"0x",2) ){
01106 sprintf(zBuf, "0x%p", p->db);
01107 }
01108 Tcl_AppendResult(interp, zBuf, 0);
01109
01110
01111
01112
01113 #ifdef SQLITE_TEST
01114 {
01115 extern void Md5_Register(sqlite*);
01116 Md5_Register(p->db);
01117 }
01118 #endif
01119 return TCL_OK;
01120 }
01121
01122
01123
01124
01125
01126 #ifndef USE_TCL_STUBS
01127 # undef Tcl_InitStubs
01128 # define Tcl_InitStubs(a,b,c)
01129 #endif
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 int Sqlite_Init(Tcl_Interp *interp){
01141 Tcl_InitStubs(interp, "8.0", 0);
01142 Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
01143 Tcl_PkgProvide(interp, "sqlite", "2.0");
01144 return TCL_OK;
01145 }
01146 int Tclsqlite_Init(Tcl_Interp *interp){
01147 Tcl_InitStubs(interp, "8.0", 0);
01148 Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
01149 Tcl_PkgProvide(interp, "sqlite", "2.0");
01150 return TCL_OK;
01151 }
01152 int Sqlite_SafeInit(Tcl_Interp *interp){
01153 return TCL_OK;
01154 }
01155 int Tclsqlite_SafeInit(Tcl_Interp *interp){
01156 return TCL_OK;
01157 }
01158
01159 #if 0
01160
01161
01162
01163
01164 int Et_AppInit(Tcl_Interp *interp){
01165 return Sqlite_Init(interp);
01166 }
01167 #endif
01168
01169
01170
01171
01172 #if defined(TCLSH) && TCLSH>0
01173
01174
01175
01176
01177
01178
01179 #if TCLSH==1
01180 static char zMainloop[] =
01181 "set line {}\n"
01182 "while {![eof stdin]} {\n"
01183 "if {$line!=\"\"} {\n"
01184 "puts -nonewline \"> \"\n"
01185 "} else {\n"
01186 "puts -nonewline \"% \"\n"
01187 "}\n"
01188 "flush stdout\n"
01189 "append line [gets stdin]\n"
01190 "if {[info complete $line]} {\n"
01191 "if {[catch {uplevel #0 $line} result]} {\n"
01192 "puts stderr \"Error: $result\"\n"
01193 "} elseif {$result!=\"\"} {\n"
01194 "puts $result\n"
01195 "}\n"
01196 "set line {}\n"
01197 "} else {\n"
01198 "append line \\n\n"
01199 "}\n"
01200 "}\n"
01201 ;
01202 #endif
01203
01204 int Libsqlite_Init( Tcl_Interp *interp) {
01205 #ifdef TCL_THREADS
01206 if (Thread_Init(interp) == TCL_ERROR) {
01207 return TCL_ERROR;
01208 }
01209 #endif
01210 Sqlite_Init(interp);
01211 #ifdef SQLITE_TEST
01212 {
01213 extern int Sqlitetest1_Init(Tcl_Interp*);
01214 extern int Sqlitetest2_Init(Tcl_Interp*);
01215 extern int Sqlitetest3_Init(Tcl_Interp*);
01216 extern int Md5_Init(Tcl_Interp*);
01217 Sqlitetest1_Init(interp);
01218 Sqlitetest2_Init(interp);
01219 Sqlitetest3_Init(interp);
01220 Md5_Init(interp);
01221 Tcl_StaticPackage(interp, "sqlite", Libsqlite_Init, Libsqlite_Init);
01222 }
01223 #endif
01224 return TCL_OK;
01225 }
01226
01227 #define TCLSH_MAIN main
01228 #if TCLSH==1
01229 int TCLSH_MAIN(int argc, char **argv){
01230 #ifndef TCL_THREADS
01231 Tcl_Interp *interp;
01232 Tcl_FindExecutable(argv[0]);
01233 interp = Tcl_CreateInterp();
01234 Libsqlite_Init(interp);
01235 if( argc>=2 ){
01236 int i;
01237 Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
01238 Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
01239 for(i=2; i<argc; i++){
01240 Tcl_SetVar(interp, "argv", argv[i],
01241 TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
01242 }
01243 if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
01244 const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
01245 if( zInfo==0 ) zInfo = interp->result;
01246 fprintf(stderr,"%s: %s\n", *argv, zInfo);
01247 return TCL_ERROR;
01248 }
01249 }else{
01250 Tcl_GlobalEval(interp, zMainloop);
01251 }
01252 return 0;
01253 #else
01254 Tcl_Main(argc, argv, Libsqlite_Init);
01255 #endif
01256 return 0;
01257 }
01258 #endif
01259
01260
01261
01262
01263
01264 #if TCLSH==2
01265 static char zAnalysis[] =
01266 #include "spaceanal_tcl.h"
01267 ;
01268
01269 int main(int argc, char **argv){
01270 Tcl_Interp *interp;
01271 int i;
01272 Tcl_FindExecutable(argv[0]);
01273 interp = Tcl_CreateInterp();
01274 Libsqlite_Init(interp);
01275 Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY);
01276 Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
01277 for(i=1; i<argc; i++){
01278 Tcl_SetVar(interp, "argv", argv[i],
01279 TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
01280 }
01281 if( Tcl_GlobalEval(interp, zAnalysis)!=TCL_OK ){
01282 const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
01283 if( zInfo==0 ) zInfo = interp->result;
01284 fprintf(stderr,"%s: %s\n", *argv, zInfo);
01285 return TCL_ERROR;
01286 }
01287 return 0;
01288 }
01289 #endif
01290
01291 #endif
01292
01293 #endif