test_tclvar.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. ** 2006 June 13
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. **
  7. ** May you do good and not evil.
  8. ** May you find forgiveness for yourself and forgive others.
  9. ** May you share freely, never taking more than you give.
  10. **
  11. *************************************************************************
  12. ** Code for testing the virtual table interfaces. This code
  13. ** is not included in the SQLite library. It is used for automated
  14. ** testing of the SQLite library.
  15. **
  16. ** The emphasis of this file is a virtual table that provides
  17. ** access to TCL variables.
  18. */
  19. #include "sqliteInt.h"
  20. #include "tcl.h"
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #ifndef SQLITE_OMIT_VIRTUALTABLE
  24. typedef struct tclvar_vtab tclvar_vtab;
  25. typedef struct tclvar_cursor tclvar_cursor;
  26. /*
  27. ** A tclvar virtual-table object
  28. */
  29. struct tclvar_vtab {
  30. sqlite3_vtab base;
  31. Tcl_Interp *interp;
  32. };
  33. /* A tclvar cursor object */
  34. struct tclvar_cursor {
  35. sqlite3_vtab_cursor base;
  36. Tcl_Obj *pList1; /* Result of [info vars ?pattern?] */
  37. Tcl_Obj *pList2; /* Result of [array names [lindex $pList1 $i1]] */
  38. int i1; /* Current item in pList1 */
  39. int i2; /* Current item (if any) in pList2 */
  40. };
  41. /* Methods for the tclvar module */
  42. static int tclvarConnect(
  43. sqlite3 *db,
  44. void *pAux,
  45. int argc, const char *const*argv,
  46. sqlite3_vtab **ppVtab,
  47. char **pzErr
  48. ){
  49. tclvar_vtab *pVtab;
  50. static const char zSchema[] =
  51. "CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
  52. pVtab = sqlite3MallocZero( sizeof(*pVtab) );
  53. if( pVtab==0 ) return SQLITE_NOMEM;
  54. *ppVtab = &pVtab->base;
  55. pVtab->interp = (Tcl_Interp *)pAux;
  56. sqlite3_declare_vtab(db, zSchema);
  57. return SQLITE_OK;
  58. }
  59. /* Note that for this virtual table, the xCreate and xConnect
  60. ** methods are identical. */
  61. static int tclvarDisconnect(sqlite3_vtab *pVtab){
  62. sqlite3_free(pVtab);
  63. return SQLITE_OK;
  64. }
  65. /* The xDisconnect and xDestroy methods are also the same */
  66. /*
  67. ** Open a new tclvar cursor.
  68. */
  69. static int tclvarOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  70. tclvar_cursor *pCur;
  71. pCur = sqlite3MallocZero(sizeof(tclvar_cursor));
  72. *ppCursor = &pCur->base;
  73. return SQLITE_OK;
  74. }
  75. /*
  76. ** Close a tclvar cursor.
  77. */
  78. static int tclvarClose(sqlite3_vtab_cursor *cur){
  79. tclvar_cursor *pCur = (tclvar_cursor *)cur;
  80. if( pCur->pList1 ){
  81. Tcl_DecrRefCount(pCur->pList1);
  82. }
  83. if( pCur->pList2 ){
  84. Tcl_DecrRefCount(pCur->pList2);
  85. }
  86. sqlite3_free(pCur);
  87. return SQLITE_OK;
  88. }
  89. /*
  90. ** Returns 1 if data is ready, or 0 if not.
  91. */
  92. static int next2(Tcl_Interp *interp, tclvar_cursor *pCur, Tcl_Obj *pObj){
  93. Tcl_Obj *p;
  94. if( pObj ){
  95. if( !pCur->pList2 ){
  96. p = Tcl_NewStringObj("array names", -1);
  97. Tcl_IncrRefCount(p);
  98. Tcl_ListObjAppendElement(0, p, pObj);
  99. Tcl_EvalObjEx(interp, p, TCL_EVAL_GLOBAL);
  100. Tcl_DecrRefCount(p);
  101. pCur->pList2 = Tcl_GetObjResult(interp);
  102. Tcl_IncrRefCount(pCur->pList2);
  103. assert( pCur->i2==0 );
  104. }else{
  105. int n = 0;
  106. pCur->i2++;
  107. Tcl_ListObjLength(0, pCur->pList2, &n);
  108. if( pCur->i2>=n ){
  109. Tcl_DecrRefCount(pCur->pList2);
  110. pCur->pList2 = 0;
  111. pCur->i2 = 0;
  112. return 0;
  113. }
  114. }
  115. }
  116. return 1;
  117. }
  118. static int tclvarNext(sqlite3_vtab_cursor *cur){
  119. Tcl_Obj *pObj;
  120. int n = 0;
  121. int ok = 0;
  122. tclvar_cursor *pCur = (tclvar_cursor *)cur;
  123. Tcl_Interp *interp = ((tclvar_vtab *)(cur->pVtab))->interp;
  124. Tcl_ListObjLength(0, pCur->pList1, &n);
  125. while( !ok && pCur->i1<n ){
  126. Tcl_ListObjIndex(0, pCur->pList1, pCur->i1, &pObj);
  127. ok = next2(interp, pCur, pObj);
  128. if( !ok ){
  129. pCur->i1++;
  130. }
  131. }
  132. return 0;
  133. }
  134. static int tclvarFilter(
  135. sqlite3_vtab_cursor *pVtabCursor,
  136. int idxNum, const char *idxStr,
  137. int argc, sqlite3_value **argv
  138. ){
  139. tclvar_cursor *pCur = (tclvar_cursor *)pVtabCursor;
  140. Tcl_Interp *interp = ((tclvar_vtab *)(pVtabCursor->pVtab))->interp;
  141. Tcl_Obj *p = Tcl_NewStringObj("info vars", -1);
  142. Tcl_IncrRefCount(p);
  143. assert( argc==0 || argc==1 );
  144. if( argc==1 ){
  145. Tcl_Obj *pArg = Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1);
  146. Tcl_ListObjAppendElement(0, p, pArg);
  147. }
  148. Tcl_EvalObjEx(interp, p, TCL_EVAL_GLOBAL);
  149. if( pCur->pList1 ){
  150. Tcl_DecrRefCount(pCur->pList1);
  151. }
  152. if( pCur->pList2 ){
  153. Tcl_DecrRefCount(pCur->pList2);
  154. pCur->pList2 = 0;
  155. }
  156. pCur->i1 = 0;
  157. pCur->i2 = 0;
  158. pCur->pList1 = Tcl_GetObjResult(interp);
  159. Tcl_IncrRefCount(pCur->pList1);
  160. assert( pCur->i1==0 && pCur->i2==0 && pCur->pList2==0 );
  161. Tcl_DecrRefCount(p);
  162. return tclvarNext(pVtabCursor);
  163. }
  164. static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  165. Tcl_Obj *p1;
  166. Tcl_Obj *p2;
  167. const char *z1;
  168. const char *z2 = "";
  169. tclvar_cursor *pCur = (tclvar_cursor*)cur;
  170. Tcl_Interp *interp = ((tclvar_vtab *)cur->pVtab)->interp;
  171. Tcl_ListObjIndex(interp, pCur->pList1, pCur->i1, &p1);
  172. Tcl_ListObjIndex(interp, pCur->pList2, pCur->i2, &p2);
  173. z1 = Tcl_GetString(p1);
  174. if( p2 ){
  175. z2 = Tcl_GetString(p2);
  176. }
  177. switch (i) {
  178. case 0: {
  179. sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
  180. break;
  181. }
  182. case 1: {
  183. sqlite3_result_text(ctx, z2, -1, SQLITE_TRANSIENT);
  184. break;
  185. }
  186. case 2: {
  187. Tcl_Obj *pVal = Tcl_GetVar2Ex(interp, z1, *z2?z2:0, TCL_GLOBAL_ONLY);
  188. sqlite3_result_text(ctx, Tcl_GetString(pVal), -1, SQLITE_TRANSIENT);
  189. break;
  190. }
  191. }
  192. return SQLITE_OK;
  193. }
  194. static int tclvarRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  195. *pRowid = 0;
  196. return SQLITE_OK;
  197. }
  198. static int tclvarEof(sqlite3_vtab_cursor *cur){
  199. tclvar_cursor *pCur = (tclvar_cursor*)cur;
  200. return (pCur->pList2?0:1);
  201. }
  202. static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  203. int ii;
  204. for(ii=0; ii<pIdxInfo->nConstraint; ii++){
  205. struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
  206. if( pCons->iColumn==0 && pCons->usable
  207. && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
  208. struct sqlite3_index_constraint_usage *pUsage;
  209. pUsage = &pIdxInfo->aConstraintUsage[ii];
  210. pUsage->omit = 0;
  211. pUsage->argvIndex = 1;
  212. return SQLITE_OK;
  213. }
  214. }
  215. for(ii=0; ii<pIdxInfo->nConstraint; ii++){
  216. struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
  217. if( pCons->iColumn==0 && pCons->usable
  218. && pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
  219. struct sqlite3_index_constraint_usage *pUsage;
  220. pUsage = &pIdxInfo->aConstraintUsage[ii];
  221. pUsage->omit = 1;
  222. pUsage->argvIndex = 1;
  223. return SQLITE_OK;
  224. }
  225. }
  226. return SQLITE_OK;
  227. }
  228. /*
  229. ** A virtual table module that provides read-only access to a
  230. ** Tcl global variable namespace.
  231. */
  232. static sqlite3_module tclvarModule = {
  233. 0, /* iVersion */
  234. tclvarConnect,
  235. tclvarConnect,
  236. tclvarBestIndex,
  237. tclvarDisconnect,
  238. tclvarDisconnect,
  239. tclvarOpen, /* xOpen - open a cursor */
  240. tclvarClose, /* xClose - close a cursor */
  241. tclvarFilter, /* xFilter - configure scan constraints */
  242. tclvarNext, /* xNext - advance a cursor */
  243. tclvarEof, /* xEof - check for end of scan */
  244. tclvarColumn, /* xColumn - read data */
  245. tclvarRowid, /* xRowid - read data */
  246. 0, /* xUpdate */
  247. 0, /* xBegin */
  248. 0, /* xSync */
  249. 0, /* xCommit */
  250. 0, /* xRollback */
  251. 0, /* xFindMethod */
  252. 0, /* xRename */
  253. };
  254. /*
  255. ** Decode a pointer to an sqlite3 object.
  256. */
  257. extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
  258. /*
  259. ** Register the echo virtual table module.
  260. */
  261. static int register_tclvar_module(
  262. ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  263. Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
  264. int objc, /* Number of arguments */
  265. Tcl_Obj *CONST objv[] /* Command arguments */
  266. ){
  267. sqlite3 *db;
  268. if( objc!=2 ){
  269. Tcl_WrongNumArgs(interp, 1, objv, "DB");
  270. return TCL_ERROR;
  271. }
  272. if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  273. #ifndef SQLITE_OMIT_VIRTUALTABLE
  274. sqlite3_create_module(db, "tclvar", &tclvarModule, (void *)interp);
  275. #endif
  276. return TCL_OK;
  277. }
  278. #endif
  279. /*
  280. ** Register commands with the TCL interpreter.
  281. */
  282. int Sqlitetesttclvar_Init(Tcl_Interp *interp){
  283. #ifndef SQLITE_OMIT_VIRTUALTABLE
  284. static struct {
  285. char *zName;
  286. Tcl_ObjCmdProc *xProc;
  287. void *clientData;
  288. } aObjCmd[] = {
  289. { "register_tclvar_module", register_tclvar_module, 0 },
  290. };
  291. int i;
  292. for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
  293. Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
  294. aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
  295. }
  296. #endif
  297. return TCL_OK;
  298. }