15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2006 June 10
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code.  In place of
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you do good and not evil.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you find forgiveness for yourself and forgive others.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you share freely, never taking more than you give.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*************************************************************************
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Code for testing the virtual table interfaces.  This code
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is not included in the SQLite library.  It is used for automated
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** testing of the SQLite library.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqliteInt.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tcl.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_VIRTUALTABLE
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct echo_vtab echo_vtab;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct echo_cursor echo_cursor;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The test module defined in this file uses four global Tcl variables to
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** commicate with test-scripts:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     $::echo_module
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     $::echo_module_sync_fail
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     $::echo_module_begin_fail
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     $::echo_module_cost
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The variable ::echo_module is a list. Each time one of the following
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** methods is called, one or more elements are appended to the list.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This is used for automated testing of virtual table modules.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The ::echo_module_sync_fail variable is set by test scripts and read
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** by code in this file. If it is set to the name of a real table in the
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the database, then all xSync operations on echo virtual tables that
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** use the named table as a backing store will fail.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Errors can be provoked within the following echo virtual table methods:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   xBestIndex   xOpen     xFilter   xNext
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   xColumn      xRowid    xUpdate   xSync
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   xBegin       xRename
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This is done by setting the global tcl variable:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   echo_module_fail($method,$tbl)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** where $method is set to the name of the virtual table method to fail
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (i.e. "xBestIndex") and $tbl is the name of the table being echoed (not
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the name of the virtual table, the name of the underlying real table).
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** An echo virtual-table object.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** echo.vtab.aIndex is an array of booleans. The nth entry is true if
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the nth column of the real table is the left-most column of an index
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (implicit or otherwise). In other words, if SQLite can optimize
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a query like "SELECT * FROM real_table WHERE col = ?".
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Member variable aCol[] contains copies of the column names of the real
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** table.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct echo_vtab {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab base;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp;     /* Tcl interpreter containing debug variables */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db;            /* Database connection */
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isPattern;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int inTransaction;      /* True if within a transaction */
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zThis;            /* Name of the echo table */
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zTableName;       /* Name of the real table */
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zLogName;         /* Name of the log table */
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nCol;               /* Number of columns in the real table */
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *aIndex;            /* Array of size nCol. True if column has an index */
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **aCol;            /* Array of size nCol. Column names */
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* An echo cursor object */
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct echo_cursor {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab_cursor base;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int simulateVtabError(echo_vtab *p, const char *zMethod){
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zErr;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char zVarname[128];
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zVarname[127] = '\0';
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_snprintf(127, zVarname, "echo_module_fail(%s,%s)", zMethod, p->zTableName);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zErr = Tcl_GetVar(p->interp, zVarname, TCL_GLOBAL_ONLY);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( zErr ){
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->base.zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", zErr);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (zErr!=0);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Convert an SQL-style quoted string into a normal string by removing
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the quote characters.  The conversion is done in-place.  If the
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** input does not begin with a quote character, then this routine
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is a no-op.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Examples:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     "abc"   becomes   abc
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     'xyz'   becomes   xyz
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     [pqr]   becomes   pqr
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     `mno`   becomes   mno
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void dequoteString(char *z){
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int quote;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i, j;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( z==0 ) return;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  quote = z[0];
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch( quote ){
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case '\'':  break;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case '"':   break;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case '`':   break;                /* For MySQL compatibility */
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case '[':   quote = ']';  break;  /* For MS SqlServer compatibility */
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:    return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=1, j=0; z[i]; i++){
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( z[i]==quote ){
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( z[i+1]==quote ){
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        z[j++] = quote;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        i++;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        z[j++] = 0;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      z[j++] = z[i];
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Retrieve the column names for the table named zTab via database
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** connection db. SQLITE_OK is returned on success, or an sqlite error
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** code otherwise.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If successful, the number of columns is written to *pnCol. *paCol is
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** set to point at sqlite3_malloc()'d space containing the array of
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** nCol column names. The caller is responsible for calling sqlite3_free
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** on *paCol.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int getColumnNames(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zTab,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char ***paCol,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *pnCol
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **aCol = 0;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zSql;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt = 0;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nCol = 0;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Prepare the statement "SELECT * FROM <tbl>". The column names
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** of the result set of the compiled SELECT will be the same as
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** the column names of table <tbl>.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zSql = sqlite3_mprintf("SELECT * FROM %Q", zTab);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !zSql ){
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = SQLITE_NOMEM;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto out;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(zSql);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ii;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int nBytes;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zSpace;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nCol = sqlite3_column_count(pStmt);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Figure out how much space to allocate for the array of column names
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** (including space for the strings themselves). Then allocate it.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nBytes = sizeof(char *) * nCol;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(ii=0; ii<nCol; ii++){
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char *zName = sqlite3_column_name(pStmt, ii);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( !zName ){
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rc = SQLITE_NOMEM;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        goto out;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nBytes += strlen(zName)+1;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aCol = (char **)sqlite3MallocZero(nBytes);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !aCol ){
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_NOMEM;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto out;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Copy the column names into the allocated space and set up the
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** pointers in the aCol[] array.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zSpace = (char *)(&aCol[nCol]);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(ii=0; ii<nCol; ii++){
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      aCol[ii] = zSpace;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zSpace += sprintf(zSpace, "%s", sqlite3_column_name(pStmt, ii));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zSpace++;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( (zSpace-nBytes)==(char *)aCol );
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *paCol = aCol;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pnCol = nCol;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)out:
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_finalize(pStmt);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Parameter zTab is the name of a table in database db with nCol
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** columns. This function allocates an array of integers nCol in
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** size and populates it according to any implicit or explicit
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** indices on table zTab.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If successful, SQLITE_OK is returned and *paIndex set to point
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** at the allocated array. Otherwise, an error code is returned.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** See comments associated with the member variable aIndex above
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** "struct echo_vtab" for details of the contents of the array.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int getIndexArray(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db,             /* Database connection */
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zTab,        /* Name of table in database db */
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nCol,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int **paIndex
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt = 0;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *aIndex = 0;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zSql;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Allocate space for the index array */
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aIndex = (int *)sqlite3MallocZero(sizeof(int) * nCol);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !aIndex ){
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = SQLITE_NOMEM;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto get_index_array_out;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Compile an sqlite pragma to loop through all indices on table zTab */
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zSql = sqlite3_mprintf("PRAGMA index_list(%s)", zTab);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !zSql ){
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = SQLITE_NOMEM;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto get_index_array_out;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(zSql);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* For each index, figure out the left-most column and set the
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** corresponding entry in aIndex[] to 1.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char *zIdx = (const char *)sqlite3_column_text(pStmt, 1);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_stmt *pStmt2 = 0;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zSql = sqlite3_mprintf("PRAGMA index_info(%s)", zIdx);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !zSql ){
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_NOMEM;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto get_index_array_out;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_prepare(db, zSql, -1, &pStmt2, 0);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zSql);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pStmt2 && sqlite3_step(pStmt2)==SQLITE_ROW ){
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int cid = sqlite3_column_int(pStmt2, 1);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( cid>=0 && cid<nCol );
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      aIndex[cid] = 1;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pStmt2 ){
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = sqlite3_finalize(pStmt2);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc!=SQLITE_OK ){
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto get_index_array_out;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)get_index_array_out:
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pStmt ){
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int rc2 = sqlite3_finalize(pStmt);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc==SQLITE_OK ){
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = rc2;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc!=SQLITE_OK ){
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(aIndex);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aIndex = 0;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *paIndex = aIndex;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Global Tcl variable $echo_module is a list. This routine appends
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the string element zArg to that list in interpreter interp.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void appendToEchoModule(Tcl_Interp *interp, const char *zArg){
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_SetVar(interp, "echo_module", (zArg?zArg:""), flags);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is called from within the echo-modules xCreate and
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** xConnect methods. The argc and argv arguments are copies of those
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** passed to the calling method. This function is responsible for
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** calling sqlite3_declare_vtab() to declare the schema of the virtual
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** table being created or connected.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If the constructor was passed just one argument, i.e.:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   CREATE TABLE t1 AS echo(t2);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Then t2 is assumed to be the name of a *real* database table. The
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** schema of the virtual table is declared by passing a copy of the
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** CREATE TABLE statement for the real table to sqlite3_declare_vtab().
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Hence, the virtual table should have exactly the same column names and
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** types as the real table.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoDeclareVtab(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pVtab->zTableName ){
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_stmt *pStmt = 0;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_prepare(db,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        -1, &pStmt, 0);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc==SQLITE_OK ){
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_bind_text(pStmt, 1, pVtab->zTableName, -1, 0);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( sqlite3_step(pStmt)==SQLITE_ROW ){
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int rc2;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const char *zCreateTable = (const char *)sqlite3_column_text(pStmt, 0);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rc = sqlite3_declare_vtab(db, zCreateTable);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rc2 = sqlite3_finalize(pStmt);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( rc==SQLITE_OK ){
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rc = rc2;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rc = sqlite3_finalize(pStmt);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( rc==SQLITE_OK ){
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rc = SQLITE_ERROR;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( rc==SQLITE_OK ){
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rc = getColumnNames(db, pVtab->zTableName, &pVtab->aCol, &pVtab->nCol);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( rc==SQLITE_OK ){
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rc = getIndexArray(db, pVtab->zTableName, pVtab->nCol, &pVtab->aIndex);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function frees all runtime structures associated with the virtual
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** table pVtab.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoDestructor(sqlite3_vtab *pVtab){
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *p = (echo_vtab*)pVtab;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p->aIndex);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p->aCol);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p->zThis);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p->zTableName);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p->zLogName);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct EchoModule EchoModule;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct EchoModule {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is called to do the work of the xConnect() method -
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to allocate the required in-memory structures for a newly connected
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** virtual table.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoConstructor(
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pAux,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc, const char *const*argv,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab **ppVtab,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **pzErr
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Allocate the sqlite3_vtab/echo_vtab structure itself */
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pVtab = sqlite3MallocZero( sizeof(*pVtab) );
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !pVtab ){
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_NOMEM;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pVtab->interp = ((EchoModule *)pAux)->interp;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pVtab->db = db;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Allocate echo_vtab.zThis */
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pVtab->zThis = sqlite3_mprintf("%s", argv[2]);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !pVtab->zThis ){
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echoDestructor((sqlite3_vtab *)pVtab);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_NOMEM;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Allocate echo_vtab.zTableName */
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( argc>3 ){
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pVtab->zTableName = sqlite3_mprintf("%s", argv[3]);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dequoteString(pVtab->zTableName);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pVtab->zTableName && pVtab->zTableName[0]=='*' ){
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char *z = sqlite3_mprintf("%s%s", argv[2], &(pVtab->zTableName[1]));
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_free(pVtab->zTableName);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pVtab->zTableName = z;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pVtab->isPattern = 1;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !pVtab->zTableName ){
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      echoDestructor((sqlite3_vtab *)pVtab);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SQLITE_NOMEM;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Log the arguments to this function to Tcl var ::echo_module */
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<argc; i++){
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appendToEchoModule(pVtab->interp, argv[i]);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Invoke sqlite3_declare_vtab and set up other members of the echo_vtab
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** structure. If an error occurs, delete the sqlite3_vtab structure and
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** return an error code.
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = echoDeclareVtab(pVtab, db);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc!=SQLITE_OK ){
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echoDestructor((sqlite3_vtab *)pVtab);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rc;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Success. Set *ppVtab and return */
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ppVtab = &pVtab->base;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xCreate method.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoCreate(
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pAux,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc, const char *const*argv,
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab **ppVtab,
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **pzErr
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(((EchoModule *)pAux)->interp, "xCreate");
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = echoConstructor(db, pAux, argc, argv, ppVtab, pzErr);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If there were two arguments passed to the module at the SQL level
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** (i.e. "CREATE VIRTUAL TABLE tbl USING echo(arg1, arg2)"), then
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** the second argument is used as a table name. Attempt to create
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** such a table with a single column, "logmsg". This table will
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** be used to log calls to the xUpdate method. It will be deleted
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** when the virtual table is DROPed.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** Note: The main point of this is to test that we can drop tables
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** from within an xDestroy method call.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK && argc==5 ){
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zSql;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo_vtab *pVtab = *(echo_vtab **)ppVtab;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pVtab->zLogName = sqlite3_mprintf("%s", argv[4]);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zSql = sqlite3_mprintf("CREATE TABLE %Q(logmsg)", pVtab->zLogName);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_exec(db, zSql, 0, 0, 0);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zSql);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc!=SQLITE_OK ){
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( *ppVtab && rc!=SQLITE_OK ){
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echoDestructor(*ppVtab);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *ppVtab = 0;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*(echo_vtab**)ppVtab)->inTransaction = 1;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xConnect method.
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoConnect(
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pAux,
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc, const char *const*argv,
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab **ppVtab,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **pzErr
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(((EchoModule *)pAux)->interp, "xConnect");
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return echoConstructor(db, pAux, argc, argv, ppVtab, pzErr);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xDisconnect method.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoDisconnect(sqlite3_vtab *pVtab){
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDisconnect");
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return echoDestructor(pVtab);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xDestroy method.
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoDestroy(sqlite3_vtab *pVtab){
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *p = (echo_vtab *)pVtab;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDestroy");
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Drop the "log" table, if one exists (see echoCreate() for details) */
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p && p->zLogName ){
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zSql;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zSql = sqlite3_mprintf("DROP TABLE %Q", p->zLogName);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zSql);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = echoDestructor(pVtab);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xOpen method.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_cursor *pCur;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError((echo_vtab *)pVTab, "xOpen") ){
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur = sqlite3MallocZero(sizeof(echo_cursor));
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ppCursor = (sqlite3_vtab_cursor *)pCur;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (pCur ? SQLITE_OK : SQLITE_NOMEM);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xClose method.
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoClose(sqlite3_vtab_cursor *cur){
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_cursor *pCur = (echo_cursor *)cur;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt = pCur->pStmt;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->pStmt = 0;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(pCur);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = sqlite3_finalize(pStmt);
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return non-zero if the cursor does not currently point to a valid record
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (i.e if the scan has finished), or zero otherwise.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoEof(sqlite3_vtab_cursor *cur){
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (((echo_cursor *)cur)->pStmt ? 0 : 1);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xNext method.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoNext(sqlite3_vtab_cursor *cur){
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_cursor *pCur = (echo_cursor *)cur;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError((echo_vtab *)(cur->pVtab), "xNext") ){
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCur->pStmt ){
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_step(pCur->pStmt);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc==SQLITE_ROW ){
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_OK;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = sqlite3_finalize(pCur->pStmt);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->pStmt = 0;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xColumn method.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int iCol = i + 1;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError((echo_vtab *)(cur->pVtab), "xColumn") ){
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !pStmt ){
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_null(ctx);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( sqlite3_data_count(pStmt)>iCol );
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_value(ctx, sqlite3_column_value(pStmt, iCol));
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xRowid method.
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError((echo_vtab *)(cur->pVtab), "xRowid") ){
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pRowid = sqlite3_column_int64(pStmt, 0);
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Compute a simple hash of the null terminated string zString.
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This module uses only sqlite3_index_info.idxStr, not
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sqlite3_index_info.idxNum. So to test idxNum, when idxStr is set
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** in echoBestIndex(), idxNum is set to the corresponding hash value.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** In echoFilter(), code assert()s that the supplied idxNum value is
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** indeed the hash of the supplied idxStr.
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int hashString(const char *zString){
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int val = 0;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ii;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(ii=0; zString[ii]; ii++){
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    val = (val << 3) + (int)zString[ii];
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return val;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Echo virtual table module xFilter method.
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoFilter(
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab_cursor *pVtabCursor,
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int idxNum, const char *idxStr,
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc, sqlite3_value **argv
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_cursor *pCur = (echo_cursor *)pVtabCursor;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db = pVtab->db;
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(pVtab, "xFilter") ){
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Check that idxNum matches idxStr */
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( idxNum==hashString(idxStr) );
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Log arguments to the ::echo_module Tcl variable */
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(pVtab->interp, "xFilter");
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(pVtab->interp, idxStr);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<argc; i++){
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appendToEchoModule(pVtab->interp, (const char*)sqlite3_value_text(argv[i]));
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_finalize(pCur->pStmt);
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->pStmt = 0;
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Prepare the SQL statement created by echoBestIndex and bind the
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** runtime parameters passed to this function to it.
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = sqlite3_prepare(db, idxStr, -1, &pCur->pStmt, 0);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCur->pStmt || rc!=SQLITE_OK );
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; rc==SQLITE_OK && i<argc; i++){
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_bind_value(pCur->pStmt, i+1, argv[i]);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If everything was successful, advance to the first row of the scan */
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = echoNext(pVtabCursor);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A helper function used by echoUpdate() and echoBestIndex() for
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** manipulating strings in concert with the sqlite3_mprintf() function.
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Parameter pzStr points to a pointer to a string allocated with
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sqlite3_mprintf. The second parameter, zAppend, points to another
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** string. The two strings are concatenated together and *pzStr
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** set to point at the result. The initial buffer pointed to by *pzStr
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is deallocated via sqlite3_free().
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If the third argument, doFree, is true, then sqlite3_free() is
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** also called to free the buffer pointed to by zAppend.
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void string_concat(char **pzStr, char *zAppend, int doFree, int *pRc){
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zIn = *pzStr;
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !zAppend && doFree && *pRc==SQLITE_OK ){
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pRc = SQLITE_NOMEM;
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( *pRc!=SQLITE_OK ){
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zIn);
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zIn = 0;
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( zIn ){
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char *zTemp = zIn;
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zIn = sqlite3_mprintf("%s%s", zIn, zAppend);
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_free(zTemp);
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zIn = sqlite3_mprintf("%s", zAppend);
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !zIn ){
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pRc = SQLITE_NOMEM;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pzStr = zIn;
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( doFree ){
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zAppend);
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The echo module implements the subset of query constraints and sort
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** orders that may take advantage of SQLite indices on the underlying
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** real table. For example, if the real table is declared as:
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     CREATE TABLE real(a, b, c);
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     CREATE INDEX real_index ON real(b);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** then the echo module handles WHERE or ORDER BY clauses that refer
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to the column "b", but not "a" or "c". If a multi-column index is
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** present, only its left most column is considered.
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This xBestIndex method encodes the proposed search strategy as
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** an SQL query on the real table underlying the virtual echo module
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** table and stores the query in sqlite3_index_info.idxStr. The SQL
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** statement is of the form:
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   SELECT rowid, * FROM <real-table> ?<where-clause>? ?<order-by-clause>?
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** where the <where-clause> and <order-by-clause> are determined
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** by the contents of the structure pointed to by the pIdxInfo argument.
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ii;
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zQuery = 0;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zNew;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nArg = 0;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zSep = "WHERE";
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)tab;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt = 0;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp = pVtab->interp;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nRow;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int useIdx = 0;
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int useCost = 0;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double cost;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isIgnoreUsable = 0;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( Tcl_GetVar(interp, "echo_module_ignore_usable", TCL_GLOBAL_ONLY) ){
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    isIgnoreUsable = 1;
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(pVtab, "xBestIndex") ){
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Determine the number of rows in the table and store this value in local
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** variable nRow. The 'estimated-cost' of the scan will be the number of
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** rows in the table for a linear scan, or the log (base 2) of the
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** number of rows if the proposed scan uses an index.
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( Tcl_GetVar(interp, "echo_module_cost", TCL_GLOBAL_ONLY) ){
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cost = atof(Tcl_GetVar(interp, "echo_module_cost", TCL_GLOBAL_ONLY));
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    useCost = 1;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zQuery = sqlite3_mprintf("SELECT count(*) FROM %Q", pVtab->zTableName);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !zQuery ){
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SQLITE_NOMEM;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_prepare(pVtab->db, zQuery, -1, &pStmt, 0);
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zQuery);
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc!=SQLITE_OK ){
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rc;
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_step(pStmt);
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nRow = sqlite3_column_int(pStmt, 0);
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_finalize(pStmt);
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc!=SQLITE_OK ){
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rc;
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zQuery = sqlite3_mprintf("SELECT rowid, * FROM %Q", pVtab->zTableName);
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !zQuery ){
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_NOMEM;
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(ii=0; ii<pIdxInfo->nConstraint; ii++){
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const struct sqlite3_index_constraint *pConstraint;
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct sqlite3_index_constraint_usage *pUsage;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int iCol;
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pConstraint = &pIdxInfo->aConstraint[ii];
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pUsage = &pIdxInfo->aConstraintUsage[ii];
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !isIgnoreUsable && !pConstraint->usable ) continue;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iCol = pConstraint->iColumn;
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pVtab->aIndex[iCol] || iCol<0 ){
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char *zCol = pVtab->aCol[iCol];
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char *zOp = 0;
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      useIdx = 1;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( iCol<0 ){
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        zCol = "rowid";
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch( pConstraint->op ){
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SQLITE_INDEX_CONSTRAINT_EQ:
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          zOp = "="; break;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SQLITE_INDEX_CONSTRAINT_LT:
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          zOp = "<"; break;
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SQLITE_INDEX_CONSTRAINT_GT:
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          zOp = ">"; break;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SQLITE_INDEX_CONSTRAINT_LE:
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          zOp = "<="; break;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SQLITE_INDEX_CONSTRAINT_GE:
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          zOp = ">="; break;
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SQLITE_INDEX_CONSTRAINT_MATCH:
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          zOp = "LIKE"; break;
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( zOp[0]=='L' ){
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')",
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               zSep, zCol);
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zCol, zOp);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_concat(&zQuery, zNew, 1, &rc);
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zSep = "AND";
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pUsage->argvIndex = ++nArg;
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pUsage->omit = 1;
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If there is only one term in the ORDER BY clause, and it is
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** on a column that this virtual table has an index for, then consume
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** the ORDER BY clause.
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pIdxInfo->nOrderBy==1 && pVtab->aIndex[pIdxInfo->aOrderBy->iColumn] ){
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int iCol = pIdxInfo->aOrderBy->iColumn;
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zCol = pVtab->aCol[iCol];
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zDir = pIdxInfo->aOrderBy->desc?"DESC":"ASC";
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( iCol<0 ){
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zCol = "rowid";
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zNew = sqlite3_mprintf(" ORDER BY %s %s", zCol, zDir);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_concat(&zQuery, zNew, 1, &rc);
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIdxInfo->orderByConsumed = 1;
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(pVtab->interp, "xBestIndex");;
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(pVtab->interp, zQuery);
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !zQuery ){
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rc;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pIdxInfo->idxNum = hashString(zQuery);
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pIdxInfo->idxStr = zQuery;
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pIdxInfo->needToFreeIdxStr = 1;
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( useCost ){
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIdxInfo->estimatedCost = cost;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( useIdx ){
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Approximation of log2(nRow). */
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for( ii=0; ii<(sizeof(int)*8); ii++ ){
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( nRow & (1<<ii) ){
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pIdxInfo->estimatedCost = (double)ii;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIdxInfo->estimatedCost = (double)nRow;
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The xUpdate method for echo module virtual tables.
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    apData[0]  apData[1]  apData[2..]
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INTEGER                              DELETE
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INTEGER    NULL       (nCol args)    UPDATE (do not set rowid)
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INTEGER    INTEGER    (nCol args)    UPDATE (with SET rowid = <arg1>)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    NULL       NULL       (nCol args)    INSERT INTO (automatic rowid value)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    NULL       INTEGER    (nCol args)    INSERT (incl. rowid value)
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int echoUpdate(
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab *tab,
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nData,
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_value **apData,
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite_int64 *pRowid
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)tab;
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db = pVtab->db;
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_stmt *pStmt;
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *z = 0;               /* SQL statement to execute */
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bindArgZero = 0;       /* True to bind apData[0] to sql var no. nData */
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bindArgOne = 0;        /* True to bind apData[1] to sql var no. 1 */
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;                     /* Counter variable used by for loops */
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( nData==pVtab->nCol+2 || nData==1 );
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Ticket #3083 - make sure we always start a transaction prior to
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** making any changes to a virtual table */
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pVtab->inTransaction );
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(pVtab, "xUpdate") ){
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If apData[0] is an integer and nData>1 then do an UPDATE */
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zSep = " SET";
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    z = sqlite3_mprintf("UPDATE %Q", pVtab->zTableName);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !z ){
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_NOMEM;
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bindArgOne = (apData[1] && sqlite3_value_type(apData[1])==SQLITE_INTEGER);
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bindArgZero = 1;
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( bindArgOne ){
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       string_concat(&z, " SET rowid=?1 ", 0, &rc);
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       zSep = ",";
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=2; i<nData; i++){
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( apData[i]==0 ) continue;
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_concat(&z, sqlite3_mprintf(
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "%s %Q=?%d", zSep, pVtab->aCol[i-2], i), 1, &rc);
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zSep = ",";
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 1, &rc);
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If apData[0] is an integer and nData==1 then do a DELETE */
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if( nData==1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    z = sqlite3_mprintf("DELETE FROM %Q WHERE rowid = ?1", pVtab->zTableName);
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !z ){
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_NOMEM;
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bindArgZero = 1;
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If the first argument is NULL and there are more than two args, INSERT */
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if( nData>2 && sqlite3_value_type(apData[0])==SQLITE_NULL ){
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ii;
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zInsert = 0;
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zValues = 0;
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zInsert = sqlite3_mprintf("INSERT INTO %Q (", pVtab->zTableName);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !zInsert ){
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_NOMEM;
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( sqlite3_value_type(apData[1])==SQLITE_INTEGER ){
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bindArgOne = 1;
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zValues = sqlite3_mprintf("?");
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_concat(&zInsert, "rowid", 0, &rc);
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert((pVtab->nCol+2)==nData);
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(ii=2; ii<nData; ii++){
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_concat(&zInsert,
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3_mprintf("%s%Q", zValues?", ":"", pVtab->aCol[ii-2]), 1, &rc);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_concat(&zValues,
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3_mprintf("%s?%d", zValues?", ":"", ii), 1, &rc);
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_concat(&z, zInsert, 1, &rc);
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_concat(&z, ") VALUES(", 0, &rc);
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_concat(&z, zValues, 1, &rc);
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_concat(&z, ")", 0, &rc);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Anything else is an error */
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else{
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(0);
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_prepare(db, z, -1, &pStmt, 0);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( rc!=SQLITE_OK || pStmt );
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(z);
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ) {
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( bindArgZero ){
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_bind_value(pStmt, nData, apData[0]);
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( bindArgOne ){
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_bind_value(pStmt, 1, apData[1]);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=2; i<nData && rc==SQLITE_OK; i++){
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( apData[i] ) rc = sqlite3_bind_value(pStmt, i, apData[i]);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc==SQLITE_OK ){
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_step(pStmt);
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = sqlite3_finalize(pStmt);
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_finalize(pStmt);
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pRowid && rc==SQLITE_OK ){
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pRowid = sqlite3_last_insert_rowid(db);
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc!=SQLITE_OK ){
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab->zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", sqlite3_errmsg(db));
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** xBegin, xSync, xCommit and xRollback callbacks for echo module
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** virtual tables. Do nothing other than add the name of the callback
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to the $::echo_module Tcl variable.
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoTransactionCall(sqlite3_vtab *tab, const char *zCall){
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *z;
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)tab;
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  z = sqlite3_mprintf("echo(%s)", pVtab->zTableName);
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( z==0 ) return SQLITE_NOMEM;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(pVtab->interp, zCall);
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appendToEchoModule(pVtab->interp, z);
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(z);
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoBegin(sqlite3_vtab *tab){
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)tab;
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp = pVtab->interp;
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zVal;
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Ticket #3083 - do not start a transaction if we are already in
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** a transaction */
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( !pVtab->inTransaction );
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(pVtab, "xBegin") ){
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = echoTransactionCall(tab, "xBegin");
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Check if the $::echo_module_begin_fail variable is defined. If it is,
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** and it is set to the name of the real table underlying this virtual
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** echo module table, then cause this xSync operation to fail.
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zVal = Tcl_GetVar(interp, "echo_module_begin_fail", TCL_GLOBAL_ONLY);
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = SQLITE_ERROR;
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pVtab->inTransaction = 1;
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoSync(sqlite3_vtab *tab){
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)tab;
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp = pVtab->interp;
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zVal;
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Ticket #3083 - Only call xSync if we have previously started a
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** transaction */
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pVtab->inTransaction );
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(pVtab, "xSync") ){
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = echoTransactionCall(tab, "xSync");
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc==SQLITE_OK ){
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Check if the $::echo_module_sync_fail variable is defined. If it is,
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** and it is set to the name of the real table underlying this virtual
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** echo module table, then cause this xSync operation to fail.
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zVal = Tcl_GetVar(interp, "echo_module_sync_fail", TCL_GLOBAL_ONLY);
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = -1;
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoCommit(sqlite3_vtab *tab){
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab*)tab;
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Ticket #3083 - Only call xCommit if we have previously started
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** a transaction */
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pVtab->inTransaction );
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(pVtab, "xCommit") ){
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3BeginBenignMalloc();
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = echoTransactionCall(tab, "xCommit");
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3EndBenignMalloc();
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pVtab->inTransaction = 0;
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoRollback(sqlite3_vtab *tab){
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab*)tab;
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Ticket #3083 - Only call xRollback if we have previously started
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** a transaction */
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pVtab->inTransaction );
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = echoTransactionCall(tab, "xRollback");
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pVtab->inTransaction = 0;
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of "GLOB" function on the echo module.  Pass
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** all arguments to the ::echo_glob_overload procedure of TCL
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** and return the result of that procedure as a string.
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void overloadedGlobFunction(
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_context *pContext,
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nArg,
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_value **apArg
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp = sqlite3_user_data(pContext);
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_DString str;
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_DStringInit(&str);
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_DStringAppendElement(&str, "::echo_glob_overload");
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<nArg; i++){
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_DStringAppendElement(&str, (char*)sqlite3_value_text(apArg[i]));
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = Tcl_Eval(interp, Tcl_DStringValue(&str));
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_DStringFree(&str);
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc ){
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_error(pContext, Tcl_GetStringResult(interp), -1);
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_text(pContext, Tcl_GetStringResult(interp),
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        -1, SQLITE_TRANSIENT);
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_ResetResult(interp);
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This is the xFindFunction implementation for the echo module.
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** SQLite calls this routine when the first argument of a function
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is a column of an echo virtual table.  This routine can optionally
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** override the implementation of that function.  It will choose to
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** do so if the function is named "glob", and a TCL command named
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** ::echo_glob_overload exists.
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoFindFunction(
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab *vtab,
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nArg,
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zFuncName,
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void **ppArg
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *pVtab = (echo_vtab *)vtab;
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp = pVtab->interp;
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_CmdInfo info;
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( strcmp(zFuncName,"glob")!=0 ){
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( Tcl_GetCommandInfo(interp, "::echo_glob_overload", &info)==0 ){
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pxFunc = overloadedGlobFunction;
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ppArg = interp;
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int echoRename(sqlite3_vtab *vtab, const char *zNewName){
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo_vtab *p = (echo_vtab *)vtab;
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( simulateVtabError(p, "xRename") ){
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->isPattern ){
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int nThis = strlen(p->zThis);
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zSql = sqlite3_mprintf("ALTER TABLE %s RENAME TO %s%s",
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->zTableName, zNewName, &p->zTableName[nThis]
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    );
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zSql);
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A virtual table module that merely "echos" the contents of another
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** table (like an SQL VIEW).
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_module echoModule = {
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                         /* iVersion */
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoCreate,
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoConnect,
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoBestIndex,
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoDisconnect,
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoDestroy,
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoOpen,                  /* xOpen - open a cursor */
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoClose,                 /* xClose - close a cursor */
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoFilter,                /* xFilter - configure scan constraints */
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoNext,                  /* xNext - advance a cursor */
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoEof,                   /* xEof */
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoColumn,                /* xColumn - read data */
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoRowid,                 /* xRowid - read data */
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoUpdate,                /* xUpdate - write data */
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoBegin,                 /* xBegin - begin transaction */
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoSync,                  /* xSync - sync transaction */
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoCommit,                /* xCommit - commit transaction */
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoRollback,              /* xRollback - rollback transaction */
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoFindFunction,          /* xFindFunction - function overloading */
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echoRename,                /* xRename - rename the table */
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Decode a pointer to an sqlite3 object.
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void moduleDestroy(void *p){
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p);
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Register the echo virtual table module.
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int register_echo_module(
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int objc,              /* Number of arguments */
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Obj *CONST objv[]  /* Command arguments */
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db;
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EchoModule *pMod;
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( objc!=2 ){
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_WrongNumArgs(interp, 1, objv, "DB");
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TCL_ERROR;
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pMod = sqlite3_malloc(sizeof(EchoModule));
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pMod->interp = interp;
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_create_module_v2(db, "echo", &echoModule, (void*)pMod, moduleDestroy);
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TCL_OK;
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Tcl interface to sqlite3_declare_vtab, invoked as follows from Tcl:
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sqlite3_declare_vtab DB SQL
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int declare_vtab(
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int objc,              /* Number of arguments */
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Obj *CONST objv[]  /* Command arguments */
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db;
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( objc!=3 ){
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_WrongNumArgs(interp, 1, objv, "DB SQL");
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TCL_ERROR;
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = sqlite3_declare_vtab(db, Tcl_GetString(objv[2]));
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rc!=SQLITE_OK ){
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TCL_ERROR;
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TCL_OK;
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Register commands with the TCL interpreter.
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Sqlitetest8_Init(Tcl_Interp *interp){
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_VIRTUALTABLE
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static struct {
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     char *zName;
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     Tcl_ObjCmdProc *xProc;
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     void *clientData;
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } aObjCmd[] = {
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     { "register_echo_module",   register_echo_module, 0 },
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     { "sqlite3_declare_vtab",   declare_vtab, 0 },
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TCL_OK;
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1342