Fossil SCM

Add the "query" command to the TH1 language, used to query the repository database.

drh 2012-11-24 14:44 UTC ticket-enhancements
Commit f6ac3c6f3de328e7735e355561da9c19063b02ac
+7
--- src/th.c
+++ src/th.c
@@ -1148,10 +1148,17 @@
11481148
return TH_ERROR;
11491149
}
11501150
11511151
return Th_SetResult(interp, pValue->zData, pValue->nData);
11521152
}
1153
+
1154
+/*
1155
+** Return true if variable (zVar, nVar) exists.
1156
+*/
1157
+int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
1158
+ return thFindValue(interp, zVar, nVar, 0, 0)!=0;
1159
+}
11531160
11541161
/*
11551162
** String (zVar, nVar) must contain the name of a scalar variable or
11561163
** array member. If the variable does not exist it is created. The
11571164
** variable is set to the value supplied in string (zValue, nValue).
11581165
--- src/th.c
+++ src/th.c
@@ -1148,10 +1148,17 @@
1148 return TH_ERROR;
1149 }
1150
1151 return Th_SetResult(interp, pValue->zData, pValue->nData);
1152 }
 
 
 
 
 
 
 
1153
1154 /*
1155 ** String (zVar, nVar) must contain the name of a scalar variable or
1156 ** array member. If the variable does not exist it is created. The
1157 ** variable is set to the value supplied in string (zValue, nValue).
1158
--- src/th.c
+++ src/th.c
@@ -1148,10 +1148,17 @@
1148 return TH_ERROR;
1149 }
1150
1151 return Th_SetResult(interp, pValue->zData, pValue->nData);
1152 }
1153
1154 /*
1155 ** Return true if variable (zVar, nVar) exists.
1156 */
1157 int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
1158 return thFindValue(interp, zVar, nVar, 0, 0)!=0;
1159 }
1160
1161 /*
1162 ** String (zVar, nVar) must contain the name of a scalar variable or
1163 ** array member. If the variable does not exist it is created. The
1164 ** variable is set to the value supplied in string (zValue, nValue).
1165
+1
--- src/th.h
+++ src/th.h
@@ -49,10 +49,11 @@
4949
5050
/*
5151
** Access TH variables in the current stack frame. If the variable name
5252
** begins with "::", the lookup is in the top level (global) frame.
5353
*/
54
+int Th_ExistsVar(Th_Interp *, const char *, int);
5455
int Th_GetVar(Th_Interp *, const char *, int);
5556
int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
5657
int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
5758
int Th_UnsetVar(Th_Interp *, const char *, int);
5859
5960
--- src/th.h
+++ src/th.h
@@ -49,10 +49,11 @@
49
50 /*
51 ** Access TH variables in the current stack frame. If the variable name
52 ** begins with "::", the lookup is in the top level (global) frame.
53 */
 
54 int Th_GetVar(Th_Interp *, const char *, int);
55 int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
56 int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
57 int Th_UnsetVar(Th_Interp *, const char *, int);
58
59
--- src/th.h
+++ src/th.h
@@ -49,10 +49,11 @@
49
50 /*
51 ** Access TH variables in the current stack frame. If the variable name
52 ** begins with "::", the lookup is in the top level (global) frame.
53 */
54 int Th_ExistsVar(Th_Interp *, const char *, int);
55 int Th_GetVar(Th_Interp *, const char *, int);
56 int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
57 int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
58 int Th_UnsetVar(Th_Interp *, const char *, int);
59
60
+2 -2
--- src/th_lang.c
+++ src/th_lang.c
@@ -856,12 +856,12 @@
856856
int rc;
857857
858858
if( argc!=3 ){
859859
return Th_WrongNumArgs(interp, "info exists var");
860860
}
861
- rc = Th_GetVar(interp, argv[2], argl[2]);
862
- Th_SetResultInt(interp, rc?0:1);
861
+ rc = Th_ExistsVar(interp, argv[2], argl[2]);
862
+ Th_SetResultInt(interp, rc);
863863
return TH_OK;
864864
}
865865
866866
/*
867867
** TH Syntax:
868868
--- src/th_lang.c
+++ src/th_lang.c
@@ -856,12 +856,12 @@
856 int rc;
857
858 if( argc!=3 ){
859 return Th_WrongNumArgs(interp, "info exists var");
860 }
861 rc = Th_GetVar(interp, argv[2], argl[2]);
862 Th_SetResultInt(interp, rc?0:1);
863 return TH_OK;
864 }
865
866 /*
867 ** TH Syntax:
868
--- src/th_lang.c
+++ src/th_lang.c
@@ -856,12 +856,12 @@
856 int rc;
857
858 if( argc!=3 ){
859 return Th_WrongNumArgs(interp, "info exists var");
860 }
861 rc = Th_ExistsVar(interp, argv[2], argl[2]);
862 Th_SetResultInt(interp, rc);
863 return TH_OK;
864 }
865
866 /*
867 ** TH Syntax:
868
--- src/th_main.c
+++ src/th_main.c
@@ -18,10 +18,11 @@
1818
** This file contains an interface between the TH scripting language
1919
** (an independent project) and fossil.
2020
*/
2121
#include "config.h"
2222
#include "th_main.h"
23
+#include "sqlite3.h"
2324
2425
/*
2526
** Global variable counting the number of outstanding calls to malloc()
2627
** made by the th1 implementation. This is used to catch memory leaks
2728
** in the interpreter. Obviously, it also means th1 is not threadsafe.
@@ -575,10 +576,86 @@
575576
encode16(aRand, zOut, n);
576577
Th_SetResult(interp, (const char *)zOut, -1);
577578
return TH_OK;
578579
}
579580
581
+/*
582
+** TH1 command: query SQL CODE
583
+**
584
+** Run the SQL query given by the SQL argument. For each row in the result
585
+** set, run CODE.
586
+**
587
+** In SQL, parameters such as $var are filled in using the value of variable
588
+** "var". Result values are stored in variables with the column name prior
589
+** to each invocation of CODE.
590
+*/
591
+static int queryCmd(
592
+ Th_Interp *interp,
593
+ void *p,
594
+ int argc,
595
+ const char **argv,
596
+ int *argl
597
+){
598
+ sqlite3_stmt *pStmt;
599
+ int rc;
600
+ const char *zSql;
601
+ int nSql;
602
+ const char *zTail;
603
+ int n, i;
604
+ int res = TH_OK;
605
+ int nVar;
606
+
607
+ if( argc!=3 ){
608
+ return Th_WrongNumArgs(interp, "query SQL CODE");
609
+ }
610
+ if( g.db==0 ){
611
+ Th_ErrorMessage(interp, "database is not open", 0, 0);
612
+ return TH_ERROR;
613
+ }
614
+ zSql = argv[1];
615
+ nSql = argl[1];
616
+ while( res==TH_OK && nSql>0 ){
617
+ rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
618
+ if( rc!=0 ){
619
+ Th_ErrorMessage(interp, "SQL error: ", sqlite3_errmsg(g.db), -1);
620
+ return TH_ERROR;
621
+ }
622
+ n = (int)(zTail - zSql);
623
+ zSql += n;
624
+ nSql -= n;
625
+ if( pStmt==0 ) continue;
626
+ nVar = sqlite3_bind_parameter_count(pStmt);
627
+ for(i=1; i<=nVar; i++){
628
+ const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
629
+ int szVar = zVar ? th_strlen(zVar) : 0;
630
+ if( szVar>1 && zVar[0]=='$'
631
+ && Th_GetVar(interp, zVar+1, szVar-1)==TH_OK ){
632
+ int nVal;
633
+ const char *zVal = Th_GetResult(interp, &nVal);
634
+ sqlite3_bind_text(pStmt, i, zVal, nVal, SQLITE_TRANSIENT);
635
+ }
636
+ }
637
+ while( res==TH_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
638
+ int nCol = sqlite3_column_count(pStmt);
639
+ for(i=0; i<nCol; i++){
640
+ const char *zCol = sqlite3_column_name(pStmt, i);
641
+ int szCol = th_strlen(zCol);
642
+ const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
643
+ int szVal = sqlite3_column_bytes(pStmt, i);
644
+ Th_SetVar(interp, zCol, szCol, zVal, szVal);
645
+ }
646
+ res = Th_Eval(interp, 0, argv[2], argl[2]);
647
+ if( res==TH_BREAK || res==TH_CONTINUE ) res = TH_OK;
648
+ }
649
+ rc = sqlite3_finalize(pStmt);
650
+ if( rc!=SQLITE_OK ){
651
+ Th_ErrorMessage(interp, "SQL error: ", sqlite3_errmsg(g.db), -1);
652
+ return TH_ERROR;
653
+ }
654
+ }
655
+ return res;
656
+}
580657
581658
/*
582659
** Make sure the interpreter has been initialized. Initialize it if
583660
** it has not been already.
584661
**
@@ -601,10 +678,11 @@
601678
{"hasfeature", hasfeatureCmd, 0},
602679
{"html", putsCmd, (void*)&aFlags[0]},
603680
{"htmlize", htmlizeCmd, 0},
604681
{"linecount", linecntCmd, 0},
605682
{"puts", putsCmd, (void*)&aFlags[1]},
683
+ {"query", queryCmd, 0},
606684
{"randhex", randhexCmd, 0},
607685
{"repository", repositoryCmd, 0},
608686
{"stime", stimeCmd, 0},
609687
{"utime", utimeCmd, 0},
610688
{"wiki", wikiCmd, (void*)&aFlags[0]},
611689
--- src/th_main.c
+++ src/th_main.c
@@ -18,10 +18,11 @@
18 ** This file contains an interface between the TH scripting language
19 ** (an independent project) and fossil.
20 */
21 #include "config.h"
22 #include "th_main.h"
 
23
24 /*
25 ** Global variable counting the number of outstanding calls to malloc()
26 ** made by the th1 implementation. This is used to catch memory leaks
27 ** in the interpreter. Obviously, it also means th1 is not threadsafe.
@@ -575,10 +576,86 @@
575 encode16(aRand, zOut, n);
576 Th_SetResult(interp, (const char *)zOut, -1);
577 return TH_OK;
578 }
579
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
580
581 /*
582 ** Make sure the interpreter has been initialized. Initialize it if
583 ** it has not been already.
584 **
@@ -601,10 +678,11 @@
601 {"hasfeature", hasfeatureCmd, 0},
602 {"html", putsCmd, (void*)&aFlags[0]},
603 {"htmlize", htmlizeCmd, 0},
604 {"linecount", linecntCmd, 0},
605 {"puts", putsCmd, (void*)&aFlags[1]},
 
606 {"randhex", randhexCmd, 0},
607 {"repository", repositoryCmd, 0},
608 {"stime", stimeCmd, 0},
609 {"utime", utimeCmd, 0},
610 {"wiki", wikiCmd, (void*)&aFlags[0]},
611
--- src/th_main.c
+++ src/th_main.c
@@ -18,10 +18,11 @@
18 ** This file contains an interface between the TH scripting language
19 ** (an independent project) and fossil.
20 */
21 #include "config.h"
22 #include "th_main.h"
23 #include "sqlite3.h"
24
25 /*
26 ** Global variable counting the number of outstanding calls to malloc()
27 ** made by the th1 implementation. This is used to catch memory leaks
28 ** in the interpreter. Obviously, it also means th1 is not threadsafe.
@@ -575,10 +576,86 @@
576 encode16(aRand, zOut, n);
577 Th_SetResult(interp, (const char *)zOut, -1);
578 return TH_OK;
579 }
580
581 /*
582 ** TH1 command: query SQL CODE
583 **
584 ** Run the SQL query given by the SQL argument. For each row in the result
585 ** set, run CODE.
586 **
587 ** In SQL, parameters such as $var are filled in using the value of variable
588 ** "var". Result values are stored in variables with the column name prior
589 ** to each invocation of CODE.
590 */
591 static int queryCmd(
592 Th_Interp *interp,
593 void *p,
594 int argc,
595 const char **argv,
596 int *argl
597 ){
598 sqlite3_stmt *pStmt;
599 int rc;
600 const char *zSql;
601 int nSql;
602 const char *zTail;
603 int n, i;
604 int res = TH_OK;
605 int nVar;
606
607 if( argc!=3 ){
608 return Th_WrongNumArgs(interp, "query SQL CODE");
609 }
610 if( g.db==0 ){
611 Th_ErrorMessage(interp, "database is not open", 0, 0);
612 return TH_ERROR;
613 }
614 zSql = argv[1];
615 nSql = argl[1];
616 while( res==TH_OK && nSql>0 ){
617 rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
618 if( rc!=0 ){
619 Th_ErrorMessage(interp, "SQL error: ", sqlite3_errmsg(g.db), -1);
620 return TH_ERROR;
621 }
622 n = (int)(zTail - zSql);
623 zSql += n;
624 nSql -= n;
625 if( pStmt==0 ) continue;
626 nVar = sqlite3_bind_parameter_count(pStmt);
627 for(i=1; i<=nVar; i++){
628 const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
629 int szVar = zVar ? th_strlen(zVar) : 0;
630 if( szVar>1 && zVar[0]=='$'
631 && Th_GetVar(interp, zVar+1, szVar-1)==TH_OK ){
632 int nVal;
633 const char *zVal = Th_GetResult(interp, &nVal);
634 sqlite3_bind_text(pStmt, i, zVal, nVal, SQLITE_TRANSIENT);
635 }
636 }
637 while( res==TH_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
638 int nCol = sqlite3_column_count(pStmt);
639 for(i=0; i<nCol; i++){
640 const char *zCol = sqlite3_column_name(pStmt, i);
641 int szCol = th_strlen(zCol);
642 const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
643 int szVal = sqlite3_column_bytes(pStmt, i);
644 Th_SetVar(interp, zCol, szCol, zVal, szVal);
645 }
646 res = Th_Eval(interp, 0, argv[2], argl[2]);
647 if( res==TH_BREAK || res==TH_CONTINUE ) res = TH_OK;
648 }
649 rc = sqlite3_finalize(pStmt);
650 if( rc!=SQLITE_OK ){
651 Th_ErrorMessage(interp, "SQL error: ", sqlite3_errmsg(g.db), -1);
652 return TH_ERROR;
653 }
654 }
655 return res;
656 }
657
658 /*
659 ** Make sure the interpreter has been initialized. Initialize it if
660 ** it has not been already.
661 **
@@ -601,10 +678,11 @@
678 {"hasfeature", hasfeatureCmd, 0},
679 {"html", putsCmd, (void*)&aFlags[0]},
680 {"htmlize", htmlizeCmd, 0},
681 {"linecount", linecntCmd, 0},
682 {"puts", putsCmd, (void*)&aFlags[1]},
683 {"query", queryCmd, 0},
684 {"randhex", randhexCmd, 0},
685 {"repository", repositoryCmd, 0},
686 {"stime", stimeCmd, 0},
687 {"utime", utimeCmd, 0},
688 {"wiki", wikiCmd, (void*)&aFlags[0]},
689

Keyboard Shortcuts

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