/ Check-in [d805fc0c]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge trunk changes into this branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wapptest
Files: files | file ages | folders
SHA3-256: d805fc0cf1c4ef07a7bc947f75828931e3788d0e64730caab3b42ae58009a194
User & Date: dan 2019-04-11 19:04:01
Context
2019-04-11
19:07
Add the test/wapptest.tcl script, an alternative to releasetest.tcl that uses wapp to provide the user-interface. check-in: edd87cd6 user: dan tags: trunk
19:04
Merge trunk changes into this branch. Closed-Leaf check-in: d805fc0c user: dan tags: wapptest
19:03
Further tweaks to wapptest.tcl. Add the ability to run the extra (n)debug tests that releasetest.tcl runs. check-in: ec9c4f6d user: dan tags: wapptest
17:06
Remove the vfslog.c extension from the testfixture target in main.mk, as that extension has no TCL bindings and is inaccessible. check-in: d71f8bbc user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added ext/rbu/rbupartial.test.













































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 2019 April 11
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

source [file join [file dirname [info script]] rbu_common.tcl]
set ::testprefix rbupartial

db close
sqlite3_shutdown
sqlite3_config_uri 1

foreach {tn without_rowid a b c d} {
  1 ""              a b c d
  2 "WITHOUT ROWID" aaa bbb ccc ddd
  3 "WITHOUT ROWID" "\"hello\"" {"one'two"}  {[c]} ddd
  4 "WITHOUT ROWID" {`a b`} {"one'two"}  {[c c c]} ddd
  5 "" a b c {"d""d"}
  6 "" {'one''two'} b {"c""c"} {"d""d"}
} {
  eval [string map [list \
    %WITHOUT_ROWID% $without_rowid %A% $a %B% $b %C% $c %D% $d
  ] {
  reset_db
  do_execsql_test $tn.1.0 {
    CREATE TABLE t1(%A% PRIMARY KEY, %B%, %C%, %D%) %WITHOUT_ROWID% ;
    CREATE INDEX i1b  ON t1(%B%);
    CREATE INDEX i1b2 ON t1(%B%) WHERE %C%<5;
    CREATE INDEX i1b3 ON t1(%B%) WHERE %C%>=5;

    CREATE INDEX i1c  ON t1(%C%);
    CREATE INDEX i1c2 ON t1(%C%) WHERE %C% IS NULL;
    CREATE INDEX i1c3 ON t1(%C%) WHERE %C% IS NOT NULL;

    CREATE INDEX i1c4 ON t1(%C%) WHERE %D% < 'd';
  }

  do_execsql_test $tn.1.1 {
    INSERT INTO t1 VALUES(0, NULL, NULL, 'a');
    INSERT INTO t1 VALUES(1, 2, 3, 'b');
    INSERT INTO t1 VALUES(4, 5, 6, 'c');
    INSERT INTO t1 VALUES(7, 8, 9, 'd');
  }

  forcedelete rbu.db
  do_test $tn.1.2 {
    sqlite3 rbu rbu.db
    rbu eval {
      CREATE TABLE data_t1(%A%, %B%, %C%, %D%, rbu_control);

      INSERT INTO data_t1 VALUES(10, 11, 12, 'e', 0);
      INSERT INTO data_t1 VALUES(13, 14, NULL, 'f', 0);

      INSERT INTO data_t1 VALUES(0, NULL, NULL, NULL, 1);
      INSERT INTO data_t1 VALUES(4, NULL, NULL, NULL, 1);

      INSERT INTO data_t1 VALUES(7, NULL, 4, NULL, '..x.');
      INSERT INTO data_t1 VALUES(1, 10, NULL, NULL, '.xx.');
    }
    rbu close
  } {}

  do_test $tn.1.3 {
    run_rbu test.db rbu.db
    execsql { PRAGMA integrity_check }
  } {ok}

  do_execsql_test $tn.1.4 {
    SELECT * FROM t1 ORDER BY %A%;
  } {
    1 10 {} b   7 8 4 d   10 11 12 e   13 14 {} f
  }

  set step 0
  do_rbu_vacuum_test $tn.1.5 0
  }]
}

finish_test

Changes to ext/rbu/sqlite3rbu.c.

236
237
238
239
240
241
242





243
244
245
246
247
248
249
....
1246
1247
1248
1249
1250
1251
1252

1253
1254



1255
1256
1257
1258
1259
1260
1261
....
1953
1954
1955
1956
1957
1958
1959
























































1960
1961
1962
1963
1964
1965
1966
....
1983
1984
1985
1986
1987
1988
1989

1990
1991
1992
1993
1994
1995
1996

1997
1998
1999
2000
2001
2002
2003
....
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050


2051
2052
2053
2054
2055
2056
2057
2058
2059
2060

2061
2062
2063
2064
2065
2066
2067
**     * a special "cleanup table" state.
**
** abIndexed:
**   If the table has no indexes on it, abIndexed is set to NULL. Otherwise,
**   it points to an array of flags nTblCol elements in size. The flag is
**   set for each column that is either a part of the PK or a part of an
**   index. Or clear otherwise.





**   
*/
struct RbuObjIter {
  sqlite3_stmt *pTblIter;         /* Iterate through tables */
  sqlite3_stmt *pIdxIter;         /* Index iterator */
  int nTblCol;                    /* Size of azTblCol[] array */
  char **azTblCol;                /* Array of unquoted target column names */
................................................................................
        sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
    );
  }

  pIter->nIndex = 0;
  while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
    const char *zIdx = (const char*)sqlite3_column_text(pList, 1);

    sqlite3_stmt *pXInfo = 0;
    if( zIdx==0 ) break;



    p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
        sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
    );
    while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
      int iCid = sqlite3_column_int(pXInfo, 1);
      if( iCid>=0 ) pIter->abIndexed[iCid] = 1;
    }
................................................................................
    rc = sqlite3_reset(p->objiter.pTmpInsert);
  }

  if( rc!=SQLITE_OK ){
    sqlite3_result_error_code(pCtx, rc);
  }
}

























































/*
** Ensure that the SQLite statement handles required to update the 
** target database object currently indicated by the iterator passed 
** as the second argument are available.
*/
static int rbuObjIterPrepareAll(
................................................................................

    if( zIdx ){
      const char *zTbl = pIter->zTbl;
      char *zImposterCols = 0;    /* Columns for imposter table */
      char *zImposterPK = 0;      /* Primary key declaration for imposter */
      char *zWhere = 0;           /* WHERE clause on PK columns */
      char *zBind = 0;

      int nBind = 0;

      assert( pIter->eType!=RBU_PK_VTAB );
      zCollist = rbuObjIterGetIndexCols(
          p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
      );
      zBind = rbuObjIterGetBindlist(p, nBind);


      /* Create the imposter table used to write to this index. */
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum);
      rbuMPrintfExec(p, p->dbMain,
          "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID",
          zTbl, zImposterCols, zImposterPK
................................................................................
      }

      /* Create the SELECT statement to read keys in sorted order */
      if( p->rc==SQLITE_OK ){
        char *zSql;
        if( rbuIsVacuum(p) ){
          zSql = sqlite3_mprintf(
              "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
              zCollist, 
              pIter->zDataTbl,
              zCollist, zLimit
          );
        }else

        if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
          zSql = sqlite3_mprintf(
              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
              zCollist, p->zStateDb, pIter->zDataTbl,
              zCollist, zLimit
          );
        }else{
          zSql = sqlite3_mprintf(
              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
              "UNION ALL "
              "SELECT %s, rbu_control FROM '%q' "
              "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
              "ORDER BY %s%s",
              zCollist, p->zStateDb, pIter->zDataTbl, 
              zCollist, pIter->zDataTbl, 


              zCollist, zLimit
          );
        }
        p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql);
      }

      sqlite3_free(zImposterCols);
      sqlite3_free(zImposterPK);
      sqlite3_free(zWhere);
      sqlite3_free(zBind);

    }else{
      int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
                    ||(pIter->eType==RBU_PK_NONE)
                    ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
      const char *zTbl = pIter->zTbl;       /* Table this step applies to */
      const char *zWrite;                   /* Imposter table name */








>
>
>
>
>







 







>


>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







>







 







|


|





|

|



|


|

|

>
>










>







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
....
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
....
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
....
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
....
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
**     * a special "cleanup table" state.
**
** abIndexed:
**   If the table has no indexes on it, abIndexed is set to NULL. Otherwise,
**   it points to an array of flags nTblCol elements in size. The flag is
**   set for each column that is either a part of the PK or a part of an
**   index. Or clear otherwise.
**
**   If there are one or more partial indexes on the table, all fields of
**   this array set set to 1. This is because in that case, the module has
**   no way to tell which fields will be required to add and remove entries
**   from the partial indexes.
**   
*/
struct RbuObjIter {
  sqlite3_stmt *pTblIter;         /* Iterate through tables */
  sqlite3_stmt *pIdxIter;         /* Index iterator */
  int nTblCol;                    /* Size of azTblCol[] array */
  char **azTblCol;                /* Array of unquoted target column names */
................................................................................
        sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
    );
  }

  pIter->nIndex = 0;
  while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
    const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
    int bPartial = sqlite3_column_int(pList, 4);
    sqlite3_stmt *pXInfo = 0;
    if( zIdx==0 ) break;
    if( bPartial ){
      memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol);
    }
    p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
        sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
    );
    while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
      int iCid = sqlite3_column_int(pXInfo, 1);
      if( iCid>=0 ) pIter->abIndexed[iCid] = 1;
    }
................................................................................
    rc = sqlite3_reset(p->objiter.pTmpInsert);
  }

  if( rc!=SQLITE_OK ){
    sqlite3_result_error_code(pCtx, rc);
  }
}

static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
  sqlite3_stmt *pStmt = 0;
  int rc = p->rc;
  char *zRet = 0;

  if( rc==SQLITE_OK ){
    rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
        "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
    );
  }
  if( rc==SQLITE_OK ){
    int rc2;
    rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC);
    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
      const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
      if( zSql ){
        int nParen = 0;           /* Number of open parenthesis */
        int i;
        for(i=0; zSql[i]; i++){
          char c = zSql[i];
          if( c=='(' ){
            nParen++;
          }
          else if( c==')' ){
            nParen--;
            if( nParen==0 ){
              i++;
              break;
            }
          }else if( c=='"' || c=='\'' || c=='`' ){
            for(i++; 1; i++){
              if( zSql[i]==c ){
                if( zSql[i+1]!=c ) break;
                i++;
              }
            }
          }else if( c=='[' ){
            for(i++; 1; i++){
              if( zSql[i]==']' ) break;
            }
          }
        }
        if( zSql[i] ){
          zRet = rbuStrndup(&zSql[i], &rc);
        }
      }
    }

    rc2 = sqlite3_finalize(pStmt);
    if( rc==SQLITE_OK ) rc = rc2;
  }

  p->rc = rc;
  return zRet;
}

/*
** Ensure that the SQLite statement handles required to update the 
** target database object currently indicated by the iterator passed 
** as the second argument are available.
*/
static int rbuObjIterPrepareAll(
................................................................................

    if( zIdx ){
      const char *zTbl = pIter->zTbl;
      char *zImposterCols = 0;    /* Columns for imposter table */
      char *zImposterPK = 0;      /* Primary key declaration for imposter */
      char *zWhere = 0;           /* WHERE clause on PK columns */
      char *zBind = 0;
      char *zPart = 0;
      int nBind = 0;

      assert( pIter->eType!=RBU_PK_VTAB );
      zCollist = rbuObjIterGetIndexCols(
          p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
      );
      zBind = rbuObjIterGetBindlist(p, nBind);
      zPart = rbuObjIterGetIndexWhere(p, pIter);

      /* Create the imposter table used to write to this index. */
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum);
      rbuMPrintfExec(p, p->dbMain,
          "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID",
          zTbl, zImposterCols, zImposterPK
................................................................................
      }

      /* Create the SELECT statement to read keys in sorted order */
      if( p->rc==SQLITE_OK ){
        char *zSql;
        if( rbuIsVacuum(p) ){
          zSql = sqlite3_mprintf(
              "SELECT %s, 0 AS rbu_control FROM '%q' %s ORDER BY %s%s",
              zCollist, 
              pIter->zDataTbl,
              zPart, zCollist, zLimit
          );
        }else

        if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
          zSql = sqlite3_mprintf(
              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s",
              zCollist, p->zStateDb, pIter->zDataTbl,
              zPart, zCollist, zLimit
          );
        }else{
          zSql = sqlite3_mprintf(
              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s "
              "UNION ALL "
              "SELECT %s, rbu_control FROM '%q' "
              "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 "
              "ORDER BY %s%s",
              zCollist, p->zStateDb, pIter->zDataTbl, zPart,
              zCollist, pIter->zDataTbl, 
              zPart,
              (zPart ? "AND" : "WHERE"),
              zCollist, zLimit
          );
        }
        p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql);
      }

      sqlite3_free(zImposterCols);
      sqlite3_free(zImposterPK);
      sqlite3_free(zWhere);
      sqlite3_free(zBind);
      sqlite3_free(zPart);
    }else{
      int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
                    ||(pIter->eType==RBU_PK_NONE)
                    ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
      const char *zTbl = pIter->zTbl;       /* Table this step applies to */
      const char *zWrite;                   /* Imposter table name */

Changes to main.mk.

374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  $(TOP)/ext/misc/regexp.c \
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \
  $(TOP)/ext/misc/vfslog.c \
  $(TOP)/ext/misc/zipfile.c \
  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \
  $(TOP)/ext/fts5/fts5_test_tok.c


#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c







<







374
375
376
377
378
379
380

381
382
383
384
385
386
387
  $(TOP)/ext/misc/regexp.c \
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \

  $(TOP)/ext/misc/zipfile.c \
  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \
  $(TOP)/ext/fts5/fts5_test_tok.c


#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c

Changes to src/btree.c.

6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
*/
static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
  MemPage *pTrunk = 0;                /* Free-list trunk page */
  Pgno iTrunk = 0;                    /* Page number of free-list trunk page */ 
  MemPage *pPage1 = pBt->pPage1;      /* Local reference to page 1 */
  MemPage *pPage;                     /* Page being freed. May be NULL. */
  int rc;                             /* Return Code */
  int nFree;                          /* Initial number of pages on free-list */

  assert( sqlite3_mutex_held(pBt->mutex) );
  assert( CORRUPT_DB || iPage>1 );
  assert( !pMemPage || pMemPage->pgno==iPage );

  if( iPage<2 || iPage>pBt->nPage ){
    return SQLITE_CORRUPT_BKPT;







|







6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
*/
static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
  MemPage *pTrunk = 0;                /* Free-list trunk page */
  Pgno iTrunk = 0;                    /* Page number of free-list trunk page */ 
  MemPage *pPage1 = pBt->pPage1;      /* Local reference to page 1 */
  MemPage *pPage;                     /* Page being freed. May be NULL. */
  int rc;                             /* Return Code */
  u32 nFree;                          /* Initial number of pages on free-list */

  assert( sqlite3_mutex_held(pBt->mutex) );
  assert( CORRUPT_DB || iPage>1 );
  assert( !pMemPage || pMemPage->pgno==iPage );

  if( iPage<2 || iPage>pBt->nPage ){
    return SQLITE_CORRUPT_BKPT;

Changes to src/build.c.

4394
4395
4396
4397
4398
4399
4400
4401

4402
4403
4404
4405
4406
4407
4408
  Index *pIdx       /* The index that triggers the constraint */
){
  char *zErr;
  int j;
  StrAccum errMsg;
  Table *pTab = pIdx->pTable;

  sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);

  if( pIdx->aColExpr ){
    sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName);
  }else{
    for(j=0; j<pIdx->nKeyCol; j++){
      char *zCol;
      assert( pIdx->aiColumn[j]>=0 );
      zCol = pTab->aCol[pIdx->aiColumn[j]].zName;







|
>







4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
  Index *pIdx       /* The index that triggers the constraint */
){
  char *zErr;
  int j;
  StrAccum errMsg;
  Table *pTab = pIdx->pTable;

  sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 
                      pParse->db->aLimit[SQLITE_LIMIT_LENGTH]);
  if( pIdx->aColExpr ){
    sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName);
  }else{
    for(j=0; j<pIdx->nKeyCol; j++){
      char *zCol;
      assert( pIdx->aiColumn[j]>=0 );
      zCol = pTab->aCol[pIdx->aiColumn[j]].zName;

Changes to src/printf.c.

133
134
135
136
137
138
139

140
141
142
143
144
145
146
/*
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
  assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
  p->accError = eError;
  if( p->mxAlloc ) sqlite3_str_reset(p);

}

/*
** Extra argument values from a PrintfArguments object
*/
static sqlite3_int64 getIntArg(PrintfArguments *p){
  if( p->nArg<=p->nUsed ) return 0;







>







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
  assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
  p->accError = eError;
  if( p->mxAlloc ) sqlite3_str_reset(p);
  if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError);
}

/*
** Extra argument values from a PrintfArguments object
*/
static sqlite3_int64 getIntArg(PrintfArguments *p){
  if( p->nArg<=p->nUsed ) return 0;

Changes to src/sqliteInt.h.

3830
3831
3832
3833
3834
3835
3836

3837
3838
3839
3840
3841
3842
3843
  void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
#endif
#endif


void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ErrorMsg(Parse*, const char*, ...);

void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);







>







3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
  void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
#endif
#endif


void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ErrorMsg(Parse*, const char*, ...);
int sqlite3ErrorToParser(sqlite3*,int);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);

Changes to src/test4.c.

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
...
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
#define N_THREAD 26
static Thread threadset[N_THREAD];


/*
** The main loop for a thread.  Threads use busy waiting. 
*/
static void *thread_main(void *pArg){
  Thread *p = (Thread*)pArg;
  if( p->db ){
    sqlite3_close(p->db);
  }
  sqlite3_open(p->zFilename, &p->db);
  if( SQLITE_OK!=sqlite3_errcode(p->db) ){
    p->zErr = strdup(sqlite3_errmsg(p->db));
................................................................................
    return TCL_ERROR;
  }
  threadset[i].busy = 1;
  sqlite3_free(threadset[i].zFilename);
  threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]);
  threadset[i].opnum = 1;
  threadset[i].completed = 0;
  rc = pthread_create(&x, 0, thread_main, &threadset[i]);
  if( rc ){
    Tcl_AppendResult(interp, "failed to create the thread", 0);
    sqlite3_free(threadset[i].zFilename);
    threadset[i].busy = 0;
    return TCL_ERROR;
  }
  pthread_detach(x);
  return TCL_OK;
}

/*
** Wait for a thread to reach its idle state.
*/
static void thread_wait(Thread *p){
  while( p->opnum>p->completed ) sched_yield();
}

/*
** Usage:  thread_wait ID
**
** Wait on thread ID to reach its idle state.
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  return TCL_OK;
}

/*
** Stop a thread.
*/
static void stop_thread(Thread *p){
  thread_wait(p);
  p->xOp = 0;
  p->opnum++;
  thread_wait(p);
  sqlite3_free(p->zArg);
  p->zArg = 0;
  sqlite3_free(p->zFilename);
  p->zFilename = 0;
  p->busy = 0;
}

................................................................................
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID", 0);
    return TCL_ERROR;
  }
  if( argv[1][0]=='*' && argv[1][1]==0 ){
    for(i=0; i<N_THREAD; i++){
      if( threadset[i].busy ) stop_thread(&threadset[i]);
    }
  }else{
    i = parse_thread_id(interp, argv[1]);
    if( i<0 ) return TCL_ERROR;
    if( !threadset[i].busy ){
      Tcl_AppendResult(interp, "no such thread", 0);
      return TCL_ERROR;
    }
    stop_thread(&threadset[i]);
  }
  return TCL_OK;
}

/*
** Usage: thread_argc  ID
**
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc);
  Tcl_AppendResult(interp, zBuf, 0);
  return TCL_OK;
}

/*
** Usage: thread_argv  ID   N
................................................................................
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
  thread_wait(&threadset[i]);
  if( n<0 || n>=threadset[i].argc ){
    Tcl_AppendResult(interp, "column number out of range", 0);
    return TCL_ERROR;
  }
  Tcl_AppendResult(interp, threadset[i].argv[n], 0);
  return TCL_OK;
}
................................................................................
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
  thread_wait(&threadset[i]);
  if( n<0 || n>=threadset[i].argc ){
    Tcl_AppendResult(interp, "column number out of range", 0);
    return TCL_ERROR;
  }
  Tcl_AppendResult(interp, threadset[i].colv[n], 0);
  return TCL_OK;
}
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  zName = sqlite3ErrName(threadset[i].rc);
  Tcl_AppendResult(interp, zName, 0);
  return TCL_OK;
}

/*
** Usage: thread_error  ID
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  Tcl_AppendResult(interp, threadset[i].zErr, 0);
  return TCL_OK;
}

/*
** This procedure runs in the thread to compile an SQL statement.
*/
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  threadset[i].xOp = do_compile;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);
  threadset[i].opnum++;
  return TCL_OK;
}

................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  threadset[i].xOp = do_step;
  threadset[i].opnum++;
  return TCL_OK;
}

/*
** This procedure runs in the thread to finalize a virtual machine.
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  threadset[i].xOp = do_finalize;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = 0;
  threadset[i].opnum++;
  return TCL_OK;
}

................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  j = parse_thread_id(interp, argv[2]);
  if( j<0 ) return TCL_ERROR;
  if( !threadset[j].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[j]);
  temp = threadset[i].db;
  threadset[i].db = threadset[j].db;
  threadset[j].db = temp;
  return TCL_OK;
}

/*
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db);
  threadset[i].db = 0;
  Tcl_AppendResult(interp, zBuf, (char*)0);
  return TCL_OK;
}

/*
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  assert( !threadset[i].db );
  threadset[i].db = (sqlite3*)sqlite3TestTextToPtr(argv[2]);
  return TCL_OK;
}

/*
** Usage: thread_stmt_get ID
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  thread_wait(&threadset[i]);
  sqlite3TestMakePointerStr(interp, zBuf, threadset[i].pStmt);
  threadset[i].pStmt = 0;
  Tcl_AppendResult(interp, zBuf, (char*)0);
  return TCL_OK;
}

/*







|







 







|













|







 







|






|
|


|







 







|








|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|






|







 







|







 







|







 







|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
...
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
#define N_THREAD 26
static Thread threadset[N_THREAD];


/*
** The main loop for a thread.  Threads use busy waiting. 
*/
static void *test_thread_main(void *pArg){
  Thread *p = (Thread*)pArg;
  if( p->db ){
    sqlite3_close(p->db);
  }
  sqlite3_open(p->zFilename, &p->db);
  if( SQLITE_OK!=sqlite3_errcode(p->db) ){
    p->zErr = strdup(sqlite3_errmsg(p->db));
................................................................................
    return TCL_ERROR;
  }
  threadset[i].busy = 1;
  sqlite3_free(threadset[i].zFilename);
  threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]);
  threadset[i].opnum = 1;
  threadset[i].completed = 0;
  rc = pthread_create(&x, 0, test_thread_main, &threadset[i]);
  if( rc ){
    Tcl_AppendResult(interp, "failed to create the thread", 0);
    sqlite3_free(threadset[i].zFilename);
    threadset[i].busy = 0;
    return TCL_ERROR;
  }
  pthread_detach(x);
  return TCL_OK;
}

/*
** Wait for a thread to reach its idle state.
*/
static void test_thread_wait(Thread *p){
  while( p->opnum>p->completed ) sched_yield();
}

/*
** Usage:  thread_wait ID
**
** Wait on thread ID to reach its idle state.
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  return TCL_OK;
}

/*
** Stop a thread.
*/
static void test_stop_thread(Thread *p){
  test_thread_wait(p);
  p->xOp = 0;
  p->opnum++;
  test_thread_wait(p);
  sqlite3_free(p->zArg);
  p->zArg = 0;
  sqlite3_free(p->zFilename);
  p->zFilename = 0;
  p->busy = 0;
}

................................................................................
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID", 0);
    return TCL_ERROR;
  }
  if( argv[1][0]=='*' && argv[1][1]==0 ){
    for(i=0; i<N_THREAD; i++){
      if( threadset[i].busy ) test_stop_thread(&threadset[i]);
    }
  }else{
    i = parse_thread_id(interp, argv[1]);
    if( i<0 ) return TCL_ERROR;
    if( !threadset[i].busy ){
      Tcl_AppendResult(interp, "no such thread", 0);
      return TCL_ERROR;
    }
    test_stop_thread(&threadset[i]);
  }
  return TCL_OK;
}

/*
** Usage: thread_argc  ID
**
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc);
  Tcl_AppendResult(interp, zBuf, 0);
  return TCL_OK;
}

/*
** Usage: thread_argv  ID   N
................................................................................
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
  test_thread_wait(&threadset[i]);
  if( n<0 || n>=threadset[i].argc ){
    Tcl_AppendResult(interp, "column number out of range", 0);
    return TCL_ERROR;
  }
  Tcl_AppendResult(interp, threadset[i].argv[n], 0);
  return TCL_OK;
}
................................................................................
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
  test_thread_wait(&threadset[i]);
  if( n<0 || n>=threadset[i].argc ){
    Tcl_AppendResult(interp, "column number out of range", 0);
    return TCL_ERROR;
  }
  Tcl_AppendResult(interp, threadset[i].colv[n], 0);
  return TCL_OK;
}
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  zName = sqlite3ErrName(threadset[i].rc);
  Tcl_AppendResult(interp, zName, 0);
  return TCL_OK;
}

/*
** Usage: thread_error  ID
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  Tcl_AppendResult(interp, threadset[i].zErr, 0);
  return TCL_OK;
}

/*
** This procedure runs in the thread to compile an SQL statement.
*/
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_compile;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);
  threadset[i].opnum++;
  return TCL_OK;
}

................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_step;
  threadset[i].opnum++;
  return TCL_OK;
}

/*
** This procedure runs in the thread to finalize a virtual machine.
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  threadset[i].xOp = do_finalize;
  sqlite3_free(threadset[i].zArg);
  threadset[i].zArg = 0;
  threadset[i].opnum++;
  return TCL_OK;
}

................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  j = parse_thread_id(interp, argv[2]);
  if( j<0 ) return TCL_ERROR;
  if( !threadset[j].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[j]);
  temp = threadset[i].db;
  threadset[i].db = threadset[j].db;
  threadset[j].db = temp;
  return TCL_OK;
}

/*
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db);
  threadset[i].db = 0;
  Tcl_AppendResult(interp, zBuf, (char*)0);
  return TCL_OK;
}

/*
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  assert( !threadset[i].db );
  threadset[i].db = (sqlite3*)sqlite3TestTextToPtr(argv[2]);
  return TCL_OK;
}

/*
** Usage: thread_stmt_get ID
................................................................................
  }
  i = parse_thread_id(interp, argv[1]);
  if( i<0 ) return TCL_ERROR;
  if( !threadset[i].busy ){
    Tcl_AppendResult(interp, "no such thread", 0);
    return TCL_ERROR;
  }
  test_thread_wait(&threadset[i]);
  sqlite3TestMakePointerStr(interp, zBuf, threadset[i].pStmt);
  threadset[i].pStmt = 0;
  Tcl_AppendResult(interp, zBuf, (char*)0);
  return TCL_OK;
}

/*

Changes to src/util.c.

228
229
230
231
232
233
234













235
236
237
238
239
240
241
  }else{
    pParse->nErr++;
    sqlite3DbFree(db, pParse->zErrMsg);
    pParse->zErrMsg = zMsg;
    pParse->rc = SQLITE_ERROR;
  }
}














/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters.  The conversion is done in-place.  If the
** input does not begin with a quote character, then this routine
** is a no-op.
**







>
>
>
>
>
>
>
>
>
>
>
>
>







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  }else{
    pParse->nErr++;
    sqlite3DbFree(db, pParse->zErrMsg);
    pParse->zErrMsg = zMsg;
    pParse->rc = SQLITE_ERROR;
  }
}

/*
** If database connection db is currently parsing SQL, then transfer
** error code errCode to that parser if the parser has not already
** encountered some other kind of error.
*/
int sqlite3ErrorToParser(sqlite3 *db, int errCode){
  Parse *pParse;
  if( db==0 || (pParse = db->pParse)==0 ) return errCode;
  pParse->rc = errCode;
  pParse->nErr++;
  return errCode;
}

/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters.  The conversion is done in-place.  If the
** input does not begin with a quote character, then this routine
** is a no-op.
**

Changes to src/vdbemem.c.

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
305
306
307
308
309
310
311

312
313
314
315
316
317
318
....
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
  assert( sqlite3VdbeCheckMemInvariants(pMem) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  testcase( pMem->db==0 );

  /* If the bPreserve flag is set to true, then the memory cell must already
  ** contain a valid string or blob value.  */
  assert( bPreserve==0 
       || pMem->flags&(MEM_Blob|MEM_Str)
       || MemNullNochng(pMem)
  );
  testcase( bPreserve && pMem->z==0 );

  assert( pMem->szMalloc==0
       || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
  if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
    pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
    bPreserve = 0;
................................................................................
  testcase( sqlite3_value_nochange(pMem) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );

  /* Set nByte to the number of bytes required to store the expanded blob. */
  nByte = pMem->n + pMem->u.nZero;
  if( nByte<=0 ){

    nByte = 1;
  }
  if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
    return SQLITE_NOMEM_BKPT;
  }

  memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
................................................................................
  */
  if( xDel==SQLITE_TRANSIENT ){
    u32 nAlloc = nByte;
    if( flags&MEM_Term ){
      nAlloc += (enc==SQLITE_UTF8?1:2);
    }
    if( nByte>iLimit ){
      return SQLITE_TOOBIG;
    }
    testcase( nAlloc==0 );
    testcase( nAlloc==31 );
    testcase( nAlloc==32 );
    if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){
      return SQLITE_NOMEM_BKPT;
    }







<
|
<
<







 







>







 







|







188
189
190
191
192
193
194

195


196
197
198
199
200
201
202
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
....
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
  assert( sqlite3VdbeCheckMemInvariants(pMem) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  testcase( pMem->db==0 );

  /* If the bPreserve flag is set to true, then the memory cell must already
  ** contain a valid string or blob value.  */

  assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );


  testcase( bPreserve && pMem->z==0 );

  assert( pMem->szMalloc==0
       || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
  if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
    pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
    bPreserve = 0;
................................................................................
  testcase( sqlite3_value_nochange(pMem) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );

  /* Set nByte to the number of bytes required to store the expanded blob. */
  nByte = pMem->n + pMem->u.nZero;
  if( nByte<=0 ){
    if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK;
    nByte = 1;
  }
  if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
    return SQLITE_NOMEM_BKPT;
  }

  memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
................................................................................
  */
  if( xDel==SQLITE_TRANSIENT ){
    u32 nAlloc = nByte;
    if( flags&MEM_Term ){
      nAlloc += (enc==SQLITE_UTF8?1:2);
    }
    if( nByte>iLimit ){
      return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
    }
    testcase( nAlloc==0 );
    testcase( nAlloc==31 );
    testcase( nAlloc==32 );
    if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){
      return SQLITE_NOMEM_BKPT;
    }

Changes to test/sqllimits1.test.

885
886
887
888
889
890
891










892
  ))))
} "1 {too many columns in result set}"


foreach {key value} [array get saved] {
  catch {set $key $value}
}










finish_test







>
>
>
>
>
>
>
>
>
>

885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
  ))))
} "1 {too many columns in result set}"


foreach {key value} [array get saved] {
  catch {set $key $value}
}

#-------------------------------------------------------------------------
# At one point the following caused an assert() to fail.
#
sqlite3_limit db SQLITE_LIMIT_LENGTH 10000
set nm [string repeat x 10000]
do_catchsql_test sqllimits1-17.1 "
  CREATE TABLE $nm (x PRIMARY KEY)
" {1 {string or blob too big}}

finish_test

Changes to tool/omittest.tcl.

188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204

205
206
207
208
209

210
211
212
213
214
215
216

217
218


219
220
221

222
223
224
225

226
227
228

229
230
231
232
233
234
235
236
237

238
239
240
241
242
243
244
    SQLITE_OMIT_AUTOINIT \
    SQLITE_OMIT_AUTOMATIC_INDEX \
    SQLITE_OMIT_AUTORESET \
    SQLITE_OMIT_AUTOVACUUM \
    SQLITE_OMIT_BETWEEN_OPTIMIZATION \
    SQLITE_OMIT_BLOB_LITERAL \
    SQLITE_OMIT_BTREECOUNT \
    SQLITE_OMIT_BUILTIN_TEST \
    SQLITE_OMIT_CAST \
    SQLITE_OMIT_CHECK \
    SQLITE_OMIT_COMPILEOPTION_DIAGS \
    SQLITE_OMIT_COMPLETE \
    SQLITE_OMIT_COMPOUND_SELECT \

    SQLITE_OMIT_CTE \
    SQLITE_OMIT_DATETIME_FUNCS \
    SQLITE_OMIT_DECLTYPE \
    SQLITE_OMIT_DEPRECATED \

    SQLITE_OMIT_EXPLAIN \
    SQLITE_OMIT_FLAG_PRAGMAS \
    SQLITE_OMIT_FLOATING_POINT \
    SQLITE_OMIT_FOREIGN_KEY \
    SQLITE_OMIT_GET_TABLE \

    SQLITE_OMIT_INCRBLOB \
    SQLITE_OMIT_INTEGRITY_CHECK \
    SQLITE_OMIT_LIKE_OPTIMIZATION \
    SQLITE_OMIT_LOAD_EXTENSION \
    SQLITE_OMIT_LOCALTIME \
    SQLITE_OMIT_LOOKASIDE \
    SQLITE_OMIT_MEMORYDB \

    SQLITE_OMIT_OR_OPTIMIZATION \
    SQLITE_OMIT_PAGER_PRAGMAS \


    SQLITE_OMIT_PRAGMA \
    SQLITE_OMIT_PROGRESS_CALLBACK \
    SQLITE_OMIT_QUICKBALANCE \

    SQLITE_OMIT_REINDEX \
    SQLITE_OMIT_SCHEMA_PRAGMAS \
    SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \
    SQLITE_OMIT_SHARED_CACHE \

    SQLITE_OMIT_SUBQUERY \
    SQLITE_OMIT_TCL_VARIABLE \
    SQLITE_OMIT_TEMPDB \

    SQLITE_OMIT_TRACE \
    SQLITE_OMIT_TRIGGER \
    SQLITE_OMIT_TRUNCATE_OPTIMIZATION \
    SQLITE_OMIT_UNIQUE_ENFORCEMENT \
    SQLITE_OMIT_UTF16 \
    SQLITE_OMIT_VACUUM \
    SQLITE_OMIT_VIEW \
    SQLITE_OMIT_VIRTUALTABLE \
    SQLITE_OMIT_WAL \

    SQLITE_OMIT_WSD \
    SQLITE_OMIT_XFER_OPT \
  ]

  set ::ENABLE_SYMBOLS [list \
    SQLITE_DISABLE_DIRSYNC \
    SQLITE_DISABLE_LFS \







<





>




>





>







>


>
>



>




>



>



|





>







188
189
190
191
192
193
194

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
    SQLITE_OMIT_AUTOINIT \
    SQLITE_OMIT_AUTOMATIC_INDEX \
    SQLITE_OMIT_AUTORESET \
    SQLITE_OMIT_AUTOVACUUM \
    SQLITE_OMIT_BETWEEN_OPTIMIZATION \
    SQLITE_OMIT_BLOB_LITERAL \
    SQLITE_OMIT_BTREECOUNT \

    SQLITE_OMIT_CAST \
    SQLITE_OMIT_CHECK \
    SQLITE_OMIT_COMPILEOPTION_DIAGS \
    SQLITE_OMIT_COMPLETE \
    SQLITE_OMIT_COMPOUND_SELECT \
    SQLITE_OMIT_CONFLICT_CLAUSE \
    SQLITE_OMIT_CTE \
    SQLITE_OMIT_DATETIME_FUNCS \
    SQLITE_OMIT_DECLTYPE \
    SQLITE_OMIT_DEPRECATED \
    SQLITE_OMIT_DISKIO \
    SQLITE_OMIT_EXPLAIN \
    SQLITE_OMIT_FLAG_PRAGMAS \
    SQLITE_OMIT_FLOATING_POINT \
    SQLITE_OMIT_FOREIGN_KEY \
    SQLITE_OMIT_GET_TABLE \
    SQLITE_OMIT_HEX_INTEGER \
    SQLITE_OMIT_INCRBLOB \
    SQLITE_OMIT_INTEGRITY_CHECK \
    SQLITE_OMIT_LIKE_OPTIMIZATION \
    SQLITE_OMIT_LOAD_EXTENSION \
    SQLITE_OMIT_LOCALTIME \
    SQLITE_OMIT_LOOKASIDE \
    SQLITE_OMIT_MEMORYDB \
    SQLITE_OMIT_MEMORY_ALLOCATION \
    SQLITE_OMIT_OR_OPTIMIZATION \
    SQLITE_OMIT_PAGER_PRAGMAS \
    SQLITE_OMIT_PARSER_TRACE \
    SQLITE_OMIT_POPEN \
    SQLITE_OMIT_PRAGMA \
    SQLITE_OMIT_PROGRESS_CALLBACK \
    SQLITE_OMIT_QUICKBALANCE \
    SQLITE_OMIT_RANDOMNESS \
    SQLITE_OMIT_REINDEX \
    SQLITE_OMIT_SCHEMA_PRAGMAS \
    SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \
    SQLITE_OMIT_SHARED_CACHE \
    SQLITE_OMIT_SHUTDOWN_DIRECTORIES \
    SQLITE_OMIT_SUBQUERY \
    SQLITE_OMIT_TCL_VARIABLE \
    SQLITE_OMIT_TEMPDB \
    SQLITE_OMIT_TEST_CONTROL \
    SQLITE_OMIT_TRACE \
    SQLITE_OMIT_TRIGGER \
    SQLITE_OMIT_TRUNCATE_OPTIMIZATION \
    SQLITE_OMIT_UPSERT \
    SQLITE_OMIT_UTF16 \
    SQLITE_OMIT_VACUUM \
    SQLITE_OMIT_VIEW \
    SQLITE_OMIT_VIRTUALTABLE \
    SQLITE_OMIT_WAL \
    SQLITE_OMIT_WINDOWFUNC \
    SQLITE_OMIT_WSD \
    SQLITE_OMIT_XFER_OPT \
  ]

  set ::ENABLE_SYMBOLS [list \
    SQLITE_DISABLE_DIRSYNC \
    SQLITE_DISABLE_LFS \