Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | added th1 query API. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | th1-query-api |
Files: | files | file ages | folders |
SHA1: |
c3b10e12a148e2d62a4b2298bb813358 |
User & Date: | stephan 2012-07-14 00:20:58.230 |
Context
2012-07-14
| ||
00:56 | Added query_col_int and query_col_double. Renamed query_column_xxx to query_col_xxx. ... (check-in: b01eb58b user: stephan tags: th1-query-api) | |
00:20 | added th1 query API. ... (check-in: c3b10e12 user: stephan tags: th1-query-api) | |
2012-07-13
| ||
20:52 | minor formatting fix. ... (check-in: 31545360 user: stephan tags: trunk) | |
Changes
Changes to src/th.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | struct Th_Interp { Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */ char *zResult; /* Current interpreter result (Th_Malloc()ed) */ int nResult; /* number of bytes in zResult */ Th_Hash *paCmd; /* Table of registered commands */ Th_Frame *pFrame; /* Current execution frame */ int isListMode; /* True if thSplitList() should operate in "list" mode */ }; /* ** Each TH command registered using Th_CreateCommand() is represented ** by an instance of the following structure stored in the Th_Interp.paCmd ** hash-table. */ | > > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | struct Th_Interp { Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */ char *zResult; /* Current interpreter result (Th_Malloc()ed) */ int nResult; /* number of bytes in zResult */ Th_Hash *paCmd; /* Table of registered commands */ Th_Frame *pFrame; /* Current execution frame */ int isListMode; /* True if thSplitList() should operate in "list" mode */ #ifdef TH_USE_SQLITE struct { sqlite3_stmt ** aStmt; int nStmt; int rc; } stmt; #endif }; /* ** Each TH command registered using Th_CreateCommand() is represented ** by an instance of the following structure stored in the Th_Interp.paCmd ** hash-table. */ |
︙ | ︙ | |||
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 | /* Delete any result currently stored in the interpreter. */ Th_SetResult(interp, 0, 0); /* Delete all registered commands and the command hash-table itself. */ Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp); Th_HashDelete(interp, interp->paCmd); /* Delete the interpreter structure itself. */ Th_Free(interp, (void *)interp); } /* ** Create a new interpreter. */ | > > > > > > > > > | 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 | /* Delete any result currently stored in the interpreter. */ Th_SetResult(interp, 0, 0); /* Delete all registered commands and the command hash-table itself. */ Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp); Th_HashDelete(interp, interp->paCmd); #ifdef TH_USE_SQLITE { int i; for( i = 0; i < interp->stmt.nStmt; ++i ){ Th_FinalizeStmt( interp, i ); } } #endif /* Delete the interpreter structure itself. */ Th_Free(interp, (void *)interp); } /* ** Create a new interpreter. */ |
︙ | ︙ | |||
2603 2604 2605 2606 2607 2608 2609 | *z++ = zExp[i]; } } *z = '\0'; return Th_SetResult(interp, zBuf, -1); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 | *z++ = zExp[i]; } } *z = '\0'; return Th_SetResult(interp, zBuf, -1); } #ifdef TH_USE_SQLITE extern void *fossil_realloc(void *p, size_t n); int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){ int i, x; sqlite3_stmt * s; sqlite3_stmt ** list = interp->stmt.aStmt; for( i = 0; i < interp->stmt.nStmt; ++i ){ s = list[i]; if(NULL==s){ list[i] = pStmt; return i+1; } } x = (interp->stmt.nStmt + 1) * 2; list = (sqlite3_stmt**)fossil_realloc( list, sizeof(sqlite3_stmt*)*x ); for( i = interp->stmt.nStmt; i < x; ++i ){ list[i] = NULL; } list[interp->stmt.nStmt] = pStmt; x = interp->stmt.nStmt; interp->stmt.nStmt = i; interp->stmt.aStmt = list; return x + 1; } int Th_FinalizeStmt(Th_Interp *interp, int stmtId){ sqlite3_stmt * st; int rc = 0; assert( stmtId>0 && stmtId<=interp->stmt.nStmt ); st = interp->stmt.aStmt[stmtId-1]; if(NULL != st){ interp->stmt.aStmt[stmtId-1] = NULL; sqlite3_finalize(st); return 0; } return 1; } sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId){ return ((stmtId<1) || (stmtId > interp->stmt.nStmt)) ? NULL : interp->stmt.aStmt[stmtId-1]; } #endif /* end TH_USE_SQLITE */ |
Changes to src/th.h.
1 2 3 4 5 6 7 | /* This header file defines the external interface to the custom Scripting ** Language (TH) interpreter. TH is very similar to TCL but is not an ** exact clone. */ /* | > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #ifdef TH_USE_SQLITE #if 0==TH_USE_SQLITE #undef TH_USE_SQLITE #endif #endif #define TH_USE_SQLITE #ifdef TH_USE_SQLITE #include "sqlite3.h" #endif /* This header file defines the external interface to the custom Scripting ** Language (TH) interpreter. TH is very similar to TCL but is not an ** exact clone. */ /* |
︙ | ︙ | |||
177 178 179 180 181 182 183 | /* ** Useful functions from th_lang.c. */ int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand; int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*); | > > > > > > > > > | 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | /* ** Useful functions from th_lang.c. */ int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand; int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*); #ifdef TH_USE_SQLITE #include "stddef.h" /* size_t */ extern void *fossil_realloc(void *p, size_t n); int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt); int Th_FinalizeStmt(Th_Interp *interp, int stmtId); sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId); #endif |
Changes to src/th_main.c.
︙ | ︙ | |||
93 94 95 96 97 98 99 | } if( g.cgiOutput ){ cgi_append_content(z, n); }else{ fwrite(z, 1, n, stdout); fflush(stdout); } | | > > > > > > > > > > | | > > > > | > > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | } if( g.cgiOutput ){ cgi_append_content(z, n); }else{ fwrite(z, 1, n, stdout); fflush(stdout); } if( encode ) fossil_free((char*)z); } } struct PutsCmdData { char escapeHtml; char const * sep; char const * eol; }; typedef struct PutsCmdData PutsCmdData; /* ** TH command: puts STRING ** TH command: html STRING ** ** Output STRING as HTML (html) or unchanged (puts). */ static int putsCmd( Th_Interp *interp, void *pConvert, int argc, const char **argv, int *argl ){ PutsCmdData const * fmt = (PutsCmdData const *)pConvert; const int sepLen = fmt->sep ? strlen(fmt->sep) : 0; int i; if( argc<2 ){ return Th_WrongNumArgs(interp, "puts STRING ...STRING_N"); } for( i = 1; i < argc; ++i ){ if(sepLen && (i>1)){ sendText(fmt->sep, sepLen, 0); } sendText((char const*)argv[i], argl[i], fmt->escapeHtml); } if(fmt->eol){ sendText(fmt->eol, strlen(fmt->eol), 0); } return TH_OK; } /* ** TH command: wiki STRING ** ** Render the input string as wiki. |
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | } if( openRepository ) db_find_and_open_repository(OPEN_OK_NOT_FOUND, 0); } Th_SetResult(interp, g.zRepositoryName, -1); return TH_OK; } /* ** Make sure the interpreter has been initialized. Initialize it if ** it has not been already. ** ** The interpreter is stored in the g.interp global variable. */ void Th_FossilInit(void){ static struct _Command { const char *zName; Th_CommandProc xProc; void *pContext; } aCommand[] = { {"anycap", anycapCmd, 0}, {"combobox", comboboxCmd, 0}, {"enable_output", enableOutputCmd, 0}, {"linecount", linecntCmd, 0}, {"hascap", hascapCmd, 0}, {"hasfeature", hasfeatureCmd, 0}, {"htmlize", htmlizeCmd, 0}, {"date", dateCmd, 0}, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | } if( openRepository ) db_find_and_open_repository(OPEN_OK_NOT_FOUND, 0); } Th_SetResult(interp, g.zRepositoryName, -1); return TH_OK; } #ifdef TH_USE_SQLITE static int queryPrepareCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ char const * zSql; sqlite3_stmt * pStmt = NULL; int rc; char const * errMsg = NULL; if( argc!=2 ){ return Th_WrongNumArgs(interp, "query_prepare STRING"); } zSql = argv[1]; rc = sqlite3_prepare( g.db, zSql, strlen(zSql), &pStmt, NULL ); if(SQLITE_OK==rc){ if(sqlite3_column_count( pStmt ) < 1){ errMsg = "Only SELECT-like queries are supported."; rc = SQLITE_ERROR; sqlite3_finalize( pStmt ); pStmt = NULL; } }else{ errMsg = sqlite3_errmsg( g.db ); } if(SQLITE_OK!=rc){ assert(NULL != errMsg); assert(NULL == pStmt); Th_ErrorMessage(interp, "error preparing SQL:", errMsg, -1); return TH_ERROR; } rc = Th_AddStmt( interp, pStmt ); assert( rc >= 0 && "AddStmt failed."); Th_SetResultInt( interp, rc ); return TH_OK; } static sqlite3_stmt * queryStmtHandle(Th_Interp *interp, char const * arg, int argLen, int * stmtId ){ int rc = 0; sqlite3_stmt * pStmt = NULL; if( 0 == Th_ToInt( interp, arg, argLen, &rc ) ){ if(stmtId){ *stmtId = rc; } pStmt = Th_GetStmt( interp, rc ); if(NULL==pStmt){ Th_ErrorMessage(interp, "no such statement handle:", arg, -1); } } return pStmt; } static int queryFinalizeCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ char * zSql; sqlite3_stmt * pStmt = NULL; int rc = 0; char const * arg; if( argc!=2 ){ return Th_WrongNumArgs(interp, "query_finalize StmtHandle"); } arg = argv[1]; pStmt = queryStmtHandle(interp, arg, argl[1], &rc); if( rc < 1 ){ return TH_ERROR; } assert( NULL != pStmt ); rc = Th_FinalizeStmt( interp, rc ); Th_SetResultInt( interp, rc ); return TH_OK; } static void queryReportDbErr( Th_Interp * interp, int rc ){ char const * msg = sqlite3_errmsg( g.db ); Th_ErrorMessage(interp, "db error:", msg, -1); } static int queryStepCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ sqlite3_stmt * pStmt = NULL; int rc = 0; if( argc!=2 ){ return Th_WrongNumArgs(interp, "query_step StmtHandle"); } pStmt = queryStmtHandle(interp, argv[1], argl[1], &rc); if( rc < 1 ){ return TH_ERROR; } rc = sqlite3_step( pStmt ); switch(rc){ case SQLITE_ROW: rc = 1; break; case SQLITE_DONE: rc = 0; break; default: queryReportDbErr( interp, rc ); return TH_ERROR; } Th_SetResultInt( interp, rc ); return TH_OK; } static int queryColStringCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ sqlite3_stmt * pStmt = NULL; char const * val; int index; int rc = 0; int valLen; if( argc!=3 ){ return Th_WrongNumArgs(interp, "query_column_string StmtHandle Index"); } pStmt = queryStmtHandle(interp, argv[1], argl[1], &rc); if( rc < 1 ){ return TH_ERROR; } if( 0 != Th_ToInt( interp, argv[2], argl[2], &index ) ){ return TH_ERROR; } val = sqlite3_column_text( pStmt, index ); valLen = val ? sqlite3_column_bytes( pStmt, index ) : 0; Th_SetResult( interp, val, valLen ); return TH_OK; } static int queryColCountCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ int rc; sqlite3_stmt * pStmt = NULL; if( argc!=2 ){ return Th_WrongNumArgs(interp, "query_column_count StmtHandle"); } pStmt = queryStmtHandle(interp, argv[1], argl[1], NULL); if( NULL == pStmt ){ return TH_ERROR; } rc = sqlite3_column_count( pStmt ); Th_SetResultInt( interp, rc ); return TH_OK; } static int queryColNameCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ sqlite3_stmt * pStmt = NULL; char const * val; int index; int rc = 0; int valLen; if( argc!=3 ){ return Th_WrongNumArgs(interp, "query_column_name StmtHandle Index"); } pStmt = queryStmtHandle(interp, argv[1], argl[1], &rc); if( rc < 1 ){ return TH_ERROR; } if( 0 != Th_ToInt( interp, argv[2], argl[2], &index ) ){ return TH_ERROR; } val = sqlite3_column_name( pStmt, index ); if(NULL==val){ Th_ErrorMessage(interp, "Column index out of bounds(?):", argv[2], -1); return TH_ERROR; }else{ Th_SetResult( interp, val, strlen( val ) ); return TH_OK; } } #endif /* end TH_USE_SQLITE */ /* ** Make sure the interpreter has been initialized. Initialize it if ** it has not been already. ** ** The interpreter is stored in the g.interp global variable. */ void Th_FossilInit(void){ static PutsCmdData puts_Html = {0, 0, 0}; static PutsCmdData puts_Normal = {1, 0, 0}; static PutsCmdData puts_Ext = {1, " ", "\n"}; static struct _Command { const char *zName; Th_CommandProc xProc; void *pContext; } aCommand[] = { {"anycap", anycapCmd, 0}, {"combobox", comboboxCmd, 0}, {"enable_output", enableOutputCmd, 0}, {"linecount", linecntCmd, 0}, {"hascap", hascapCmd, 0}, {"hasfeature", hasfeatureCmd, 0}, {"htmlize", htmlizeCmd, 0}, {"date", dateCmd, 0}, {"html", putsCmd, &puts_Html}, {"puts", putsCmd, &puts_Normal}, {"putsl", putsCmd, &puts_Ext}, #ifdef TH_USE_SQLITE {"query_column_count", queryColCountCmd, 0}, {"query_column_name", queryColNameCmd, 0}, {"query_finalize", queryFinalizeCmd, 0}, {"query_prepare", queryPrepareCmd, 0}, {"query_step", queryStepCmd, 0}, {"query_column_string", queryColStringCmd, 0}, #endif {"wiki", wikiCmd, 0}, {"repository", repositoryCmd, 0}, {0, 0, 0} }; if( g.interp==0 ){ int i; g.interp = Th_CreateInterp(&vtab); |
︙ | ︙ | |||
620 621 622 623 624 625 626 627 628 629 | void test_th_render(void){ Blob in; if( g.argc<3 ){ usage("FILE"); } db_open_config(0); /* Needed for global "tcl" setting. */ blob_zero(&in); blob_read_from_file(&in, g.argv[2]); Th_Render(blob_str(&in)); } | > | 852 853 854 855 856 857 858 859 860 861 862 | void test_th_render(void){ Blob in; if( g.argc<3 ){ usage("FILE"); } db_open_config(0); /* Needed for global "tcl" setting. */ blob_zero(&in); db_find_and_open_repository(OPEN_ANY_SCHEMA,0) /* for query_xxx tests. */; blob_read_from_file(&in, g.argv[2]); Th_Render(blob_str(&in)); } |
Added test/th1-query-api-1.th1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | <th1> proc bar {} { puts "json ?= [hasfeature json]\n" puts "tcl ?= [hasfeature tcl]\n" puts "ssl ?= [hasfeature ssl]\n" puts [lindex {a b c} 1] "\n" proc foo {a {b steve}} { puts "a = ${a}\n" puts "b = ${b}\n" } foo hi world foo hi {string list} # foo puts a b c foo \n } bar foo leaky proc xyz {} { return 42 } set a [xyz] puts "a=${a}" ! \n set stmt [query_prepare {SELECT login, cap FROM user}] set colCount [query_column_count $stmt] puts "query column count: ${colCount}\n" #set stmt2 [query_prepare {SELECT cap, login FROM user}] #puts "stmt=${stmt} stmt2=${stmt2}\n" #putsl "step =" [query_step $stmt] #putsl "val =" [query_column_string $stmt 1] proc noop {} {} proc incr {name {step 1}} { upvar $name x set x [expr $x+$step] } set sep " " set i 0 set colNames(0) 0 for {set i 0} {$i < $colCount} {incr i} { set colNames($i) [query_column_name $stmt $i] } for {set row 0} {0 < [query_step $stmt]} {incr row} { for {set i 0} {$i < $colCount} {incr i} { if {$i > 0} { puts $sep } else { puts "#$row: $sep" } puts $colNames($i) = [query_column_string $stmt $i] } puts "\n" } unset row query_finalize $stmt #query_finalize $stmt2 proc query_step_each {{stmt} {callback}} { set colNames(0) 0 set colCount [query_column_count $stmt] for {set i 0} {$i < $colCount} {incr i} { set colNames($i) [query_column_name $stmt $i] } upvar cb $callback for {set row 0} {0 < [query_step $stmt]} {incr row} { #puts "Calling callback: $stmt $colCount colNames\n" $callback $stmt $colCount } } set stmt [query_prepare {SELECT login FROM user}] set rc 0 catch { proc my_each {stmt colCount} { for {set i 0} {$i < $colCount} {incr i} { if {$i > 0} { puts $sep } puts [query_column_string $stmt $i] } puts "\n" # error "hi!" } query_step_each $stmt my_each } rc query_finalize $stmt puts rc = $rc </th1> |