Fossil SCM

th1 query API now accepts the statement ID as the first arg after the query command or later on after the subcommand, for all subcommands where this makes sense.

stephan 2012-07-15 14:31 th1-query-api
Commit 09d7df15972dcf3d91e90ab64f43b2f4e6d8a82a
+225 -86
--- src/th_main.c
+++ src/th_main.c
@@ -569,11 +569,11 @@
569569
570570
571571
/*
572572
** TH Syntax:
573573
**
574
-** argv_getat Index
574
+** argv at Index
575575
**
576576
** Returns the raw argument at the given index, throwing if
577577
** out of bounds.
578578
*/
579579
static int argvGetAtCmd(
@@ -608,11 +608,11 @@
608608
609609
610610
/*
611611
** TH Syntax:
612612
**
613
-** argv_getstr longName ??shortName? ?defaultValue??
613
+** argv getstr longName ??shortName? ?defaultValue??
614614
**
615615
** Functions more or less like Fossil's find_option().
616616
** If the given argument is found then its value is returned,
617617
** else defaultValue is returned. If that is not set
618618
** and the option is not found, an error is thrown.
@@ -679,11 +679,11 @@
679679
}
680680
681681
/*
682682
** TH Syntax:
683683
**
684
-** argv_getbool longName ??shortName? ?defaultValue??
684
+** argv getbool longName ??shortName? ?defaultValue??
685685
**
686686
** Works just like argv_getstr but treats any empty value or one
687687
** starting with the digit '0' as a boolean false.
688688
**
689689
** Returns the result as an integer 0 (false) or 1 (true).
@@ -752,11 +752,11 @@
752752
}
753753
754754
/*
755755
** TH Syntax:
756756
**
757
-** argv_getint longName ?shortName? ?defaultValue?
757
+** argv getint longName ?shortName? ?defaultValue?
758758
*/
759759
static int argvFindOptionIntCmd(
760760
Th_Interp *interp,
761761
void *p,
762762
int argc,
@@ -843,11 +843,11 @@
843843
844844
#ifdef TH_ENABLE_SQLITE
845845
846846
/*
847847
** Adds the given prepared statement to the interpreter. Returns the
848
-** statements opaque identifier (a positive value). Ownerships of
848
+** statement's opaque identifier (a positive value). Ownerships of
849849
** pStmt is transfered to interp and it must be cleaned up by the
850850
** client by calling Th_FinalizeStmt(), passing it the value returned
851851
** by this function.
852852
**
853853
** If interp is destroyed before all statements are finalized,
@@ -861,10 +861,11 @@
861861
** On error (statement not found) non-0 is returned. After this
862862
** call, some subsequent call to Th_AddStmt() may return the
863863
** same statement ID.
864864
*/
865865
static int Th_FinalizeStmt(Th_Interp *interp, int stmtId);
866
+static int Th_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt *);
866867
867868
/*
868869
** Fetches the statement with the given ID, as returned by
869870
** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
870871
** refers) to a statement added via Th_AddStmt().
@@ -921,10 +922,30 @@
921922
return 0;
922923
}else{
923924
return 1;
924925
}
925926
}
927
+
928
+static int Th_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt * pSt){
929
+ Th_Sqlite * sq = Th_sqlite_manager(interp);
930
+ int i = 0;
931
+ sqlite3_stmt * st = NULL;
932
+ int rc = 0;
933
+ for( ; i < sq->nStmt; ++i ){
934
+ st = sq->aStmt[i];
935
+ if(st == pSt) break;
936
+ }
937
+ if( st == pSt ){
938
+ assert( i>=0 && i<sq->nStmt );
939
+ sq->aStmt[i] = NULL;
940
+ sqlite3_finalize(st);
941
+ return 0;
942
+ }else{
943
+ return 1;
944
+ }
945
+}
946
+
926947
927948
static sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){
928949
Th_Sqlite * sq = Th_sqlite_manager(interp);
929950
return ((stmtId<1) || (stmtId > sq->nStmt))
930951
? NULL
@@ -955,11 +976,11 @@
955976
956977
957978
/*
958979
** TH Syntax:
959980
**
960
-** query_prepare SQL
981
+** query prepare SQL
961982
**
962983
** Returns an opaque statement identifier.
963984
*/
964985
static int queryPrepareCmd(
965986
Th_Interp *interp,
@@ -1028,11 +1049,12 @@
10281049
}
10291050
10301051
/*
10311052
** TH Syntax:
10321053
**
1033
-** query_finalize stmtId
1054
+** query finalize stmtId
1055
+** query stmtId finalize
10341056
**
10351057
** sqlite3_finalize()s the given statement.
10361058
*/
10371059
static int queryFinalizeCmd(
10381060
Th_Interp *interp,
@@ -1039,26 +1061,31 @@
10391061
void *p,
10401062
int argc,
10411063
const char **argv,
10421064
int *argl
10431065
){
1066
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1067
+ int requireArgc = pStmt ? 1 : 2;
10441068
char * zSql;
1045
- sqlite3_stmt * pStmt = NULL;
1046
- int rc = 0;
1069
+ int stId = 0;
10471070
char const * arg;
1048
- if( argc!=2 ){
1071
+ int rc;
1072
+ if( argc!=requireArgc ){
10491073
return Th_WrongNumArgs2(interp,
10501074
argv[0], argl[0],
10511075
"StmtHandle");
10521076
}
1053
- arg = argv[1];
1054
- pStmt = queryStmtHandle(interp, arg, argl[1], &rc);
1055
- if( rc < 1 ){
1056
- return TH_ERROR;
1077
+ if(!pStmt){
1078
+ arg = argv[1];
1079
+ pStmt = queryStmtHandle(interp, arg, argl[1], &stId);
1080
+ if(!pStmt){
1081
+ Th_ErrorMessage(interp, "Not a valid statement handle argument.", NULL, 0);
1082
+ return TH_ERROR;
1083
+ }
10571084
}
10581085
assert( NULL != pStmt );
1059
- rc = Th_FinalizeStmt( interp, rc );
1086
+ rc = Th_FinalizeStmt2( interp, pStmt );
10601087
Th_SetResultInt( interp, rc );
10611088
return TH_OK;
10621089
}
10631090
10641091
/*
@@ -1079,11 +1106,11 @@
10791106
** least 3.
10801107
**
10811108
** On success it returns 0, sets *pStmt to the referenced statement
10821109
** handle, and pIndex (if not NULL) to the integer value of argv[2]
10831110
** argument. On error it reports the error via TH, returns non-0, and
1084
-** modifies neither pStmt not pIndex.
1111
+** modifies neither pStmt nor pIndex.
10851112
*/
10861113
static int queryStmtIndexArgs(
10871114
Th_Interp * interp,
10881115
int argc,
10891116
char const ** argv,
@@ -1106,11 +1133,11 @@
11061133
}
11071134
if( 0 != Th_ToInt( interp, argv[2], argl[2], &index ) ){
11081135
return TH_ERROR;
11091136
}
11101137
}
1111
- stmt = queryStmtHandle(interp, argv[1], argl[1], NULL);
1138
+ stmt = *pStmt ? *pStmt : queryStmtHandle(interp, argv[1], argl[1], NULL);
11121139
if( NULL == stmt ){
11131140
return TH_ERROR;
11141141
}else{
11151142
*pStmt = stmt;
11161143
if( pIndex ){
@@ -1121,11 +1148,12 @@
11211148
}
11221149
11231150
/*
11241151
** TH Syntax:
11251152
**
1126
-** query_step stmtId
1153
+** query step stmtId
1154
+** query stmtId step
11271155
**
11281156
** Steps the given statement handle. Returns 0 at the end of the set,
11291157
** a positive value if it fetches a row, and throws on error.
11301158
*/
11311159
static int queryStepCmd(
@@ -1133,18 +1161,19 @@
11331161
void *p,
11341162
int argc,
11351163
const char **argv,
11361164
int *argl
11371165
){
1138
- sqlite3_stmt * pStmt = NULL;
1166
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1167
+ int requireArgc = pStmt ? 1 : 2;
11391168
int rc = 0;
1140
- if( argc!=2 ){
1169
+ if( argc!=requireArgc ){
11411170
return Th_WrongNumArgs2(interp,
11421171
argv[0], argl[0],
11431172
"StmtHandle");
11441173
}
1145
- if(0 != queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, NULL)){
1174
+ if(!pStmt && 0 != queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, NULL)){
11461175
return TH_ERROR;
11471176
}
11481177
assert(NULL != pStmt);
11491178
rc = sqlite3_step( pStmt );
11501179
switch(rc){
@@ -1162,11 +1191,12 @@
11621191
}
11631192
11641193
/*
11651194
** TH Syntax:
11661195
**
1167
-** query_col_string stmtId Index
1196
+** query col string stmtId Index
1197
+** query stmtId col string Index
11681198
**
11691199
** Returns the result column value at the given 0-based index.
11701200
*/
11711201
static int queryColStringCmd(
11721202
Th_Interp *interp,
@@ -1173,20 +1203,25 @@
11731203
void *p,
11741204
int argc,
11751205
const char **argv,
11761206
int *argl
11771207
){
1178
- sqlite3_stmt * pStmt = NULL;
1208
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1209
+ int requireArgc = pStmt ? 2 : 3;
11791210
char const * val;
11801211
int index = -1;
11811212
int valLen;
1182
- if( argc!=3 ){
1213
+ if( argc!=requireArgc ){
11831214
return Th_WrongNumArgs2(interp,
11841215
argv[0], argl[0],
11851216
"StmtHandle Index");
11861217
}
1187
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1218
+ if(!pStmt){
1219
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1220
+ }else{
1221
+ Th_ToInt(interp, argv[1], argl[1], &index);
1222
+ }
11881223
if(index < 0){
11891224
return TH_ERROR;
11901225
}
11911226
val = sqlite3_column_text( pStmt, index );
11921227
valLen = val ? sqlite3_column_bytes( pStmt, index ) : 0;
@@ -1195,11 +1230,12 @@
11951230
}
11961231
11971232
/*
11981233
** TH Syntax:
11991234
**
1200
-** query_col_int stmtId Index
1235
+** query col int stmtId Index
1236
+** query stmtId col int Index
12011237
**
12021238
** Returns the result column value at the given 0-based index.
12031239
*/
12041240
static int queryColIntCmd(
12051241
Th_Interp *interp,
@@ -1206,19 +1242,25 @@
12061242
void *p,
12071243
int argc,
12081244
const char **argv,
12091245
int *argl
12101246
){
1211
- sqlite3_stmt * pStmt = NULL;
1247
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1248
+ int requireArgc = pStmt ? 2 : 3;
12121249
int rc = 0;
12131250
int index = -1;
1214
- if( argc!=3 ){
1251
+ if( argc!=requireArgc ){
12151252
return Th_WrongNumArgs2(interp,
12161253
argv[0], argl[0],
12171254
"StmtHandle Index");
12181255
}
1219
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1256
+ if(!pStmt){
1257
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1258
+ }else{
1259
+ Th_ToInt(interp, argv[1], argl[1], &index);
1260
+ }
1261
+
12201262
if(index < 0){
12211263
return TH_ERROR;
12221264
}
12231265
Th_SetResultInt( interp, sqlite3_column_int( pStmt, index ) );
12241266
return TH_OK;
@@ -1225,11 +1267,12 @@
12251267
}
12261268
12271269
/*
12281270
** TH Syntax:
12291271
**
1230
-** query_col_double stmtId Index
1272
+** query col double stmtId Index
1273
+** query stmtId col double Index
12311274
**
12321275
** Returns the result column value at the given 0-based index.
12331276
*/
12341277
static int queryColDoubleCmd(
12351278
Th_Interp *interp,
@@ -1236,19 +1279,24 @@
12361279
void *p,
12371280
int argc,
12381281
const char **argv,
12391282
int *argl
12401283
){
1241
- sqlite3_stmt * pStmt = NULL;
1284
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1285
+ int requireArgc = pStmt ? 2 : 3;
12421286
double rc = 0;
12431287
int index = -1;
1244
- if( argc!=3 ){
1288
+ if( argc!=requireArgc ){
12451289
return Th_WrongNumArgs2(interp,
12461290
argv[0], argl[0],
12471291
"StmtHandle Index");
12481292
}
1249
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1293
+ if(!pStmt){
1294
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1295
+ }else{
1296
+ Th_ToInt(interp, argv[1], argl[1], &index);
1297
+ }
12501298
if(index < 0){
12511299
return TH_ERROR;
12521300
}
12531301
Th_SetResultDouble( interp, sqlite3_column_double( pStmt, index ) );
12541302
return TH_OK;
@@ -1255,11 +1303,12 @@
12551303
}
12561304
12571305
/*
12581306
** TH Syntax:
12591307
**
1260
-** query_col_is_null stmtId Index
1308
+** query col is_null stmtId Index
1309
+** query stmtId col is_null Index
12611310
**
12621311
** Returns non-0 if the given 0-based result column index contains
12631312
** an SQL NULL value, else returns 0.
12641313
*/
12651314
static int queryColIsNullCmd(
@@ -1267,19 +1316,24 @@
12671316
void *p,
12681317
int argc,
12691318
const char **argv,
12701319
int *argl
12711320
){
1272
- sqlite3_stmt * pStmt = NULL;
1321
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1322
+ int requireArgc = pStmt ? 2 : 3;
12731323
double rc = 0;
12741324
int index = -1;
1275
- if( argc!=3 ){
1325
+ if( argc!=requireArgc ){
12761326
return Th_WrongNumArgs2(interp,
12771327
argv[0], argl[0],
12781328
"StmtHandle Index");
12791329
}
1280
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1330
+ if(!pStmt){
1331
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1332
+ }else{
1333
+ Th_ToInt(interp, argv[1], argl[1], &index);
1334
+ }
12811335
if(index < 0){
12821336
return TH_ERROR;
12831337
}
12841338
Th_SetResultInt( interp,
12851339
SQLITE_NULL==sqlite3_column_type( pStmt, index )
@@ -1288,11 +1342,12 @@
12881342
}
12891343
12901344
/*
12911345
** TH Syntax:
12921346
**
1293
-** query_col_type stmtId Index
1347
+** query col type stmtId Index
1348
+** query stmtId col type Index
12941349
**
12951350
** Returns the sqlite type identifier for the given 0-based result
12961351
** column index. The values are available in TH as $SQLITE_NULL,
12971352
** $SQLITE_INTEGER, etc.
12981353
*/
@@ -1301,19 +1356,24 @@
13011356
void *p,
13021357
int argc,
13031358
const char **argv,
13041359
int *argl
13051360
){
1306
- sqlite3_stmt * pStmt = NULL;
1361
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1362
+ int requireArgc = pStmt ? 2 : 3;
13071363
double rc = 0;
13081364
int index = -1;
1309
- if( argc!=3 ){
1365
+ if( argc!=requireArgc ){
13101366
return Th_WrongNumArgs2(interp,
13111367
argv[0], argl[0],
13121368
"StmtHandle Index");
13131369
}
1314
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1370
+ if(!pStmt){
1371
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1372
+ }else{
1373
+ Th_ToInt( interp, argv[1], argl[1], &index );
1374
+ }
13151375
if(index < 0){
13161376
return TH_ERROR;
13171377
}
13181378
Th_SetResultInt( interp, sqlite3_column_type( pStmt, index ) );
13191379
return TH_OK;
@@ -1320,11 +1380,12 @@
13201380
}
13211381
13221382
/*
13231383
** TH Syntax:
13241384
**
1325
-** query_col_count stmtId
1385
+** query col count stmtId
1386
+** query stmtId col count
13261387
**
13271388
** Returns the number of result columns in the query.
13281389
*/
13291390
static int queryColCountCmd(
13301391
Th_Interp *interp,
@@ -1332,29 +1393,33 @@
13321393
int argc,
13331394
const char **argv,
13341395
int *argl
13351396
){
13361397
int rc;
1337
- sqlite3_stmt * pStmt = NULL;
1338
- if( argc!=2 ){
1398
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1399
+ int requireArgc = pStmt ? 1 : 2;
1400
+ if( argc!=requireArgc ){
13391401
return Th_WrongNumArgs2(interp,
13401402
argv[0], argl[0],
13411403
"StmtHandle");
13421404
}
1343
- pStmt = queryStmtHandle(interp, argv[1], argl[1], NULL);
1344
- if( NULL == pStmt ){
1345
- return TH_ERROR;
1405
+ if(!pStmt){
1406
+ pStmt = queryStmtHandle(interp, argv[1], argl[1], NULL);
1407
+ if( NULL == pStmt ){
1408
+ return TH_ERROR;
1409
+ }
13461410
}
13471411
rc = sqlite3_column_count( pStmt );
13481412
Th_SetResultInt( interp, rc );
13491413
return TH_OK;
13501414
}
13511415
13521416
/*
13531417
** TH Syntax:
13541418
**
1355
-** query_col_count stmtId Index
1419
+** query col name stmtId Index
1420
+** query stmtId col name Index
13561421
**
13571422
** Returns the result column name at the given 0-based index.
13581423
*/
13591424
static int queryColNameCmd(
13601425
Th_Interp *interp,
@@ -1361,22 +1426,26 @@
13611426
void *p,
13621427
int argc,
13631428
const char **argv,
13641429
int *argl
13651430
){
1366
- sqlite3_stmt * pStmt = NULL;
1431
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1432
+ int requireArgc = pStmt ? 2 : 3;
13671433
char const * val;
13681434
int rc = 0;
13691435
int index = -1;
1370
- if( argc!=3 ){
1436
+ if( argc!=requireArgc ){
13711437
return Th_WrongNumArgs2(interp,
13721438
argv[0], argl[0],
13731439
"StmtHandle Index");
13741440
}
1375
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1441
+ if(!pStmt){
1442
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1443
+ }else{
1444
+ Th_ToInt( interp, argv[1], argl[1], &index );
1445
+ }
13761446
if(index < 0){
1377
- assert(NULL==pStmt);
13781447
return TH_ERROR;
13791448
}
13801449
assert(NULL!=pStmt);
13811450
val = sqlite3_column_name( pStmt, index );
13821451
if(NULL==val){
@@ -1386,41 +1455,56 @@
13861455
Th_SetResult( interp, val, strlen( val ) );
13871456
return TH_OK;
13881457
}
13891458
}
13901459
1460
+/*
1461
+** TH Syntax:
1462
+**
1463
+** query col time stmtId Index format
1464
+** query stmtId col name Index format
1465
+**
1466
+** Returns the result column name at the given 0-based index.
1467
+*/
13911468
static int queryColTimeCmd(
13921469
Th_Interp *interp,
13931470
void *ctx,
13941471
int argc,
13951472
const char **argv,
13961473
int *argl
13971474
){
1398
- sqlite3_stmt * pStmt = NULL;
1475
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)ctx;
1476
+ int minArgs = pStmt ? 3 : 4;
1477
+ int argPos;
13991478
char const * val;
14001479
char * fval;
14011480
int i, rc = 0;
14021481
int index = -1;
14031482
char const * fmt;
14041483
Blob sql = empty_blob;
1405
- if( argc<4 ){
1484
+ if( argc<minArgs ){
14061485
return Th_WrongNumArgs2(interp,
14071486
argv[0], argl[0],
14081487
"StmtHandle Index Format");
14091488
}
1410
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1489
+ if(!pStmt){
1490
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1491
+ argPos = 3;
1492
+ }else{
1493
+ Th_ToInt( interp, argv[1], argl[1], &index );
1494
+ argPos = 2;
1495
+ }
14111496
if(index < 0){
1412
- assert(NULL==pStmt);
14131497
return TH_ERROR;
14141498
}
14151499
val = sqlite3_column_text( pStmt, index );
1416
- fmt = argv[3];
1500
+ fmt = argv[argPos++];
14171501
assert(NULL!=pStmt);
14181502
blob_appendf(&sql,"SELECT strftime(%Q,%Q",
14191503
fmt, val);
1420
- if(argc>4){
1421
- for(i = 4; i < argc; ++i ){
1504
+ if(argc>argPos){
1505
+ for(i = argPos; i < argc; ++i ){
14221506
blob_appendf(&sql, ",%Q", argv[i]);
14231507
}
14241508
}
14251509
blob_append(&sql, ")", 1);
14261510
fval = db_text(NULL,"%s", sql.aData);
@@ -1436,11 +1520,10 @@
14361520
void *ctx,
14371521
int argc,
14381522
const char **argv,
14391523
int *argl
14401524
){
1441
- sqlite3_stmt * pStmt = NULL;
14421525
char const * val;
14431526
char * fval;
14441527
int i, rc = 0;
14451528
int index = -1;
14461529
char const * fmt;
@@ -1469,11 +1552,12 @@
14691552
14701553
14711554
/*
14721555
** TH Syntax:
14731556
**
1474
-** query_bind_null stmtId Index
1557
+** query bind null stmtId Index
1558
+** query stmtId bind null Index
14751559
**
14761560
** Binds a value to the given 1-based parameter index.
14771561
*/
14781562
static int queryBindNullCmd(
14791563
Th_Interp *interp,
@@ -1480,19 +1564,24 @@
14801564
void *p,
14811565
int argc,
14821566
const char **argv,
14831567
int *argl
14841568
){
1485
- sqlite3_stmt * pStmt = NULL;
1569
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1570
+ int requireArgc = pStmt ? 2 : 3;
14861571
int rc;
14871572
int index = 0;
1488
- if( argc!=3 ){
1573
+ if( argc!=requireArgc ){
14891574
return Th_WrongNumArgs2(interp,
14901575
argv[0], argl[0],
14911576
"StmtHandle Index");
14921577
}
1493
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1578
+ if(!pStmt){
1579
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1580
+ }else{
1581
+ Th_ToInt( interp, argv[1], argl[1], &index );
1582
+ }
14941583
if(index < 1){
14951584
return TH_ERROR;
14961585
}
14971586
rc = sqlite3_bind_null( pStmt, index );
14981587
if(rc){
@@ -1504,11 +1593,12 @@
15041593
15051594
15061595
/*
15071596
** TH Syntax:
15081597
**
1509
-** query_bind_string stmtId Index Value
1598
+** query bind string stmtId Index Value
1599
+** query stmtId bind string Index Value
15101600
**
15111601
** Binds a value to the given 1-based parameter index.
15121602
*/
15131603
static int queryBindStringCmd(
15141604
Th_Interp *interp,
@@ -1515,19 +1605,24 @@
15151605
void *p,
15161606
int argc,
15171607
const char **argv,
15181608
int *argl
15191609
){
1520
- sqlite3_stmt * pStmt = NULL;
1610
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1611
+ int requireArgc = pStmt ? 3 : 4;
15211612
int rc;
15221613
int index = 0;
1523
- if( argc!=4 ){
1614
+ if( argc!=requireArgc ){
15241615
return Th_WrongNumArgs2(interp,
15251616
argv[0], argl[0],
15261617
"StmtHandle Index Value");
15271618
}
1528
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1619
+ if(!pStmt){
1620
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1621
+ }else{
1622
+ Th_ToInt( interp, argv[1], argl[1], &index );
1623
+ }
15291624
if(index < 1){
15301625
return TH_ERROR;
15311626
}
15321627
rc = sqlite3_bind_text( pStmt, index, argv[3], argl[3], SQLITE_TRANSIENT );
15331628
if(rc){
@@ -1538,11 +1633,12 @@
15381633
}
15391634
15401635
/*
15411636
** TH Syntax:
15421637
**
1543
-** query_bind_int stmtId Index Value
1638
+** query bind int stmtId Index Value
1639
+** query stmtId bind int Index Value
15441640
**
15451641
** Binds a value to the given 1-based parameter index.
15461642
*/
15471643
static int queryBindIntCmd(
15481644
Th_Interp *interp,
@@ -1549,24 +1645,32 @@
15491645
void *p,
15501646
int argc,
15511647
const char **argv,
15521648
int *argl
15531649
){
1554
- sqlite3_stmt * pStmt = NULL;
1650
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1651
+ int requireArgc = pStmt ? 3 : 4;
15551652
int rc;
1556
- int val;
15571653
int index = 0;
1558
- if( argc!=4 ){
1654
+ int argPos;
1655
+ int val;
1656
+ if( argc!=requireArgc ){
15591657
return Th_WrongNumArgs2(interp,
15601658
argv[0], argl[0],
15611659
"StmtHandle Index Value");
15621660
}
1563
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1661
+ if(!pStmt){
1662
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1663
+ argPos = 3;
1664
+ }else{
1665
+ Th_ToInt( interp, argv[1], argl[1], &index );
1666
+ argPos = 2;
1667
+ }
15641668
if(index < 1){
15651669
return TH_ERROR;
15661670
}
1567
- if( 0 != Th_ToInt( interp, argv[3], argl[3], &val ) ){
1671
+ if( 0 != Th_ToInt( interp, argv[argPos], argl[argPos], &val ) ){
15681672
return TH_ERROR;
15691673
}
15701674
15711675
rc = sqlite3_bind_int( pStmt, index, val );
15721676
if(rc){
@@ -1577,11 +1681,12 @@
15771681
}
15781682
15791683
/*
15801684
** TH Syntax:
15811685
**
1582
-** query_bind_double stmtId Index Value
1686
+** query bind double stmtId Index Value
1687
+** query stmtId bind double Index Value
15831688
**
15841689
** Binds a value to the given 1-based parameter index.
15851690
*/
15861691
static int queryBindDoubleCmd(
15871692
Th_Interp *interp,
@@ -1588,24 +1693,32 @@
15881693
void *p,
15891694
int argc,
15901695
const char **argv,
15911696
int *argl
15921697
){
1593
- sqlite3_stmt * pStmt = NULL;
1698
+ sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1699
+ int requireArgc = pStmt ? 3 : 4;
15941700
int rc;
1595
- double val;
15961701
int index = 0;
1597
- if( argc!=4 ){
1702
+ int argPos;
1703
+ double val;
1704
+ if( argc!=requireArgc ){
15981705
return Th_WrongNumArgs2(interp,
15991706
argv[0], argl[0],
16001707
"StmtHandle Index Value");
16011708
}
1602
- queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1709
+ if(!pStmt){
1710
+ queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1711
+ argPos = 3;
1712
+ }else{
1713
+ Th_ToInt( interp, argv[1], argl[1], &index );
1714
+ argPos = 2;
1715
+ }
16031716
if(index < 1){
16041717
return TH_ERROR;
16051718
}
1606
- if( 0 != Th_ToDouble( interp, argv[3], argl[3], &val ) ){
1719
+ if( 0 != Th_ToDouble( interp, argv[argPos], argl[argPos], &val ) ){
16071720
return TH_ERROR;
16081721
}
16091722
16101723
rc = sqlite3_bind_double( pStmt, index, val );
16111724
if(rc){
@@ -1639,17 +1752,17 @@
16391752
const char **argv,
16401753
int *argl
16411754
){
16421755
static Th_SubCommand aSub[] = {
16431756
{"count", queryColCountCmd},
1644
- {"is_null", queryColIsNullCmd},
1757
+ {"is_null", queryColIsNullCmd},
16451758
{"name", queryColNameCmd},
16461759
{"double", queryColDoubleCmd},
16471760
{"int", queryColIntCmd},
16481761
{"string", queryColStringCmd},
16491762
{"time", queryColTimeCmd},
1650
- {"type", queryColTypeCmd},
1763
+ {"type", queryColTypeCmd},
16511764
{0, 0}
16521765
};
16531766
Th_CallSubCommand2( interp, ctx, argc, argv, argl, aSub );
16541767
}
16551768
@@ -1659,22 +1772,48 @@
16591772
void *ctx,
16601773
int argc,
16611774
const char **argv,
16621775
int *argl
16631776
){
1664
- Th_Sqlite * sq = Th_sqlite_manager(interp);
1665
- static Th_SubCommand aSub[] = {
1777
+ int stmtId = 0;
1778
+ sqlite3_stmt * pStmt = NULL;
1779
+ static Th_SubCommand aSubAll[] = {
16661780
{"bind", queryBindTopLevelCmd},
16671781
{"col", queryColTopLevelCmd},
16681782
{"step", queryStepCmd},
16691783
{"finalize", queryFinalizeCmd},
16701784
{"prepare", queryPrepareCmd},
16711785
{"strftime", queryStrftimeCmd},
16721786
{0, 0}
16731787
};
1674
- assert( NULL != sq );
1675
- Th_CallSubCommand2( interp, sq, argc, argv, argl, aSub );
1788
+ static Th_SubCommand aSubWithStmt[] = {
1789
+ /* These entries are coded to deal with
1790
+ being supplied a statement via pStmt
1791
+ or via one of their args.
1792
+ */
1793
+ {"bind", queryBindTopLevelCmd},
1794
+ {"col", queryColTopLevelCmd},
1795
+ {"step", queryStepCmd},
1796
+ {"finalize", queryFinalizeCmd},
1797
+ {0, 0}
1798
+ };
1799
+
1800
+
1801
+ assert( NULL != Th_sqlite_manager(interp) );
1802
+ if( 1 == argc ){
1803
+ Th_WrongNumArgs2( interp, argv[0], argl[0],
1804
+ "subcommand");
1805
+ return TH_ERROR;
1806
+ }else if( 0 == Th_TryInt(interp,argv[1], argl[1], &stmtId) ){
1807
+ ++argv;
1808
+ ++argl;
1809
+ --argc;
1810
+ pStmt = Th_GetStmt( interp, stmtId );
1811
+ }
1812
+
1813
+ Th_CallSubCommand2( interp, pStmt, argc, argv, argl,
1814
+ pStmt ? aSubWithStmt : aSubAll );
16761815
}
16771816
16781817
16791818
int th_register_query(Th_Interp *interp){
16801819
enum { BufLen = 100 };
16811820
--- src/th_main.c
+++ src/th_main.c
@@ -569,11 +569,11 @@
569
570
571 /*
572 ** TH Syntax:
573 **
574 ** argv_getat Index
575 **
576 ** Returns the raw argument at the given index, throwing if
577 ** out of bounds.
578 */
579 static int argvGetAtCmd(
@@ -608,11 +608,11 @@
608
609
610 /*
611 ** TH Syntax:
612 **
613 ** argv_getstr longName ??shortName? ?defaultValue??
614 **
615 ** Functions more or less like Fossil's find_option().
616 ** If the given argument is found then its value is returned,
617 ** else defaultValue is returned. If that is not set
618 ** and the option is not found, an error is thrown.
@@ -679,11 +679,11 @@
679 }
680
681 /*
682 ** TH Syntax:
683 **
684 ** argv_getbool longName ??shortName? ?defaultValue??
685 **
686 ** Works just like argv_getstr but treats any empty value or one
687 ** starting with the digit '0' as a boolean false.
688 **
689 ** Returns the result as an integer 0 (false) or 1 (true).
@@ -752,11 +752,11 @@
752 }
753
754 /*
755 ** TH Syntax:
756 **
757 ** argv_getint longName ?shortName? ?defaultValue?
758 */
759 static int argvFindOptionIntCmd(
760 Th_Interp *interp,
761 void *p,
762 int argc,
@@ -843,11 +843,11 @@
843
844 #ifdef TH_ENABLE_SQLITE
845
846 /*
847 ** Adds the given prepared statement to the interpreter. Returns the
848 ** statements opaque identifier (a positive value). Ownerships of
849 ** pStmt is transfered to interp and it must be cleaned up by the
850 ** client by calling Th_FinalizeStmt(), passing it the value returned
851 ** by this function.
852 **
853 ** If interp is destroyed before all statements are finalized,
@@ -861,10 +861,11 @@
861 ** On error (statement not found) non-0 is returned. After this
862 ** call, some subsequent call to Th_AddStmt() may return the
863 ** same statement ID.
864 */
865 static int Th_FinalizeStmt(Th_Interp *interp, int stmtId);
 
866
867 /*
868 ** Fetches the statement with the given ID, as returned by
869 ** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
870 ** refers) to a statement added via Th_AddStmt().
@@ -921,10 +922,30 @@
921 return 0;
922 }else{
923 return 1;
924 }
925 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
927 static sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){
928 Th_Sqlite * sq = Th_sqlite_manager(interp);
929 return ((stmtId<1) || (stmtId > sq->nStmt))
930 ? NULL
@@ -955,11 +976,11 @@
955
956
957 /*
958 ** TH Syntax:
959 **
960 ** query_prepare SQL
961 **
962 ** Returns an opaque statement identifier.
963 */
964 static int queryPrepareCmd(
965 Th_Interp *interp,
@@ -1028,11 +1049,12 @@
1028 }
1029
1030 /*
1031 ** TH Syntax:
1032 **
1033 ** query_finalize stmtId
 
1034 **
1035 ** sqlite3_finalize()s the given statement.
1036 */
1037 static int queryFinalizeCmd(
1038 Th_Interp *interp,
@@ -1039,26 +1061,31 @@
1039 void *p,
1040 int argc,
1041 const char **argv,
1042 int *argl
1043 ){
 
 
1044 char * zSql;
1045 sqlite3_stmt * pStmt = NULL;
1046 int rc = 0;
1047 char const * arg;
1048 if( argc!=2 ){
 
1049 return Th_WrongNumArgs2(interp,
1050 argv[0], argl[0],
1051 "StmtHandle");
1052 }
1053 arg = argv[1];
1054 pStmt = queryStmtHandle(interp, arg, argl[1], &rc);
1055 if( rc < 1 ){
1056 return TH_ERROR;
 
 
 
1057 }
1058 assert( NULL != pStmt );
1059 rc = Th_FinalizeStmt( interp, rc );
1060 Th_SetResultInt( interp, rc );
1061 return TH_OK;
1062 }
1063
1064 /*
@@ -1079,11 +1106,11 @@
1079 ** least 3.
1080 **
1081 ** On success it returns 0, sets *pStmt to the referenced statement
1082 ** handle, and pIndex (if not NULL) to the integer value of argv[2]
1083 ** argument. On error it reports the error via TH, returns non-0, and
1084 ** modifies neither pStmt not pIndex.
1085 */
1086 static int queryStmtIndexArgs(
1087 Th_Interp * interp,
1088 int argc,
1089 char const ** argv,
@@ -1106,11 +1133,11 @@
1106 }
1107 if( 0 != Th_ToInt( interp, argv[2], argl[2], &index ) ){
1108 return TH_ERROR;
1109 }
1110 }
1111 stmt = queryStmtHandle(interp, argv[1], argl[1], NULL);
1112 if( NULL == stmt ){
1113 return TH_ERROR;
1114 }else{
1115 *pStmt = stmt;
1116 if( pIndex ){
@@ -1121,11 +1148,12 @@
1121 }
1122
1123 /*
1124 ** TH Syntax:
1125 **
1126 ** query_step stmtId
 
1127 **
1128 ** Steps the given statement handle. Returns 0 at the end of the set,
1129 ** a positive value if it fetches a row, and throws on error.
1130 */
1131 static int queryStepCmd(
@@ -1133,18 +1161,19 @@
1133 void *p,
1134 int argc,
1135 const char **argv,
1136 int *argl
1137 ){
1138 sqlite3_stmt * pStmt = NULL;
 
1139 int rc = 0;
1140 if( argc!=2 ){
1141 return Th_WrongNumArgs2(interp,
1142 argv[0], argl[0],
1143 "StmtHandle");
1144 }
1145 if(0 != queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, NULL)){
1146 return TH_ERROR;
1147 }
1148 assert(NULL != pStmt);
1149 rc = sqlite3_step( pStmt );
1150 switch(rc){
@@ -1162,11 +1191,12 @@
1162 }
1163
1164 /*
1165 ** TH Syntax:
1166 **
1167 ** query_col_string stmtId Index
 
1168 **
1169 ** Returns the result column value at the given 0-based index.
1170 */
1171 static int queryColStringCmd(
1172 Th_Interp *interp,
@@ -1173,20 +1203,25 @@
1173 void *p,
1174 int argc,
1175 const char **argv,
1176 int *argl
1177 ){
1178 sqlite3_stmt * pStmt = NULL;
 
1179 char const * val;
1180 int index = -1;
1181 int valLen;
1182 if( argc!=3 ){
1183 return Th_WrongNumArgs2(interp,
1184 argv[0], argl[0],
1185 "StmtHandle Index");
1186 }
1187 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1188 if(index < 0){
1189 return TH_ERROR;
1190 }
1191 val = sqlite3_column_text( pStmt, index );
1192 valLen = val ? sqlite3_column_bytes( pStmt, index ) : 0;
@@ -1195,11 +1230,12 @@
1195 }
1196
1197 /*
1198 ** TH Syntax:
1199 **
1200 ** query_col_int stmtId Index
 
1201 **
1202 ** Returns the result column value at the given 0-based index.
1203 */
1204 static int queryColIntCmd(
1205 Th_Interp *interp,
@@ -1206,19 +1242,25 @@
1206 void *p,
1207 int argc,
1208 const char **argv,
1209 int *argl
1210 ){
1211 sqlite3_stmt * pStmt = NULL;
 
1212 int rc = 0;
1213 int index = -1;
1214 if( argc!=3 ){
1215 return Th_WrongNumArgs2(interp,
1216 argv[0], argl[0],
1217 "StmtHandle Index");
1218 }
1219 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
 
1220 if(index < 0){
1221 return TH_ERROR;
1222 }
1223 Th_SetResultInt( interp, sqlite3_column_int( pStmt, index ) );
1224 return TH_OK;
@@ -1225,11 +1267,12 @@
1225 }
1226
1227 /*
1228 ** TH Syntax:
1229 **
1230 ** query_col_double stmtId Index
 
1231 **
1232 ** Returns the result column value at the given 0-based index.
1233 */
1234 static int queryColDoubleCmd(
1235 Th_Interp *interp,
@@ -1236,19 +1279,24 @@
1236 void *p,
1237 int argc,
1238 const char **argv,
1239 int *argl
1240 ){
1241 sqlite3_stmt * pStmt = NULL;
 
1242 double rc = 0;
1243 int index = -1;
1244 if( argc!=3 ){
1245 return Th_WrongNumArgs2(interp,
1246 argv[0], argl[0],
1247 "StmtHandle Index");
1248 }
1249 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1250 if(index < 0){
1251 return TH_ERROR;
1252 }
1253 Th_SetResultDouble( interp, sqlite3_column_double( pStmt, index ) );
1254 return TH_OK;
@@ -1255,11 +1303,12 @@
1255 }
1256
1257 /*
1258 ** TH Syntax:
1259 **
1260 ** query_col_is_null stmtId Index
 
1261 **
1262 ** Returns non-0 if the given 0-based result column index contains
1263 ** an SQL NULL value, else returns 0.
1264 */
1265 static int queryColIsNullCmd(
@@ -1267,19 +1316,24 @@
1267 void *p,
1268 int argc,
1269 const char **argv,
1270 int *argl
1271 ){
1272 sqlite3_stmt * pStmt = NULL;
 
1273 double rc = 0;
1274 int index = -1;
1275 if( argc!=3 ){
1276 return Th_WrongNumArgs2(interp,
1277 argv[0], argl[0],
1278 "StmtHandle Index");
1279 }
1280 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1281 if(index < 0){
1282 return TH_ERROR;
1283 }
1284 Th_SetResultInt( interp,
1285 SQLITE_NULL==sqlite3_column_type( pStmt, index )
@@ -1288,11 +1342,12 @@
1288 }
1289
1290 /*
1291 ** TH Syntax:
1292 **
1293 ** query_col_type stmtId Index
 
1294 **
1295 ** Returns the sqlite type identifier for the given 0-based result
1296 ** column index. The values are available in TH as $SQLITE_NULL,
1297 ** $SQLITE_INTEGER, etc.
1298 */
@@ -1301,19 +1356,24 @@
1301 void *p,
1302 int argc,
1303 const char **argv,
1304 int *argl
1305 ){
1306 sqlite3_stmt * pStmt = NULL;
 
1307 double rc = 0;
1308 int index = -1;
1309 if( argc!=3 ){
1310 return Th_WrongNumArgs2(interp,
1311 argv[0], argl[0],
1312 "StmtHandle Index");
1313 }
1314 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1315 if(index < 0){
1316 return TH_ERROR;
1317 }
1318 Th_SetResultInt( interp, sqlite3_column_type( pStmt, index ) );
1319 return TH_OK;
@@ -1320,11 +1380,12 @@
1320 }
1321
1322 /*
1323 ** TH Syntax:
1324 **
1325 ** query_col_count stmtId
 
1326 **
1327 ** Returns the number of result columns in the query.
1328 */
1329 static int queryColCountCmd(
1330 Th_Interp *interp,
@@ -1332,29 +1393,33 @@
1332 int argc,
1333 const char **argv,
1334 int *argl
1335 ){
1336 int rc;
1337 sqlite3_stmt * pStmt = NULL;
1338 if( argc!=2 ){
 
1339 return Th_WrongNumArgs2(interp,
1340 argv[0], argl[0],
1341 "StmtHandle");
1342 }
1343 pStmt = queryStmtHandle(interp, argv[1], argl[1], NULL);
1344 if( NULL == pStmt ){
1345 return TH_ERROR;
 
 
1346 }
1347 rc = sqlite3_column_count( pStmt );
1348 Th_SetResultInt( interp, rc );
1349 return TH_OK;
1350 }
1351
1352 /*
1353 ** TH Syntax:
1354 **
1355 ** query_col_count stmtId Index
 
1356 **
1357 ** Returns the result column name at the given 0-based index.
1358 */
1359 static int queryColNameCmd(
1360 Th_Interp *interp,
@@ -1361,22 +1426,26 @@
1361 void *p,
1362 int argc,
1363 const char **argv,
1364 int *argl
1365 ){
1366 sqlite3_stmt * pStmt = NULL;
 
1367 char const * val;
1368 int rc = 0;
1369 int index = -1;
1370 if( argc!=3 ){
1371 return Th_WrongNumArgs2(interp,
1372 argv[0], argl[0],
1373 "StmtHandle Index");
1374 }
1375 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1376 if(index < 0){
1377 assert(NULL==pStmt);
1378 return TH_ERROR;
1379 }
1380 assert(NULL!=pStmt);
1381 val = sqlite3_column_name( pStmt, index );
1382 if(NULL==val){
@@ -1386,41 +1455,56 @@
1386 Th_SetResult( interp, val, strlen( val ) );
1387 return TH_OK;
1388 }
1389 }
1390
 
 
 
 
 
 
 
 
1391 static int queryColTimeCmd(
1392 Th_Interp *interp,
1393 void *ctx,
1394 int argc,
1395 const char **argv,
1396 int *argl
1397 ){
1398 sqlite3_stmt * pStmt = NULL;
 
 
1399 char const * val;
1400 char * fval;
1401 int i, rc = 0;
1402 int index = -1;
1403 char const * fmt;
1404 Blob sql = empty_blob;
1405 if( argc<4 ){
1406 return Th_WrongNumArgs2(interp,
1407 argv[0], argl[0],
1408 "StmtHandle Index Format");
1409 }
1410 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
 
 
1411 if(index < 0){
1412 assert(NULL==pStmt);
1413 return TH_ERROR;
1414 }
1415 val = sqlite3_column_text( pStmt, index );
1416 fmt = argv[3];
1417 assert(NULL!=pStmt);
1418 blob_appendf(&sql,"SELECT strftime(%Q,%Q",
1419 fmt, val);
1420 if(argc>4){
1421 for(i = 4; i < argc; ++i ){
1422 blob_appendf(&sql, ",%Q", argv[i]);
1423 }
1424 }
1425 blob_append(&sql, ")", 1);
1426 fval = db_text(NULL,"%s", sql.aData);
@@ -1436,11 +1520,10 @@
1436 void *ctx,
1437 int argc,
1438 const char **argv,
1439 int *argl
1440 ){
1441 sqlite3_stmt * pStmt = NULL;
1442 char const * val;
1443 char * fval;
1444 int i, rc = 0;
1445 int index = -1;
1446 char const * fmt;
@@ -1469,11 +1552,12 @@
1469
1470
1471 /*
1472 ** TH Syntax:
1473 **
1474 ** query_bind_null stmtId Index
 
1475 **
1476 ** Binds a value to the given 1-based parameter index.
1477 */
1478 static int queryBindNullCmd(
1479 Th_Interp *interp,
@@ -1480,19 +1564,24 @@
1480 void *p,
1481 int argc,
1482 const char **argv,
1483 int *argl
1484 ){
1485 sqlite3_stmt * pStmt = NULL;
 
1486 int rc;
1487 int index = 0;
1488 if( argc!=3 ){
1489 return Th_WrongNumArgs2(interp,
1490 argv[0], argl[0],
1491 "StmtHandle Index");
1492 }
1493 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1494 if(index < 1){
1495 return TH_ERROR;
1496 }
1497 rc = sqlite3_bind_null( pStmt, index );
1498 if(rc){
@@ -1504,11 +1593,12 @@
1504
1505
1506 /*
1507 ** TH Syntax:
1508 **
1509 ** query_bind_string stmtId Index Value
 
1510 **
1511 ** Binds a value to the given 1-based parameter index.
1512 */
1513 static int queryBindStringCmd(
1514 Th_Interp *interp,
@@ -1515,19 +1605,24 @@
1515 void *p,
1516 int argc,
1517 const char **argv,
1518 int *argl
1519 ){
1520 sqlite3_stmt * pStmt = NULL;
 
1521 int rc;
1522 int index = 0;
1523 if( argc!=4 ){
1524 return Th_WrongNumArgs2(interp,
1525 argv[0], argl[0],
1526 "StmtHandle Index Value");
1527 }
1528 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
1529 if(index < 1){
1530 return TH_ERROR;
1531 }
1532 rc = sqlite3_bind_text( pStmt, index, argv[3], argl[3], SQLITE_TRANSIENT );
1533 if(rc){
@@ -1538,11 +1633,12 @@
1538 }
1539
1540 /*
1541 ** TH Syntax:
1542 **
1543 ** query_bind_int stmtId Index Value
 
1544 **
1545 ** Binds a value to the given 1-based parameter index.
1546 */
1547 static int queryBindIntCmd(
1548 Th_Interp *interp,
@@ -1549,24 +1645,32 @@
1549 void *p,
1550 int argc,
1551 const char **argv,
1552 int *argl
1553 ){
1554 sqlite3_stmt * pStmt = NULL;
 
1555 int rc;
1556 int val;
1557 int index = 0;
1558 if( argc!=4 ){
 
 
1559 return Th_WrongNumArgs2(interp,
1560 argv[0], argl[0],
1561 "StmtHandle Index Value");
1562 }
1563 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
 
 
1564 if(index < 1){
1565 return TH_ERROR;
1566 }
1567 if( 0 != Th_ToInt( interp, argv[3], argl[3], &val ) ){
1568 return TH_ERROR;
1569 }
1570
1571 rc = sqlite3_bind_int( pStmt, index, val );
1572 if(rc){
@@ -1577,11 +1681,12 @@
1577 }
1578
1579 /*
1580 ** TH Syntax:
1581 **
1582 ** query_bind_double stmtId Index Value
 
1583 **
1584 ** Binds a value to the given 1-based parameter index.
1585 */
1586 static int queryBindDoubleCmd(
1587 Th_Interp *interp,
@@ -1588,24 +1693,32 @@
1588 void *p,
1589 int argc,
1590 const char **argv,
1591 int *argl
1592 ){
1593 sqlite3_stmt * pStmt = NULL;
 
1594 int rc;
1595 double val;
1596 int index = 0;
1597 if( argc!=4 ){
 
 
1598 return Th_WrongNumArgs2(interp,
1599 argv[0], argl[0],
1600 "StmtHandle Index Value");
1601 }
1602 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
 
 
 
 
 
 
1603 if(index < 1){
1604 return TH_ERROR;
1605 }
1606 if( 0 != Th_ToDouble( interp, argv[3], argl[3], &val ) ){
1607 return TH_ERROR;
1608 }
1609
1610 rc = sqlite3_bind_double( pStmt, index, val );
1611 if(rc){
@@ -1639,17 +1752,17 @@
1639 const char **argv,
1640 int *argl
1641 ){
1642 static Th_SubCommand aSub[] = {
1643 {"count", queryColCountCmd},
1644 {"is_null", queryColIsNullCmd},
1645 {"name", queryColNameCmd},
1646 {"double", queryColDoubleCmd},
1647 {"int", queryColIntCmd},
1648 {"string", queryColStringCmd},
1649 {"time", queryColTimeCmd},
1650 {"type", queryColTypeCmd},
1651 {0, 0}
1652 };
1653 Th_CallSubCommand2( interp, ctx, argc, argv, argl, aSub );
1654 }
1655
@@ -1659,22 +1772,48 @@
1659 void *ctx,
1660 int argc,
1661 const char **argv,
1662 int *argl
1663 ){
1664 Th_Sqlite * sq = Th_sqlite_manager(interp);
1665 static Th_SubCommand aSub[] = {
 
1666 {"bind", queryBindTopLevelCmd},
1667 {"col", queryColTopLevelCmd},
1668 {"step", queryStepCmd},
1669 {"finalize", queryFinalizeCmd},
1670 {"prepare", queryPrepareCmd},
1671 {"strftime", queryStrftimeCmd},
1672 {0, 0}
1673 };
1674 assert( NULL != sq );
1675 Th_CallSubCommand2( interp, sq, argc, argv, argl, aSub );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1676 }
1677
1678
1679 int th_register_query(Th_Interp *interp){
1680 enum { BufLen = 100 };
1681
--- src/th_main.c
+++ src/th_main.c
@@ -569,11 +569,11 @@
569
570
571 /*
572 ** TH Syntax:
573 **
574 ** argv at Index
575 **
576 ** Returns the raw argument at the given index, throwing if
577 ** out of bounds.
578 */
579 static int argvGetAtCmd(
@@ -608,11 +608,11 @@
608
609
610 /*
611 ** TH Syntax:
612 **
613 ** argv getstr longName ??shortName? ?defaultValue??
614 **
615 ** Functions more or less like Fossil's find_option().
616 ** If the given argument is found then its value is returned,
617 ** else defaultValue is returned. If that is not set
618 ** and the option is not found, an error is thrown.
@@ -679,11 +679,11 @@
679 }
680
681 /*
682 ** TH Syntax:
683 **
684 ** argv getbool longName ??shortName? ?defaultValue??
685 **
686 ** Works just like argv_getstr but treats any empty value or one
687 ** starting with the digit '0' as a boolean false.
688 **
689 ** Returns the result as an integer 0 (false) or 1 (true).
@@ -752,11 +752,11 @@
752 }
753
754 /*
755 ** TH Syntax:
756 **
757 ** argv getint longName ?shortName? ?defaultValue?
758 */
759 static int argvFindOptionIntCmd(
760 Th_Interp *interp,
761 void *p,
762 int argc,
@@ -843,11 +843,11 @@
843
844 #ifdef TH_ENABLE_SQLITE
845
846 /*
847 ** Adds the given prepared statement to the interpreter. Returns the
848 ** statement's opaque identifier (a positive value). Ownerships of
849 ** pStmt is transfered to interp and it must be cleaned up by the
850 ** client by calling Th_FinalizeStmt(), passing it the value returned
851 ** by this function.
852 **
853 ** If interp is destroyed before all statements are finalized,
@@ -861,10 +861,11 @@
861 ** On error (statement not found) non-0 is returned. After this
862 ** call, some subsequent call to Th_AddStmt() may return the
863 ** same statement ID.
864 */
865 static int Th_FinalizeStmt(Th_Interp *interp, int stmtId);
866 static int Th_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt *);
867
868 /*
869 ** Fetches the statement with the given ID, as returned by
870 ** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
871 ** refers) to a statement added via Th_AddStmt().
@@ -921,10 +922,30 @@
922 return 0;
923 }else{
924 return 1;
925 }
926 }
927
928 static int Th_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt * pSt){
929 Th_Sqlite * sq = Th_sqlite_manager(interp);
930 int i = 0;
931 sqlite3_stmt * st = NULL;
932 int rc = 0;
933 for( ; i < sq->nStmt; ++i ){
934 st = sq->aStmt[i];
935 if(st == pSt) break;
936 }
937 if( st == pSt ){
938 assert( i>=0 && i<sq->nStmt );
939 sq->aStmt[i] = NULL;
940 sqlite3_finalize(st);
941 return 0;
942 }else{
943 return 1;
944 }
945 }
946
947
948 static sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){
949 Th_Sqlite * sq = Th_sqlite_manager(interp);
950 return ((stmtId<1) || (stmtId > sq->nStmt))
951 ? NULL
@@ -955,11 +976,11 @@
976
977
978 /*
979 ** TH Syntax:
980 **
981 ** query prepare SQL
982 **
983 ** Returns an opaque statement identifier.
984 */
985 static int queryPrepareCmd(
986 Th_Interp *interp,
@@ -1028,11 +1049,12 @@
1049 }
1050
1051 /*
1052 ** TH Syntax:
1053 **
1054 ** query finalize stmtId
1055 ** query stmtId finalize
1056 **
1057 ** sqlite3_finalize()s the given statement.
1058 */
1059 static int queryFinalizeCmd(
1060 Th_Interp *interp,
@@ -1039,26 +1061,31 @@
1061 void *p,
1062 int argc,
1063 const char **argv,
1064 int *argl
1065 ){
1066 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1067 int requireArgc = pStmt ? 1 : 2;
1068 char * zSql;
1069 int stId = 0;
 
1070 char const * arg;
1071 int rc;
1072 if( argc!=requireArgc ){
1073 return Th_WrongNumArgs2(interp,
1074 argv[0], argl[0],
1075 "StmtHandle");
1076 }
1077 if(!pStmt){
1078 arg = argv[1];
1079 pStmt = queryStmtHandle(interp, arg, argl[1], &stId);
1080 if(!pStmt){
1081 Th_ErrorMessage(interp, "Not a valid statement handle argument.", NULL, 0);
1082 return TH_ERROR;
1083 }
1084 }
1085 assert( NULL != pStmt );
1086 rc = Th_FinalizeStmt2( interp, pStmt );
1087 Th_SetResultInt( interp, rc );
1088 return TH_OK;
1089 }
1090
1091 /*
@@ -1079,11 +1106,11 @@
1106 ** least 3.
1107 **
1108 ** On success it returns 0, sets *pStmt to the referenced statement
1109 ** handle, and pIndex (if not NULL) to the integer value of argv[2]
1110 ** argument. On error it reports the error via TH, returns non-0, and
1111 ** modifies neither pStmt nor pIndex.
1112 */
1113 static int queryStmtIndexArgs(
1114 Th_Interp * interp,
1115 int argc,
1116 char const ** argv,
@@ -1106,11 +1133,11 @@
1133 }
1134 if( 0 != Th_ToInt( interp, argv[2], argl[2], &index ) ){
1135 return TH_ERROR;
1136 }
1137 }
1138 stmt = *pStmt ? *pStmt : queryStmtHandle(interp, argv[1], argl[1], NULL);
1139 if( NULL == stmt ){
1140 return TH_ERROR;
1141 }else{
1142 *pStmt = stmt;
1143 if( pIndex ){
@@ -1121,11 +1148,12 @@
1148 }
1149
1150 /*
1151 ** TH Syntax:
1152 **
1153 ** query step stmtId
1154 ** query stmtId step
1155 **
1156 ** Steps the given statement handle. Returns 0 at the end of the set,
1157 ** a positive value if it fetches a row, and throws on error.
1158 */
1159 static int queryStepCmd(
@@ -1133,18 +1161,19 @@
1161 void *p,
1162 int argc,
1163 const char **argv,
1164 int *argl
1165 ){
1166 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1167 int requireArgc = pStmt ? 1 : 2;
1168 int rc = 0;
1169 if( argc!=requireArgc ){
1170 return Th_WrongNumArgs2(interp,
1171 argv[0], argl[0],
1172 "StmtHandle");
1173 }
1174 if(!pStmt && 0 != queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, NULL)){
1175 return TH_ERROR;
1176 }
1177 assert(NULL != pStmt);
1178 rc = sqlite3_step( pStmt );
1179 switch(rc){
@@ -1162,11 +1191,12 @@
1191 }
1192
1193 /*
1194 ** TH Syntax:
1195 **
1196 ** query col string stmtId Index
1197 ** query stmtId col string Index
1198 **
1199 ** Returns the result column value at the given 0-based index.
1200 */
1201 static int queryColStringCmd(
1202 Th_Interp *interp,
@@ -1173,20 +1203,25 @@
1203 void *p,
1204 int argc,
1205 const char **argv,
1206 int *argl
1207 ){
1208 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1209 int requireArgc = pStmt ? 2 : 3;
1210 char const * val;
1211 int index = -1;
1212 int valLen;
1213 if( argc!=requireArgc ){
1214 return Th_WrongNumArgs2(interp,
1215 argv[0], argl[0],
1216 "StmtHandle Index");
1217 }
1218 if(!pStmt){
1219 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1220 }else{
1221 Th_ToInt(interp, argv[1], argl[1], &index);
1222 }
1223 if(index < 0){
1224 return TH_ERROR;
1225 }
1226 val = sqlite3_column_text( pStmt, index );
1227 valLen = val ? sqlite3_column_bytes( pStmt, index ) : 0;
@@ -1195,11 +1230,12 @@
1230 }
1231
1232 /*
1233 ** TH Syntax:
1234 **
1235 ** query col int stmtId Index
1236 ** query stmtId col int Index
1237 **
1238 ** Returns the result column value at the given 0-based index.
1239 */
1240 static int queryColIntCmd(
1241 Th_Interp *interp,
@@ -1206,19 +1242,25 @@
1242 void *p,
1243 int argc,
1244 const char **argv,
1245 int *argl
1246 ){
1247 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1248 int requireArgc = pStmt ? 2 : 3;
1249 int rc = 0;
1250 int index = -1;
1251 if( argc!=requireArgc ){
1252 return Th_WrongNumArgs2(interp,
1253 argv[0], argl[0],
1254 "StmtHandle Index");
1255 }
1256 if(!pStmt){
1257 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1258 }else{
1259 Th_ToInt(interp, argv[1], argl[1], &index);
1260 }
1261
1262 if(index < 0){
1263 return TH_ERROR;
1264 }
1265 Th_SetResultInt( interp, sqlite3_column_int( pStmt, index ) );
1266 return TH_OK;
@@ -1225,11 +1267,12 @@
1267 }
1268
1269 /*
1270 ** TH Syntax:
1271 **
1272 ** query col double stmtId Index
1273 ** query stmtId col double Index
1274 **
1275 ** Returns the result column value at the given 0-based index.
1276 */
1277 static int queryColDoubleCmd(
1278 Th_Interp *interp,
@@ -1236,19 +1279,24 @@
1279 void *p,
1280 int argc,
1281 const char **argv,
1282 int *argl
1283 ){
1284 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1285 int requireArgc = pStmt ? 2 : 3;
1286 double rc = 0;
1287 int index = -1;
1288 if( argc!=requireArgc ){
1289 return Th_WrongNumArgs2(interp,
1290 argv[0], argl[0],
1291 "StmtHandle Index");
1292 }
1293 if(!pStmt){
1294 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1295 }else{
1296 Th_ToInt(interp, argv[1], argl[1], &index);
1297 }
1298 if(index < 0){
1299 return TH_ERROR;
1300 }
1301 Th_SetResultDouble( interp, sqlite3_column_double( pStmt, index ) );
1302 return TH_OK;
@@ -1255,11 +1303,12 @@
1303 }
1304
1305 /*
1306 ** TH Syntax:
1307 **
1308 ** query col is_null stmtId Index
1309 ** query stmtId col is_null Index
1310 **
1311 ** Returns non-0 if the given 0-based result column index contains
1312 ** an SQL NULL value, else returns 0.
1313 */
1314 static int queryColIsNullCmd(
@@ -1267,19 +1316,24 @@
1316 void *p,
1317 int argc,
1318 const char **argv,
1319 int *argl
1320 ){
1321 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1322 int requireArgc = pStmt ? 2 : 3;
1323 double rc = 0;
1324 int index = -1;
1325 if( argc!=requireArgc ){
1326 return Th_WrongNumArgs2(interp,
1327 argv[0], argl[0],
1328 "StmtHandle Index");
1329 }
1330 if(!pStmt){
1331 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1332 }else{
1333 Th_ToInt(interp, argv[1], argl[1], &index);
1334 }
1335 if(index < 0){
1336 return TH_ERROR;
1337 }
1338 Th_SetResultInt( interp,
1339 SQLITE_NULL==sqlite3_column_type( pStmt, index )
@@ -1288,11 +1342,12 @@
1342 }
1343
1344 /*
1345 ** TH Syntax:
1346 **
1347 ** query col type stmtId Index
1348 ** query stmtId col type Index
1349 **
1350 ** Returns the sqlite type identifier for the given 0-based result
1351 ** column index. The values are available in TH as $SQLITE_NULL,
1352 ** $SQLITE_INTEGER, etc.
1353 */
@@ -1301,19 +1356,24 @@
1356 void *p,
1357 int argc,
1358 const char **argv,
1359 int *argl
1360 ){
1361 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1362 int requireArgc = pStmt ? 2 : 3;
1363 double rc = 0;
1364 int index = -1;
1365 if( argc!=requireArgc ){
1366 return Th_WrongNumArgs2(interp,
1367 argv[0], argl[0],
1368 "StmtHandle Index");
1369 }
1370 if(!pStmt){
1371 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1372 }else{
1373 Th_ToInt( interp, argv[1], argl[1], &index );
1374 }
1375 if(index < 0){
1376 return TH_ERROR;
1377 }
1378 Th_SetResultInt( interp, sqlite3_column_type( pStmt, index ) );
1379 return TH_OK;
@@ -1320,11 +1380,12 @@
1380 }
1381
1382 /*
1383 ** TH Syntax:
1384 **
1385 ** query col count stmtId
1386 ** query stmtId col count
1387 **
1388 ** Returns the number of result columns in the query.
1389 */
1390 static int queryColCountCmd(
1391 Th_Interp *interp,
@@ -1332,29 +1393,33 @@
1393 int argc,
1394 const char **argv,
1395 int *argl
1396 ){
1397 int rc;
1398 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1399 int requireArgc = pStmt ? 1 : 2;
1400 if( argc!=requireArgc ){
1401 return Th_WrongNumArgs2(interp,
1402 argv[0], argl[0],
1403 "StmtHandle");
1404 }
1405 if(!pStmt){
1406 pStmt = queryStmtHandle(interp, argv[1], argl[1], NULL);
1407 if( NULL == pStmt ){
1408 return TH_ERROR;
1409 }
1410 }
1411 rc = sqlite3_column_count( pStmt );
1412 Th_SetResultInt( interp, rc );
1413 return TH_OK;
1414 }
1415
1416 /*
1417 ** TH Syntax:
1418 **
1419 ** query col name stmtId Index
1420 ** query stmtId col name Index
1421 **
1422 ** Returns the result column name at the given 0-based index.
1423 */
1424 static int queryColNameCmd(
1425 Th_Interp *interp,
@@ -1361,22 +1426,26 @@
1426 void *p,
1427 int argc,
1428 const char **argv,
1429 int *argl
1430 ){
1431 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1432 int requireArgc = pStmt ? 2 : 3;
1433 char const * val;
1434 int rc = 0;
1435 int index = -1;
1436 if( argc!=requireArgc ){
1437 return Th_WrongNumArgs2(interp,
1438 argv[0], argl[0],
1439 "StmtHandle Index");
1440 }
1441 if(!pStmt){
1442 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1443 }else{
1444 Th_ToInt( interp, argv[1], argl[1], &index );
1445 }
1446 if(index < 0){
 
1447 return TH_ERROR;
1448 }
1449 assert(NULL!=pStmt);
1450 val = sqlite3_column_name( pStmt, index );
1451 if(NULL==val){
@@ -1386,41 +1455,56 @@
1455 Th_SetResult( interp, val, strlen( val ) );
1456 return TH_OK;
1457 }
1458 }
1459
1460 /*
1461 ** TH Syntax:
1462 **
1463 ** query col time stmtId Index format
1464 ** query stmtId col name Index format
1465 **
1466 ** Returns the result column name at the given 0-based index.
1467 */
1468 static int queryColTimeCmd(
1469 Th_Interp *interp,
1470 void *ctx,
1471 int argc,
1472 const char **argv,
1473 int *argl
1474 ){
1475 sqlite3_stmt * pStmt = (sqlite3_stmt*)ctx;
1476 int minArgs = pStmt ? 3 : 4;
1477 int argPos;
1478 char const * val;
1479 char * fval;
1480 int i, rc = 0;
1481 int index = -1;
1482 char const * fmt;
1483 Blob sql = empty_blob;
1484 if( argc<minArgs ){
1485 return Th_WrongNumArgs2(interp,
1486 argv[0], argl[0],
1487 "StmtHandle Index Format");
1488 }
1489 if(!pStmt){
1490 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1491 argPos = 3;
1492 }else{
1493 Th_ToInt( interp, argv[1], argl[1], &index );
1494 argPos = 2;
1495 }
1496 if(index < 0){
 
1497 return TH_ERROR;
1498 }
1499 val = sqlite3_column_text( pStmt, index );
1500 fmt = argv[argPos++];
1501 assert(NULL!=pStmt);
1502 blob_appendf(&sql,"SELECT strftime(%Q,%Q",
1503 fmt, val);
1504 if(argc>argPos){
1505 for(i = argPos; i < argc; ++i ){
1506 blob_appendf(&sql, ",%Q", argv[i]);
1507 }
1508 }
1509 blob_append(&sql, ")", 1);
1510 fval = db_text(NULL,"%s", sql.aData);
@@ -1436,11 +1520,10 @@
1520 void *ctx,
1521 int argc,
1522 const char **argv,
1523 int *argl
1524 ){
 
1525 char const * val;
1526 char * fval;
1527 int i, rc = 0;
1528 int index = -1;
1529 char const * fmt;
@@ -1469,11 +1552,12 @@
1552
1553
1554 /*
1555 ** TH Syntax:
1556 **
1557 ** query bind null stmtId Index
1558 ** query stmtId bind null Index
1559 **
1560 ** Binds a value to the given 1-based parameter index.
1561 */
1562 static int queryBindNullCmd(
1563 Th_Interp *interp,
@@ -1480,19 +1564,24 @@
1564 void *p,
1565 int argc,
1566 const char **argv,
1567 int *argl
1568 ){
1569 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1570 int requireArgc = pStmt ? 2 : 3;
1571 int rc;
1572 int index = 0;
1573 if( argc!=requireArgc ){
1574 return Th_WrongNumArgs2(interp,
1575 argv[0], argl[0],
1576 "StmtHandle Index");
1577 }
1578 if(!pStmt){
1579 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1580 }else{
1581 Th_ToInt( interp, argv[1], argl[1], &index );
1582 }
1583 if(index < 1){
1584 return TH_ERROR;
1585 }
1586 rc = sqlite3_bind_null( pStmt, index );
1587 if(rc){
@@ -1504,11 +1593,12 @@
1593
1594
1595 /*
1596 ** TH Syntax:
1597 **
1598 ** query bind string stmtId Index Value
1599 ** query stmtId bind string Index Value
1600 **
1601 ** Binds a value to the given 1-based parameter index.
1602 */
1603 static int queryBindStringCmd(
1604 Th_Interp *interp,
@@ -1515,19 +1605,24 @@
1605 void *p,
1606 int argc,
1607 const char **argv,
1608 int *argl
1609 ){
1610 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1611 int requireArgc = pStmt ? 3 : 4;
1612 int rc;
1613 int index = 0;
1614 if( argc!=requireArgc ){
1615 return Th_WrongNumArgs2(interp,
1616 argv[0], argl[0],
1617 "StmtHandle Index Value");
1618 }
1619 if(!pStmt){
1620 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1621 }else{
1622 Th_ToInt( interp, argv[1], argl[1], &index );
1623 }
1624 if(index < 1){
1625 return TH_ERROR;
1626 }
1627 rc = sqlite3_bind_text( pStmt, index, argv[3], argl[3], SQLITE_TRANSIENT );
1628 if(rc){
@@ -1538,11 +1633,12 @@
1633 }
1634
1635 /*
1636 ** TH Syntax:
1637 **
1638 ** query bind int stmtId Index Value
1639 ** query stmtId bind int Index Value
1640 **
1641 ** Binds a value to the given 1-based parameter index.
1642 */
1643 static int queryBindIntCmd(
1644 Th_Interp *interp,
@@ -1549,24 +1645,32 @@
1645 void *p,
1646 int argc,
1647 const char **argv,
1648 int *argl
1649 ){
1650 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1651 int requireArgc = pStmt ? 3 : 4;
1652 int rc;
 
1653 int index = 0;
1654 int argPos;
1655 int val;
1656 if( argc!=requireArgc ){
1657 return Th_WrongNumArgs2(interp,
1658 argv[0], argl[0],
1659 "StmtHandle Index Value");
1660 }
1661 if(!pStmt){
1662 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1663 argPos = 3;
1664 }else{
1665 Th_ToInt( interp, argv[1], argl[1], &index );
1666 argPos = 2;
1667 }
1668 if(index < 1){
1669 return TH_ERROR;
1670 }
1671 if( 0 != Th_ToInt( interp, argv[argPos], argl[argPos], &val ) ){
1672 return TH_ERROR;
1673 }
1674
1675 rc = sqlite3_bind_int( pStmt, index, val );
1676 if(rc){
@@ -1577,11 +1681,12 @@
1681 }
1682
1683 /*
1684 ** TH Syntax:
1685 **
1686 ** query bind double stmtId Index Value
1687 ** query stmtId bind double Index Value
1688 **
1689 ** Binds a value to the given 1-based parameter index.
1690 */
1691 static int queryBindDoubleCmd(
1692 Th_Interp *interp,
@@ -1588,24 +1693,32 @@
1693 void *p,
1694 int argc,
1695 const char **argv,
1696 int *argl
1697 ){
1698 sqlite3_stmt * pStmt = (sqlite3_stmt*)p;
1699 int requireArgc = pStmt ? 3 : 4;
1700 int rc;
 
1701 int index = 0;
1702 int argPos;
1703 double val;
1704 if( argc!=requireArgc ){
1705 return Th_WrongNumArgs2(interp,
1706 argv[0], argl[0],
1707 "StmtHandle Index Value");
1708 }
1709 if(!pStmt){
1710 queryStmtIndexArgs(interp, argc, argv, argl, &pStmt, &index);
1711 argPos = 3;
1712 }else{
1713 Th_ToInt( interp, argv[1], argl[1], &index );
1714 argPos = 2;
1715 }
1716 if(index < 1){
1717 return TH_ERROR;
1718 }
1719 if( 0 != Th_ToDouble( interp, argv[argPos], argl[argPos], &val ) ){
1720 return TH_ERROR;
1721 }
1722
1723 rc = sqlite3_bind_double( pStmt, index, val );
1724 if(rc){
@@ -1639,17 +1752,17 @@
1752 const char **argv,
1753 int *argl
1754 ){
1755 static Th_SubCommand aSub[] = {
1756 {"count", queryColCountCmd},
1757 {"is_null", queryColIsNullCmd},
1758 {"name", queryColNameCmd},
1759 {"double", queryColDoubleCmd},
1760 {"int", queryColIntCmd},
1761 {"string", queryColStringCmd},
1762 {"time", queryColTimeCmd},
1763 {"type", queryColTypeCmd},
1764 {0, 0}
1765 };
1766 Th_CallSubCommand2( interp, ctx, argc, argv, argl, aSub );
1767 }
1768
@@ -1659,22 +1772,48 @@
1772 void *ctx,
1773 int argc,
1774 const char **argv,
1775 int *argl
1776 ){
1777 int stmtId = 0;
1778 sqlite3_stmt * pStmt = NULL;
1779 static Th_SubCommand aSubAll[] = {
1780 {"bind", queryBindTopLevelCmd},
1781 {"col", queryColTopLevelCmd},
1782 {"step", queryStepCmd},
1783 {"finalize", queryFinalizeCmd},
1784 {"prepare", queryPrepareCmd},
1785 {"strftime", queryStrftimeCmd},
1786 {0, 0}
1787 };
1788 static Th_SubCommand aSubWithStmt[] = {
1789 /* These entries are coded to deal with
1790 being supplied a statement via pStmt
1791 or via one of their args.
1792 */
1793 {"bind", queryBindTopLevelCmd},
1794 {"col", queryColTopLevelCmd},
1795 {"step", queryStepCmd},
1796 {"finalize", queryFinalizeCmd},
1797 {0, 0}
1798 };
1799
1800
1801 assert( NULL != Th_sqlite_manager(interp) );
1802 if( 1 == argc ){
1803 Th_WrongNumArgs2( interp, argv[0], argl[0],
1804 "subcommand");
1805 return TH_ERROR;
1806 }else if( 0 == Th_TryInt(interp,argv[1], argl[1], &stmtId) ){
1807 ++argv;
1808 ++argl;
1809 --argc;
1810 pStmt = Th_GetStmt( interp, stmtId );
1811 }
1812
1813 Th_CallSubCommand2( interp, pStmt, argc, argv, argl,
1814 pStmt ? aSubWithStmt : aSubAll );
1815 }
1816
1817
1818 int th_register_query(Th_Interp *interp){
1819 enum { BufLen = 100 };
1820
--- test/th1-query-api-1.th1
+++ test/th1-query-api-1.th1
@@ -1,33 +1,10 @@
11
This is not a formal test suite, but a tinkering ground.
22
Run it through "fossil test-th-render THIS_FILE".
33
<th1>
4
-proc bar {} {
5
-puts "json ?= [hasfeature json]\n"
6
-puts "tcl ?= [hasfeature tcl]\n"
7
-puts "ssl ?= [hasfeature ssl]\n"
8
-puts [lindex {a b c} 1] "\n"
9
-proc foo {a {b steve}} {
10
- puts "a = ${a}\n"
11
- puts "b = ${b}\n"
12
-}
13
-foo hi world
14
-foo hi {string list}
15
-# foo
16
-puts a b c foo \n
17
-}
18
-bar
19
-foo leaky
20
-
21
-proc xyz {} {
22
- return 42
23
-}
24
-set a [xyz]
25
-puts "a=${a}" ! \n
26
-
274
set stmt [query prepare {SELECT login, cap FROM user}]
28
-set colCount [query col count $stmt]
5
+set colCount [query $stmt col count]
296
puts "query column count: ${colCount}\n"
307
puts "stmt id=${stmt}\n"
318
329
proc noop {} {}
3310
proc incr {name {step 1}} {
@@ -38,38 +15,39 @@
3815
3916
set sep " "
4017
set i 0
4118
set colNames(0) 0
4219
for {set i 0} {$i < $colCount} {incr i} {
43
- set colNames($i) [query col name $stmt $i]
20
+ set colNames($i) [query $stmt col name $i]
4421
puts "colNames($i)=" $colNames($i) "\n"
4522
}
4623
47
-for {set row 0} {0 < [query step $stmt]} {incr row} {
24
+for {set row 0} {0 < [query $stmt step]} {incr row} {
4825
for {set i 0} {$i < $colCount} {incr i} {
4926
if {$i > 0} {
5027
puts $sep
5128
} else {
5229
puts "#$row: $sep"
5330
}
54
- puts $colNames($i) = [query col string $stmt $i]
31
+ puts $colNames($i) = [query $stmt col string $i]
5532
}
5633
puts "\n"
5734
}
5835
unset row
5936
60
-query finalize $stmt
37
+query $stmt finalize
38
+#query finalize $stmt
6139
6240
6341
proc query_step_each {{stmt} {callback}} {
6442
set colNames(0) 0
65
- set colCount [query col count $stmt]
43
+ set colCount [query $stmt col count]
6644
for {set i 0} {$i < $colCount} {incr i} {
67
- set colNames($i) [query col name $stmt $i]
45
+ set colNames($i) [query $stmt col name $i]
6846
}
6947
upvar cb $callback
70
- for {set row 0} {0 < [query step $stmt]} {incr row} {
48
+ for {set row 0} {0 < [query $stmt step]} {incr row} {
7149
#puts "Calling callback: $stmt $colCount colNames\n"
7250
$callback $stmt $colCount
7351
}
7452
}
7553
@@ -80,29 +58,28 @@
8058
puts "stmt ID=" $stmt "\n"
8159
query bind int $stmt 1 3
8260
#set stmt [query prepare $sql]
8361
#query bind string $stmt 1 stephan
8462
#set stmt [query prepare $sql]
85
-#query bind null $stmt 1
86
-set rc 0
63
+#query $stmt bind null 1
8764
puts "USER LIST:\n"
8865
catch {
8966
proc my_each {stmt colCount} {
9067
upvar 2 sep sep
91
- puts [query col int $stmt 0] " (type=" [query col type $stmt 0] ")" $sep
92
- puts [query col double $stmt 0] $sep
93
- puts [query col string $stmt 1] " (type=" [query col type $stmt 1] ")" $sep
94
- puts "isnull 0 ?= " [query col is_null $stmt 0] $sep
68
+ puts [query $stmt col int 0] " (type=" [query $stmt col type 0] ")" $sep
69
+ puts [query $stmt col double 0] $sep
70
+ puts [query $stmt col string 1] " (type=" [query $stmt col type 1] ")" $sep
71
+ puts "isnull 0 ?= " [query $stmt col is_null 0] $sep
9572
puts "isnull 2 ?= " [query col is_null $stmt 2]
9673
# for {set i 0} {$i < $colCount} {incr i} {
9774
# if {$i > 0} { puts $sep }
9875
# }
9976
puts "\n"
10077
# error "hi!"
10178
}
102
- query step_each $stmt my_each
103
-# query step_each $stmt {
79
+ query_step_each $stmt my_each
80
+# query_step_each $stmt {
10481
# proc each {stmt cc} { puts hi "\n" }
10582
# }
10683
} rc
10784
query finalize $stmt
10885
puts rc = $rc "\n"
@@ -143,33 +120,33 @@
143120
for {set i 0} {$i < $max} {incr i} {
144121
set s($i) [query prepare "SELECT $i"]
145122
puts "s($i) = $s($i)\n"
146123
}
147124
for {set i 0} {$i < $max} {incr i} {
148
- query step $s($i)
125
+ query $s($i) step
149126
}
150127
for {set i 0} {$i < $max} {incr i} {
151128
puts "closing stmt $s($i)\n"
152
- query finalize $s($i)
129
+ query $s($i) finalize
153130
}
154131
155132
puts "Preparing again\n"
156133
157134
for {set i 0} {$i < $max} {incr i} {
158135
set s($i) [query prepare "SELECT $i"]
159136
puts "s($i) = $s($i)\n"
160137
}
161138
for {set i 0} {$i < $max} {incr i} {
162
- query step $s($i)
139
+ query $s($i) step
163140
}
164141
puts "Closing again\n"
165142
166143
for {set i 0} {$i < $max} {incr i} {
167144
puts "closing stmt $s($i)\n"
168
- query finalize $s($i)
145
+ query $s($i) finalize
169146
}
170147
}
171148
multiStmt
172149
173150
enable_output 1
174151
puts "If you got this far, you win!\n"
175152
</th1>
176153
--- test/th1-query-api-1.th1
+++ test/th1-query-api-1.th1
@@ -1,33 +1,10 @@
1 This is not a formal test suite, but a tinkering ground.
2 Run it through "fossil test-th-render THIS_FILE".
3 <th1>
4 proc bar {} {
5 puts "json ?= [hasfeature json]\n"
6 puts "tcl ?= [hasfeature tcl]\n"
7 puts "ssl ?= [hasfeature ssl]\n"
8 puts [lindex {a b c} 1] "\n"
9 proc foo {a {b steve}} {
10 puts "a = ${a}\n"
11 puts "b = ${b}\n"
12 }
13 foo hi world
14 foo hi {string list}
15 # foo
16 puts a b c foo \n
17 }
18 bar
19 foo leaky
20
21 proc xyz {} {
22 return 42
23 }
24 set a [xyz]
25 puts "a=${a}" ! \n
26
27 set stmt [query prepare {SELECT login, cap FROM user}]
28 set colCount [query col count $stmt]
29 puts "query column count: ${colCount}\n"
30 puts "stmt id=${stmt}\n"
31
32 proc noop {} {}
33 proc incr {name {step 1}} {
@@ -38,38 +15,39 @@
38
39 set sep " "
40 set i 0
41 set colNames(0) 0
42 for {set i 0} {$i < $colCount} {incr i} {
43 set colNames($i) [query col name $stmt $i]
44 puts "colNames($i)=" $colNames($i) "\n"
45 }
46
47 for {set row 0} {0 < [query step $stmt]} {incr row} {
48 for {set i 0} {$i < $colCount} {incr i} {
49 if {$i > 0} {
50 puts $sep
51 } else {
52 puts "#$row: $sep"
53 }
54 puts $colNames($i) = [query col string $stmt $i]
55 }
56 puts "\n"
57 }
58 unset row
59
60 query finalize $stmt
 
61
62
63 proc query_step_each {{stmt} {callback}} {
64 set colNames(0) 0
65 set colCount [query col count $stmt]
66 for {set i 0} {$i < $colCount} {incr i} {
67 set colNames($i) [query col name $stmt $i]
68 }
69 upvar cb $callback
70 for {set row 0} {0 < [query step $stmt]} {incr row} {
71 #puts "Calling callback: $stmt $colCount colNames\n"
72 $callback $stmt $colCount
73 }
74 }
75
@@ -80,29 +58,28 @@
80 puts "stmt ID=" $stmt "\n"
81 query bind int $stmt 1 3
82 #set stmt [query prepare $sql]
83 #query bind string $stmt 1 stephan
84 #set stmt [query prepare $sql]
85 #query bind null $stmt 1
86 set rc 0
87 puts "USER LIST:\n"
88 catch {
89 proc my_each {stmt colCount} {
90 upvar 2 sep sep
91 puts [query col int $stmt 0] " (type=" [query col type $stmt 0] ")" $sep
92 puts [query col double $stmt 0] $sep
93 puts [query col string $stmt 1] " (type=" [query col type $stmt 1] ")" $sep
94 puts "isnull 0 ?= " [query col is_null $stmt 0] $sep
95 puts "isnull 2 ?= " [query col is_null $stmt 2]
96 # for {set i 0} {$i < $colCount} {incr i} {
97 # if {$i > 0} { puts $sep }
98 # }
99 puts "\n"
100 # error "hi!"
101 }
102 query step_each $stmt my_each
103 # query step_each $stmt {
104 # proc each {stmt cc} { puts hi "\n" }
105 # }
106 } rc
107 query finalize $stmt
108 puts rc = $rc "\n"
@@ -143,33 +120,33 @@
143 for {set i 0} {$i < $max} {incr i} {
144 set s($i) [query prepare "SELECT $i"]
145 puts "s($i) = $s($i)\n"
146 }
147 for {set i 0} {$i < $max} {incr i} {
148 query step $s($i)
149 }
150 for {set i 0} {$i < $max} {incr i} {
151 puts "closing stmt $s($i)\n"
152 query finalize $s($i)
153 }
154
155 puts "Preparing again\n"
156
157 for {set i 0} {$i < $max} {incr i} {
158 set s($i) [query prepare "SELECT $i"]
159 puts "s($i) = $s($i)\n"
160 }
161 for {set i 0} {$i < $max} {incr i} {
162 query step $s($i)
163 }
164 puts "Closing again\n"
165
166 for {set i 0} {$i < $max} {incr i} {
167 puts "closing stmt $s($i)\n"
168 query finalize $s($i)
169 }
170 }
171 multiStmt
172
173 enable_output 1
174 puts "If you got this far, you win!\n"
175 </th1>
176
--- test/th1-query-api-1.th1
+++ test/th1-query-api-1.th1
@@ -1,33 +1,10 @@
1 This is not a formal test suite, but a tinkering ground.
2 Run it through "fossil test-th-render THIS_FILE".
3 <th1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4 set stmt [query prepare {SELECT login, cap FROM user}]
5 set colCount [query $stmt col count]
6 puts "query column count: ${colCount}\n"
7 puts "stmt id=${stmt}\n"
8
9 proc noop {} {}
10 proc incr {name {step 1}} {
@@ -38,38 +15,39 @@
15
16 set sep " "
17 set i 0
18 set colNames(0) 0
19 for {set i 0} {$i < $colCount} {incr i} {
20 set colNames($i) [query $stmt col name $i]
21 puts "colNames($i)=" $colNames($i) "\n"
22 }
23
24 for {set row 0} {0 < [query $stmt step]} {incr row} {
25 for {set i 0} {$i < $colCount} {incr i} {
26 if {$i > 0} {
27 puts $sep
28 } else {
29 puts "#$row: $sep"
30 }
31 puts $colNames($i) = [query $stmt col string $i]
32 }
33 puts "\n"
34 }
35 unset row
36
37 query $stmt finalize
38 #query finalize $stmt
39
40
41 proc query_step_each {{stmt} {callback}} {
42 set colNames(0) 0
43 set colCount [query $stmt col count]
44 for {set i 0} {$i < $colCount} {incr i} {
45 set colNames($i) [query $stmt col name $i]
46 }
47 upvar cb $callback
48 for {set row 0} {0 < [query $stmt step]} {incr row} {
49 #puts "Calling callback: $stmt $colCount colNames\n"
50 $callback $stmt $colCount
51 }
52 }
53
@@ -80,29 +58,28 @@
58 puts "stmt ID=" $stmt "\n"
59 query bind int $stmt 1 3
60 #set stmt [query prepare $sql]
61 #query bind string $stmt 1 stephan
62 #set stmt [query prepare $sql]
63 #query $stmt bind null 1
 
64 puts "USER LIST:\n"
65 catch {
66 proc my_each {stmt colCount} {
67 upvar 2 sep sep
68 puts [query $stmt col int 0] " (type=" [query $stmt col type 0] ")" $sep
69 puts [query $stmt col double 0] $sep
70 puts [query $stmt col string 1] " (type=" [query $stmt col type 1] ")" $sep
71 puts "isnull 0 ?= " [query $stmt col is_null 0] $sep
72 puts "isnull 2 ?= " [query col is_null $stmt 2]
73 # for {set i 0} {$i < $colCount} {incr i} {
74 # if {$i > 0} { puts $sep }
75 # }
76 puts "\n"
77 # error "hi!"
78 }
79 query_step_each $stmt my_each
80 # query_step_each $stmt {
81 # proc each {stmt cc} { puts hi "\n" }
82 # }
83 } rc
84 query finalize $stmt
85 puts rc = $rc "\n"
@@ -143,33 +120,33 @@
120 for {set i 0} {$i < $max} {incr i} {
121 set s($i) [query prepare "SELECT $i"]
122 puts "s($i) = $s($i)\n"
123 }
124 for {set i 0} {$i < $max} {incr i} {
125 query $s($i) step
126 }
127 for {set i 0} {$i < $max} {incr i} {
128 puts "closing stmt $s($i)\n"
129 query $s($i) finalize
130 }
131
132 puts "Preparing again\n"
133
134 for {set i 0} {$i < $max} {incr i} {
135 set s($i) [query prepare "SELECT $i"]
136 puts "s($i) = $s($i)\n"
137 }
138 for {set i 0} {$i < $max} {incr i} {
139 query $s($i) step
140 }
141 puts "Closing again\n"
142
143 for {set i 0} {$i < $max} {incr i} {
144 puts "closing stmt $s($i)\n"
145 query $s($i) finalize
146 }
147 }
148 multiStmt
149
150 enable_output 1
151 puts "If you got this far, you win!\n"
152 </th1>
153
+36 -15
--- www/th1_query.wiki
+++ www/th1_query.wiki
@@ -8,23 +8,44 @@
88
<nowiki><pre>
99
&lt;th1>
1010
catch {
1111
set stmt [query prepare "SELECT login, cap FROM user"]
1212
puts "stmt ID=$stmt\n"
13
- for {} {0 < [query step $stmt]} {} {
14
- puts [query col string $stmt 0] ": " [query col string $stmt 1] "\n"
13
+ for {} {0 < [query $stmt step]} {} {
14
+ puts [query $stmt col string 0] ": " [query $stmt col string 1] "\n"
1515
}
16
- query finalize $stmt
16
+ query $stmt finalize
1717
return 0
1818
} rc
1919
if {0 != $rc} {
2020
puts "ERROR: $rc\n"
2121
}
2222
&lt;th1>
2323
</pre></nowiki>
2424
25
-The various subcommands are summarized below...
25
+The various subcommands are summarized in the following subsections, and here
26
+are some notes regarding calling conventions:
27
+
28
+The (bind, col, step, finalize) functions accept their statement ID argument
29
+either right after the "query" command or right after the final subcommand.
30
+The following examples demonstrate this:
31
+
32
+<nowiki><pre>
33
+query $stmt step
34
+query step $stmt
35
+
36
+
37
+query $stmt finalize
38
+query finalize $stmt
39
+
40
+query col string $stmt 1
41
+query $stmt col string 1
42
+
43
+query bind string $stmt 1 "foo"
44
+query $stmt bind string 1 "foo"
45
+</pre></nowiki>
46
+
2647
2748
<h2>prepare</h2>
2849
2950
This subcommand prepares a query for execution. It returns a statement handle
3051
ID which must be passed to any other functions using the API.
@@ -38,11 +59,11 @@
3859
calls to <tt>prepare</tt> might re-use the same statement statement
3960
ID.
4061
4162
<nowiki><pre>
4263
set stmt [query prepare "SELECT ..."]
43
-query finalize $stmt
64
+query $stmt finalize
4465
</pre></nowiki>
4566
4667
4768
<h2>step</h2>
4869
@@ -49,12 +70,12 @@
4970
This subcommand steps the result set by one row. It returns 0
5071
at the end of the set, a positive value if a new row is available,
5172
and throws for any other condition.
5273
5374
<nowiki><pre>
54
-for {} {0 &lt; [query step $stmt]} {} {
55
- puts [query col string $stmt 0] "\n"
75
+for {} {0 &lt; [query $stmt step]} {} {
76
+ puts [query $stmt col string 0] "\n"
5677
}
5778
</pre></nowiki>
5879
5980
6081
<h2>strftime</h2>
@@ -62,11 +83,11 @@
6283
This works like <tt>col time</tt> (described below) but takes its
6384
value from an arbitrary source specified by the 3rd argument.
6485
6586
<nowiki><pre>
6687
query strftime %s 1319211587 unixepoch
67
-query strftime {%Y%m%d @ %H:%M:%S} [query col string $stmt 2] {+10 years}]
88
+query strftime {%Y%m%d @ %H:%M:%S} [query $stmt col string 2] {+10 years}]
6889
</pre></nowiki>
6990
7091
7192
<h2>bind xxx</h2>
7293
@@ -80,15 +101,15 @@
80101
81102
Achtung: the bind API uses 1-based indexes, just like SQL does.
82103
83104
<nowiki><pre>
84105
set stmt [query prepare "SELECT ... WHERE user=?"]
85
-query bind_int $stmt 1 drh
86
-if {0 &lt; [query step $stmt]} {
87
- puts [query col string $stmt 0] "\n"
106
+query $stmt bind int 1 drh
107
+if {0 &lt; [query $stmt step]} {
108
+ puts [query $stmt col string 0] "\n"
88109
}
89
-query finalize $stmt
110
+query $stmt finalize
90111
</pre></nowiki>
91112
92113
93114
<h2>col xxx</h2>
94115
@@ -110,14 +131,14 @@
110131
This function is a proxy for sqlite3's
111132
<tt>[http://www.sqlite.org/lang_datefunc.html|strftime()]</tt> function. It is used like this:
112133
113134
114135
<nowiki><pre>
115
-query col time $stmt $index {%Y%m%d @ %H:%M:%S}
136
+query $stmt col time $index {%Y%m%d @ %H:%M:%S}
116137
</pre></nowiki>
117138
118139
Any remaining arguments are treated as "modifiers" and passed as-is to strfmtime. For example:
119140
120141
<nowiki><pre>
121
-query col time $stmt $index {%Y%m%d @ %H:%M:%S} {+5 years}
122
-query col time $stmt $index %s unixepoch
142
+query $stmt col time $index {%Y%m%d @ %H:%M:%S} {+5 years}
143
+query $stmt col time $index %s unixepoch
123144
</pre></nowiki>
124145
--- www/th1_query.wiki
+++ www/th1_query.wiki
@@ -8,23 +8,44 @@
8 <nowiki><pre>
9 &lt;th1>
10 catch {
11 set stmt [query prepare "SELECT login, cap FROM user"]
12 puts "stmt ID=$stmt\n"
13 for {} {0 < [query step $stmt]} {} {
14 puts [query col string $stmt 0] ": " [query col string $stmt 1] "\n"
15 }
16 query finalize $stmt
17 return 0
18 } rc
19 if {0 != $rc} {
20 puts "ERROR: $rc\n"
21 }
22 &lt;th1>
23 </pre></nowiki>
24
25 The various subcommands are summarized below...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
27 <h2>prepare</h2>
28
29 This subcommand prepares a query for execution. It returns a statement handle
30 ID which must be passed to any other functions using the API.
@@ -38,11 +59,11 @@
38 calls to <tt>prepare</tt> might re-use the same statement statement
39 ID.
40
41 <nowiki><pre>
42 set stmt [query prepare "SELECT ..."]
43 query finalize $stmt
44 </pre></nowiki>
45
46
47 <h2>step</h2>
48
@@ -49,12 +70,12 @@
49 This subcommand steps the result set by one row. It returns 0
50 at the end of the set, a positive value if a new row is available,
51 and throws for any other condition.
52
53 <nowiki><pre>
54 for {} {0 &lt; [query step $stmt]} {} {
55 puts [query col string $stmt 0] "\n"
56 }
57 </pre></nowiki>
58
59
60 <h2>strftime</h2>
@@ -62,11 +83,11 @@
62 This works like <tt>col time</tt> (described below) but takes its
63 value from an arbitrary source specified by the 3rd argument.
64
65 <nowiki><pre>
66 query strftime %s 1319211587 unixepoch
67 query strftime {%Y%m%d @ %H:%M:%S} [query col string $stmt 2] {+10 years}]
68 </pre></nowiki>
69
70
71 <h2>bind xxx</h2>
72
@@ -80,15 +101,15 @@
80
81 Achtung: the bind API uses 1-based indexes, just like SQL does.
82
83 <nowiki><pre>
84 set stmt [query prepare "SELECT ... WHERE user=?"]
85 query bind_int $stmt 1 drh
86 if {0 &lt; [query step $stmt]} {
87 puts [query col string $stmt 0] "\n"
88 }
89 query finalize $stmt
90 </pre></nowiki>
91
92
93 <h2>col xxx</h2>
94
@@ -110,14 +131,14 @@
110 This function is a proxy for sqlite3's
111 <tt>[http://www.sqlite.org/lang_datefunc.html|strftime()]</tt> function. It is used like this:
112
113
114 <nowiki><pre>
115 query col time $stmt $index {%Y%m%d @ %H:%M:%S}
116 </pre></nowiki>
117
118 Any remaining arguments are treated as "modifiers" and passed as-is to strfmtime. For example:
119
120 <nowiki><pre>
121 query col time $stmt $index {%Y%m%d @ %H:%M:%S} {+5 years}
122 query col time $stmt $index %s unixepoch
123 </pre></nowiki>
124
--- www/th1_query.wiki
+++ www/th1_query.wiki
@@ -8,23 +8,44 @@
8 <nowiki><pre>
9 &lt;th1>
10 catch {
11 set stmt [query prepare "SELECT login, cap FROM user"]
12 puts "stmt ID=$stmt\n"
13 for {} {0 < [query $stmt step]} {} {
14 puts [query $stmt col string 0] ": " [query $stmt col string 1] "\n"
15 }
16 query $stmt finalize
17 return 0
18 } rc
19 if {0 != $rc} {
20 puts "ERROR: $rc\n"
21 }
22 &lt;th1>
23 </pre></nowiki>
24
25 The various subcommands are summarized in the following subsections, and here
26 are some notes regarding calling conventions:
27
28 The (bind, col, step, finalize) functions accept their statement ID argument
29 either right after the "query" command or right after the final subcommand.
30 The following examples demonstrate this:
31
32 <nowiki><pre>
33 query $stmt step
34 query step $stmt
35
36
37 query $stmt finalize
38 query finalize $stmt
39
40 query col string $stmt 1
41 query $stmt col string 1
42
43 query bind string $stmt 1 "foo"
44 query $stmt bind string 1 "foo"
45 </pre></nowiki>
46
47
48 <h2>prepare</h2>
49
50 This subcommand prepares a query for execution. It returns a statement handle
51 ID which must be passed to any other functions using the API.
@@ -38,11 +59,11 @@
59 calls to <tt>prepare</tt> might re-use the same statement statement
60 ID.
61
62 <nowiki><pre>
63 set stmt [query prepare "SELECT ..."]
64 query $stmt finalize
65 </pre></nowiki>
66
67
68 <h2>step</h2>
69
@@ -49,12 +70,12 @@
70 This subcommand steps the result set by one row. It returns 0
71 at the end of the set, a positive value if a new row is available,
72 and throws for any other condition.
73
74 <nowiki><pre>
75 for {} {0 &lt; [query $stmt step]} {} {
76 puts [query $stmt col string 0] "\n"
77 }
78 </pre></nowiki>
79
80
81 <h2>strftime</h2>
@@ -62,11 +83,11 @@
83 This works like <tt>col time</tt> (described below) but takes its
84 value from an arbitrary source specified by the 3rd argument.
85
86 <nowiki><pre>
87 query strftime %s 1319211587 unixepoch
88 query strftime {%Y%m%d @ %H:%M:%S} [query $stmt col string 2] {+10 years}]
89 </pre></nowiki>
90
91
92 <h2>bind xxx</h2>
93
@@ -80,15 +101,15 @@
101
102 Achtung: the bind API uses 1-based indexes, just like SQL does.
103
104 <nowiki><pre>
105 set stmt [query prepare "SELECT ... WHERE user=?"]
106 query $stmt bind int 1 drh
107 if {0 &lt; [query $stmt step]} {
108 puts [query $stmt col string 0] "\n"
109 }
110 query $stmt finalize
111 </pre></nowiki>
112
113
114 <h2>col xxx</h2>
115
@@ -110,14 +131,14 @@
131 This function is a proxy for sqlite3's
132 <tt>[http://www.sqlite.org/lang_datefunc.html|strftime()]</tt> function. It is used like this:
133
134
135 <nowiki><pre>
136 query $stmt col time $index {%Y%m%d @ %H:%M:%S}
137 </pre></nowiki>
138
139 Any remaining arguments are treated as "modifiers" and passed as-is to strfmtime. For example:
140
141 <nowiki><pre>
142 query $stmt col time $index {%Y%m%d @ %H:%M:%S} {+5 years}
143 query $stmt col time $index %s unixepoch
144 </pre></nowiki>
145

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button