| | @@ -18,18 +18,17 @@ |
| 18 | 18 | ** This file contains an interface between the TH scripting language |
| 19 | 19 | ** (an independent project) and fossil. |
| 20 | 20 | */ |
| 21 | 21 | #include "config.h" |
| 22 | 22 | #include "th_main.h" |
| 23 | + |
| 24 | +#ifdef TH_ENABLE_QUERY |
| 23 | 25 | #ifndef INTERFACE |
| 24 | | -#include "blob.h" |
| 25 | | -#endif |
| 26 | | -#ifdef TH_ENABLE_SQLITE |
| 27 | 26 | #include "sqlite3.h" |
| 28 | 27 | #endif |
| 28 | +#endif |
| 29 | 29 | |
| 30 | | -/*#include "th_main.h"*/ |
| 31 | 30 | /* |
| 32 | 31 | ** Global variable counting the number of outstanding calls to malloc() |
| 33 | 32 | ** made by the th1 implementation. This is used to catch memory leaks |
| 34 | 33 | ** in the interpreter. Obviously, it also means th1 is not threadsafe. |
| 35 | 34 | */ |
| | @@ -50,32 +49,28 @@ |
| 50 | 49 | nOutstandingMalloc--; |
| 51 | 50 | } |
| 52 | 51 | fossil_free(p); |
| 53 | 52 | } |
| 54 | 53 | |
| 54 | +/* |
| 55 | +** Default Th_Vtab::xRealloc() implementation. |
| 56 | +*/ |
| 55 | 57 | static void *xRealloc(void * p, unsigned int n){ |
| 58 | + assert(n>=0 && "Invalid memory (re/de)allocation size."); |
| 56 | 59 | if(0 == n){ |
| 57 | 60 | xFree(p); |
| 58 | 61 | return NULL; |
| 59 | 62 | }else if(NULL == p){ |
| 60 | 63 | return xMalloc(n); |
| 61 | 64 | }else{ |
| 62 | 65 | return fossil_realloc(p, n) |
| 63 | | - /* FIXME: try to find some reasonable nOutstandingMalloc |
| 64 | | - heuristics, e.g. if !p then ++, if !n then --, etc. |
| 66 | + /* In theory nOutstandingMalloc doesn't need to be updated here |
| 67 | + unless xRealloc() is sorely misused. |
| 65 | 68 | */; |
| 66 | 69 | } |
| 67 | 70 | } |
| 68 | 71 | |
| 69 | | -static Th_Vtab vtab = { xRealloc, { |
| 70 | | - NULL /*write()*/, |
| 71 | | - NULL/*dispose()*/, |
| 72 | | - NULL/*pState*/, |
| 73 | | - 1/*enabled*/ |
| 74 | | - } |
| 75 | | -}; |
| 76 | | - |
| 77 | 72 | /* |
| 78 | 73 | ** Generate a TH1 trace message if debugging is enabled. |
| 79 | 74 | */ |
| 80 | 75 | void Th_Trace(const char *zFormat, ...){ |
| 81 | 76 | va_list ap; |
| | @@ -85,10 +80,18 @@ |
| 85 | 80 | } |
| 86 | 81 | |
| 87 | 82 | |
| 88 | 83 | /* |
| 89 | 84 | ** True if output is enabled. False if disabled. |
| 85 | +** |
| 86 | +** We "could" replace this with Th_OutputEnable() and friends, but |
| 87 | +** there is a functional difference: this particular flag prohibits |
| 88 | +** some extra escaping which would happen (but be discared, unused) if |
| 89 | +** relied solely on that API. Also, because that API only works on the |
| 90 | +** current Vtab_Output handler, relying soly on that handling would |
| 91 | +** introduce incompatible behaviour with the historical enable_output |
| 92 | +** command. |
| 90 | 93 | */ |
| 91 | 94 | static int enableOutput = 1; |
| 92 | 95 | |
| 93 | 96 | /* |
| 94 | 97 | ** TH command: enable_output BOOLEAN |
| | @@ -106,16 +109,18 @@ |
| 106 | 109 | return Th_WrongNumArgs2(interp, |
| 107 | 110 | argv[0], argl[0], |
| 108 | 111 | "BOOLEAN"); |
| 109 | 112 | }else{ |
| 110 | 113 | int rc = Th_ToInt(interp, argv[1], argl[1], &enableOutput); |
| 111 | | - vtab.out.enabled = enableOutput; |
| 112 | 114 | return rc; |
| 113 | 115 | } |
| 114 | 116 | } |
| 115 | 117 | |
| 116 | | -int Th_output_f_cgi_content( char const * zData, int nData, void * pState ){ |
| 118 | +/* |
| 119 | +** Th_Output_f() impl which sends all output to cgi_append_content(). |
| 120 | +*/ |
| 121 | +static int Th_Output_f_cgi_content( char const * zData, int nData, void * pState ){ |
| 117 | 122 | cgi_append_content(zData, nData); |
| 118 | 123 | return nData; |
| 119 | 124 | } |
| 120 | 125 | |
| 121 | 126 | |
| | @@ -132,27 +137,39 @@ |
| 132 | 137 | if( n<0 ) n = strlen(z); |
| 133 | 138 | if( encode ){ |
| 134 | 139 | z = htmlize(z, n); |
| 135 | 140 | n = strlen(z); |
| 136 | 141 | } |
| 137 | | - Th_output( pInterp, z, n ); |
| 142 | + Th_Output( pInterp, z, n ); |
| 138 | 143 | if( encode ) fossil_free((char*)z); |
| 139 | 144 | } |
| 140 | 145 | } |
| 141 | 146 | |
| 147 | +/* |
| 148 | +** Internal state for the putsCmd() function, allowing it to be used |
| 149 | +** as the basis for multiple implementations with slightly different |
| 150 | +** behaviours based on the context. An instance of this type must be |
| 151 | +** set as the Context parameter for any putsCmd()-based script command |
| 152 | +** binding. |
| 153 | +*/ |
| 142 | 154 | struct PutsCmdData { |
| 143 | | - char escapeHtml; |
| 144 | | - char const * sep; |
| 145 | | - char const * eol; |
| 155 | + char escapeHtml; /* If true, htmlize all output. */ |
| 156 | + char const * sep; /* Optional NUL-terminated separator to output |
| 157 | + between arguments. May be NULL. */ |
| 158 | + char const * eol; /* Optional NUL-terminated end-of-line separator, |
| 159 | + output after the final argument. May be NULL. */ |
| 146 | 160 | }; |
| 147 | 161 | typedef struct PutsCmdData PutsCmdData; |
| 148 | 162 | |
| 149 | 163 | /* |
| 150 | 164 | ** TH command: puts STRING |
| 151 | 165 | ** TH command: html STRING |
| 152 | 166 | ** |
| 153 | | -** Output STRING as HTML (html) or unchanged (puts). |
| 167 | +** Output STRING as HTML (html) or unchanged (puts). |
| 168 | +** |
| 169 | +** pConvert MUST be a (PutsCmdData [const]*). It is not modified by |
| 170 | +** this function. |
| 154 | 171 | */ |
| 155 | 172 | static int putsCmd( |
| 156 | 173 | Th_Interp *interp, |
| 157 | 174 | void *pConvert, |
| 158 | 175 | int argc, |
| | @@ -229,11 +246,12 @@ |
| 229 | 246 | free(zOut); |
| 230 | 247 | return TH_OK; |
| 231 | 248 | } |
| 232 | 249 | |
| 233 | 250 | #if 0 |
| 234 | | -/* i'm not sure we need this */ |
| 251 | +/* This is not yet needed, but something like it may become useful for |
| 252 | + custom page/command support, for rendering snippets/templates. */ |
| 235 | 253 | /* |
| 236 | 254 | ** TH command: render STRING |
| 237 | 255 | ** |
| 238 | 256 | ** Render the input string as TH1. |
| 239 | 257 | */ |
| | @@ -247,11 +265,11 @@ |
| 247 | 265 | if( argc<2 ){ |
| 248 | 266 | return Th_WrongNumArgs2(interp, |
| 249 | 267 | argv[0], argl[0], |
| 250 | 268 | "STRING ?STRING...?"); |
| 251 | 269 | }else{ |
| 252 | | - Th_Ob_Man * man = Th_ob_manager(interp); |
| 270 | + Th_Ob_Manager * man = Th_Ob_GetManager(interp); |
| 253 | 271 | Blob * b = NULL; |
| 254 | 272 | Blob buf = empty_blob; |
| 255 | 273 | int rc, i; |
| 256 | 274 | /*FIXME: assert(NULL != man && man->interp==interp);*/ |
| 257 | 275 | man->interp = interp; |
| | @@ -263,18 +281,18 @@ |
| 263 | 281 | for( i = 1; TH_OK==rc && i < argc; ++i ){ |
| 264 | 282 | char const * str = argv[i]; |
| 265 | 283 | blob_append( &buf, str, argl[i] ); |
| 266 | 284 | /*rc = Th_Render( str, Th_Render_Flags_NO_DOLLAR_DEREF );*/ |
| 267 | 285 | } |
| 268 | | - rc = Th_ob_push( man, &b ); |
| 286 | + rc = Th_Ob_Push( man, &b ); |
| 269 | 287 | if(rc){ |
| 270 | 288 | blob_reset( &buf ); |
| 271 | 289 | return rc; |
| 272 | 290 | } |
| 273 | 291 | rc = Th_Render( buf.aData, Th_Render_Flags_DEFAULT ); |
| 274 | 292 | blob_reset(&buf); |
| 275 | | - b = Th_ob_pop( man ); |
| 293 | + b = Th_Ob_Pop( man ); |
| 276 | 294 | if(TH_OK==rc){ |
| 277 | 295 | Th_SetResult( interp, b->aData, b->nUsed ); |
| 278 | 296 | } |
| 279 | 297 | blob_reset( b ); |
| 280 | 298 | Th_Free( interp, b ); |
| | @@ -544,15 +562,12 @@ |
| 544 | 562 | return TH_OK; |
| 545 | 563 | } |
| 546 | 564 | |
| 547 | 565 | |
| 548 | 566 | #ifdef TH_ENABLE_ARGV |
| 549 | | -extern const char *find_option(const char *zLong, |
| 550 | | - const char *zShort, |
| 551 | | - int hasArg) /* from main.c */; |
| 552 | 567 | /* |
| 553 | | -** TH Syntax: |
| 568 | +** TH command: |
| 554 | 569 | ** |
| 555 | 570 | ** argv len |
| 556 | 571 | ** |
| 557 | 572 | ** Returns the number of command-line arguments. |
| 558 | 573 | */ |
| | @@ -568,11 +583,11 @@ |
| 568 | 583 | } |
| 569 | 584 | |
| 570 | 585 | |
| 571 | 586 | |
| 572 | 587 | /* |
| 573 | | -** TH Syntax: |
| 588 | +** TH command: |
| 574 | 589 | ** |
| 575 | 590 | ** argv at Index |
| 576 | 591 | ** |
| 577 | 592 | ** Returns the raw argument at the given index, throwing if |
| 578 | 593 | ** out of bounds. |
| | @@ -607,11 +622,11 @@ |
| 607 | 622 | return TH_OK; |
| 608 | 623 | } |
| 609 | 624 | |
| 610 | 625 | |
| 611 | 626 | /* |
| 612 | | -** TH Syntax: |
| 627 | +** TH command: |
| 613 | 628 | ** |
| 614 | 629 | ** argv getstr longName ??shortName? ?defaultValue?? |
| 615 | 630 | ** |
| 616 | 631 | ** Functions more or less like Fossil's find_option(). |
| 617 | 632 | ** If the given argument is found then its value is returned, |
| | @@ -678,15 +693,15 @@ |
| 678 | 693 | Th_SetResult( interp, zVal, zVal ? strlen(zVal) : 0 ); |
| 679 | 694 | return TH_OK; |
| 680 | 695 | } |
| 681 | 696 | |
| 682 | 697 | /* |
| 683 | | -** TH Syntax: |
| 698 | +** TH command: |
| 684 | 699 | ** |
| 685 | 700 | ** argv getbool longName ??shortName? ?defaultValue?? |
| 686 | 701 | ** |
| 687 | | -** Works just like argv_getstr but treats any empty value or one |
| 702 | +** Works just like argv getstr but treats any empty value or one |
| 688 | 703 | ** starting with the digit '0' as a boolean false. |
| 689 | 704 | ** |
| 690 | 705 | ** Returns the result as an integer 0 (false) or 1 (true). |
| 691 | 706 | */ |
| 692 | 707 | static int argvFindOptionBoolCmd( |
| | @@ -751,13 +766,16 @@ |
| 751 | 766 | Th_SetResultInt( interp, zVal ? 1 : 0 ); |
| 752 | 767 | return TH_OK; |
| 753 | 768 | } |
| 754 | 769 | |
| 755 | 770 | /* |
| 756 | | -** TH Syntax: |
| 771 | +** TH command: |
| 757 | 772 | ** |
| 758 | 773 | ** argv getint longName ?shortName? ?defaultValue? |
| 774 | +** |
| 775 | +** Works like argv getstr but returns the value as an integer |
| 776 | +** (throwing an error if the argument cannot be converted). |
| 759 | 777 | */ |
| 760 | 778 | static int argvFindOptionIntCmd( |
| 761 | 779 | Th_Interp *interp, |
| 762 | 780 | void *p, |
| 763 | 781 | int argc, |
| | @@ -811,10 +829,17 @@ |
| 811 | 829 | Th_ToInt(interp, zVal, strlen(zVal), &val); |
| 812 | 830 | Th_SetResultInt( interp, val ); |
| 813 | 831 | return TH_OK; |
| 814 | 832 | } |
| 815 | 833 | |
| 834 | +/* |
| 835 | +** TH command: |
| 836 | +** |
| 837 | +** argv subcommand |
| 838 | +** |
| 839 | +** This is the top-level dispatching function. |
| 840 | +*/ |
| 816 | 841 | static int argvTopLevelCmd( |
| 817 | 842 | Th_Interp *interp, |
| 818 | 843 | void *ctx, |
| 819 | 844 | int argc, |
| 820 | 845 | const char **argv, |
| | @@ -834,63 +859,58 @@ |
| 834 | 859 | int th_register_argv(Th_Interp *interp){ |
| 835 | 860 | static Th_Command_Reg aCommand[] = { |
| 836 | 861 | {"argv", argvTopLevelCmd, 0 }, |
| 837 | 862 | {0, 0, 0} |
| 838 | 863 | }; |
| 839 | | - Th_register_commands( interp, aCommand ); |
| 864 | + Th_RegisterCommands( interp, aCommand ); |
| 840 | 865 | } |
| 841 | 866 | |
| 842 | 867 | #endif |
| 843 | 868 | /* end TH_ENABLE_ARGV */ |
| 844 | 869 | |
| 845 | | -#ifdef TH_ENABLE_SQLITE |
| 870 | +#ifdef TH_ENABLE_QUERY |
| 846 | 871 | |
| 847 | 872 | /* |
| 848 | 873 | ** Adds the given prepared statement to the interpreter. Returns the |
| 849 | 874 | ** statement's opaque identifier (a positive value). Ownerships of |
| 850 | 875 | ** pStmt is transfered to interp and it must be cleaned up by the |
| 851 | | -** client by calling Th_FinalizeStmt(), passing it the value returned |
| 876 | +** client by calling Th_query_FinalizeStmt(), passing it the value returned |
| 852 | 877 | ** by this function. |
| 853 | 878 | ** |
| 854 | 879 | ** If interp is destroyed before all statements are finalized, |
| 855 | 880 | ** it will finalize them but may emit a warning message. |
| 856 | 881 | */ |
| 857 | | -static int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt); |
| 858 | | - |
| 859 | | -/* |
| 860 | | -** Expects stmtId to be a statement identifier returned by |
| 861 | | -** Th_AddStmt(). On success, finalizes the statement and returns 0. |
| 862 | | -** On error (statement not found) non-0 is returned. After this |
| 863 | | -** call, some subsequent call to Th_AddStmt() may return the |
| 864 | | -** same statement ID. |
| 865 | | -*/ |
| 866 | | -static int Th_FinalizeStmt(Th_Interp *interp, int stmtId); |
| 867 | | -static int Th_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt *); |
| 868 | | - |
| 869 | | -/* |
| 870 | | -** Fetches the statement with the given ID, as returned by |
| 871 | | -** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer |
| 872 | | -** refers) to a statement added via Th_AddStmt(). |
| 873 | | -*/ |
| 874 | | -static sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId); |
| 875 | | - |
| 876 | | - |
| 877 | | -struct Th_Sqlite { |
| 878 | | - sqlite3_stmt ** aStmt; |
| 879 | | - int nStmt; |
| 880 | | - int colCmdIndex; |
| 882 | +static int Th_query_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt); |
| 883 | + |
| 884 | + |
| 885 | +/* |
| 886 | +** Internal state for the "query" API. |
| 887 | +*/ |
| 888 | +struct Th_Query { |
| 889 | + sqlite3_stmt ** aStmt; /* Array of statement handles. */ |
| 890 | + int nStmt; /* number of entries in aStmt. */ |
| 891 | + int colCmdIndex; /* column index argument. Set by some top-level dispatchers |
| 892 | + for their subcommands. |
| 893 | + */ |
| 881 | 894 | }; |
| 882 | | -#define Th_Sqlite_KEY "Th_Sqlite" |
| 883 | | -typedef struct Th_Sqlite Th_Sqlite; |
| 895 | +/* |
| 896 | +** Internal key for use with Th_Data_Add(). |
| 897 | +*/ |
| 898 | +#define Th_Query_KEY "Th_Query" |
| 899 | +typedef struct Th_Query Th_Query; |
| 884 | 900 | |
| 885 | | -static Th_Sqlite * Th_sqlite_manager( Th_Interp * interp ){ |
| 886 | | - void * p = Th_Data_Get( interp, Th_Sqlite_KEY ); |
| 887 | | - return p ? (Th_Sqlite*)p : NULL; |
| 901 | +/* |
| 902 | +** Returns the Th_Query object associated with the given interpreter, |
| 903 | +** or 0 if there is not one. |
| 904 | +*/ |
| 905 | +static Th_Query * Th_query_manager( Th_Interp * interp ){ |
| 906 | + void * p = Th_GetData( interp, Th_Query_KEY ); |
| 907 | + return p ? (Th_Query*)p : NULL; |
| 888 | 908 | } |
| 889 | 909 | |
| 890 | | -static int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){ |
| 891 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 910 | +static int Th_query_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){ |
| 911 | + Th_Query * sq = Th_query_manager(interp); |
| 892 | 912 | int i, x; |
| 893 | 913 | sqlite3_stmt * s; |
| 894 | 914 | sqlite3_stmt ** list = sq->aStmt; |
| 895 | 915 | for( i = 0; i < sq->nStmt; ++i ){ |
| 896 | 916 | s = list[i]; |
| | @@ -910,12 +930,19 @@ |
| 910 | 930 | sq->aStmt = list; |
| 911 | 931 | return x + 1; |
| 912 | 932 | } |
| 913 | 933 | |
| 914 | 934 | |
| 915 | | -static int Th_FinalizeStmt(Th_Interp *interp, int stmtId){ |
| 916 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 935 | +/* |
| 936 | +** Expects stmtId to be a statement identifier returned by |
| 937 | +** Th_query_AddStmt(). On success, finalizes the statement and returns 0. |
| 938 | +** On error (statement not found) non-0 is returned. After this |
| 939 | +** call, some subsequent call to Th_query_AddStmt() may return the |
| 940 | +** same statement ID. |
| 941 | +*/ |
| 942 | +static int Th_query_FinalizeStmt(Th_Interp *interp, int stmtId){ |
| 943 | + Th_Query * sq = Th_query_manager(interp); |
| 917 | 944 | sqlite3_stmt * st; |
| 918 | 945 | int rc = 0; |
| 919 | 946 | assert( stmtId>0 && stmtId<=sq->nStmt ); |
| 920 | 947 | st = sq->aStmt[stmtId-1]; |
| 921 | 948 | if(NULL != st){ |
| | @@ -925,12 +952,16 @@ |
| 925 | 952 | }else{ |
| 926 | 953 | return 1; |
| 927 | 954 | } |
| 928 | 955 | } |
| 929 | 956 | |
| 930 | | -static int Th_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt * pSt){ |
| 931 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 957 | +/* |
| 958 | +** Works like Th_query_FinalizeStmt() but takes a statement pointer, which |
| 959 | +** must have been Th_query_AddStmt()'d to the given interpreter. |
| 960 | +*/ |
| 961 | +static int Th_query_FinalizeStmt2(Th_Interp *interp, sqlite3_stmt * pSt){ |
| 962 | + Th_Query * sq = Th_query_manager(interp); |
| 932 | 963 | int i = 0; |
| 933 | 964 | sqlite3_stmt * st = NULL; |
| 934 | 965 | int rc = 0; |
| 935 | 966 | for( ; i < sq->nStmt; ++i ){ |
| 936 | 967 | st = sq->aStmt[i]; |
| | @@ -945,42 +976,50 @@ |
| 945 | 976 | return 1; |
| 946 | 977 | } |
| 947 | 978 | } |
| 948 | 979 | |
| 949 | 980 | |
| 950 | | -static sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){ |
| 951 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 952 | | - return ((stmtId<1) || (stmtId > sq->nStmt)) |
| 981 | +/* |
| 982 | +** Fetches the statement with the given ID, as returned by |
| 983 | +** Th_query_AddStmt(). Returns NULL if stmtId does not refer (or no longer |
| 984 | +** refers) to a statement added via Th_query_AddStmt(). |
| 985 | +*/ |
| 986 | +static sqlite3_stmt * Th_query_GetStmt(Th_Interp *interp, int stmtId){ |
| 987 | + Th_Query * sq = Th_query_manager(interp); |
| 988 | + return (!sq || (stmtId<1) || (stmtId > sq->nStmt)) |
| 953 | 989 | ? NULL |
| 954 | 990 | : sq->aStmt[stmtId-1]; |
| 955 | 991 | } |
| 956 | 992 | |
| 957 | 993 | |
| 994 | +/* |
| 995 | +** Th_GCEntry finalizer which requires that p be a (Th_Query*). |
| 996 | +*/ |
| 958 | 997 | static void finalizerSqlite( Th_Interp * interp, void * p ){ |
| 959 | | - Th_Sqlite * sq = (Th_Sqlite *)p; |
| 998 | + Th_Query * sq = (Th_Query *)p; |
| 960 | 999 | int i; |
| 961 | 1000 | sqlite3_stmt * st = NULL; |
| 962 | 1001 | if(!sq) { |
| 963 | | - fossil_warning("Got a finalizer call for a NULL Th_Sqlite."); |
| 1002 | + fossil_warning("Got a finalizer call for a NULL Th_Query."); |
| 964 | 1003 | return; |
| 965 | 1004 | } |
| 966 | 1005 | for( i = 0; i < sq->nStmt; ++i ){ |
| 967 | 1006 | st = sq->aStmt[i]; |
| 968 | 1007 | if(NULL != st){ |
| 969 | 1008 | fossil_warning("Auto-finalizing unfinalized " |
| 970 | 1009 | "statement id #%d: %s", |
| 971 | 1010 | i+1, sqlite3_sql(st)); |
| 972 | | - Th_FinalizeStmt( interp, i+1 ); |
| 1011 | + Th_query_FinalizeStmt( interp, i+1 ); |
| 973 | 1012 | } |
| 974 | 1013 | } |
| 975 | 1014 | Th_Free(interp, sq->aStmt); |
| 976 | 1015 | Th_Free(interp, sq); |
| 977 | 1016 | } |
| 978 | 1017 | |
| 979 | 1018 | |
| 980 | 1019 | /* |
| 981 | | -** TH Syntax: |
| 1020 | +** TH command: |
| 982 | 1021 | ** |
| 983 | 1022 | ** query prepare SQL |
| 984 | 1023 | ** |
| 985 | 1024 | ** Returns an opaque statement identifier. |
| 986 | 1025 | */ |
| | @@ -1016,11 +1055,11 @@ |
| 1016 | 1055 | assert(NULL != errMsg); |
| 1017 | 1056 | assert(NULL == pStmt); |
| 1018 | 1057 | Th_ErrorMessage(interp, "error preparing SQL:", errMsg, -1); |
| 1019 | 1058 | return TH_ERROR; |
| 1020 | 1059 | } |
| 1021 | | - rc = Th_AddStmt( interp, pStmt ); |
| 1060 | + rc = Th_query_AddStmt( interp, pStmt ); |
| 1022 | 1061 | assert( rc >= 0 && "AddStmt failed."); |
| 1023 | 1062 | Th_SetResultInt( interp, rc ); |
| 1024 | 1063 | return TH_OK; |
| 1025 | 1064 | } |
| 1026 | 1065 | |
| | @@ -1039,21 +1078,21 @@ |
| 1039 | 1078 | sqlite3_stmt * pStmt = NULL; |
| 1040 | 1079 | if( 0 == Th_ToInt( interp, arg, argLen, &rc ) ){ |
| 1041 | 1080 | if(stmtId){ |
| 1042 | 1081 | *stmtId = rc; |
| 1043 | 1082 | } |
| 1044 | | - pStmt = Th_GetStmt( interp, rc ); |
| 1083 | + pStmt = Th_query_GetStmt( interp, rc ); |
| 1045 | 1084 | if(NULL==pStmt){ |
| 1046 | 1085 | Th_ErrorMessage(interp, "no such statement handle:", arg, -1); |
| 1047 | 1086 | } |
| 1048 | 1087 | } |
| 1049 | 1088 | return pStmt; |
| 1050 | 1089 | |
| 1051 | 1090 | } |
| 1052 | 1091 | |
| 1053 | 1092 | /* |
| 1054 | | -** TH Syntax: |
| 1093 | +** TH command: |
| 1055 | 1094 | ** |
| 1056 | 1095 | ** query finalize stmtId |
| 1057 | 1096 | ** query stmtId finalize |
| 1058 | 1097 | ** |
| 1059 | 1098 | ** sqlite3_finalize()s the given statement. |
| | @@ -1083,11 +1122,11 @@ |
| 1083 | 1122 | Th_ErrorMessage(interp, "Not a valid statement handle argument.", NULL, 0); |
| 1084 | 1123 | return TH_ERROR; |
| 1085 | 1124 | } |
| 1086 | 1125 | } |
| 1087 | 1126 | assert( NULL != pStmt ); |
| 1088 | | - rc = Th_FinalizeStmt2( interp, pStmt ); |
| 1127 | + rc = Th_query_FinalizeStmt2( interp, pStmt ); |
| 1089 | 1128 | Th_SetResultInt( interp, rc ); |
| 1090 | 1129 | return TH_OK; |
| 1091 | 1130 | } |
| 1092 | 1131 | |
| 1093 | 1132 | /* |
| | @@ -1148,11 +1187,11 @@ |
| 1148 | 1187 | return 0; |
| 1149 | 1188 | } |
| 1150 | 1189 | } |
| 1151 | 1190 | |
| 1152 | 1191 | /* |
| 1153 | | -** TH Syntax: |
| 1192 | +** TH command: |
| 1154 | 1193 | ** |
| 1155 | 1194 | ** query step stmtId |
| 1156 | 1195 | ** query stmtId step |
| 1157 | 1196 | ** |
| 1158 | 1197 | ** Steps the given statement handle. Returns 0 at the end of the set, |
| | @@ -1190,10 +1229,18 @@ |
| 1190 | 1229 | } |
| 1191 | 1230 | Th_SetResultInt( interp, rc ); |
| 1192 | 1231 | return TH_OK; |
| 1193 | 1232 | } |
| 1194 | 1233 | |
| 1234 | +/* |
| 1235 | +** TH command: |
| 1236 | +** |
| 1237 | +** query StmtId reset |
| 1238 | +** query reset StmtId |
| 1239 | +** |
| 1240 | +** Equivalent to sqlite3_reset(). |
| 1241 | +*/ |
| 1195 | 1242 | static int queryResetCmd( |
| 1196 | 1243 | Th_Interp *interp, |
| 1197 | 1244 | void *p, |
| 1198 | 1245 | int argc, |
| 1199 | 1246 | const char **argv, |
| | @@ -1209,11 +1256,11 @@ |
| 1209 | 1256 | } |
| 1210 | 1257 | } |
| 1211 | 1258 | |
| 1212 | 1259 | |
| 1213 | 1260 | /* |
| 1214 | | -** TH Syntax: |
| 1261 | +** TH command: |
| 1215 | 1262 | ** |
| 1216 | 1263 | ** query col string stmtId Index |
| 1217 | 1264 | ** query stmtId col string Index |
| 1218 | 1265 | ** query stmtId col Index string |
| 1219 | 1266 | ** |
| | @@ -1224,11 +1271,11 @@ |
| 1224 | 1271 | void *p, |
| 1225 | 1272 | int argc, |
| 1226 | 1273 | const char **argv, |
| 1227 | 1274 | int *argl |
| 1228 | 1275 | ){ |
| 1229 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1276 | + Th_Query * sq = Th_query_manager(interp); |
| 1230 | 1277 | int index = sq->colCmdIndex; |
| 1231 | 1278 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1232 | 1279 | int requireArgc = pStmt ? 2 : 3; |
| 1233 | 1280 | char const * val; |
| 1234 | 1281 | int valLen; |
| | @@ -1251,11 +1298,11 @@ |
| 1251 | 1298 | Th_SetResult( interp, val, valLen ); |
| 1252 | 1299 | return TH_OK; |
| 1253 | 1300 | } |
| 1254 | 1301 | |
| 1255 | 1302 | /* |
| 1256 | | -** TH Syntax: |
| 1303 | +** TH command: |
| 1257 | 1304 | ** |
| 1258 | 1305 | ** query col int stmtId Index |
| 1259 | 1306 | ** query stmtId col int Index |
| 1260 | 1307 | ** query stmtId col Index int |
| 1261 | 1308 | ** |
| | @@ -1266,11 +1313,11 @@ |
| 1266 | 1313 | void *p, |
| 1267 | 1314 | int argc, |
| 1268 | 1315 | const char **argv, |
| 1269 | 1316 | int *argl |
| 1270 | 1317 | ){ |
| 1271 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1318 | + Th_Query * sq = Th_query_manager(interp); |
| 1272 | 1319 | int index = sq->colCmdIndex; |
| 1273 | 1320 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1274 | 1321 | int requireArgc = pStmt ? 2 : 3; |
| 1275 | 1322 | int rc = 0; |
| 1276 | 1323 | if( index >= 0 ) --requireArgc; |
| | @@ -1290,11 +1337,11 @@ |
| 1290 | 1337 | Th_SetResultInt( interp, sqlite3_column_int( pStmt, index ) ); |
| 1291 | 1338 | return TH_OK; |
| 1292 | 1339 | } |
| 1293 | 1340 | |
| 1294 | 1341 | /* |
| 1295 | | -** TH Syntax: |
| 1342 | +** TH command: |
| 1296 | 1343 | ** |
| 1297 | 1344 | ** query col double stmtId Index |
| 1298 | 1345 | ** query stmtId col double Index |
| 1299 | 1346 | ** query stmtId col Index double |
| 1300 | 1347 | ** |
| | @@ -1305,11 +1352,11 @@ |
| 1305 | 1352 | void *p, |
| 1306 | 1353 | int argc, |
| 1307 | 1354 | const char **argv, |
| 1308 | 1355 | int *argl |
| 1309 | 1356 | ){ |
| 1310 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1357 | + Th_Query * sq = Th_query_manager(interp); |
| 1311 | 1358 | int index = sq->colCmdIndex; |
| 1312 | 1359 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1313 | 1360 | int requireArgc = pStmt ? 2 : 3; |
| 1314 | 1361 | double rc = 0; |
| 1315 | 1362 | if( index >= 0 ) --requireArgc; |
| | @@ -1329,14 +1376,14 @@ |
| 1329 | 1376 | Th_SetResultDouble( interp, sqlite3_column_double( pStmt, index ) ); |
| 1330 | 1377 | return TH_OK; |
| 1331 | 1378 | } |
| 1332 | 1379 | |
| 1333 | 1380 | /* |
| 1334 | | -** TH Syntax: |
| 1381 | +** TH command: |
| 1335 | 1382 | ** |
| 1336 | 1383 | ** query col isnull stmtId Index |
| 1337 | | -** query stmtId col is_null Index |
| 1384 | +** query stmtId col isnull Index |
| 1338 | 1385 | ** query stmtId col Index isnull |
| 1339 | 1386 | ** |
| 1340 | 1387 | ** Returns non-0 if the given 0-based result column index contains |
| 1341 | 1388 | ** an SQL NULL value, else returns 0. |
| 1342 | 1389 | */ |
| | @@ -1345,11 +1392,11 @@ |
| 1345 | 1392 | void *p, |
| 1346 | 1393 | int argc, |
| 1347 | 1394 | const char **argv, |
| 1348 | 1395 | int *argl |
| 1349 | 1396 | ){ |
| 1350 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1397 | + Th_Query * sq = Th_query_manager(interp); |
| 1351 | 1398 | int index = sq->colCmdIndex; |
| 1352 | 1399 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1353 | 1400 | int requireArgc = pStmt ? 2 : 3; |
| 1354 | 1401 | if( index >= 0 ) --requireArgc; |
| 1355 | 1402 | double rc = 0; |
| | @@ -1371,11 +1418,11 @@ |
| 1371 | 1418 | ? 1 : 0); |
| 1372 | 1419 | return TH_OK; |
| 1373 | 1420 | } |
| 1374 | 1421 | |
| 1375 | 1422 | /* |
| 1376 | | -** TH Syntax: |
| 1423 | +** TH command: |
| 1377 | 1424 | ** |
| 1378 | 1425 | ** query col type stmtId Index |
| 1379 | 1426 | ** query stmtId col type Index |
| 1380 | 1427 | ** query stmtId col Index type |
| 1381 | 1428 | ** |
| | @@ -1388,11 +1435,11 @@ |
| 1388 | 1435 | void *p, |
| 1389 | 1436 | int argc, |
| 1390 | 1437 | const char **argv, |
| 1391 | 1438 | int *argl |
| 1392 | 1439 | ){ |
| 1393 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1440 | + Th_Query * sq = Th_query_manager(interp); |
| 1394 | 1441 | int index = sq->colCmdIndex; |
| 1395 | 1442 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1396 | 1443 | int requireArgc = pStmt ? 2 : 3; |
| 1397 | 1444 | if( index >= 0 ) --requireArgc; |
| 1398 | 1445 | double rc = 0; |
| | @@ -1412,11 +1459,11 @@ |
| 1412 | 1459 | Th_SetResultInt( interp, sqlite3_column_type( pStmt, index ) ); |
| 1413 | 1460 | return TH_OK; |
| 1414 | 1461 | } |
| 1415 | 1462 | |
| 1416 | 1463 | /* |
| 1417 | | -** TH Syntax: |
| 1464 | +** TH command: |
| 1418 | 1465 | ** |
| 1419 | 1466 | ** query col count stmtId |
| 1420 | 1467 | ** query stmtId col count |
| 1421 | 1468 | ** |
| 1422 | 1469 | ** Returns the number of result columns in the query. |
| | @@ -1446,11 +1493,11 @@ |
| 1446 | 1493 | Th_SetResultInt( interp, rc ); |
| 1447 | 1494 | return TH_OK; |
| 1448 | 1495 | } |
| 1449 | 1496 | |
| 1450 | 1497 | /* |
| 1451 | | -** TH Syntax: |
| 1498 | +** TH command: |
| 1452 | 1499 | ** |
| 1453 | 1500 | ** query col name stmtId Index |
| 1454 | 1501 | ** query stmtId col name Index |
| 1455 | 1502 | ** query stmtId col Index name |
| 1456 | 1503 | ** |
| | @@ -1461,11 +1508,11 @@ |
| 1461 | 1508 | void *p, |
| 1462 | 1509 | int argc, |
| 1463 | 1510 | const char **argv, |
| 1464 | 1511 | int *argl |
| 1465 | 1512 | ){ |
| 1466 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1513 | + Th_Query * sq = Th_query_manager(interp); |
| 1467 | 1514 | int index = sq->colCmdIndex; |
| 1468 | 1515 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1469 | 1516 | int requireArgc = pStmt ? 2 : 3; |
| 1470 | 1517 | char const * val; |
| 1471 | 1518 | int rc = 0; |
| | @@ -1493,11 +1540,11 @@ |
| 1493 | 1540 | return TH_OK; |
| 1494 | 1541 | } |
| 1495 | 1542 | } |
| 1496 | 1543 | |
| 1497 | 1544 | /* |
| 1498 | | -** TH Syntax: |
| 1545 | +** TH command: |
| 1499 | 1546 | ** |
| 1500 | 1547 | ** query col time stmtId Index format |
| 1501 | 1548 | ** query stmtId col name Index format |
| 1502 | 1549 | ** query stmtId col Index name format |
| 1503 | 1550 | ** |
| | @@ -1508,11 +1555,11 @@ |
| 1508 | 1555 | void *ctx, |
| 1509 | 1556 | int argc, |
| 1510 | 1557 | const char **argv, |
| 1511 | 1558 | int *argl |
| 1512 | 1559 | ){ |
| 1513 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1560 | + Th_Query * sq = Th_query_manager(interp); |
| 1514 | 1561 | int index = sq->colCmdIndex; |
| 1515 | 1562 | sqlite3_stmt * pStmt = (sqlite3_stmt*)ctx; |
| 1516 | 1563 | int minArgs = pStmt ? 3 : 4; |
| 1517 | 1564 | int argPos; |
| 1518 | 1565 | char const * val; |
| | @@ -1555,10 +1602,17 @@ |
| 1555 | 1602 | Th_SetResult( interp, fval, fval ? strlen(fval) : 0 ); |
| 1556 | 1603 | fossil_free(fval); |
| 1557 | 1604 | return 0; |
| 1558 | 1605 | } |
| 1559 | 1606 | |
| 1607 | +/* |
| 1608 | +** TH command: |
| 1609 | +** |
| 1610 | +** query strftime TimeVal ?Modifiers...? |
| 1611 | +** |
| 1612 | +** Acts as a proxy to sqlite3's strftime() SQL function. |
| 1613 | +*/ |
| 1560 | 1614 | static int queryStrftimeCmd( |
| 1561 | 1615 | Th_Interp *interp, |
| 1562 | 1616 | void *ctx, |
| 1563 | 1617 | int argc, |
| 1564 | 1618 | const char **argv, |
| | @@ -1592,11 +1646,11 @@ |
| 1592 | 1646 | return 0; |
| 1593 | 1647 | } |
| 1594 | 1648 | |
| 1595 | 1649 | |
| 1596 | 1650 | /* |
| 1597 | | -** TH Syntax: |
| 1651 | +** TH command: |
| 1598 | 1652 | ** |
| 1599 | 1653 | ** query bind null stmtId Index |
| 1600 | 1654 | ** query stmtId bind null Index |
| 1601 | 1655 | ** |
| 1602 | 1656 | ** Binds a value to the given 1-based parameter index. |
| | @@ -1606,11 +1660,11 @@ |
| 1606 | 1660 | void *p, |
| 1607 | 1661 | int argc, |
| 1608 | 1662 | const char **argv, |
| 1609 | 1663 | int *argl |
| 1610 | 1664 | ){ |
| 1611 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1665 | + Th_Query * sq = Th_query_manager(interp); |
| 1612 | 1666 | int index = sq->colCmdIndex; |
| 1613 | 1667 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1614 | 1668 | int requireArgc = pStmt ? 2 : 3; |
| 1615 | 1669 | if( index > 0 ) --requireArgc; |
| 1616 | 1670 | int rc; |
| | @@ -1635,11 +1689,11 @@ |
| 1635 | 1689 | return TH_OK; |
| 1636 | 1690 | } |
| 1637 | 1691 | |
| 1638 | 1692 | |
| 1639 | 1693 | /* |
| 1640 | | -** TH Syntax: |
| 1694 | +** TH command: |
| 1641 | 1695 | ** |
| 1642 | 1696 | ** query bind string stmtId Index Value |
| 1643 | 1697 | ** query stmtId bind string Index Value |
| 1644 | 1698 | ** |
| 1645 | 1699 | ** Binds a value to the given 1-based parameter index. |
| | @@ -1649,11 +1703,11 @@ |
| 1649 | 1703 | void *p, |
| 1650 | 1704 | int argc, |
| 1651 | 1705 | const char **argv, |
| 1652 | 1706 | int *argl |
| 1653 | 1707 | ){ |
| 1654 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1708 | + Th_Query * sq = Th_query_manager(interp); |
| 1655 | 1709 | int index = sq->colCmdIndex; |
| 1656 | 1710 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1657 | 1711 | int requireArgc = pStmt ? 3 : 4; |
| 1658 | 1712 | int rc; |
| 1659 | 1713 | int argPos; |
| | @@ -1682,11 +1736,11 @@ |
| 1682 | 1736 | Th_SetResultInt( interp, 0 ); |
| 1683 | 1737 | return TH_OK; |
| 1684 | 1738 | } |
| 1685 | 1739 | |
| 1686 | 1740 | /* |
| 1687 | | -** TH Syntax: |
| 1741 | +** TH command: |
| 1688 | 1742 | ** |
| 1689 | 1743 | ** query bind int stmtId Index Value |
| 1690 | 1744 | ** query stmtId bind int Index Value |
| 1691 | 1745 | ** |
| 1692 | 1746 | ** Binds a value to the given 1-based parameter index. |
| | @@ -1696,11 +1750,11 @@ |
| 1696 | 1750 | void *p, |
| 1697 | 1751 | int argc, |
| 1698 | 1752 | const char **argv, |
| 1699 | 1753 | int *argl |
| 1700 | 1754 | ){ |
| 1701 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1755 | + Th_Query * sq = Th_query_manager(interp); |
| 1702 | 1756 | int index = sq->colCmdIndex; |
| 1703 | 1757 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1704 | 1758 | int requireArgc = pStmt ? 3 : 4; |
| 1705 | 1759 | int rc; |
| 1706 | 1760 | int argPos; |
| | @@ -1734,11 +1788,11 @@ |
| 1734 | 1788 | Th_SetResultInt( interp, 0 ); |
| 1735 | 1789 | return TH_OK; |
| 1736 | 1790 | } |
| 1737 | 1791 | |
| 1738 | 1792 | /* |
| 1739 | | -** TH Syntax: |
| 1793 | +** TH command: |
| 1740 | 1794 | ** |
| 1741 | 1795 | ** query bind double stmtId Index Value |
| 1742 | 1796 | ** query stmtId bind double Index Value |
| 1743 | 1797 | ** |
| 1744 | 1798 | ** Binds a value to the given 1-based parameter index. |
| | @@ -1748,11 +1802,11 @@ |
| 1748 | 1802 | void *p, |
| 1749 | 1803 | int argc, |
| 1750 | 1804 | const char **argv, |
| 1751 | 1805 | int *argl |
| 1752 | 1806 | ){ |
| 1753 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1807 | + Th_Query * sq = Th_query_manager(interp); |
| 1754 | 1808 | int index = sq->colCmdIndex; |
| 1755 | 1809 | sqlite3_stmt * pStmt = (sqlite3_stmt*)p; |
| 1756 | 1810 | int requireArgc = pStmt ? 3 : 4; |
| 1757 | 1811 | int rc; |
| 1758 | 1812 | int argPos; |
| | @@ -1785,10 +1839,18 @@ |
| 1785 | 1839 | } |
| 1786 | 1840 | Th_SetResultInt( interp, 0 ); |
| 1787 | 1841 | return TH_OK; |
| 1788 | 1842 | } |
| 1789 | 1843 | |
| 1844 | +/* |
| 1845 | +** TH command: |
| 1846 | +** |
| 1847 | +** bind subcommand StmtId... |
| 1848 | +** bind StmtId subcommand... |
| 1849 | +** |
| 1850 | +** This is the top-level dispatcher for the "bind" family of commands. |
| 1851 | +*/ |
| 1790 | 1852 | static int queryBindTopLevelCmd( |
| 1791 | 1853 | Th_Interp *interp, |
| 1792 | 1854 | void *ctx, |
| 1793 | 1855 | int argc, |
| 1794 | 1856 | const char **argv, |
| | @@ -1800,15 +1862,15 @@ |
| 1800 | 1862 | {"double", queryBindDoubleCmd}, |
| 1801 | 1863 | {"null", queryBindNullCmd}, |
| 1802 | 1864 | {"string", queryBindStringCmd}, |
| 1803 | 1865 | {0, 0} |
| 1804 | 1866 | }; |
| 1805 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1867 | + Th_Query * sq = Th_query_manager(interp); |
| 1806 | 1868 | assert(NULL != sq); |
| 1807 | 1869 | if( 1 == argc ){ |
| 1808 | 1870 | Th_WrongNumArgs2( interp, argv[0], argl[0], |
| 1809 | | - "subcommand"); |
| 1871 | + "subcommand: int|double|null|string"); |
| 1810 | 1872 | return TH_ERROR; |
| 1811 | 1873 | }else if( 0 == Th_TryInt(interp,argv[1], argl[1], &colIndex) ){ |
| 1812 | 1874 | if(colIndex <0){ |
| 1813 | 1875 | Th_ErrorMessage( interp, "Invalid column index.", NULL, 0); |
| 1814 | 1876 | return TH_ERROR; |
| | @@ -1820,10 +1882,18 @@ |
| 1820 | 1882 | sq->colCmdIndex = colIndex; |
| 1821 | 1883 | Th_CallSubCommand2( interp, ctx, argc, argv, argl, aSub ); |
| 1822 | 1884 | |
| 1823 | 1885 | } |
| 1824 | 1886 | |
| 1887 | +/* |
| 1888 | +** TH command: |
| 1889 | +** |
| 1890 | +** query col subcommand ... |
| 1891 | +** query StmtId col subcommand ... |
| 1892 | +** |
| 1893 | +** This is the top-level dispatcher for the col subcommands. |
| 1894 | +*/ |
| 1825 | 1895 | static int queryColTopLevelCmd( |
| 1826 | 1896 | Th_Interp *interp, |
| 1827 | 1897 | void *ctx, |
| 1828 | 1898 | int argc, |
| 1829 | 1899 | const char **argv, |
| | @@ -1841,10 +1911,16 @@ |
| 1841 | 1911 | {"time", queryColTimeCmd}, |
| 1842 | 1912 | {"type", queryColTypeCmd}, |
| 1843 | 1913 | {0, 0} |
| 1844 | 1914 | }; |
| 1845 | 1915 | static Th_SubCommand aSubWithIndex[] = { |
| 1916 | + /* |
| 1917 | + This subset is coded to accept the column index |
| 1918 | + either before the subcommand name or after it. |
| 1919 | + If called like (bind StmtId subcommand) then |
| 1920 | + only these commands will be checked. |
| 1921 | + */ |
| 1846 | 1922 | {"is_null", queryColIsNullCmd}, |
| 1847 | 1923 | {"isnull", queryColIsNullCmd}, |
| 1848 | 1924 | {"name", queryColNameCmd}, |
| 1849 | 1925 | {"double", queryColDoubleCmd}, |
| 1850 | 1926 | {"int", queryColIntCmd}, |
| | @@ -1851,15 +1927,17 @@ |
| 1851 | 1927 | {"string", queryColStringCmd}, |
| 1852 | 1928 | {"time", queryColTimeCmd}, |
| 1853 | 1929 | {"type", queryColTypeCmd}, |
| 1854 | 1930 | {0, 0} |
| 1855 | 1931 | }; |
| 1856 | | - Th_Sqlite * sq = Th_sqlite_manager(interp); |
| 1932 | + Th_Query * sq = Th_query_manager(interp); |
| 1857 | 1933 | assert(NULL != sq); |
| 1858 | 1934 | if( 1 == argc ){ |
| 1859 | 1935 | Th_WrongNumArgs2( interp, argv[0], argl[0], |
| 1860 | | - "subcommand"); |
| 1936 | + "subcommand: " |
| 1937 | + "count|is_null|isnull|name|" |
| 1938 | + "double|int|string|time|type"); |
| 1861 | 1939 | return TH_ERROR; |
| 1862 | 1940 | }else if( 0 == Th_TryInt(interp,argv[1], argl[1], &colIndex) ){ |
| 1863 | 1941 | if(colIndex <0){ |
| 1864 | 1942 | Th_ErrorMessage( interp, "Invalid column index.", NULL, 0); |
| 1865 | 1943 | return TH_ERROR; |
| | @@ -1872,10 +1950,18 @@ |
| 1872 | 1950 | Th_CallSubCommand2( interp, ctx, argc, argv, argl, |
| 1873 | 1951 | (colIndex<0) ? aSub : aSubWithIndex ); |
| 1874 | 1952 | } |
| 1875 | 1953 | |
| 1876 | 1954 | |
| 1955 | +/* |
| 1956 | +** TH command: |
| 1957 | +** |
| 1958 | +** query subcommand ... |
| 1959 | +** query StmtId subcommand ... |
| 1960 | +** |
| 1961 | +** This is the top-level dispatcher for the query subcommand. |
| 1962 | +*/ |
| 1877 | 1963 | static int queryTopLevelCmd( |
| 1878 | 1964 | Th_Interp *interp, |
| 1879 | 1965 | void *ctx, |
| 1880 | 1966 | int argc, |
| 1881 | 1967 | const char **argv, |
| | @@ -1884,48 +1970,50 @@ |
| 1884 | 1970 | int stmtId = 0; |
| 1885 | 1971 | sqlite3_stmt * pStmt = NULL; |
| 1886 | 1972 | static Th_SubCommand aSubAll[] = { |
| 1887 | 1973 | {"bind", queryBindTopLevelCmd}, |
| 1888 | 1974 | {"col", queryColTopLevelCmd}, |
| 1975 | + {"finalize", queryFinalizeCmd}, |
| 1976 | + {"prepare", queryPrepareCmd}, |
| 1889 | 1977 | {"reset", queryResetCmd}, |
| 1890 | 1978 | {"step", queryStepCmd}, |
| 1891 | | - {"finalize", queryFinalizeCmd}, |
| 1892 | | - {"prepare", queryPrepareCmd}, |
| 1893 | 1979 | {"strftime", queryStrftimeCmd}, |
| 1894 | 1980 | {0, 0} |
| 1895 | 1981 | }; |
| 1896 | 1982 | static Th_SubCommand aSubWithStmt[] = { |
| 1897 | | - /* These entries are coded to deal with |
| 1898 | | - being supplied a statement via pStmt |
| 1899 | | - or via one of their args. |
| 1900 | | - */ |
| 1983 | + /* This subset is coded to deal with being supplied a statement |
| 1984 | + via pStmt or via one of their args. When called like (query |
| 1985 | + StmtId ...) only these subcommands will be checked.*/ |
| 1901 | 1986 | {"bind", queryBindTopLevelCmd}, |
| 1902 | 1987 | {"col", queryColTopLevelCmd}, |
| 1903 | 1988 | {"step", queryStepCmd}, |
| 1904 | 1989 | {"finalize", queryFinalizeCmd}, |
| 1905 | 1990 | {"reset", queryResetCmd}, |
| 1906 | 1991 | {0, 0} |
| 1907 | 1992 | }; |
| 1908 | 1993 | |
| 1909 | 1994 | |
| 1910 | | - assert( NULL != Th_sqlite_manager(interp) ); |
| 1995 | + assert( NULL != Th_query_manager(interp) ); |
| 1911 | 1996 | if( 1 == argc ){ |
| 1912 | 1997 | Th_WrongNumArgs2( interp, argv[0], argl[0], |
| 1913 | | - "subcommand"); |
| 1998 | + "subcommand: bind|col|finalize|prepare|reset|step|strftime"); |
| 1914 | 1999 | return TH_ERROR; |
| 1915 | 2000 | }else if( 0 == Th_TryInt(interp,argv[1], argl[1], &stmtId) ){ |
| 1916 | 2001 | ++argv; |
| 1917 | 2002 | ++argl; |
| 1918 | 2003 | --argc; |
| 1919 | | - pStmt = Th_GetStmt( interp, stmtId ); |
| 2004 | + pStmt = Th_query_GetStmt( interp, stmtId ); |
| 1920 | 2005 | } |
| 1921 | 2006 | |
| 1922 | 2007 | Th_CallSubCommand2( interp, pStmt, argc, argv, argl, |
| 1923 | 2008 | pStmt ? aSubWithStmt : aSubAll ); |
| 1924 | 2009 | } |
| 1925 | 2010 | |
| 1926 | | - |
| 2011 | +/* |
| 2012 | +** Registers the "query" API with the given interpreter. Returns TH_OK |
| 2013 | +** on success, TH_ERROR on error. |
| 2014 | +*/ |
| 1927 | 2015 | int th_register_query(Th_Interp *interp){ |
| 1928 | 2016 | enum { BufLen = 100 }; |
| 1929 | 2017 | char buf[BufLen]; |
| 1930 | 2018 | int i, l; |
| 1931 | 2019 | #define SET(K) l = snprintf(buf, BufLen, "%d", K); \ |
| | @@ -1943,50 +2031,44 @@ |
| 1943 | 2031 | int rc = TH_OK; |
| 1944 | 2032 | static Th_Command_Reg aCommand[] = { |
| 1945 | 2033 | {"query", queryTopLevelCmd, 0}, |
| 1946 | 2034 | {0, 0, 0} |
| 1947 | 2035 | }; |
| 1948 | | - rc = Th_register_commands( interp, aCommand ); |
| 2036 | + rc = Th_RegisterCommands( interp, aCommand ); |
| 1949 | 2037 | if(TH_OK==rc){ |
| 1950 | | - Th_Sqlite * sq = Th_Malloc(interp, sizeof(Th_Sqlite)); |
| 2038 | + Th_Query * sq = Th_Malloc(interp, sizeof(Th_Query)); |
| 1951 | 2039 | if(!sq){ |
| 1952 | 2040 | rc = TH_ERROR; |
| 1953 | 2041 | }else{ |
| 1954 | 2042 | assert( NULL == sq->aStmt ); |
| 1955 | 2043 | assert( 0 == sq->nStmt ); |
| 1956 | | - Th_Data_Set( interp, Th_Sqlite_KEY, sq, finalizerSqlite ); |
| 1957 | | - assert( sq == Th_sqlite_manager(interp) ); |
| 2044 | + Th_SetData( interp, Th_Query_KEY, sq, finalizerSqlite ); |
| 2045 | + assert( sq == Th_query_manager(interp) ); |
| 1958 | 2046 | } |
| 1959 | 2047 | } |
| 1960 | 2048 | return rc; |
| 1961 | 2049 | } |
| 1962 | 2050 | |
| 1963 | 2051 | #endif |
| 1964 | | -/* end TH_ENABLE_SQLITE */ |
| 1965 | | - |
| 1966 | | -int Th_register_commands( Th_Interp * interp, |
| 1967 | | - Th_Command_Reg const * aCommand ){ |
| 1968 | | - int i; |
| 1969 | | - int rc = TH_OK; |
| 1970 | | - for(i=0; (TH_OK==rc) && aCommand[i].zName; ++i){ |
| 1971 | | - if ( !aCommand[i].zName ) break; |
| 1972 | | - else if( !aCommand[i].xProc ) continue; |
| 1973 | | - else{ |
| 1974 | | - rc = Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, |
| 1975 | | - aCommand[i].pContext, 0); |
| 1976 | | - } |
| 1977 | | - } |
| 1978 | | - return rc; |
| 1979 | | -} |
| 2052 | +/* end TH_ENABLE_QUERY */ |
| 1980 | 2053 | |
| 1981 | 2054 | /* |
| 1982 | 2055 | ** Make sure the interpreter has been initialized. Initialize it if |
| 1983 | 2056 | ** it has not been already. |
| 1984 | 2057 | ** |
| 1985 | 2058 | ** The interpreter is stored in the g.interp global variable. |
| 1986 | 2059 | */ |
| 1987 | 2060 | void Th_FossilInit(void){ |
| 2061 | + /* The fossil-internal Th_Vtab instance. */ |
| 2062 | + static Th_Vtab vtab = { xRealloc, {/*out*/ |
| 2063 | + NULL /*write()*/, |
| 2064 | + NULL/*dispose()*/, |
| 2065 | + NULL/*pState*/, |
| 2066 | + 1/*enabled*/ |
| 2067 | + } |
| 2068 | + }; |
| 2069 | + |
| 1988 | 2070 | static PutsCmdData puts_Html = {0, 0, 0}; |
| 1989 | 2071 | static PutsCmdData puts_Normal = {1, 0, 0}; |
| 1990 | 2072 | static Th_Command_Reg aCommand[] = { |
| 1991 | 2073 | {"anycap", anycapCmd, 0}, |
| 1992 | 2074 | {"combobox", comboboxCmd, 0}, |
| | @@ -2007,13 +2089,13 @@ |
| 2007 | 2089 | {0, 0, 0} |
| 2008 | 2090 | }; |
| 2009 | 2091 | if( g.interp==0 ){ |
| 2010 | 2092 | int i; |
| 2011 | 2093 | if(g.cgiOutput){ |
| 2012 | | - vtab.out.write = Th_output_f_cgi_content; |
| 2094 | + vtab.out.write = Th_Output_f_cgi_content; |
| 2013 | 2095 | }else{ |
| 2014 | | - vtab.out = Th_Vtab_Output_FILE; |
| 2096 | + vtab.out = Th_Vtab_OutputMethods_FILE; |
| 2015 | 2097 | vtab.out.pState = stdout; |
| 2016 | 2098 | } |
| 2017 | 2099 | vtab.out.enabled = enableOutput; |
| 2018 | 2100 | g.interp = Th_CreateInterp(&vtab); |
| 2019 | 2101 | th_register_language(g.interp); /* Basic scripting commands. */ |
| | @@ -2020,20 +2102,20 @@ |
| 2020 | 2102 | #ifdef FOSSIL_ENABLE_TCL |
| 2021 | 2103 | if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){ |
| 2022 | 2104 | th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */ |
| 2023 | 2105 | } |
| 2024 | 2106 | #endif |
| 2025 | | -#ifdef TH_ENABLE_OUTBUF |
| 2107 | +#ifdef TH_ENABLE_OB |
| 2026 | 2108 | th_register_ob(g.interp); |
| 2027 | 2109 | #endif |
| 2028 | | -#ifdef TH_ENABLE_SQLITE |
| 2110 | +#ifdef TH_ENABLE_QUERY |
| 2029 | 2111 | th_register_query(g.interp); |
| 2030 | 2112 | #endif |
| 2031 | 2113 | #ifdef TH_ENABLE_ARGV |
| 2032 | 2114 | th_register_argv(g.interp); |
| 2033 | 2115 | #endif |
| 2034 | | - Th_register_commands( g.interp, aCommand ); |
| 2116 | + Th_RegisterCommands( g.interp, aCommand ); |
| 2035 | 2117 | Th_Eval( g.interp, 0, "proc incr {name {step 1}} {\n" |
| 2036 | 2118 | "upvar $name x\n" |
| 2037 | 2119 | "set x [expr $x+$step]\n" |
| 2038 | 2120 | "}", -1 ); |
| 2039 | 2121 | } |
| | @@ -2140,11 +2222,11 @@ |
| 2140 | 2222 | ** then TH1 variables are $aaa or $<aaa>. The first form of variable |
| 2141 | 2223 | ** is literal. The second is run through htmlize before being |
| 2142 | 2224 | ** inserted. |
| 2143 | 2225 | ** |
| 2144 | 2226 | ** This routine processes the template and writes the results |
| 2145 | | -** via Th_output(). |
| 2227 | +** via Th_Output(). |
| 2146 | 2228 | */ |
| 2147 | 2229 | int Th_Render(const char *z, int flags){ |
| 2148 | 2230 | int i = 0; |
| 2149 | 2231 | int n; |
| 2150 | 2232 | int rc = TH_OK; |
| | @@ -2201,12 +2283,16 @@ |
| 2201 | 2283 | ** COMMAND: th1 |
| 2202 | 2284 | ** |
| 2203 | 2285 | ** Processes a file provided on the command line as a TH1-capable |
| 2204 | 2286 | ** script/page. Output is sent to stdout or the CGI output buffer, as |
| 2205 | 2287 | ** appropriate. The input file is assumed to be text/wiki/HTML content |
| 2206 | | -** which may contain TH1 tag blocks. Each block is executed in the |
| 2207 | | -** same TH1 interpreter instance. |
| 2288 | +** which may contain TH1 tag blocks and variables in the form $var or |
| 2289 | +** $<var>. Each block is executed in the same TH1 interpreter |
| 2290 | +** instance. |
| 2291 | +** |
| 2292 | +** ACHTUNG: not all of the $variables which are set in CGI mode |
| 2293 | +** are available via this (CLI) command. |
| 2208 | 2294 | ** |
| 2209 | 2295 | */ |
| 2210 | 2296 | void test_th_render(void){ |
| 2211 | 2297 | Blob in; |
| 2212 | 2298 | if( g.argc<3 ){ |
| | @@ -2213,12 +2299,12 @@ |
| 2213 | 2299 | usage("FILE"); |
| 2214 | 2300 | assert(0 && "usage() does not return"); |
| 2215 | 2301 | } |
| 2216 | 2302 | blob_zero(&in); |
| 2217 | 2303 | db_open_config(0); /* Needed for global "tcl" setting. */ |
| 2218 | | -#ifdef TH_ENABLE_SQLITE |
| 2304 | +#ifdef TH_ENABLE_QUERY |
| 2219 | 2305 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0) |
| 2220 | 2306 | /* required for th1 query API. */; |
| 2221 | 2307 | #endif |
| 2222 | 2308 | blob_read_from_file(&in, g.argv[2]); |
| 2223 | 2309 | Th_Render(blob_str(&in), Th_Render_Flags_DEFAULT); |
| 2224 | 2310 | } |
| 2225 | 2311 | |