Fossil SCM

Refactored th1/sqlite bits to use Th_Data_Get/Set(), removed sqlite data from Th_Interp class. Other minor cleanups.

stephan 2012-07-15 12:27 th1-query-api
Commit 3167ff33f84ef8324c4a8c2af0cdbbb83494b08c
4 files changed +19 -89 +14 -35 +145 -30 +2 -1
+19 -89
--- src/th.c
+++ src/th.c
@@ -44,16 +44,10 @@
4444
object. It would be more efficient to store
4545
these in a list (we don't expect many
4646
entries), but Th_Hash has the strong advantage
4747
of being here and working.
4848
*/
49
-#ifdef TH_USE_SQLITE
50
- struct {
51
- sqlite3_stmt ** aStmt;
52
- int nStmt;
53
- } stmt; /* list of prepared statements */
54
-#endif
5549
};
5650
5751
/*
5852
** Each TH command registered using Th_CreateCommand() is represented
5953
** by an instance of the following structure stored in the Th_Interp.paCmd
@@ -1731,26 +1725,10 @@
17311725
17321726
/* Delete all registered commands and the command hash-table itself. */
17331727
Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
17341728
Th_HashDelete(interp, interp->paCmd);
17351729
1736
-#ifdef TH_USE_SQLITE
1737
- {
1738
- int i;
1739
- sqlite3_stmt * st;
1740
- for( i = 0; i < interp->stmt.nStmt; ++i ){
1741
- st = interp->stmt.aStmt[i];
1742
- if(NULL != st){
1743
- fossil_warning("Auto-finalizing unfinalized query_prepare "
1744
- "statement id #%d: %s",
1745
- i+1, sqlite3_sql(st));
1746
- Th_FinalizeStmt( interp, i+1 );
1747
- }
1748
- }
1749
- Th_Free(interp, interp->stmt.aStmt);
1750
- }
1751
-#endif
17521730
17531731
/* Delete the interpreter structure itself. */
17541732
Th_Free(interp, (void *)interp);
17551733
}
17561734
@@ -2764,60 +2742,13 @@
27642742
}
27652743
void * Th_Data_Get( Th_Interp * interp, char const * key ){
27662744
Th_HashEntry * e = interp->paGc
27672745
? Th_HashFind(interp, interp->paGc, key, th_strlen(key), 0)
27682746
: NULL;
2769
- return e ? e->pData : NULL;
2770
-}
2771
-
2772
-#ifdef TH_USE_SQLITE
2773
-int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){
2774
- int i, x;
2775
- sqlite3_stmt * s;
2776
- sqlite3_stmt ** list = interp->stmt.aStmt;
2777
- for( i = 0; i < interp->stmt.nStmt; ++i ){
2778
- s = list[i];
2779
- if(NULL==s){
2780
- list[i] = pStmt;
2781
- return i+1;
2782
- }
2783
- }
2784
- x = (interp->stmt.nStmt + 1) * 2;
2785
- list = (sqlite3_stmt**)fossil_realloc( list, sizeof(sqlite3_stmt*)*x );
2786
- for( i = interp->stmt.nStmt; i < x; ++i ){
2787
- list[i] = NULL;
2788
- }
2789
- list[interp->stmt.nStmt] = pStmt;
2790
- x = interp->stmt.nStmt;
2791
- interp->stmt.nStmt = i;
2792
- interp->stmt.aStmt = list;
2793
- return x + 1;
2794
-}
2795
-
2796
-
2797
-int Th_FinalizeStmt(Th_Interp *interp, int stmtId){
2798
- sqlite3_stmt * st;
2799
- int rc = 0;
2800
- assert( stmtId>0 && stmtId<=interp->stmt.nStmt );
2801
- st = interp->stmt.aStmt[stmtId-1];
2802
- if(NULL != st){
2803
- interp->stmt.aStmt[stmtId-1] = NULL;
2804
- sqlite3_finalize(st);
2805
- return 0;
2806
- }else{
2807
- return 1;
2808
- }
2809
-}
2810
-
2811
-sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){
2812
- return ((stmtId<1) || (stmtId > interp->stmt.nStmt))
2813
- ? NULL
2814
- : interp->stmt.aStmt[stmtId-1];
2815
-}
2816
-
2817
-#endif
2818
-/* end TH_USE_SQLITE */
2747
+ return e ? ((Th_GcEntry*)e->pData)->pData : NULL;
2748
+}
2749
+
28192750
28202751
28212752
#ifdef TH_USE_OUTBUF
28222753
/* Reminder: the ob code "really" belongs in th_lang.c,
28232754
but we need access to Th_Interp internals in order to
@@ -2840,19 +2771,15 @@
28402771
Th_output_f_ob /*f*/, \
28412772
NULL /*pState*/,\
28422773
1/*enabled*/\
28432774
}
28442775
static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
2845
-static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m;
28462776
static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m;
28472777
static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m;
28482778
#define Th_Ob_Man_KEY "Th_Ob_Man"
28492779
Th_Ob_Man * Th_ob_manager(Th_Interp *interp){
2850
- void * rc = Th_Data_Get(interp, Th_Ob_Man_KEY );
2851
- return rc
2852
- ? ((Th_GcEntry*)rc)->pData
2853
- : NULL;
2780
+ return (Th_Ob_Man*) Th_Data_Get(interp, Th_Ob_Man_KEY );
28542781
}
28552782
28562783
28572784
Blob * Th_ob_current( Th_Ob_Man * pMan ){
28582785
return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
@@ -2921,25 +2848,25 @@
29212848
pMan->interp->pVtab->out = Th_Vtab_Ob.out;
29222849
pMan->interp->pVtab->out.pState = pMan;
29232850
if( pOut ){
29242851
*pOut = pBlob;
29252852
}
2853
+ /*printf( "push: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
29262854
return TH_OK;
29272855
error:
29282856
if( pBlob ){
29292857
Th_Free( pMan->interp, pBlob );
29302858
}
29312859
return TH_ERROR;
29322860
}
29332861
2934
-
2935
-
29362862
Blob * Th_ob_pop( Th_Ob_Man * pMan ){
29372863
if( pMan->cursor < 0 ){
29382864
return NULL;
29392865
}else{
29402866
Blob * rc;
2867
+ /*printf( "pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
29412868
assert( pMan->nBuf > pMan->cursor );
29422869
rc = pMan->aBuf[pMan->cursor];
29432870
pMan->aBuf[pMan->cursor] = NULL;
29442871
pMan->interp->pVtab->out = pMan->aOutput[pMan->cursor];
29452872
pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty;
@@ -2947,11 +2874,13 @@
29472874
Th_Interp * interp = pMan->interp;
29482875
Th_Free( pMan->interp, pMan->aBuf );
29492876
Th_Free( pMan->interp, pMan->aOutput );
29502877
*pMan = Th_Ob_Man_empty;
29512878
pMan->interp = interp;
2879
+ assert(-1 == pMan->cursor);
29522880
}
2881
+ /*printf( "post-pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
29532882
return rc;
29542883
}
29552884
}
29562885
29572886
void Th_ob_cleanup( Th_Ob_Man * man ){
@@ -3152,13 +3081,11 @@
31523081
Th_Ob_Man * man = (Th_Ob_Man*)p;
31533082
/*printf("finalizerObMan(%p,%p)\n", interp, p );*/
31543083
if(man){
31553084
assert( interp == man->interp );
31563085
Th_ob_cleanup( man );
3157
- if( man != &Th_Ob_Man_instance ){
3158
- Th_Free( interp, man );
3159
- }
3086
+ Th_Free( interp, man );
31603087
}
31613088
}
31623089
31633090
/*
31643091
** TH Syntax:
@@ -3199,21 +3126,24 @@
31993126
{0,0,0}
32003127
};
32013128
rc = Th_register_commands( interp, aCommand );
32023129
if(NULL == Th_ob_manager(interp)){
32033130
Th_Ob_Man * pMan;
3204
- pMan = 1
3205
- ? &Th_Ob_Man_instance
3206
- : Th_Malloc(interp, sizeof(Th_Ob_Man));
3207
- /* *pMan = Th_Ob_Man_empty;*/
3208
- pMan->interp = interp;
3209
- Th_Data_Set( interp, Th_Ob_Man_KEY, pMan, finalizerObMan );
3210
- assert( NULL != Th_ob_manager(interp) );
3131
+ pMan = Th_Malloc(interp, sizeof(Th_Ob_Man));
3132
+ if(!pMan){
3133
+ rc = TH_ERROR;
3134
+ }else{
3135
+ *pMan = Th_Ob_Man_empty;
3136
+ pMan->interp = interp;
3137
+ assert( -1 == pMan->cursor );
3138
+ Th_Data_Set( interp, Th_Ob_Man_KEY, pMan, finalizerObMan );
3139
+ assert( NULL != Th_ob_manager(interp) );
3140
+ }
32113141
}
32123142
return rc;
32133143
}
32143144
32153145
#undef Th_Ob_Man_empty_m
32163146
#undef Th_Ob_Man_KEY
32173147
#endif
32183148
/* end TH_USE_OUTBUF */
32193149
32203150
--- src/th.c
+++ src/th.c
@@ -44,16 +44,10 @@
44 object. It would be more efficient to store
45 these in a list (we don't expect many
46 entries), but Th_Hash has the strong advantage
47 of being here and working.
48 */
49 #ifdef TH_USE_SQLITE
50 struct {
51 sqlite3_stmt ** aStmt;
52 int nStmt;
53 } stmt; /* list of prepared statements */
54 #endif
55 };
56
57 /*
58 ** Each TH command registered using Th_CreateCommand() is represented
59 ** by an instance of the following structure stored in the Th_Interp.paCmd
@@ -1731,26 +1725,10 @@
1731
1732 /* Delete all registered commands and the command hash-table itself. */
1733 Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
1734 Th_HashDelete(interp, interp->paCmd);
1735
1736 #ifdef TH_USE_SQLITE
1737 {
1738 int i;
1739 sqlite3_stmt * st;
1740 for( i = 0; i < interp->stmt.nStmt; ++i ){
1741 st = interp->stmt.aStmt[i];
1742 if(NULL != st){
1743 fossil_warning("Auto-finalizing unfinalized query_prepare "
1744 "statement id #%d: %s",
1745 i+1, sqlite3_sql(st));
1746 Th_FinalizeStmt( interp, i+1 );
1747 }
1748 }
1749 Th_Free(interp, interp->stmt.aStmt);
1750 }
1751 #endif
1752
1753 /* Delete the interpreter structure itself. */
1754 Th_Free(interp, (void *)interp);
1755 }
1756
@@ -2764,60 +2742,13 @@
2764 }
2765 void * Th_Data_Get( Th_Interp * interp, char const * key ){
2766 Th_HashEntry * e = interp->paGc
2767 ? Th_HashFind(interp, interp->paGc, key, th_strlen(key), 0)
2768 : NULL;
2769 return e ? e->pData : NULL;
2770 }
2771
2772 #ifdef TH_USE_SQLITE
2773 int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){
2774 int i, x;
2775 sqlite3_stmt * s;
2776 sqlite3_stmt ** list = interp->stmt.aStmt;
2777 for( i = 0; i < interp->stmt.nStmt; ++i ){
2778 s = list[i];
2779 if(NULL==s){
2780 list[i] = pStmt;
2781 return i+1;
2782 }
2783 }
2784 x = (interp->stmt.nStmt + 1) * 2;
2785 list = (sqlite3_stmt**)fossil_realloc( list, sizeof(sqlite3_stmt*)*x );
2786 for( i = interp->stmt.nStmt; i < x; ++i ){
2787 list[i] = NULL;
2788 }
2789 list[interp->stmt.nStmt] = pStmt;
2790 x = interp->stmt.nStmt;
2791 interp->stmt.nStmt = i;
2792 interp->stmt.aStmt = list;
2793 return x + 1;
2794 }
2795
2796
2797 int Th_FinalizeStmt(Th_Interp *interp, int stmtId){
2798 sqlite3_stmt * st;
2799 int rc = 0;
2800 assert( stmtId>0 && stmtId<=interp->stmt.nStmt );
2801 st = interp->stmt.aStmt[stmtId-1];
2802 if(NULL != st){
2803 interp->stmt.aStmt[stmtId-1] = NULL;
2804 sqlite3_finalize(st);
2805 return 0;
2806 }else{
2807 return 1;
2808 }
2809 }
2810
2811 sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){
2812 return ((stmtId<1) || (stmtId > interp->stmt.nStmt))
2813 ? NULL
2814 : interp->stmt.aStmt[stmtId-1];
2815 }
2816
2817 #endif
2818 /* end TH_USE_SQLITE */
2819
2820
2821 #ifdef TH_USE_OUTBUF
2822 /* Reminder: the ob code "really" belongs in th_lang.c,
2823 but we need access to Th_Interp internals in order to
@@ -2840,19 +2771,15 @@
2840 Th_output_f_ob /*f*/, \
2841 NULL /*pState*/,\
2842 1/*enabled*/\
2843 }
2844 static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
2845 static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m;
2846 static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m;
2847 static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m;
2848 #define Th_Ob_Man_KEY "Th_Ob_Man"
2849 Th_Ob_Man * Th_ob_manager(Th_Interp *interp){
2850 void * rc = Th_Data_Get(interp, Th_Ob_Man_KEY );
2851 return rc
2852 ? ((Th_GcEntry*)rc)->pData
2853 : NULL;
2854 }
2855
2856
2857 Blob * Th_ob_current( Th_Ob_Man * pMan ){
2858 return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
@@ -2921,25 +2848,25 @@
2921 pMan->interp->pVtab->out = Th_Vtab_Ob.out;
2922 pMan->interp->pVtab->out.pState = pMan;
2923 if( pOut ){
2924 *pOut = pBlob;
2925 }
 
2926 return TH_OK;
2927 error:
2928 if( pBlob ){
2929 Th_Free( pMan->interp, pBlob );
2930 }
2931 return TH_ERROR;
2932 }
2933
2934
2935
2936 Blob * Th_ob_pop( Th_Ob_Man * pMan ){
2937 if( pMan->cursor < 0 ){
2938 return NULL;
2939 }else{
2940 Blob * rc;
 
2941 assert( pMan->nBuf > pMan->cursor );
2942 rc = pMan->aBuf[pMan->cursor];
2943 pMan->aBuf[pMan->cursor] = NULL;
2944 pMan->interp->pVtab->out = pMan->aOutput[pMan->cursor];
2945 pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty;
@@ -2947,11 +2874,13 @@
2947 Th_Interp * interp = pMan->interp;
2948 Th_Free( pMan->interp, pMan->aBuf );
2949 Th_Free( pMan->interp, pMan->aOutput );
2950 *pMan = Th_Ob_Man_empty;
2951 pMan->interp = interp;
 
2952 }
 
2953 return rc;
2954 }
2955 }
2956
2957 void Th_ob_cleanup( Th_Ob_Man * man ){
@@ -3152,13 +3081,11 @@
3152 Th_Ob_Man * man = (Th_Ob_Man*)p;
3153 /*printf("finalizerObMan(%p,%p)\n", interp, p );*/
3154 if(man){
3155 assert( interp == man->interp );
3156 Th_ob_cleanup( man );
3157 if( man != &Th_Ob_Man_instance ){
3158 Th_Free( interp, man );
3159 }
3160 }
3161 }
3162
3163 /*
3164 ** TH Syntax:
@@ -3199,21 +3126,24 @@
3199 {0,0,0}
3200 };
3201 rc = Th_register_commands( interp, aCommand );
3202 if(NULL == Th_ob_manager(interp)){
3203 Th_Ob_Man * pMan;
3204 pMan = 1
3205 ? &Th_Ob_Man_instance
3206 : Th_Malloc(interp, sizeof(Th_Ob_Man));
3207 /* *pMan = Th_Ob_Man_empty;*/
3208 pMan->interp = interp;
3209 Th_Data_Set( interp, Th_Ob_Man_KEY, pMan, finalizerObMan );
3210 assert( NULL != Th_ob_manager(interp) );
 
 
 
3211 }
3212 return rc;
3213 }
3214
3215 #undef Th_Ob_Man_empty_m
3216 #undef Th_Ob_Man_KEY
3217 #endif
3218 /* end TH_USE_OUTBUF */
3219
3220
--- src/th.c
+++ src/th.c
@@ -44,16 +44,10 @@
44 object. It would be more efficient to store
45 these in a list (we don't expect many
46 entries), but Th_Hash has the strong advantage
47 of being here and working.
48 */
 
 
 
 
 
 
49 };
50
51 /*
52 ** Each TH command registered using Th_CreateCommand() is represented
53 ** by an instance of the following structure stored in the Th_Interp.paCmd
@@ -1731,26 +1725,10 @@
1725
1726 /* Delete all registered commands and the command hash-table itself. */
1727 Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
1728 Th_HashDelete(interp, interp->paCmd);
1729
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1730
1731 /* Delete the interpreter structure itself. */
1732 Th_Free(interp, (void *)interp);
1733 }
1734
@@ -2764,60 +2742,13 @@
2742 }
2743 void * Th_Data_Get( Th_Interp * interp, char const * key ){
2744 Th_HashEntry * e = interp->paGc
2745 ? Th_HashFind(interp, interp->paGc, key, th_strlen(key), 0)
2746 : NULL;
2747 return e ? ((Th_GcEntry*)e->pData)->pData : NULL;
2748 }
2749
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2750
2751
2752 #ifdef TH_USE_OUTBUF
2753 /* Reminder: the ob code "really" belongs in th_lang.c,
2754 but we need access to Th_Interp internals in order to
@@ -2840,19 +2771,15 @@
2771 Th_output_f_ob /*f*/, \
2772 NULL /*pState*/,\
2773 1/*enabled*/\
2774 }
2775 static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
 
2776 static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m;
2777 static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m;
2778 #define Th_Ob_Man_KEY "Th_Ob_Man"
2779 Th_Ob_Man * Th_ob_manager(Th_Interp *interp){
2780 return (Th_Ob_Man*) Th_Data_Get(interp, Th_Ob_Man_KEY );
 
 
 
2781 }
2782
2783
2784 Blob * Th_ob_current( Th_Ob_Man * pMan ){
2785 return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
@@ -2921,25 +2848,25 @@
2848 pMan->interp->pVtab->out = Th_Vtab_Ob.out;
2849 pMan->interp->pVtab->out.pState = pMan;
2850 if( pOut ){
2851 *pOut = pBlob;
2852 }
2853 /*printf( "push: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
2854 return TH_OK;
2855 error:
2856 if( pBlob ){
2857 Th_Free( pMan->interp, pBlob );
2858 }
2859 return TH_ERROR;
2860 }
2861
 
 
2862 Blob * Th_ob_pop( Th_Ob_Man * pMan ){
2863 if( pMan->cursor < 0 ){
2864 return NULL;
2865 }else{
2866 Blob * rc;
2867 /*printf( "pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
2868 assert( pMan->nBuf > pMan->cursor );
2869 rc = pMan->aBuf[pMan->cursor];
2870 pMan->aBuf[pMan->cursor] = NULL;
2871 pMan->interp->pVtab->out = pMan->aOutput[pMan->cursor];
2872 pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty;
@@ -2947,11 +2874,13 @@
2874 Th_Interp * interp = pMan->interp;
2875 Th_Free( pMan->interp, pMan->aBuf );
2876 Th_Free( pMan->interp, pMan->aOutput );
2877 *pMan = Th_Ob_Man_empty;
2878 pMan->interp = interp;
2879 assert(-1 == pMan->cursor);
2880 }
2881 /*printf( "post-pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
2882 return rc;
2883 }
2884 }
2885
2886 void Th_ob_cleanup( Th_Ob_Man * man ){
@@ -3152,13 +3081,11 @@
3081 Th_Ob_Man * man = (Th_Ob_Man*)p;
3082 /*printf("finalizerObMan(%p,%p)\n", interp, p );*/
3083 if(man){
3084 assert( interp == man->interp );
3085 Th_ob_cleanup( man );
3086 Th_Free( interp, man );
 
 
3087 }
3088 }
3089
3090 /*
3091 ** TH Syntax:
@@ -3199,21 +3126,24 @@
3126 {0,0,0}
3127 };
3128 rc = Th_register_commands( interp, aCommand );
3129 if(NULL == Th_ob_manager(interp)){
3130 Th_Ob_Man * pMan;
3131 pMan = Th_Malloc(interp, sizeof(Th_Ob_Man));
3132 if(!pMan){
3133 rc = TH_ERROR;
3134 }else{
3135 *pMan = Th_Ob_Man_empty;
3136 pMan->interp = interp;
3137 assert( -1 == pMan->cursor );
3138 Th_Data_Set( interp, Th_Ob_Man_KEY, pMan, finalizerObMan );
3139 assert( NULL != Th_ob_manager(interp) );
3140 }
3141 }
3142 return rc;
3143 }
3144
3145 #undef Th_Ob_Man_empty_m
3146 #undef Th_Ob_Man_KEY
3147 #endif
3148 /* end TH_USE_OUTBUF */
3149
3150
+14 -35
--- src/th.h
+++ src/th.h
@@ -1,23 +1,32 @@
11
#include "config.h"
22
3
+/*
4
+** TH_USE_SQLITE, if defined, enables the "query" family of functions.
5
+** They provide SELECT-only access to the repository db.
6
+*/
37
#define TH_USE_SQLITE
4
-#ifdef TH_USE_SQLITE
5
-#include "sqlite3.h"
6
-#endif
78
89
/*
910
** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
1011
** They are functionally similar to PHP's ob_start(), ob_end(), etc.
1112
** family of functions, providing output capturing/buffering.
1213
*/
1314
#define TH_USE_OUTBUF
14
-/*#undef TH_USE_OUTBUF*/
15
+
16
+/*
17
+** TH_USE_ARGV, if defined, enables the "argv" family of functions.
18
+** They provide access to CLI arguments as well as GET/POST arguments.
19
+** They do not provide access to POST data submitted in JSON mode.
20
+*/
21
+#define TH_USE_ARGV
22
+
23
+#ifdef TH_USE_OUTBUF
1524
#ifndef INTERFACE
1625
#include "blob.h"
1726
#endif
18
-
27
+#endif
1928
2029
/* This header file defines the external interface to the custom Scripting
2130
** Language (TH) interpreter. TH is very similar to TCL but is not an
2231
** exact clone.
2332
*/
@@ -303,40 +312,10 @@
303312
** have a NULL zName field (that is the end-of-list marker).
304313
** Returns TH_OK on success, "something else" on error.
305314
*/
306315
int Th_register_commands( Th_Interp * interp, Th_Command_Reg const * pList );
307316
308
-#ifdef TH_USE_SQLITE
309
-
310
-/*
311
-** Adds the given prepared statement to the interpreter. Returns the
312
-** statements opaque identifier (a positive value). Ownerships of
313
-** pStmt is transfered to interp and it must be cleaned up by the
314
-** client by calling Th_FinalizeStmt(), passing it the value returned
315
-** by this function.
316
-**
317
-** If interp is destroyed before all statements are finalized,
318
-** it will finalize them but may emit a warning message.
319
-*/
320
-int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt);
321
-
322
-/*
323
-** Expects stmtId to be a statement identifier returned by
324
-** Th_AddStmt(). On success, finalizes the statement and returns 0.
325
-** On error (statement not found) non-0 is returned. After this
326
-** call, some subsequent call to Th_AddStmt() may return the
327
-** same statement ID.
328
-*/
329
-int Th_FinalizeStmt(Th_Interp *interp, int stmtId);
330
-
331
-/*
332
-** Fetches the statement with the given ID, as returned by
333
-** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
334
-** refers) to a statement added via Th_AddStmt().
335
-*/
336
-sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId);
337
-#endif
338317
339318
#ifdef TH_USE_OUTBUF
340319
/*
341320
** Manager of a stack of Blob objects for output buffering.
342321
*/
343322
--- src/th.h
+++ src/th.h
@@ -1,23 +1,32 @@
1 #include "config.h"
2
 
 
 
 
3 #define TH_USE_SQLITE
4 #ifdef TH_USE_SQLITE
5 #include "sqlite3.h"
6 #endif
7
8 /*
9 ** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
10 ** They are functionally similar to PHP's ob_start(), ob_end(), etc.
11 ** family of functions, providing output capturing/buffering.
12 */
13 #define TH_USE_OUTBUF
14 /*#undef TH_USE_OUTBUF*/
 
 
 
 
 
 
 
 
15 #ifndef INTERFACE
16 #include "blob.h"
17 #endif
18
19
20 /* This header file defines the external interface to the custom Scripting
21 ** Language (TH) interpreter. TH is very similar to TCL but is not an
22 ** exact clone.
23 */
@@ -303,40 +312,10 @@
303 ** have a NULL zName field (that is the end-of-list marker).
304 ** Returns TH_OK on success, "something else" on error.
305 */
306 int Th_register_commands( Th_Interp * interp, Th_Command_Reg const * pList );
307
308 #ifdef TH_USE_SQLITE
309
310 /*
311 ** Adds the given prepared statement to the interpreter. Returns the
312 ** statements opaque identifier (a positive value). Ownerships of
313 ** pStmt is transfered to interp and it must be cleaned up by the
314 ** client by calling Th_FinalizeStmt(), passing it the value returned
315 ** by this function.
316 **
317 ** If interp is destroyed before all statements are finalized,
318 ** it will finalize them but may emit a warning message.
319 */
320 int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt);
321
322 /*
323 ** Expects stmtId to be a statement identifier returned by
324 ** Th_AddStmt(). On success, finalizes the statement and returns 0.
325 ** On error (statement not found) non-0 is returned. After this
326 ** call, some subsequent call to Th_AddStmt() may return the
327 ** same statement ID.
328 */
329 int Th_FinalizeStmt(Th_Interp *interp, int stmtId);
330
331 /*
332 ** Fetches the statement with the given ID, as returned by
333 ** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
334 ** refers) to a statement added via Th_AddStmt().
335 */
336 sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId);
337 #endif
338
339 #ifdef TH_USE_OUTBUF
340 /*
341 ** Manager of a stack of Blob objects for output buffering.
342 */
343
--- src/th.h
+++ src/th.h
@@ -1,23 +1,32 @@
1 #include "config.h"
2
3 /*
4 ** TH_USE_SQLITE, if defined, enables the "query" family of functions.
5 ** They provide SELECT-only access to the repository db.
6 */
7 #define TH_USE_SQLITE
 
 
 
8
9 /*
10 ** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
11 ** They are functionally similar to PHP's ob_start(), ob_end(), etc.
12 ** family of functions, providing output capturing/buffering.
13 */
14 #define TH_USE_OUTBUF
15
16 /*
17 ** TH_USE_ARGV, if defined, enables the "argv" family of functions.
18 ** They provide access to CLI arguments as well as GET/POST arguments.
19 ** They do not provide access to POST data submitted in JSON mode.
20 */
21 #define TH_USE_ARGV
22
23 #ifdef TH_USE_OUTBUF
24 #ifndef INTERFACE
25 #include "blob.h"
26 #endif
27 #endif
28
29 /* This header file defines the external interface to the custom Scripting
30 ** Language (TH) interpreter. TH is very similar to TCL but is not an
31 ** exact clone.
32 */
@@ -303,40 +312,10 @@
312 ** have a NULL zName field (that is the end-of-list marker).
313 ** Returns TH_OK on success, "something else" on error.
314 */
315 int Th_register_commands( Th_Interp * interp, Th_Command_Reg const * pList );
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
318 #ifdef TH_USE_OUTBUF
319 /*
320 ** Manager of a stack of Blob objects for output buffering.
321 */
322
+145 -30
--- src/th_main.c
+++ src/th_main.c
@@ -17,12 +17,17 @@
1717
**
1818
** This file contains an interface between the TH scripting language
1919
** (an independent project) and fossil.
2020
*/
2121
#include "config.h"
22
-
2322
#include "th_main.h"
23
+#ifndef INTERFACE
24
+#include "blob.h"
25
+#endif
26
+#ifdef TH_USE_SQLITE
27
+#include "sqlite3.h"
28
+#endif
2429
2530
/*#include "th_main.h"*/
2631
/*
2732
** Global variable counting the number of outstanding calls to malloc()
2833
** made by the th1 implementation. This is used to catch memory leaks
@@ -537,16 +542,18 @@
537542
Th_SetResult(interp, g.zRepositoryName, -1);
538543
return TH_OK;
539544
}
540545
541546
542
-extern const char *find_option(const char *zLong, const char *zShort, int hasArg);
543
-
547
+#ifdef TH_USE_ARGV
548
+extern const char *find_option(const char *zLong,
549
+ const char *zShort,
550
+ int hasArg) /* from main.c */;
544551
/*
545552
** TH Syntax:
546553
**
547
-** argv_len
554
+** argv len
548555
**
549556
** Returns the number of command-line arguments.
550557
*/
551558
static int argvArgcCmd(
552559
Th_Interp *interp,
@@ -557,12 +564,12 @@
557564
){
558565
Th_SetResultInt( interp, g.argc );
559566
return TH_OK;
560567
}
561568
562
-#define TH_USE_ARGV
563
-#ifdef TH_USE_ARGV
569
+
570
+
564571
/*
565572
** TH Syntax:
566573
**
567574
** argv_getat Index
568575
**
@@ -833,13 +840,121 @@
833840
834841
#endif
835842
/* end TH_USE_ARGV */
836843
837844
#ifdef TH_USE_SQLITE
838
-#ifndef INTERFACE
839
-#include "blob.h"
840
-#endif
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,
854
+** it will finalize them but may emit a warning message.
855
+*/
856
+int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt);
857
+
858
+/*
859
+** Expects stmtId to be a statement identifier returned by
860
+** Th_AddStmt(). On success, finalizes the statement and returns 0.
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
+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().
871
+*/
872
+sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId);
873
+
874
+
875
+struct Th_Sqlite {
876
+ sqlite3_stmt ** aStmt;
877
+ int nStmt;
878
+};
879
+#define Th_Sqlite_KEY "Th_Sqlite"
880
+typedef struct Th_Sqlite Th_Sqlite;
881
+
882
+static Th_Sqlite * Th_sqlite_manager( Th_Interp * interp ){
883
+ void * p = Th_Data_Get( interp, Th_Sqlite_KEY );
884
+ return p ? (Th_Sqlite*)p : NULL;
885
+}
886
+
887
+int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){
888
+ Th_Sqlite * sq = Th_sqlite_manager(interp);
889
+ int i, x;
890
+ sqlite3_stmt * s;
891
+ sqlite3_stmt ** list = sq->aStmt;
892
+ for( i = 0; i < sq->nStmt; ++i ){
893
+ s = list[i];
894
+ if(NULL==s){
895
+ list[i] = pStmt;
896
+ return i+1;
897
+ }
898
+ }
899
+ x = (sq->nStmt + 1) * 2;
900
+ list = (sqlite3_stmt**)fossil_realloc( list, sizeof(sqlite3_stmt*)*x );
901
+ for( i = sq->nStmt; i < x; ++i ){
902
+ list[i] = NULL;
903
+ }
904
+ list[sq->nStmt] = pStmt;
905
+ x = sq->nStmt;
906
+ sq->nStmt = i;
907
+ sq->aStmt = list;
908
+ return x + 1;
909
+}
910
+
911
+
912
+int Th_FinalizeStmt(Th_Interp *interp, int stmtId){
913
+ Th_Sqlite * sq = Th_sqlite_manager(interp);
914
+ sqlite3_stmt * st;
915
+ int rc = 0;
916
+ assert( stmtId>0 && stmtId<=sq->nStmt );
917
+ st = sq->aStmt[stmtId-1];
918
+ if(NULL != st){
919
+ sq->aStmt[stmtId-1] = NULL;
920
+ sqlite3_finalize(st);
921
+ return 0;
922
+ }else{
923
+ return 1;
924
+ }
925
+}
926
+
927
+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
931
+ : sq->aStmt[stmtId-1];
932
+}
933
+
934
+
935
+static void finalizerSqlite( Th_Interp * interp, void * p ){
936
+ Th_Sqlite * sq = Th_sqlite_manager( interp );
937
+ int i;
938
+ sqlite3_stmt * st = NULL;
939
+ if(!sq) {
940
+ fossil_warning("Got a finalizer call for a NULL Th_Sqlite.");
941
+ return;
942
+ }
943
+ for( i = 0; i < sq->nStmt; ++i ){
944
+ st = sq->aStmt[i];
945
+ if(NULL != st){
946
+ fossil_warning("Auto-finalizing unfinalized query_prepare "
947
+ "statement id #%d: %s",
948
+ i+1, sqlite3_sql(st));
949
+ Th_FinalizeStmt( interp, i+1 );
950
+ }
951
+ }
952
+ Th_Free(interp, sq->aStmt);
953
+ Th_Free(interp, sq);
954
+}
955
+
841956
842957
/*
843958
** TH Syntax:
844959
**
845960
** query_prepare SQL
@@ -1544,20 +1659,22 @@
15441659
void *ctx,
15451660
int argc,
15461661
const char **argv,
15471662
int *argl
15481663
){
1664
+ Th_Sqlite * sq = Th_sqlite_manager(interp);
15491665
static Th_SubCommand aSub[] = {
15501666
{"bind", queryBindTopLevelCmd},
15511667
{"col", queryColTopLevelCmd},
15521668
{"step", queryStepCmd},
15531669
{"finalize", queryFinalizeCmd},
15541670
{"prepare", queryPrepareCmd},
15551671
{"strftime", queryStrftimeCmd},
15561672
{0, 0}
15571673
};
1558
- Th_CallSubCommand2( interp, ctx, argc, argv, argl, aSub );
1674
+ assert( NULL != sq );
1675
+ Th_CallSubCommand2( interp, sq, argc, argv, argl, aSub );
15591676
}
15601677
15611678
15621679
int th_register_sqlite(Th_Interp *interp){
15631680
enum { BufLen = 100 };
@@ -1573,31 +1690,28 @@
15731690
SET(SQLITE_NULL);
15741691
SET(SQLITE_OK);
15751692
SET(SQLITE_ROW);
15761693
SET(SQLITE_TEXT);
15771694
#undef SET
1695
+ int rc = TH_OK;
15781696
static Th_Command_Reg aCommand[] = {
15791697
{"query", queryTopLevelCmd, 0},
1580
-#if 0
1581
- {"query_bind_int", queryBindIntCmd, 0},
1582
- {"query_bind_double", queryBindDoubleCmd,0},
1583
- {"query_bind_null", queryBindNullCmd, 0},
1584
- {"query_bind_string", queryBindStringCmd,0},
1585
- {"query_col_count", queryColCountCmd, 0},
1586
- {"query_col_double", queryColDoubleCmd, 0},
1587
- {"query_col_int", queryColIntCmd, 0},
1588
- {"query_col_is_null", queryColIsNullCmd, 0},
1589
- {"query_col_name", queryColNameCmd, 0},
1590
- {"query_col_string", queryColStringCmd, 0},
1591
- {"query_col_type", queryColTypeCmd, 0},
1592
- {"query_finalize", queryFinalizeCmd, 0},
1593
- {"query_prepare", queryPrepareCmd, 0},
1594
- {"query_step", queryStepCmd, 0},
1595
-#endif
15961698
{0, 0, 0}
15971699
};
1598
- Th_register_commands( interp, aCommand );
1700
+ rc = Th_register_commands( interp, aCommand );
1701
+ if(TH_OK==rc){
1702
+ Th_Sqlite * sq = Th_Malloc(interp, sizeof(Th_Sqlite));
1703
+ if(!sq){
1704
+ rc = TH_ERROR;
1705
+ }else{
1706
+ assert( NULL == sq->aStmt );
1707
+ assert( 0 == sq->nStmt );
1708
+ Th_Data_Set( interp, Th_Sqlite_KEY, sq, finalizerSqlite );
1709
+ assert( sq == Th_sqlite_manager(interp) );
1710
+ }
1711
+ }
1712
+ return rc;
15991713
}
16001714
16011715
#endif
16021716
/* end TH_USE_SQLITE */
16031717
@@ -1820,12 +1934,12 @@
18201934
i++;
18211935
}
18221936
}
18231937
if( rc==TH_ERROR ){
18241938
sendText(g.interp, "<hr><p class=\"thmainError\">ERROR: ", -1, 0);
1825
- zResult = (char*)Th_GetResult(g.interp, &n);
1826
- sendText(g.interp, (char*)zResult, n, 1);
1939
+ zResult = Th_GetResult(g.interp, &n);
1940
+ sendText(g.interp, zResult, n, 1);
18271941
sendText(g.interp, "</p>", -1, 0);
18281942
}else{
18291943
sendText(g.interp, z, i, 0);
18301944
}
18311945
return rc;
@@ -1849,10 +1963,11 @@
18491963
assert(0 && "usage() does not return");
18501964
}
18511965
blob_zero(&in);
18521966
db_open_config(0); /* Needed for global "tcl" setting. */
18531967
#ifdef TH_USE_SQLITE
1854
- db_find_and_open_repository(OPEN_ANY_SCHEMA,0) /* for query_xxx API. */;
1968
+ db_find_and_open_repository(OPEN_ANY_SCHEMA,0)
1969
+ /* required for th1 query API. */;
18551970
#endif
18561971
blob_read_from_file(&in, g.argv[2]);
18571972
Th_Render(blob_str(&in), Th_Render_Flags_DEFAULT);
18581973
}
18591974
--- src/th_main.c
+++ src/th_main.c
@@ -17,12 +17,17 @@
17 **
18 ** This file contains an interface between the TH scripting language
19 ** (an independent project) and fossil.
20 */
21 #include "config.h"
22
23 #include "th_main.h"
 
 
 
 
 
 
24
25 /*#include "th_main.h"*/
26 /*
27 ** Global variable counting the number of outstanding calls to malloc()
28 ** made by the th1 implementation. This is used to catch memory leaks
@@ -537,16 +542,18 @@
537 Th_SetResult(interp, g.zRepositoryName, -1);
538 return TH_OK;
539 }
540
541
542 extern const char *find_option(const char *zLong, const char *zShort, int hasArg);
543
 
 
544 /*
545 ** TH Syntax:
546 **
547 ** argv_len
548 **
549 ** Returns the number of command-line arguments.
550 */
551 static int argvArgcCmd(
552 Th_Interp *interp,
@@ -557,12 +564,12 @@
557 ){
558 Th_SetResultInt( interp, g.argc );
559 return TH_OK;
560 }
561
562 #define TH_USE_ARGV
563 #ifdef TH_USE_ARGV
564 /*
565 ** TH Syntax:
566 **
567 ** argv_getat Index
568 **
@@ -833,13 +840,121 @@
833
834 #endif
835 /* end TH_USE_ARGV */
836
837 #ifdef TH_USE_SQLITE
838 #ifndef INTERFACE
839 #include "blob.h"
840 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
841
842 /*
843 ** TH Syntax:
844 **
845 ** query_prepare SQL
@@ -1544,20 +1659,22 @@
1544 void *ctx,
1545 int argc,
1546 const char **argv,
1547 int *argl
1548 ){
 
1549 static Th_SubCommand aSub[] = {
1550 {"bind", queryBindTopLevelCmd},
1551 {"col", queryColTopLevelCmd},
1552 {"step", queryStepCmd},
1553 {"finalize", queryFinalizeCmd},
1554 {"prepare", queryPrepareCmd},
1555 {"strftime", queryStrftimeCmd},
1556 {0, 0}
1557 };
1558 Th_CallSubCommand2( interp, ctx, argc, argv, argl, aSub );
 
1559 }
1560
1561
1562 int th_register_sqlite(Th_Interp *interp){
1563 enum { BufLen = 100 };
@@ -1573,31 +1690,28 @@
1573 SET(SQLITE_NULL);
1574 SET(SQLITE_OK);
1575 SET(SQLITE_ROW);
1576 SET(SQLITE_TEXT);
1577 #undef SET
 
1578 static Th_Command_Reg aCommand[] = {
1579 {"query", queryTopLevelCmd, 0},
1580 #if 0
1581 {"query_bind_int", queryBindIntCmd, 0},
1582 {"query_bind_double", queryBindDoubleCmd,0},
1583 {"query_bind_null", queryBindNullCmd, 0},
1584 {"query_bind_string", queryBindStringCmd,0},
1585 {"query_col_count", queryColCountCmd, 0},
1586 {"query_col_double", queryColDoubleCmd, 0},
1587 {"query_col_int", queryColIntCmd, 0},
1588 {"query_col_is_null", queryColIsNullCmd, 0},
1589 {"query_col_name", queryColNameCmd, 0},
1590 {"query_col_string", queryColStringCmd, 0},
1591 {"query_col_type", queryColTypeCmd, 0},
1592 {"query_finalize", queryFinalizeCmd, 0},
1593 {"query_prepare", queryPrepareCmd, 0},
1594 {"query_step", queryStepCmd, 0},
1595 #endif
1596 {0, 0, 0}
1597 };
1598 Th_register_commands( interp, aCommand );
 
 
 
 
 
 
 
 
 
 
 
 
1599 }
1600
1601 #endif
1602 /* end TH_USE_SQLITE */
1603
@@ -1820,12 +1934,12 @@
1820 i++;
1821 }
1822 }
1823 if( rc==TH_ERROR ){
1824 sendText(g.interp, "<hr><p class=\"thmainError\">ERROR: ", -1, 0);
1825 zResult = (char*)Th_GetResult(g.interp, &n);
1826 sendText(g.interp, (char*)zResult, n, 1);
1827 sendText(g.interp, "</p>", -1, 0);
1828 }else{
1829 sendText(g.interp, z, i, 0);
1830 }
1831 return rc;
@@ -1849,10 +1963,11 @@
1849 assert(0 && "usage() does not return");
1850 }
1851 blob_zero(&in);
1852 db_open_config(0); /* Needed for global "tcl" setting. */
1853 #ifdef TH_USE_SQLITE
1854 db_find_and_open_repository(OPEN_ANY_SCHEMA,0) /* for query_xxx API. */;
 
1855 #endif
1856 blob_read_from_file(&in, g.argv[2]);
1857 Th_Render(blob_str(&in), Th_Render_Flags_DEFAULT);
1858 }
1859
--- src/th_main.c
+++ src/th_main.c
@@ -17,12 +17,17 @@
17 **
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 #ifndef INTERFACE
24 #include "blob.h"
25 #endif
26 #ifdef TH_USE_SQLITE
27 #include "sqlite3.h"
28 #endif
29
30 /*#include "th_main.h"*/
31 /*
32 ** Global variable counting the number of outstanding calls to malloc()
33 ** made by the th1 implementation. This is used to catch memory leaks
@@ -537,16 +542,18 @@
542 Th_SetResult(interp, g.zRepositoryName, -1);
543 return TH_OK;
544 }
545
546
547 #ifdef TH_USE_ARGV
548 extern const char *find_option(const char *zLong,
549 const char *zShort,
550 int hasArg) /* from main.c */;
551 /*
552 ** TH Syntax:
553 **
554 ** argv len
555 **
556 ** Returns the number of command-line arguments.
557 */
558 static int argvArgcCmd(
559 Th_Interp *interp,
@@ -557,12 +564,12 @@
564 ){
565 Th_SetResultInt( interp, g.argc );
566 return TH_OK;
567 }
568
569
570
571 /*
572 ** TH Syntax:
573 **
574 ** argv_getat Index
575 **
@@ -833,13 +840,121 @@
840
841 #endif
842 /* end TH_USE_ARGV */
843
844 #ifdef TH_USE_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,
854 ** it will finalize them but may emit a warning message.
855 */
856 int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt);
857
858 /*
859 ** Expects stmtId to be a statement identifier returned by
860 ** Th_AddStmt(). On success, finalizes the statement and returns 0.
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 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().
871 */
872 sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId);
873
874
875 struct Th_Sqlite {
876 sqlite3_stmt ** aStmt;
877 int nStmt;
878 };
879 #define Th_Sqlite_KEY "Th_Sqlite"
880 typedef struct Th_Sqlite Th_Sqlite;
881
882 static Th_Sqlite * Th_sqlite_manager( Th_Interp * interp ){
883 void * p = Th_Data_Get( interp, Th_Sqlite_KEY );
884 return p ? (Th_Sqlite*)p : NULL;
885 }
886
887 int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){
888 Th_Sqlite * sq = Th_sqlite_manager(interp);
889 int i, x;
890 sqlite3_stmt * s;
891 sqlite3_stmt ** list = sq->aStmt;
892 for( i = 0; i < sq->nStmt; ++i ){
893 s = list[i];
894 if(NULL==s){
895 list[i] = pStmt;
896 return i+1;
897 }
898 }
899 x = (sq->nStmt + 1) * 2;
900 list = (sqlite3_stmt**)fossil_realloc( list, sizeof(sqlite3_stmt*)*x );
901 for( i = sq->nStmt; i < x; ++i ){
902 list[i] = NULL;
903 }
904 list[sq->nStmt] = pStmt;
905 x = sq->nStmt;
906 sq->nStmt = i;
907 sq->aStmt = list;
908 return x + 1;
909 }
910
911
912 int Th_FinalizeStmt(Th_Interp *interp, int stmtId){
913 Th_Sqlite * sq = Th_sqlite_manager(interp);
914 sqlite3_stmt * st;
915 int rc = 0;
916 assert( stmtId>0 && stmtId<=sq->nStmt );
917 st = sq->aStmt[stmtId-1];
918 if(NULL != st){
919 sq->aStmt[stmtId-1] = NULL;
920 sqlite3_finalize(st);
921 return 0;
922 }else{
923 return 1;
924 }
925 }
926
927 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
931 : sq->aStmt[stmtId-1];
932 }
933
934
935 static void finalizerSqlite( Th_Interp * interp, void * p ){
936 Th_Sqlite * sq = Th_sqlite_manager( interp );
937 int i;
938 sqlite3_stmt * st = NULL;
939 if(!sq) {
940 fossil_warning("Got a finalizer call for a NULL Th_Sqlite.");
941 return;
942 }
943 for( i = 0; i < sq->nStmt; ++i ){
944 st = sq->aStmt[i];
945 if(NULL != st){
946 fossil_warning("Auto-finalizing unfinalized query_prepare "
947 "statement id #%d: %s",
948 i+1, sqlite3_sql(st));
949 Th_FinalizeStmt( interp, i+1 );
950 }
951 }
952 Th_Free(interp, sq->aStmt);
953 Th_Free(interp, sq);
954 }
955
956
957 /*
958 ** TH Syntax:
959 **
960 ** query_prepare SQL
@@ -1544,20 +1659,22 @@
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_sqlite(Th_Interp *interp){
1680 enum { BufLen = 100 };
@@ -1573,31 +1690,28 @@
1690 SET(SQLITE_NULL);
1691 SET(SQLITE_OK);
1692 SET(SQLITE_ROW);
1693 SET(SQLITE_TEXT);
1694 #undef SET
1695 int rc = TH_OK;
1696 static Th_Command_Reg aCommand[] = {
1697 {"query", queryTopLevelCmd, 0},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1698 {0, 0, 0}
1699 };
1700 rc = Th_register_commands( interp, aCommand );
1701 if(TH_OK==rc){
1702 Th_Sqlite * sq = Th_Malloc(interp, sizeof(Th_Sqlite));
1703 if(!sq){
1704 rc = TH_ERROR;
1705 }else{
1706 assert( NULL == sq->aStmt );
1707 assert( 0 == sq->nStmt );
1708 Th_Data_Set( interp, Th_Sqlite_KEY, sq, finalizerSqlite );
1709 assert( sq == Th_sqlite_manager(interp) );
1710 }
1711 }
1712 return rc;
1713 }
1714
1715 #endif
1716 /* end TH_USE_SQLITE */
1717
@@ -1820,12 +1934,12 @@
1934 i++;
1935 }
1936 }
1937 if( rc==TH_ERROR ){
1938 sendText(g.interp, "<hr><p class=\"thmainError\">ERROR: ", -1, 0);
1939 zResult = Th_GetResult(g.interp, &n);
1940 sendText(g.interp, zResult, n, 1);
1941 sendText(g.interp, "</p>", -1, 0);
1942 }else{
1943 sendText(g.interp, z, i, 0);
1944 }
1945 return rc;
@@ -1849,10 +1963,11 @@
1963 assert(0 && "usage() does not return");
1964 }
1965 blob_zero(&in);
1966 db_open_config(0); /* Needed for global "tcl" setting. */
1967 #ifdef TH_USE_SQLITE
1968 db_find_and_open_repository(OPEN_ANY_SCHEMA,0)
1969 /* required for th1 query API. */;
1970 #endif
1971 blob_read_from_file(&in, g.argv[2]);
1972 Th_Render(blob_str(&in), Th_Render_Flags_DEFAULT);
1973 }
1974
--- www/th1_argv.wiki
+++ www/th1_argv.wiki
@@ -1,9 +1,10 @@
11
<h1>TH1 "argv" API</h1>
22
33
The "argv" API provides features for accessing command-line arguments
4
-and GET/POST values.
4
+and GET/POST values. They (unfortunately) do not provide access to
5
+POST data submitted in JSON mode.
56
67
Example usage:
78
89
<nowiki><pre>
910
&lt;th1>
1011
--- www/th1_argv.wiki
+++ www/th1_argv.wiki
@@ -1,9 +1,10 @@
1 <h1>TH1 "argv" API</h1>
2
3 The "argv" API provides features for accessing command-line arguments
4 and GET/POST values.
 
5
6 Example usage:
7
8 <nowiki><pre>
9 &lt;th1>
10
--- www/th1_argv.wiki
+++ www/th1_argv.wiki
@@ -1,9 +1,10 @@
1 <h1>TH1 "argv" API</h1>
2
3 The "argv" API provides features for accessing command-line arguments
4 and GET/POST values. They (unfortunately) do not provide access to
5 POST data submitted in JSON mode.
6
7 Example usage:
8
9 <nowiki><pre>
10 &lt;th1>
11

Keyboard Shortcuts

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