@ div.adunit_banner {
@ margin: auto;
- @ width: 100%;
+ @ width: 100%%;
@ }
@ div.adunit_right {
@ float: right;
@ }
@ div.adunit_right_container {
Index: src/sha1.c
==================================================================
--- src/sha1.c
+++ src/sha1.c
@@ -17,11 +17,10 @@
**
** This implementation of SHA1.
*/
#include "config.h"
#include
-#include
#include "sha1.h"
/*
** SHA1 Implementation #1 is the hardened SHA1 implementation by
Index: src/sha3.c
==================================================================
--- src/sha3.c
+++ src/sha3.c
@@ -600,10 +600,11 @@
blob_resize(pCksum, iSize/4);
DigestToBase16(SHA3Final(&ctx), blob_buffer(pCksum), iSize/8);
return 0;
}
+#if 0 /* NOT USED */
/*
** Compute the SHA3 checksum of a zero-terminated string. The
** result is held in memory obtained from mprintf().
*/
char *sha3sum(const char *zIn, int iSize){
@@ -610,22 +611,26 @@
SHA3Context ctx;
char zDigest[132];
SHA3Init(&ctx, iSize);
SHA3Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
- DigestToBase16(SHA3Final(&ctx), zDigest, iSize/4);
+ DigestToBase16(SHA3Final(&ctx), zDigest, iSize/8);
return mprintf("%s", zDigest);
}
+#endif
/*
** COMMAND: sha3sum*
**
** Usage: %fossil sha3sum FILE...
**
** Compute an SHA3 checksum of all files named on the command-line.
** If a file is named "-" then take its content from standard input.
**
+** To be clear: The official NIST FIPS-202 implementation of SHA3
+** with the added 01 padding is used, not the original Keccak submission.
+**
** Options:
**
** --224 Compute a SHA3-224 hash
** --256 Compute a SHA3-256 hash (the default)
** --384 Compute a SHA3-384 hash
Index: src/shell.c
==================================================================
--- src/shell.c
+++ src/shell.c
@@ -16,15 +16,29 @@
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif
/*
-** If requested, include the SQLite compiler options file for MSVC.
+** Warning pragmas copied from msvc.h in the core.
*/
-#if defined(INCLUDE_MSVC_H)
-#include "msvc.h"
-#endif
+#if defined(_MSC_VER)
+#pragma warning(disable : 4054)
+#pragma warning(disable : 4055)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4130)
+#pragma warning(disable : 4152)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4206)
+#pragma warning(disable : 4210)
+#pragma warning(disable : 4232)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4306)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 4706)
+#endif /* defined(_MSC_VER) */
/*
** No support for loadable extensions in VxWorks.
*/
#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
@@ -425,10 +439,40 @@
utf8_printf(iotrace, "%s", z);
sqlite3_free(z);
}
#endif
+/*
+** Output string zUtf to stream pOut as w characters. If w is negative,
+** then right-justify the text. W is the width in UTF-8 characters, not
+** in bytes. This is different from the %*.*s specification in printf
+** since with %*.*s the width is measured in bytes, not characters.
+*/
+static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
+ int i;
+ int n;
+ int aw = w<0 ? -w : w;
+ char zBuf[1000];
+ if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
+ for(i=n=0; zUtf[i]; i++){
+ if( (zUtf[i]&0xc0)!=0x80 ){
+ n++;
+ if( n==aw ){
+ do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
+ break;
+ }
+ }
+ }
+ if( n>=aw ){
+ utf8_printf(pOut, "%.*s", i, zUtf);
+ }else if( w<0 ){
+ utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
+ }else{
+ utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
+ }
+}
+
/*
** Determines if a string is a number of not.
*/
static int isNumber(const char *z, int *realnum){
@@ -462,10 +506,22 @@
static int strlen30(const char *z){
const char *z2 = z;
while( *z2 ){ z2++; }
return 0x3fffffff & (int)(z2 - z);
}
+
+/*
+** Return the length of a string in characters. Multibyte UTF8 characters
+** count as a single character.
+*/
+static int strlenChar(const char *z){
+ int n = 0;
+ while( *z ){
+ if( (0xc0&*(z++))!=0x80 ) n++;
+ }
+ return n;
+}
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
@@ -711,10 +767,14 @@
} u;
unsigned nRate; /* Bytes of input accepted per Keccak iteration */
unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
};
+
+/* Allow the following routine to use the B0 variable, which is also
+** a macro in the termios.h header file */
+#undef B0
/*
** A single step of the Keccak mixing function for a 1600-bit state
*/
static void KeccakF1600Step(SHA3Context *p){
@@ -1122,16 +1182,71 @@
for(i=0; inRate; i++){
p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
}
return &p->u.x[p->nRate];
}
+
+/*
+** SQL function: shell_add_schema(S,X)
+**
+** Add the schema name X to the CREATE statement in S and return the result.
+** Examples:
+**
+** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
+**
+** Also works on
+**
+** CREATE INDEX
+** CREATE UNIQUE INDEX
+** CREATE VIEW
+** CREATE TRIGGER
+** CREATE VIRTUAL TABLE
+**
+** This UDF is used by the .schema command to insert the schema name of
+** attached databases into the middle of the sqlite_master.sql field.
+*/
+static void shellAddSchemaName(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ static const char *aPrefix[] = {
+ "TABLE",
+ "INDEX",
+ "UNIQUE INDEX",
+ "VIEW",
+ "TRIGGER",
+ "VIRTUAL TABLE"
+ };
+ int i = 0;
+ const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
+ const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
+ assert( nVal==2 );
+ if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
+ for(i=0; inullValue);
+ n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
if( wactualWidth) ){
p->actualWidth[i] = w;
}
if( showHdr ){
- if( w<0 ){
- utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i],
- i==nArg-1 ? rowSep : " ");
- }else{
- utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i],
- i==nArg-1 ? rowSep : " ");
- }
+ utf8_width_print(p->out, w, azCol[i]);
+ utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
}
}
if( showHdr ){
for(i=0; iactualWidth) ){
w = p->actualWidth[i];
}else{
w = 10;
}
- if( p->cMode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
- w = strlen30(azArg[i]);
+ if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
+ w = strlenChar(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
if( p->iIndentnIndent ){
utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
p->iIndent++;
}
- if( w<0 ){
- utf8_printf(p->out,"%*.*s%s",-w,-w,
- azArg[i] ? azArg[i] : p->nullValue,
- i==nArg-1 ? rowSep : " ");
- }else{
- utf8_printf(p->out,"%-*.*s%s",w,w,
- azArg[i] ? azArg[i] : p->nullValue,
- i==nArg-1 ? rowSep : " ");
- }
+ utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
+ utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
}
break;
}
case MODE_Semi: { /* .schema and .fullschema output */
printSchemaLine(p->out, azArg[0], ";\n");
@@ -1976,55 +2170,88 @@
utf8_printf(p->out, "%s", p->rowSeparator);
}
setTextMode(p->out, 1);
break;
}
- case MODE_Quote:
case MODE_Insert: {
if( azArg==0 ) break;
- if( p->cMode==MODE_Insert ){
- utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
- if( p->showHeader ){
- raw_printf(p->out,"(");
- for(i=0; i0 ? ",": "";
- utf8_printf(p->out, "%s%s", zSep, azCol[i]);
- }
- raw_printf(p->out,")");
- }
- raw_printf(p->out," VALUES(");
- }else if( p->cnt==0 && p->showHeader ){
+ utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
+ if( p->showHeader ){
+ raw_printf(p->out,"(");
+ for(i=0; i0 ) raw_printf(p->out, ",");
+ if( quoteChar(azCol[i]) ){
+ char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
+ utf8_printf(p->out, "%s", z);
+ sqlite3_free(z);
+ }else{
+ raw_printf(p->out, "%s", azCol[i]);
+ }
+ }
+ raw_printf(p->out,")");
+ }
+ p->cnt++;
+ for(i=0; iout, i>0 ? "," : " VALUES(");
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ utf8_printf(p->out,"NULL");
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ output_quoted_escaped_string(p->out, azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_INTEGER ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_hex_blob(p->out, pBlob, nBlob);
+ }else if( isNumber(azArg[i], 0) ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else{
+ output_quoted_escaped_string(p->out, azArg[i]);
+ }
+ }
+ raw_printf(p->out,");\n");
+ break;
+ }
+ case MODE_Quote: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 && p->showHeader ){
for(i=0; i0 ) raw_printf(p->out, ",");
output_quoted_string(p->out, azCol[i]);
}
raw_printf(p->out,"\n");
}
p->cnt++;
for(i=0; i0 ? ",": "";
+ if( i>0 ) raw_printf(p->out, ",");
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- utf8_printf(p->out,"%sNULL",zSep);
+ utf8_printf(p->out,"NULL");
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
output_quoted_string(p->out, azArg[i]);
- }else if( aiType && (aiType[i]==SQLITE_INTEGER
- || aiType[i]==SQLITE_FLOAT) ){
- utf8_printf(p->out,"%s%s",zSep, azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_INTEGER ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
int nBlob = sqlite3_column_bytes(p->pStmt, i);
- if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
output_hex_blob(p->out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- utf8_printf(p->out,"%s%s",zSep, azArg[i]);
+ utf8_printf(p->out,"%s", azArg[i]);
}else{
- if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
output_quoted_string(p->out, azArg[i]);
}
}
- raw_printf(p->out,p->cMode==MODE_Quote?"\n":");\n");
+ raw_printf(p->out,"\n");
break;
}
case MODE_Ascii: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; in ) appendText(p, "|", 0);
for(i=0; inCol ){
/* At this point, we know that azRowid[j] is not the name of any
** ordinary column in the table. Verify that azRowid[j] is a valid
** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
** tables will fail this last check */
- int rc;
rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
break;
}
}
@@ -2933,18 +3160,18 @@
** This is a different callback routine used for dumping the database.
** Each row received by this callback consists of a table name,
** the table type ("index" or "table") and SQL to create the table.
** This routine should print text sufficient to recreate the table.
*/
-static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
+static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
int rc;
const char *zTable;
const char *zType;
const char *zSql;
ShellState *p = (ShellState *)pArg;
- UNUSED_PARAMETER(azCol);
+ UNUSED_PARAMETER(azNotUsed);
if( nArg!=3 ) return 1;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
@@ -3086,10 +3313,11 @@
".auth ON|OFF Show authorizer callbacks\n"
#endif
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
".bail on|off Stop after hitting an error. Default OFF\n"
".binary on|off Turn binary output on or off. Default OFF\n"
+ ".cd DIRECTORY Change the working directory to DIRECTORY\n"
".changes on|off Show number of rows changed by SQL\n"
".check GLOB Fail if output since .testcase does not match\n"
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
".dbinfo ?DB? Show status information about the database\n"
@@ -3131,12 +3359,12 @@
" quote Escape answers as for SQL\n"
" tabs Tab-separated values\n"
" tcl TCL list elements\n"
".nullvalue STRING Use STRING in place of NULL values\n"
".once FILENAME Output for the next SQL command only to FILENAME\n"
- ".open ?--new? ?FILE? Close existing database and reopen FILE\n"
- " The --new starts with an empty file\n"
+ ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
+ " The --new option starts with an empty file\n"
".output ?FILENAME? Send output to FILENAME or stdout\n"
".print STRING... Print literal STRING\n"
".prompt MAIN CONTINUE Replace the standard prompts\n"
".quit Exit this program\n"
".read FILENAME Execute SQL in FILENAME\n"
@@ -3143,10 +3371,11 @@
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
".save FILE Write in-memory database into FILE\n"
".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
".schema ?PATTERN? Show the CREATE statements matching PATTERN\n"
" Add --indent for pretty-printing\n"
+ ".selftest ?--init? Run tests defined in the SELFTEST table\n"
".separator COL ?ROW? Change the column separator and optionally the row\n"
" separator for both the output mode and .import\n"
#if defined(SQLITE_ENABLE_SESSION)
".session CMD ... Create or control sessions\n"
#endif
@@ -3196,12 +3425,12 @@
/* Forward reference */
static int process_input(ShellState *p, FILE *in);
/*
** Read the content of file zName into memory obtained from sqlite3_malloc64()
-** and return a pointer to the buffer. The caller is responsible for freeing
-** the memory.
+** and return a pointer to the buffer. The caller is responsible for freeing
+** the memory.
**
** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
** read.
**
** For convenience, a nul-terminator byte is always appended to the data read
@@ -3360,10 +3589,13 @@
sha3Func, 0, 0);
sqlite3_create_function(p->db, "sha3_query", 1, SQLITE_UTF8, 0,
sha3QueryFunc, 0, 0);
sqlite3_create_function(p->db, "sha3_query", 2, SQLITE_UTF8, 0,
sha3QueryFunc, 0, 0);
+ sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,
+ shellAddSchemaName, 0, 0);
+
}
}
/*
** Do C-language style dequoting.
@@ -4204,19 +4436,19 @@
** the child table name and the child column name.
**
** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
**
** If either of the named tables or columns do not exist, this function
-** returns an empty string. An empty string is also returned if both tables
+** returns an empty string. An empty string is also returned if both tables
** and columns exist but have the same default collation sequence. Or,
** if both exist but the default collation sequences are different, this
** function returns the string " COLLATE ", where
** is the default collation sequence of the parent column.
*/
static void shellFkeyCollateClause(
- sqlite3_context *pCtx,
- int nVal,
+ sqlite3_context *pCtx,
+ int nVal,
sqlite3_value **apVal
){
sqlite3 *db = sqlite3_context_db_handle(pCtx);
const char *zParent;
const char *zParentCol;
@@ -4223,11 +4455,11 @@
const char *zParentSeq;
const char *zChild;
const char *zChildCol;
const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
int rc;
-
+
assert( nVal==4 );
zParent = (const char*)sqlite3_value_text(apVal[0]);
zParentCol = (const char*)sqlite3_value_text(apVal[1]);
zChild = (const char*)sqlite3_value_text(apVal[2]);
zChildCol = (const char*)sqlite3_value_text(apVal[3]);
@@ -4304,33 +4536,34 @@
*/
const char *zSql =
"SELECT "
" 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '"
" || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
- " || fkey_collate_clause(f.[table], f.[to], s.name, f.[from]),' AND ')"
+ " || fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
", "
" 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
" || group_concat('*=?', ' AND ') || ')'"
", "
" s.name || '(' || group_concat(f.[from], ', ') || ')'"
", "
- " f.[table] || '(' || group_concat(COALESCE(f.[to], "
- " (SELECT name FROM pragma_table_info(f.[table]) WHERE pk=seq+1)"
- " )) || ')'"
+ " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
", "
" 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
" || ' ON ' || quote(s.name) || '('"
" || group_concat(quote(f.[from]) ||"
- " fkey_collate_clause(f.[table], f.[to], s.name, f.[from]), ', ')"
+ " fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
" || ');'"
", "
" f.[table] "
-
"FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
+ "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
"GROUP BY s.name, f.id "
"ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
;
+ const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
for(i=2; i1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
bVerbose = 1;
@@ -4344,11 +4577,11 @@
azArg[0], azArg[1]
);
return SQLITE_ERROR;
}
}
-
+
/* Register the fkey_collate_clause() SQL function */
rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
0, shellFkeyCollateClause, 0, 0
);
@@ -4375,32 +4608,35 @@
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc!=SQLITE_OK ) break;
if( SQLITE_ROW==sqlite3_step(pExplain) ){
const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
- res = (0==sqlite3_strglob(zGlob, zPlan));
+ res = (
+ 0==sqlite3_strglob(zGlob, zPlan)
+ || 0==sqlite3_strglob(zGlobIPK, zPlan)
+ );
}
rc = sqlite3_finalize(pExplain);
if( rc!=SQLITE_OK ) break;
if( res<0 ){
raw_printf(stderr, "Error: internal error");
break;
}else{
- if( bGroupByParent
+ if( bGroupByParent
&& (bVerbose || res==0)
- && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
+ && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
){
raw_printf(out, "-- Parent table %s\n", zParent);
sqlite3_free(zPrev);
zPrev = sqlite3_mprintf("%s", zParent);
}
if( res==0 ){
raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
}else if( bVerbose ){
- raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
+ raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
zIndent, zFrom, zTarget
);
}
}
}
@@ -4577,10 +4813,29 @@
}else{
raw_printf(stderr, "Usage: .binary on|off\n");
rc = 1;
}
}else
+
+ if( c=='c' && strcmp(azArg[0],"cd")==0 ){
+ if( nArg==2 ){
+#if defined(_WIN32) || defined(WIN32)
+ wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
+ rc = !SetCurrentDirectoryW(z);
+ sqlite3_free(z);
+#else
+ rc = chdir(azArg[1]);
+#endif
+ if( rc ){
+ utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
+ rc = 1;
+ }
+ }else{
+ raw_printf(stderr, "Usage: .cd DIRECTORY\n");
+ rc = 1;
+ }
+ }else
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
@@ -4653,17 +4908,25 @@
}else
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
const char *zLike = 0;
int i;
+ int savedShowHeader = p->showHeader;
ShellClearFlag(p, SHFLG_PreserveRowid);
for(i=1; iout, "PRAGMA foreign_keys=OFF;\n");
raw_printf(p->out, "BEGIN TRANSACTION;\n");
p->writableSchema = 0;
+ p->showHeader = 0;
/* Set writable_schema=ON since doing so forces SQLite to initialize
** as much of the schema as it can even if the sqlite_master table is
** corrupt. */
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
p->nErr = 0;
@@ -4722,10 +4986,11 @@
p->writableSchema = 0;
}
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
+ p->showHeader = savedShowHeader;
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
if( nArg==2 ){
setOrClearFlag(p, SHFLG_Echo, azArg[1]);
@@ -5480,16 +5745,21 @@
rc = 1;
}
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+ ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
+ const char *zDiv = 0;
+ int iSchema = 0;
+
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
+ initText(&sSelect);
if( nArg>=2 && optionMatch(azArg[1], "indent") ){
data.cMode = data.mode = MODE_Pretty;
nArg--;
if( nArg==2 ) azArg[1] = azArg[2];
}
@@ -5523,37 +5793,66 @@
new_colv[0] = "sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
rc = SQLITE_OK;
}else{
- char *zSql;
- zSql = sqlite3_mprintf(
- "SELECT sql FROM "
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE lower(tbl_name) LIKE %Q"
- " AND type!='meta' AND sql NOTNULL "
- "ORDER BY rowid", azArg[1]);
- rc = sqlite3_exec(p->db, zSql, callback, &data, &zErrMsg);
- sqlite3_free(zSql);
+ zDiv = "(";
}
}else if( nArg==1 ){
- rc = sqlite3_exec(p->db,
- "SELECT sql FROM "
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
- "ORDER BY rowid",
- callback, &data, &zErrMsg
- );
+ zDiv = "(";
}else{
raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
}
+ if( zDiv ){
+ sqlite3_stmt *pStmt = 0;
+ sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
+ -1, &pStmt, 0);
+ appendText(&sSelect, "SELECT sql FROM", 0);
+ iSchema = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
+ char zScNum[30];
+ sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
+ appendText(&sSelect, zDiv, 0);
+ zDiv = " UNION ALL ";
+ if( strcmp(zDb, "main")!=0 ){
+ appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ") AS sql, type, tbl_name, name, rowid,", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, ", 0);
+ appendText(&sSelect, zDb, '\'');
+ appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ".sqlite_master", 0);
+ }else{
+ appendText(&sSelect, "SELECT sql, type, tbl_name, name, rowid, ", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, 'main' AS sname FROM sqlite_master",0);
+ }
+ }
+ sqlite3_finalize(pStmt);
+ appendText(&sSelect, ") WHERE ", 0);
+ if( nArg>1 ){
+ char *zQarg = sqlite3_mprintf("%Q", azArg[1]);
+ if( strchr(azArg[1], '.') ){
+ appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
+ }else{
+ appendText(&sSelect, "lower(tbl_name)", 0);
+ }
+ appendText(&sSelect, strchr(azArg[1], '*') ? " GLOB " : " LIKE ", 0);
+ appendText(&sSelect, zQarg, 0);
+ appendText(&sSelect, " AND ", 0);
+ sqlite3_free(zQarg);
+ }
+ appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
+ " ORDER BY snum, rowid", 0);
+ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ freeText(&sSelect);
+ }
if( zErrMsg ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}else if( rc != SQLITE_OK ){
@@ -5791,23 +6090,15 @@
if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
int bIsInit = 0; /* True to initialize the SELFTEST table */
int bVerbose = 0; /* Verbose output */
int bSelftestExists; /* True if SELFTEST already exists */
- char **azTest = 0; /* Content of the SELFTEST table */
- int nRow = 0; /* Number of rows in the SELFTEST table */
- int nCol = 4; /* Number of columns in the SELFTEST table */
- int i; /* Loop counter */
+ int i, k; /* Loop counters */
int nTest = 0; /* Number of tests runs */
int nErr = 0; /* Number of errors seen */
ShellText str; /* Answer for a query */
- static char *azDefaultTest[] = {
- 0, 0, 0, 0,
- "0", "memo", "Missing SELFTEST table - default checks only", "",
- "1", "run", "PRAGMA integrity_check", "ok"
- };
- static const int nDefaultRow = 2;
+ sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
open_db(p,0);
for(i=1; idb,
- "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
- &azTest, &nRow, &nCol, 0);
+ initText(&str);
+ appendText(&str, "x", 0);
+ for(k=bSelftestExists; k>=0; k--){
+ if( k==1 ){
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
+ -1, &pStmt, 0);
+ }else{
+ rc = sqlite3_prepare_v2(p->db,
+ "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
+ " (1,'run','PRAGMA integrity_check','ok')",
+ -1, &pStmt, 0);
+ }
if( rc ){
raw_printf(stderr, "Error querying the selftest table\n");
rc = 1;
- sqlite3_free_table(azTest);
- goto meta_command_exit;
- }else if( nRow==0 ){
- sqlite3_free_table(azTest);
- azTest = azDefaultTest;
- nRow = nDefaultRow;
- }
- }else{
- azTest = azDefaultTest;
- nRow = nDefaultRow;
- }
- initText(&str);
- appendText(&str, "x", 0);
- for(i=1; i<=nRow; i++){
- int tno = atoi(azTest[i*nCol]);
- const char *zOp = azTest[i*nCol+1];
- const char *zSql = azTest[i*nCol+2];
- const char *zAns = azTest[i*nCol+3];
-
- if( bVerbose>0 ){
- char *zQuote = sqlite3_mprintf("%q", zSql);
- printf("%d: %s %s\n", tno, zOp, zSql);
- sqlite3_free(zQuote);
- }
- if( strcmp(zOp,"memo")==0 ){
- utf8_printf(p->out, "%s\n", zSql);
- }else
- if( strcmp(zOp,"run")==0 ){
- char *zErrMsg = 0;
- str.n = 0;
- str.z[0] = 0;
- rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
- nTest++;
- if( bVerbose ){
- utf8_printf(p->out, "Result: %s\n", str.z);
- }
- if( rc || zErrMsg ){
- nErr++;
- rc = 1;
- utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
- sqlite3_free(zErrMsg);
- }else if( strcmp(zAns,str.z)!=0 ){
- nErr++;
- rc = 1;
- utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
- utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
- }
- }else
- {
- utf8_printf(stderr,
- "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
- rc = 1;
- break;
- }
- }
- freeText(&str);
- if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
+ sqlite3_finalize(pStmt);
+ goto meta_command_exit;
+ }
+ for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
+ int tno = sqlite3_column_int(pStmt, 0);
+ const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
+ const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
+ const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
+
+ k = 0;
+ if( bVerbose>0 ){
+ char *zQuote = sqlite3_mprintf("%q", zSql);
+ printf("%d: %s %s\n", tno, zOp, zSql);
+ sqlite3_free(zQuote);
+ }
+ if( strcmp(zOp,"memo")==0 ){
+ utf8_printf(p->out, "%s\n", zSql);
+ }else
+ if( strcmp(zOp,"run")==0 ){
+ char *zErrMsg = 0;
+ str.n = 0;
+ str.z[0] = 0;
+ rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
+ nTest++;
+ if( bVerbose ){
+ utf8_printf(p->out, "Result: %s\n", str.z);
+ }
+ if( rc || zErrMsg ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ sqlite3_free(zErrMsg);
+ }else if( strcmp(zAns,str.z)!=0 ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
+ utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
+ }
+ }else
+ {
+ utf8_printf(stderr,
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
+ rc = 1;
+ break;
+ }
+ } /* End loop over rows of content from SELFTEST */
+ sqlite3_finalize(pStmt);
+ } /* End loop over k */
+ freeText(&str);
utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
}else
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
if( nArg<2 || nArg>3 ){
@@ -5936,12 +6228,12 @@
z++;
if( z[0]=='-' ) z++;
if( strcmp(z,"schema")==0 ){
bSchema = 1;
}else
- if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
- || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
+ if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
+ || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
){
iSize = atoi(&z[5]);
}else
if( strcmp(z,"debug")==0 ){
bDebug = 1;
@@ -6105,63 +6397,51 @@
|| strncmp(azArg[0], "indexes", n)==0) )
){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
- char *zSql = 0;
int ii;
+ ShellText s;
+ initText(&s);
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ) return shellDatabaseError(p->db);
- /* Create an SQL statement to query for the list of tables in the
- ** main and all attached databases where the table name matches the
- ** LIKE pattern bound to variable "?1". */
- if( c=='t' ){
- zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1");
- }else if( nArg>2 ){
+ if( nArg>2 && c=='i' ){
/* It is an historical accident that the .indexes command shows an error
** when called with the wrong number of arguments whereas the .tables
** command does not. */
raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
- }else{
- zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_master"
- " WHERE type='index'"
- " AND tbl_name LIKE ?1");
}
- for(ii=0; zSql && sqlite3_step(pStmt)==SQLITE_ROW; ii++){
+ for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
- if( zDbName==0 || ii==0 ) continue;
+ if( zDbName==0 ) continue;
+ if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
+ if( sqlite3_stricmp(zDbName, "main")==0 ){
+ appendText(&s, "SELECT name FROM ", 0);
+ }else{
+ appendText(&s, "SELECT ", 0);
+ appendText(&s, zDbName, '\'');
+ appendText(&s, "||'.'||name FROM ", 0);
+ }
+ appendText(&s, zDbName, '"');
+ appendText(&s, ".sqlite_master ", 0);
if( c=='t' ){
- zSql = sqlite3_mprintf(
- "%z UNION ALL "
- "SELECT '%q.' || name FROM \"%w\".sqlite_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1", zSql, zDbName, zDbName);
+ appendText(&s," WHERE type IN ('table','view')"
+ " AND name NOT LIKE 'sqlite_%'"
+ " AND name LIKE ?1", 0);
}else{
- zSql = sqlite3_mprintf(
- "%z UNION ALL "
- "SELECT '%q.' || name FROM \"%w\".sqlite_master"
- " WHERE type='index'"
- " AND tbl_name LIKE ?1", zSql, zDbName, zDbName);
+ appendText(&s," WHERE type='index'"
+ " AND tbl_name LIKE ?1", 0);
}
}
rc = sqlite3_finalize(pStmt);
- if( zSql && rc==SQLITE_OK ){
- zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
- if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- }
- sqlite3_free(zSql);
- if( !zSql ) return shellNomemError();
+ appendText(&s, " ORDER BY 1", 0);
+ rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
+ freeText(&s);
if( rc ) return shellDatabaseError(p->db);
/* Run the SQL statement prepared by the above block. Store the results
** as an array of nul-terminated strings in azResult[]. */
nRow = nAlloc = 0;
Index: src/shun.c
==================================================================
--- src/shun.c
+++ src/shun.c
@@ -308,10 +308,11 @@
void rcvfromlist_page(void){
int ofst = atoi(PD("ofst","0"));
int showAll = P("all")!=0;
int cnt;
Stmt q;
+ const int perScreen = 500; /* RCVIDs per page */
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
@@ -322,27 +323,39 @@
}else{
style_submenu_element("All", "rcvfromlist?all=1");
}
if( ofst>0 ){
style_submenu_element("Newer", "rcvfromlist?ofst=%d",
- ofst>30 ? ofst-30 : 0);
+ ofst>perScreen ? ofst-perScreen : 0);
}
db_multi_exec(
"CREATE TEMP TABLE rcvidUsed(x INTEGER PRIMARY KEY);"
+ "CREATE TEMP TABLE rcvidSha1(x INTEGER PRIMARY KEY);"
+ "CREATE TEMP TABLE rcvidSha3(x INTEGER PRIMARY KEY);"
"INSERT OR IGNORE INTO rcvidUsed(x) SELECT rcvid FROM blob;"
+ "INSERT OR IGNORE INTO rcvidSha1(x)"
+ " SELECT rcvid FROM blob WHERE length(uuid)==40;"
+ "INSERT OR IGNORE INTO rcvidSha3(x)"
+ " SELECT rcvid FROM blob WHERE length(uuid)==64;"
);
if( db_table_exists("repository","unversioned") ){
db_multi_exec(
"INSERT OR IGNORE INTO rcvidUsed(x) SELECT rcvid FROM unversioned;"
+ "INSERT OR IGNORE INTO rcvidSha1(x)"
+ " SELECT rcvid FROM unversioned WHERE length(hash)==40;"
+ "INSERT OR IGNORE INTO rcvidSha3(x)"
+ " SELECT rcvid FROM unversioned WHERE length(hash)==64;"
);
}
db_prepare(&q,
"SELECT rcvid, login, datetime(rcvfrom.mtime), rcvfrom.ipaddr,"
- " EXISTS(SELECT 1 FROM rcvidUsed WHERE x=rcvfrom.rcvid)"
+ " EXISTS(SELECT 1 FROM rcvidUsed WHERE x=rcvfrom.rcvid),"
+ " EXISTS(SELECT 1 FROM rcvidSha1 WHERE x=rcvfrom.rcvid),"
+ " EXISTS(SELECT 1 FROM rcvidSha3 WHERE x=rcvfrom.rcvid)"
" FROM rcvfrom LEFT JOIN user USING(uid)"
" ORDER BY rcvid DESC LIMIT %d OFFSET %d",
- showAll ? -1 : 31, ofst
+ showAll ? -1 : perScreen+1, ofst
);
@ Whenever new artifacts are added to the repository, either by
@ push or using the web interface, an entry is made in the RCVFROM table
@ to record the source of that artifact. This log facilitates
@ finding and fixing attempts to inject illicit content into the
@@ -356,19 +369,24 @@
@
@
@ rcvid |
@ Date |
@ User |
+ @ Hash |
@ IP Address |
cnt = 0;
while( db_step(&q)==SQLITE_ROW ){
int rcvid = db_column_int(&q, 0);
const char *zUser = db_column_text(&q, 1);
const char *zDate = db_column_text(&q, 2);
const char *zIpAddr = db_column_text(&q, 3);
- if( cnt==30 && !showAll ){
- style_submenu_element("Older", "rcvfromlist?ofst=%d", ofst+30);
+ int usesSha1 = db_column_int(&q, 5)!=0;
+ int usesSha3 = db_column_int(&q, 6)!=0;
+ static const char *zHashType[] = { "", "sha1", "sha3", "both" };
+ const char *zHash = zHashType[usesSha1+usesSha3*2];
+ if( cnt==perScreen && !showAll ){
+ style_submenu_element("Older", "rcvfromlist?ofst=%d", ofst+perScreen);
}else{
cnt++;
@
if( db_column_int(&q,4) ){
@
@@ -376,10 +394,11 @@
}else{
@ | %d(rcvid) |
}
@ %s(zDate) |
@ %h(zUser) |
+ @ %s(zHash) |
@ %s(zIpAddr) |
@
}
}
db_finalize(&q);
Index: src/skins.c
==================================================================
--- src/skins.c
+++ src/skins.c
@@ -157,10 +157,20 @@
fossil_free(z);
}
}
return zOut;
}
+
+/*
+** Return the command-line option used to set the skin, or return NULL
+** if the default skin is being used.
+*/
+const char *skin_in_use(void){
+ if( zAltSkinDir ) return zAltSkinDir;
+ if( pAltSkin ) return pAltSkin->zLabel;
+ return 0;
+}
/*
** Return a pointer to a SkinDetail element. Return 0 if not found.
*/
static struct SkinDetail *skin_detail_find(const char *zName){
Index: src/sqlcmd.c
==================================================================
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -20,10 +20,11 @@
** is a copy of the "shell.c" code from SQLite. This file contains logic
** to initialize the code in shell.c.
*/
#include "config.h"
#include "sqlcmd.h"
+#include /* atexit() */
#if defined(FOSSIL_ENABLE_MINIZ)
# define MINIZ_HEADER_FILE_ONLY
# include "miniz.c"
#else
# include
@@ -150,22 +151,82 @@
search_sql_setup(db);
foci_register(db);
g.repositoryOpen = 1;
g.db = db;
sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "repository");
+ db_maybe_set_encryption_key(db, g.zRepositoryName);
if( g.zLocalDbName ){
- char *zSql = sqlite3_mprintf("ATTACH %Q AS 'localdb'", g.zLocalDbName);
+ char *zSql = sqlite3_mprintf("ATTACH %Q AS 'localdb' KEY ''",
+ g.zLocalDbName);
sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
if( g.zConfigDbName ){
- char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb'", g.zConfigDbName);
+ char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
+ g.zConfigDbName);
sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
return SQLITE_OK;
}
+
+/*
+** atexit() handler that cleans up global state modified by this module.
+*/
+static void sqlcmd_atexit(void) {
+ g.zConfigDbName = 0; /* prevent panic */
+}
+
+/*
+** This routine is called by the patched sqlite3 command-line shell in order
+** to load the name and database connection for the open Fossil database.
+*/
+void fossil_open(const char **pzRepoName){
+ sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit);
+ *pzRepoName = g.zRepositoryName;
+}
+
+#if USE_SEE
+/*
+** This routine is called by the patched sqlite3 command-line shell in order
+** to load the encryption key for the open Fossil database. The memory that
+** is pointed to by the value placed in pzKey must be obtained from SQLite.
+*/
+void fossil_key(const char **pzKey, int *pnKey){
+ char *zSavedKey = db_get_saved_encryption_key();
+ char *zKey;
+ size_t savedKeySize = db_get_saved_encryption_key_size();
+ size_t nByte;
+
+ if( zSavedKey==0 || savedKeySize==0 ) return;
+ nByte = savedKeySize * sizeof(char);
+ zKey = sqlite3_malloc( (int)nByte );
+ if( zKey ){
+ memcpy(zKey, zSavedKey, nByte);
+ *pzKey = zKey;
+ if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
+ *pnKey = (int)strlen(zKey);
+ }else{
+ *pnKey = -1;
+ }
+ }else{
+ fossil_fatal("failed to allocate %u bytes for key", nByte);
+ }
+}
+#endif
+
+/*
+** This routine closes the Fossil databases and/or invalidates the global
+** state variables that keep track of them.
+*/
+static void fossil_close(int bDb, int noRepository){
+ if( bDb ) db_close(1);
+ if( noRepository ) g.zRepositoryName = 0;
+ g.db = 0;
+ g.repositoryOpen = 0;
+ g.localOpen = 0;
+}
/*
** COMMAND: sqlite3
**
** Usage: %fossil sql ?OPTIONS?
@@ -226,31 +287,11 @@
fossil_close(1, noRepository);
sqlite3_shutdown();
#ifndef _WIN32
linenoiseSetMultiLine(1);
#endif
+ atexit(sqlcmd_atexit);
g.zConfigDbName = zConfigDb;
sqlite3_shell(g.argc-1, g.argv+1);
sqlite3_cancel_auto_extension((void(*)(void))sqlcmd_autoinit);
fossil_close(0, noRepository);
}
-
-/*
-** This routine is called by the patched sqlite3 command-line shell in order
-** to load the name and database connection for the open Fossil database.
-*/
-void fossil_open(const char **pzRepoName){
- sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit);
- *pzRepoName = g.zRepositoryName;
-}
-
-/*
-** This routine closes the Fossil databases and/or invalidates the global
-** state variables that keep track of them.
-*/
-void fossil_close(int bDb, int noRepository){
- if( bDb ) db_close(1);
- if( noRepository ) g.zRepositoryName = 0;
- g.db = 0;
- g.repositoryOpen = 0;
- g.localOpen = 0;
-}
Index: src/sqlite3.c
==================================================================
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.18.0. By combining all the individual C code files into this
+** version 3.20.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
** of 5% or more are commonly seen when SQLite is compiled as a single
** translation unit.
@@ -389,20 +389,20 @@
** SQLite source code has been stored in the
** Fossil configuration management
** system. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
-** string contains the date and time of the check-in (UTC) and an SHA1
-** hash of the entire source tree.
+** string contains the date and time of the check-in (UTC) and a SHA1
+** or SHA3-256 hash of the entire source tree.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.18.0"
-#define SQLITE_VERSION_NUMBER 3018000
-#define SQLITE_SOURCE_ID "2017-03-10 17:03:11 f8560c60d10c0365b33342ab05b5a953987b0471"
+#define SQLITE_VERSION "3.20.0"
+#define SQLITE_VERSION_NUMBER 3020000
+#define SQLITE_SOURCE_ID "2017-06-15 13:07:56 9afd7a2ffd3a39456190ad05e85ff6485298aae262d9e0698a58c1d73507a36f"
/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
@@ -1132,11 +1132,11 @@
** of 25 milliseconds before the first retry and with the delay increasing
** by an additional 25 milliseconds with each subsequent retry. This
** opcode allows these two values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
-** integers where the first integer i the new retry count and the second
+** integers where the first integer is the new retry count and the second
** integer is the delay. If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
** interrogated. The zDbName parameter is ignored.
**
@@ -2486,13 +2486,10 @@
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
-**
-** If the database connection closes while [sqlite3_interrupt()]
-** is running then bad things will likely happen.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2951,10 +2948,11 @@
SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
** METHOD: sqlite3
+** KEYWORDS: {authorizer callback}
**
** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
** ^The authorizer callback is invoked as SQL statements are being compiled
** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
@@ -2978,20 +2976,26 @@
**
** ^The first parameter to the authorizer callback is a copy of the third
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
** to the callback is an integer [SQLITE_COPY | action code] that specifies
** the particular action to be authorized. ^The third through sixth parameters
-** to the callback are zero-terminated strings that contain additional
-** details about the action to be authorized.
+** to the callback are either NULL pointers or zero-terminated strings
+** that contain additional details about the action to be authorized.
+** Applications must always be prepared to encounter a NULL pointer in any
+** of the third through the sixth parameters of the authorization callback.
**
** ^If the action code is [SQLITE_READ]
** and the callback returns [SQLITE_IGNORE] then the
** [prepared statement] statement is constructed to substitute
** a NULL value in place of the table column that would have
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
** return can be used to deny an untrusted user access to individual
** columns of a table.
+** ^When a table is referenced by a [SELECT] but no column values are
+** extracted from that table (for example in a query like
+** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
+** is invoked once for that table with a column name that is an empty string.
** ^If the action code is [SQLITE_DELETE] and the callback returns
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
** [truncate optimization] is disabled and all rows are deleted individually.
**
** An authorizer is used when [sqlite3_prepare | preparing]
@@ -3699,13 +3703,13 @@
** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(SQLITE_LIMIT_COMPOUND_SELECT
** The maximum number of terms in a compound SELECT statement.)^
**
** [[SQLITE_LIMIT_VDBE_OP]] ^(SQLITE_LIMIT_VDBE_OP
** The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement. This limit is not currently
-** enforced, though that might be added in some future release of
-** SQLite.)^
+** used to implement an SQL statement. If [sqlite3_prepare_v2()] or
+** the equivalent tries to allocate space for more than this many opcodes
+** in a single prepared statement, an SQLITE_NOMEM error is returned.)^
**
** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(SQLITE_LIMIT_FUNCTION_ARG
** The maximum number of arguments on a function.)^
**
** [[SQLITE_LIMIT_ATTACHED]] ^(SQLITE_LIMIT_ATTACHED
@@ -3738,10 +3742,11 @@
#define SQLITE_LIMIT_ATTACHED 7
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
#define SQLITE_LIMIT_WORKER_THREADS 11
+
/*
** CAPI3REF: Compiling An SQL Statement
** KEYWORDS: {SQL statement compiler}
** METHOD: sqlite3
@@ -3979,11 +3984,11 @@
** Unprotected sqlite3_value objects may only be used with
** [sqlite3_result_value()] and [sqlite3_bind_value()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
-typedef struct Mem sqlite3_value;
+typedef struct sqlite3_value sqlite3_value;
/*
** CAPI3REF: SQL Function Context Object
**
** The context in which an SQL function executes is stored in an
@@ -5033,14 +5038,15 @@
** metadata associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function. ^If there is no metadata
-** associated with the function argument, this sqlite3_get_auxdata() interface
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
+** value to the application-defined function. ^N is zero for the left-most
+** function argument. ^If there is no metadata
+** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
** argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
@@ -5066,10 +5072,14 @@
** sqlite3_set_auxdata() has been called.
**
** ^(In practice, metadata is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
+**
+** The value of the N parameter to these interfaces should be non-negative.
+** Future enhancements may make use of negative N values to define new
+** kinds of function caching behavior.
**
** These routines must be called from the same thread in which
** the SQL function is running.
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5885,11 +5895,13 @@
** column exists. ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
-** does not.
+** does not. If the table name parameter T in a call to
+** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
+** undefined behavior.
**
** ^The column is identified by the second, third and fourth parameters to
** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
** table or NULL.)^ ^If it is NULL, then all attached databases are searched
@@ -7398,17 +7410,24 @@
** by the prepared statement if that number is less than or equal
** to 2147483647. The number of virtual machine operations can be
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
+**
+** [[SQLITE_STMTSTATUS_MEMUSED]] SQLITE_STMTSTATUS_MEMUSED
+** ^This is the approximate number of bytes of heap memory
+** used to store the prepared statement. ^This value is not actually
+** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
+** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
**
**
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
#define SQLITE_STMTSTATUS_VM_STEP 4
+#define SQLITE_STMTSTATUS_MEMUSED 5
/*
** CAPI3REF: Custom Page Cache Object
**
** The sqlite3_pcache type is opaque. It is implemented by
@@ -9661,11 +9680,11 @@
**
** As well as the regular sqlite3changegroup_add() and
** sqlite3changegroup_output() functions, also available are the streaming
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
*/
-int sqlite3changegroup_new(sqlite3_changegroup **pp);
+SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add A Changeset To A Changegroup
**
** Add all changes within the changeset (or patchset) in buffer pData (size
@@ -9738,11 +9757,11 @@
** function returns SQLITE_NOMEM. In all cases, if an error occurs the
** final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
-int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
+SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
**
** Obtain a buffer containing a changeset (or patchset) representing the
@@ -9764,20 +9783,20 @@
** is returned and the output variables are set to the size of and a
** pointer to the output buffer, respectively. In this case it is the
** responsibility of the caller to eventually free the buffer using a
** call to sqlite3_free().
*/
-int sqlite3changegroup_output(
+SQLITE_API int sqlite3changegroup_output(
sqlite3_changegroup*,
int *pnData, /* OUT: Size of output buffer in bytes */
void **ppData /* OUT: Pointer to output buffer */
);
/*
** CAPI3REF: Delete A Changegroup Object
*/
-void sqlite3changegroup_delete(sqlite3_changegroup*);
+SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
/*
** CAPI3REF: Apply A Changeset To A Database
**
** Apply a changeset to a database. This function attempts to update the
@@ -10162,15 +10181,15 @@
SQLITE_API int sqlite3session_patchset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changegroup_add_strm(sqlite3_changegroup*,
+SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
-int sqlite3changegroup_output_strm(sqlite3_changegroup*,
+SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
@@ -10866,11 +10885,11 @@
/*
** The maximum number of opcodes in a VDBE program.
** Not currently enforced.
*/
#ifndef SQLITE_MAX_VDBE_OP
-# define SQLITE_MAX_VDBE_OP 25000
+# define SQLITE_MAX_VDBE_OP 250000000
#endif
/*
** The maximum number of arguments to an SQL function.
*/
@@ -11450,80 +11469,80 @@
#define TK_LP 22
#define TK_RP 23
#define TK_AS 24
#define TK_WITHOUT 25
#define TK_COMMA 26
-#define TK_OR 27
-#define TK_AND 28
-#define TK_IS 29
-#define TK_MATCH 30
-#define TK_LIKE_KW 31
-#define TK_BETWEEN 32
-#define TK_IN 33
-#define TK_ISNULL 34
-#define TK_NOTNULL 35
-#define TK_NE 36
-#define TK_EQ 37
-#define TK_GT 38
-#define TK_LE 39
-#define TK_LT 40
-#define TK_GE 41
-#define TK_ESCAPE 42
-#define TK_BITAND 43
-#define TK_BITOR 44
-#define TK_LSHIFT 45
-#define TK_RSHIFT 46
-#define TK_PLUS 47
-#define TK_MINUS 48
-#define TK_STAR 49
-#define TK_SLASH 50
-#define TK_REM 51
-#define TK_CONCAT 52
-#define TK_COLLATE 53
-#define TK_BITNOT 54
-#define TK_ID 55
-#define TK_INDEXED 56
-#define TK_ABORT 57
-#define TK_ACTION 58
-#define TK_AFTER 59
-#define TK_ANALYZE 60
-#define TK_ASC 61
-#define TK_ATTACH 62
-#define TK_BEFORE 63
-#define TK_BY 64
-#define TK_CASCADE 65
-#define TK_CAST 66
-#define TK_COLUMNKW 67
-#define TK_CONFLICT 68
-#define TK_DATABASE 69
-#define TK_DESC 70
-#define TK_DETACH 71
-#define TK_EACH 72
-#define TK_FAIL 73
-#define TK_FOR 74
-#define TK_IGNORE 75
-#define TK_INITIALLY 76
-#define TK_INSTEAD 77
-#define TK_NO 78
-#define TK_KEY 79
-#define TK_OF 80
-#define TK_OFFSET 81
-#define TK_PRAGMA 82
-#define TK_RAISE 83
-#define TK_RECURSIVE 84
-#define TK_REPLACE 85
-#define TK_RESTRICT 86
-#define TK_ROW 87
-#define TK_TRIGGER 88
-#define TK_VACUUM 89
-#define TK_VIEW 90
-#define TK_VIRTUAL 91
-#define TK_WITH 92
-#define TK_REINDEX 93
-#define TK_RENAME 94
-#define TK_CTIME_KW 95
-#define TK_ANY 96
+#define TK_ID 27
+#define TK_ABORT 28
+#define TK_ACTION 29
+#define TK_AFTER 30
+#define TK_ANALYZE 31
+#define TK_ASC 32
+#define TK_ATTACH 33
+#define TK_BEFORE 34
+#define TK_BY 35
+#define TK_CASCADE 36
+#define TK_CAST 37
+#define TK_COLUMNKW 38
+#define TK_CONFLICT 39
+#define TK_DATABASE 40
+#define TK_DESC 41
+#define TK_DETACH 42
+#define TK_EACH 43
+#define TK_FAIL 44
+#define TK_FOR 45
+#define TK_IGNORE 46
+#define TK_INITIALLY 47
+#define TK_INSTEAD 48
+#define TK_LIKE_KW 49
+#define TK_MATCH 50
+#define TK_NO 51
+#define TK_KEY 52
+#define TK_OF 53
+#define TK_OFFSET 54
+#define TK_PRAGMA 55
+#define TK_RAISE 56
+#define TK_RECURSIVE 57
+#define TK_REPLACE 58
+#define TK_RESTRICT 59
+#define TK_ROW 60
+#define TK_TRIGGER 61
+#define TK_VACUUM 62
+#define TK_VIEW 63
+#define TK_VIRTUAL 64
+#define TK_WITH 65
+#define TK_REINDEX 66
+#define TK_RENAME 67
+#define TK_CTIME_KW 68
+#define TK_ANY 69
+#define TK_OR 70
+#define TK_AND 71
+#define TK_IS 72
+#define TK_BETWEEN 73
+#define TK_IN 74
+#define TK_ISNULL 75
+#define TK_NOTNULL 76
+#define TK_NE 77
+#define TK_EQ 78
+#define TK_GT 79
+#define TK_LE 80
+#define TK_LT 81
+#define TK_GE 82
+#define TK_ESCAPE 83
+#define TK_BITAND 84
+#define TK_BITOR 85
+#define TK_LSHIFT 86
+#define TK_RSHIFT 87
+#define TK_PLUS 88
+#define TK_MINUS 89
+#define TK_STAR 90
+#define TK_SLASH 91
+#define TK_REM 92
+#define TK_CONCAT 93
+#define TK_COLLATE 94
+#define TK_BITNOT 95
+#define TK_INDEXED 96
#define TK_STRING 97
#define TK_JOIN_KW 98
#define TK_CONSTRAINT 99
#define TK_DEFAULT 100
#define TK_NULL 101
@@ -11583,14 +11602,15 @@
#define TK_UMINUS 155
#define TK_UPLUS 156
#define TK_REGISTER 157
#define TK_VECTOR 158
#define TK_SELECT_COLUMN 159
-#define TK_ASTERISK 160
-#define TK_SPAN 161
-#define TK_SPACE 162
-#define TK_ILLEGAL 163
+#define TK_IF_NULL_ROW 160
+#define TK_ASTERISK 161
+#define TK_SPAN 162
+#define TK_SPACE 163
+#define TK_ILLEGAL 164
/* The token codes above must all fit in 8 bits */
#define TKFLG_MASK 0xff
/* Flags that can be added to a token code when it is not
@@ -12457,23 +12477,23 @@
*/
struct BtreePayload {
const void *pKey; /* Key content for indexes. NULL for tables */
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
const void *pData; /* Data for tables. NULL for indexes */
- struct Mem *aMem; /* First of nMem value in the unpacked pKey */
+ sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */
u16 nMem; /* Number of aMem[] value. Might be zero */
int nData; /* Size of pData. 0 if none. */
int nZero; /* Extra zero data appended after pData,nData */
};
SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
int flags, int seekResult);
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes);
+SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes);
+SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
@@ -12587,11 +12607,11 @@
/*
** The names of the following types declared in vdbeInt.h are required
** for the VdbeOp definition.
*/
-typedef struct Mem Mem;
+typedef struct sqlite3_value Mem;
typedef struct SubProgram SubProgram;
/*
** A single instruction of the virtual machine has an opcode
** and as many as three operands. The instruction is recorded
@@ -12620,11 +12640,11 @@
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
- int (*xAdvance)(BtCursor *, int *);
+ int (*xAdvance)(BtCursor *, int);
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
@@ -12644,10 +12664,11 @@
struct SubProgram {
VdbeOp *aOp; /* Array of opcodes for sub-program */
int nOp; /* Elements in aOp[] */
int nMem; /* Number of memory cells required */
int nCsr; /* Number of cursors required */
+ u8 *aOnce; /* Array of OP_Once flags */
void *token; /* id that may be used to recursive triggers */
SubProgram *pNext; /* Next sub-program already visited */
};
/*
@@ -12746,151 +12767,153 @@
#define OP_Jump 18
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
#define OP_Once 20
#define OP_If 21
#define OP_IfNot 22
-#define OP_SeekLT 23 /* synopsis: key=r[P3@P4] */
-#define OP_SeekLE 24 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGE 25 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGT 26 /* synopsis: key=r[P3@P4] */
-#define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
-#define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */
-#define OP_NotFound 30 /* synopsis: key=r[P3@P4] */
-#define OP_Found 31 /* synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 32 /* synopsis: intkey=r[P3] */
-#define OP_NotExists 33 /* synopsis: intkey=r[P3] */
-#define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 36 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */
-#define OP_Eq 37 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */
-#define OP_Gt 38 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */
-#define OP_Le 39 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */
-#define OP_Lt 40 /* same as TK_LT, synopsis: IF r[P3]=r[P1] */
-#define OP_ElseNotEq 42 /* same as TK_ESCAPE */
-#define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */
-#define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_Last 53
-#define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
-#define OP_IfSmaller 55
-#define OP_SorterSort 56
-#define OP_Sort 57
-#define OP_Rewind 58
-#define OP_IdxLE 59 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGT 60 /* synopsis: key=r[P3@P4] */
-#define OP_IdxLT 61 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGE 62 /* synopsis: key=r[P3@P4] */
-#define OP_RowSetRead 63 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 64 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 65
-#define OP_FkIfZero 66 /* synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 67 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
-#define OP_IfNotZero 68 /* synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
-#define OP_DecrJumpZero 69 /* synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 70
-#define OP_VNext 71
-#define OP_Init 72 /* synopsis: Start at P2 */
-#define OP_Return 73
-#define OP_EndCoroutine 74
-#define OP_HaltIfNull 75 /* synopsis: if r[P3]=null halt */
-#define OP_Halt 76
-#define OP_Integer 77 /* synopsis: r[P2]=P1 */
-#define OP_Int64 78 /* synopsis: r[P2]=P4 */
-#define OP_String 79 /* synopsis: r[P2]='P4' (len=P1) */
-#define OP_Null 80 /* synopsis: r[P2..P3]=NULL */
-#define OP_SoftNull 81 /* synopsis: r[P1]=NULL */
-#define OP_Blob 82 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 83 /* synopsis: r[P2]=parameter(P1,P4) */
-#define OP_Move 84 /* synopsis: r[P2@P3]=r[P1@P3] */
-#define OP_Copy 85 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
-#define OP_SCopy 86 /* synopsis: r[P2]=r[P1] */
-#define OP_IntCopy 87 /* synopsis: r[P2]=r[P1] */
-#define OP_ResultRow 88 /* synopsis: output=r[P1@P2] */
-#define OP_CollSeq 89
-#define OP_Function0 90 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_Function 91 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_AddImm 92 /* synopsis: r[P1]=r[P1]+P2 */
-#define OP_RealAffinity 93
+#define OP_IfNullRow 23 /* synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT 24 /* synopsis: key=r[P3@P4] */
+#define OP_SeekLE 25 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGE 26 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGT 27 /* synopsis: key=r[P3@P4] */
+#define OP_NoConflict 28 /* synopsis: key=r[P3@P4] */
+#define OP_NotFound 29 /* synopsis: key=r[P3@P4] */
+#define OP_Found 30 /* synopsis: key=r[P3@P4] */
+#define OP_SeekRowid 31 /* synopsis: intkey=r[P3] */
+#define OP_NotExists 32 /* synopsis: intkey=r[P3] */
+#define OP_Last 33
+#define OP_IfSmaller 34
+#define OP_SorterSort 35
+#define OP_Sort 36
+#define OP_Rewind 37
+#define OP_IdxLE 38 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGT 39 /* synopsis: key=r[P3@P4] */
+#define OP_IdxLT 40 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGE 41 /* synopsis: key=r[P3@P4] */
+#define OP_RowSetRead 42 /* synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 43 /* synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 44
+#define OP_FkIfZero 45 /* synopsis: if fkctr[P1]==0 goto P2 */
+#define OP_IfPos 46 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero 47 /* synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_DecrJumpZero 48 /* synopsis: if (--r[P1])==0 goto P2 */
+#define OP_IncrVacuum 49
+#define OP_VNext 50
+#define OP_Init 51 /* synopsis: Start at P2 */
+#define OP_Return 52
+#define OP_EndCoroutine 53
+#define OP_HaltIfNull 54 /* synopsis: if r[P3]=null halt */
+#define OP_Halt 55
+#define OP_Integer 56 /* synopsis: r[P2]=P1 */
+#define OP_Int64 57 /* synopsis: r[P2]=P4 */
+#define OP_String 58 /* synopsis: r[P2]='P4' (len=P1) */
+#define OP_Null 59 /* synopsis: r[P2..P3]=NULL */
+#define OP_SoftNull 60 /* synopsis: r[P1]=NULL */
+#define OP_Blob 61 /* synopsis: r[P2]=P4 (len=P1) */
+#define OP_Variable 62 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Move 63 /* synopsis: r[P2@P3]=r[P1@P3] */
+#define OP_Copy 64 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
+#define OP_SCopy 65 /* synopsis: r[P2]=r[P1] */
+#define OP_IntCopy 66 /* synopsis: r[P2]=r[P1] */
+#define OP_ResultRow 67 /* synopsis: output=r[P1@P2] */
+#define OP_CollSeq 68
+#define OP_Function0 69 /* synopsis: r[P3]=func(r[P2@P5]) */
+#define OP_Or 70 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
+#define OP_And 71 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
+#define OP_Function 72 /* synopsis: r[P3]=func(r[P2@P5]) */
+#define OP_AddImm 73 /* synopsis: r[P1]=r[P1]+P2 */
+#define OP_RealAffinity 74
+#define OP_IsNull 75 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 76 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 77 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */
+#define OP_Eq 78 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 79 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#define OP_Le 80 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */
+#define OP_Lt 81 /* same as TK_LT, synopsis: IF r[P3]=r[P1] */
+#define OP_ElseNotEq 83 /* same as TK_ESCAPE */
+#define OP_BitAnd 84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */
+#define OP_Add 88 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 89 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 90 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_Cast 94 /* synopsis: affinity(r[P1]) */
-#define OP_Permutation 95
-#define OP_Compare 96 /* synopsis: r[P1@P3] <-> r[P2@P3] */
+#define OP_BitNot 95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
+#define OP_Permutation 96
#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_Column 98 /* synopsis: r[P3]=PX */
-#define OP_Affinity 99 /* synopsis: affinity(r[P1@P2]) */
-#define OP_MakeRecord 100 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
-#define OP_Count 101 /* synopsis: r[P2]=count() */
-#define OP_ReadCookie 102
-#define OP_SetCookie 103
-#define OP_ReopenIdx 104 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenRead 105 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenWrite 106 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenAutoindex 107 /* synopsis: nColumn=P2 */
-#define OP_OpenEphemeral 108 /* synopsis: nColumn=P2 */
-#define OP_SorterOpen 109
-#define OP_SequenceTest 110 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
-#define OP_OpenPseudo 111 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 112
-#define OP_ColumnsUsed 113
-#define OP_Sequence 114 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NewRowid 115 /* synopsis: r[P2]=rowid */
-#define OP_Insert 116 /* synopsis: intkey=r[P3] data=r[P2] */
-#define OP_InsertInt 117 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_Delete 118
-#define OP_ResetCount 119
-#define OP_SorterCompare 120 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
-#define OP_SorterData 121 /* synopsis: r[P2]=data */
-#define OP_RowData 122 /* synopsis: r[P2]=data */
-#define OP_Rowid 123 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 124
-#define OP_SorterInsert 125 /* synopsis: key=r[P2] */
-#define OP_IdxInsert 126 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 127 /* synopsis: key=r[P2@P3] */
-#define OP_Seek 128 /* synopsis: Move P3 to P1.rowid */
-#define OP_IdxRowid 129 /* synopsis: r[P2]=rowid */
-#define OP_Destroy 130
-#define OP_Clear 131
+#define OP_Compare 98 /* synopsis: r[P1@P3] <-> r[P2@P3] */
+#define OP_Column 99 /* synopsis: r[P3]=PX */
+#define OP_Affinity 100 /* synopsis: affinity(r[P1@P2]) */
+#define OP_MakeRecord 101 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
+#define OP_Count 102 /* synopsis: r[P2]=count() */
+#define OP_ReadCookie 103
+#define OP_SetCookie 104
+#define OP_ReopenIdx 105 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 106 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenWrite 107 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenDup 108
+#define OP_OpenAutoindex 109 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 110 /* synopsis: nColumn=P2 */
+#define OP_SorterOpen 111
+#define OP_SequenceTest 112 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
+#define OP_OpenPseudo 113 /* synopsis: P3 columns in r[P2] */
+#define OP_Close 114
+#define OP_ColumnsUsed 115
+#define OP_Sequence 116 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NewRowid 117 /* synopsis: r[P2]=rowid */
+#define OP_Insert 118 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_InsertInt 119 /* synopsis: intkey=P3 data=r[P2] */
+#define OP_Delete 120
+#define OP_ResetCount 121
+#define OP_SorterCompare 122 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 123 /* synopsis: r[P2]=data */
+#define OP_RowData 124 /* synopsis: r[P2]=data */
+#define OP_Rowid 125 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 126
+#define OP_SorterInsert 127 /* synopsis: key=r[P2] */
+#define OP_IdxInsert 128 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 129 /* synopsis: key=r[P2@P3] */
+#define OP_DeferredSeek 130 /* synopsis: Move P3 to P1.rowid if needed */
+#define OP_IdxRowid 131 /* synopsis: r[P2]=rowid */
#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_ResetSorter 133
-#define OP_CreateIndex 134 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 135 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_SqlExec 136
-#define OP_ParseSchema 137
-#define OP_LoadAnalysis 138
-#define OP_DropTable 139
-#define OP_DropIndex 140
-#define OP_DropTrigger 141
-#define OP_IntegrityCk 142
-#define OP_RowSetAdd 143 /* synopsis: rowset(P1)=r[P2] */
-#define OP_Param 144
-#define OP_FkCounter 145 /* synopsis: fkctr[P1]+=P2 */
-#define OP_MemMax 146 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_OffsetLimit 147 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
-#define OP_AggStep0 148 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggStep 149 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggFinal 150 /* synopsis: accum=r[P1] N=P2 */
-#define OP_Expire 151
-#define OP_TableLock 152 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 153
-#define OP_VCreate 154
-#define OP_VDestroy 155
-#define OP_VOpen 156
-#define OP_VColumn 157 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 158
-#define OP_Pagecount 159
-#define OP_MaxPgcnt 160
-#define OP_CursorHint 161
-#define OP_Noop 162
-#define OP_Explain 163
+#define OP_Destroy 133
+#define OP_Clear 134
+#define OP_ResetSorter 135
+#define OP_CreateIndex 136 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_CreateTable 137 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_SqlExec 138
+#define OP_ParseSchema 139
+#define OP_LoadAnalysis 140
+#define OP_DropTable 141
+#define OP_DropIndex 142
+#define OP_DropTrigger 143
+#define OP_IntegrityCk 144
+#define OP_RowSetAdd 145 /* synopsis: rowset(P1)=r[P2] */
+#define OP_Param 146
+#define OP_FkCounter 147 /* synopsis: fkctr[P1]+=P2 */
+#define OP_MemMax 148 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_OffsetLimit 149 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggStep0 150 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_AggStep 151 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_AggFinal 152 /* synopsis: accum=r[P1] N=P2 */
+#define OP_Expire 153
+#define OP_TableLock 154 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 155
+#define OP_VCreate 156
+#define OP_VDestroy 157
+#define OP_VOpen 158
+#define OP_VColumn 159 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 160
+#define OP_Pagecount 161
+#define OP_MaxPgcnt 162
+#define OP_CursorHint 163
+#define OP_Noop 164
+#define OP_Explain 165
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
@@ -12901,37 +12924,37 @@
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\
/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\
-/* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\
-/* 32 */ 0x09, 0x09, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\
-/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23,\
-/* 64 */ 0x0b, 0x01, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01,\
-/* 72 */ 0x01, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\
-/* 80 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
-/* 88 */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00,\
-/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\
+/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\
+/* 24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
+/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
+/* 40 */ 0x01, 0x01, 0x23, 0x0b, 0x01, 0x01, 0x03, 0x03,\
+/* 48 */ 0x03, 0x01, 0x01, 0x01, 0x02, 0x02, 0x08, 0x00,\
+/* 56 */ 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00,\
+/* 64 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x26, 0x26,\
+/* 72 */ 0x00, 0x02, 0x02, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\
+/* 80 */ 0x0b, 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26,\
+/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x02, 0x12,\
+/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\
/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 112 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00,\
-/* 128 */ 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\
-/* 144 */ 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
-/* 160 */ 0x10, 0x00, 0x00, 0x00,}
+/* 112 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
+/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04,\
+/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
+/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 144 */ 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00,\
+/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 160 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,}
/* The sqlite3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
-#define SQLITE_MX_JUMP_OPCODE 72 /* Maximum JUMP opcode */
+#define SQLITE_MX_JUMP_OPCODE 83 /* Maximum JUMP opcode */
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
/*
@@ -13355,25 +13378,25 @@
*/
struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
+ PCache *pCache; /* PRIVATE: Cache that owns this page */
PgHdr *pDirty; /* Transient list of dirty sorted by pgno */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
u32 pageHash; /* Hash of page content */
#endif
u16 flags; /* PGHDR flags defined below */
/**********************************************************************
- ** Elements above are public. All that follows is private to pcache.c
- ** and should not be accessed by other modules.
+ ** Elements above, except pCache, are public. All that follow are
+ ** private to pcache.c and should not be accessed by other modules.
+ ** pCache is grouped with the public elements for efficiency.
*/
i16 nRef; /* Number of users of this page */
- PCache *pCache; /* Cache that owns this page */
-
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
};
/* Bit values for PgHdr.flags */
@@ -13891,11 +13914,11 @@
** The "PRAGMA synchronous" statement also uses the zero-based numbers.
** In other words, the zero-based numbers are used for all external interfaces
** and the one-based values are used internally.
*/
#ifndef SQLITE_DEFAULT_SYNCHRONOUS
-# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1)
+# define SQLITE_DEFAULT_SYNCHRONOUS 2
#endif
#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
#endif
@@ -15128,11 +15151,11 @@
** The following are the meanings of bits in the Expr.flags field.
*/
#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
-#define EP_Error 0x000008 /* Expression contains one or more errors */
+ /* 0x000008 // available for use */
#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
@@ -15207,10 +15230,11 @@
** of the result column in the form: DATABASE.TABLE.COLUMN. This later
** form is used for name resolution with nested FROM clauses.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
+ int nAlloc; /* Number of a[] slots allocated */
struct ExprList_item { /* For each expression in the list */
Expr *pExpr; /* The parse tree for this expression */
char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */
@@ -15222,11 +15246,11 @@
u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */
} x;
int iConstExprReg; /* Register in which Expr value is cached */
} u;
- } *a; /* Alloc a power of two greater or equal to nExpr */
+ } a[1]; /* One slot for each expression in the list */
};
/*
** An instance of this structure is used by the parser to record both
** the parse tree for an expression and the span of input text for an
@@ -15594,14 +15618,14 @@
** An instance of this object describes where to put of the results of
** a SELECT statement.
*/
struct SelectDest {
u8 eDest; /* How to dispose of the results. On of SRT_* above. */
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
int iSDParm; /* A parameter used by the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
+ char *zAffSdst; /* Affinity used when eDest==SRT_Set */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
/*
** During code generation of statements that do inserts into AUTOINCREMENT
@@ -16079,18 +16103,21 @@
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
u8 eCode; /* A small processing code */
union { /* Extra data for callback */
- NameContext *pNC; /* Naming context */
- int n; /* A counter */
- int iCur; /* A cursor number */
- SrcList *pSrcList; /* FROM clause */
- struct SrcCount *pSrcCount; /* Counting column references */
- struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
- int *aiCol; /* array of column indexes */
- struct IdxCover *pIdxCover; /* Check for index coverage */
+ NameContext *pNC; /* Naming context */
+ int n; /* A counter */
+ int iCur; /* A cursor number */
+ SrcList *pSrcList; /* FROM clause */
+ struct SrcCount *pSrcCount; /* Counting column references */
+ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
+ int *aiCol; /* array of column indexes */
+ struct IdxCover *pIdxCover; /* Check for index coverage */
+ struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
+ ExprList *pGroupBy; /* GROUP BY clause */
+ struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */
} u;
};
/* Forward declarations */
SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*);
@@ -16097,10 +16124,14 @@
SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
+SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
+#endif
/*
** Return code from the parse-tree walking primitives and their
** callbacks.
*/
@@ -16158,15 +16189,18 @@
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3NomemError(int);
SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
+SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
#else
# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
#endif
/*
** FTS3 and FTS4 both require virtual table support
*/
@@ -16240,10 +16274,11 @@
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
+SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
SQLITE_PRIVATE void *sqlite3ScratchMalloc(int);
SQLITE_PRIVATE void sqlite3ScratchFree(void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
@@ -16555,10 +16590,11 @@
SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
+SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
@@ -17264,13 +17300,20 @@
** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
**
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
** disabled. The default value may be changed by compiling with the
** SQLITE_USE_URI symbol defined.
+**
+** URI filenames are enabled by default if SQLITE_HAS_CODEC is
+** enabled.
*/
#ifndef SQLITE_USE_URI
-# define SQLITE_USE_URI 0
+# ifdef SQLITE_HAS_CODEC
+# define SQLITE_USE_URI 1
+# else
+# define SQLITE_USE_URI 0
+# endif
#endif
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
** that compile-time option is omitted.
@@ -17487,10 +17530,16 @@
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
+#if SQLITE_DEFAULT_SYNCHRONOUS
+ "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
+#endif
+#if SQLITE_DEFAULT_WAL_SYNCHRONOUS
+ "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
+#endif
#if SQLITE_DIRECT_OVERFLOW_READ
"DIRECT_OVERFLOW_READ",
#endif
#if SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC",
@@ -18063,10 +18112,11 @@
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
+ u8 *aOnce; /* Bitmask used by OP_Once */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
AuxData *pAuxData; /* Linked list of auxdata allocations */
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
@@ -18083,11 +18133,11 @@
/*
** Internally, the vdbe manipulates nearly all SQL values as Mem
** structures. Each Mem struct may cache multiple representations (string,
** integer etc.) of the same value.
*/
-struct Mem {
+struct sqlite3_value {
union MemValue {
double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */
int nZero; /* Used when bit MEM_Zero is set in flags */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
@@ -18185,15 +18235,15 @@
** of this structure. All such structures associated with a single VM
** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
** when the VM is halted (if not before).
*/
struct AuxData {
- int iOp; /* Instruction number of OP_Function opcode */
- int iArg; /* Index of function argument. */
+ int iAuxOp; /* Instruction number of OP_Function opcode */
+ int iAuxArg; /* Index of function argument. */
void *pAux; /* Aux data pointer */
- void (*xDelete)(void *); /* Destructor for the aux data */
- AuxData *pNext; /* Next element in list */
+ void (*xDeleteAux)(void*); /* Destructor for the aux data */
+ AuxData *pNextAux; /* Next element in list */
};
/*
** The "context" argument for an installable function. A pointer to an
** instance of this structure is the first argument to the routines used
@@ -18404,11 +18454,11 @@
SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
+SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *);
SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
#if !defined(SQLITE_OMIT_SHARED_CACHE)
@@ -19213,12 +19263,14 @@
if( p->validYMD ) return;
if( !p->validJD ){
p->Y = 2000;
p->M = 1;
p->D = 1;
+ }else if( !validJulianDay(p->iJD) ){
+ datetimeError(p);
+ return;
}else{
- assert( validJulianDay(p->iJD) );
Z = (int)((p->iJD + 43200000)/86400000);
A = (int)((Z - 1867216.25)/36524.25);
A = Z + 1 + A - (A/4);
B = A + 1524;
C = (int)((B - 122.1)/365.25);
@@ -20667,11 +20719,13 @@
** Use the zone allocator available on apple products unless the
** SQLITE_WITHOUT_ZONEMALLOC symbol is defined.
*/
#include
#include
+#ifdef SQLITE_MIGHT_BE_SINGLE_CORE
#include
+#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */
static malloc_zone_t* _sqliteZone_;
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
#define SQLITE_MALLOCSIZE(x) \
@@ -20860,23 +20914,14 @@
/* defer MT decisions to system malloc */
_sqliteZone_ = malloc_default_zone();
}else{
/* only 1 core, use our own zone to contention over global locks,
** e.g. we have our own dedicated locks */
- bool success;
- malloc_zone_t* newzone = malloc_create_zone(4096, 0);
- malloc_set_zone_name(newzone, "Sqlite_Heap");
- do{
- success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
- (void * volatile *)&_sqliteZone_);
- }while(!_sqliteZone_);
- if( !success ){
- /* somebody registered a zone first */
- malloc_destroy_zone(newzone);
- }
- }
-#endif
+ _sqliteZone_ = malloc_create_zone(4096, 0);
+ malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap");
+ }
+#endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */
UNUSED_PARAMETER(NotUsed);
return SQLITE_OK;
}
/*
@@ -24657,15 +24702,16 @@
*db->pnBytesFreed += sqlite3DbMallocSize(db,p);
}
/*
** Free memory that might be associated with a particular database
-** connection.
+** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
+** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
*/
-SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
+SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
- if( p==0 ) return;
+ assert( p!=0 );
if( db ){
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
@@ -24684,10 +24730,14 @@
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
+}
+SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
+ assert( db==0 || sqlite3_mutex_held(db->mutex) );
+ if( p ) sqlite3DbFreeNN(db, p);
}
/*
** Change the size of an existing memory allocation
*/
@@ -25423,16 +25473,17 @@
}
if( precisionpWith ){
sqlite3TreeViewWith(pView, p->pWith, 1);
cnt = 1;
sqlite3TreeViewPush(pView, 1);
@@ -26372,19 +26427,24 @@
** Generate a human-readable explanation of an expression tree.
*/
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
const char *zBinOp = 0; /* Binary operator */
const char *zUniOp = 0; /* Unary operator */
- char zFlgs[30];
+ char zFlgs[60];
pView = sqlite3TreeViewPush(pView, moreToFollow);
if( pExpr==0 ){
sqlite3TreeViewLine(pView, "nil");
sqlite3TreeViewPop(pView);
return;
}
if( pExpr->flags ){
- sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
+ if( ExprHasProperty(pExpr, EP_FromJoin) ){
+ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d",
+ pExpr->flags, pExpr->iRightJoinTable);
+ }else{
+ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
+ }
}else{
zFlgs[0] = 0;
}
switch( pExpr->op ){
case TK_AGG_COLUMN: {
@@ -26598,10 +26658,15 @@
}
case TK_SELECT_COLUMN: {
sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn);
sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
break;
+ }
+ case TK_IF_NULL_ROW: {
+ sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
}
default: {
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
break;
}
@@ -28318,10 +28383,11 @@
}else{
return 0;
}
}
#endif
+ if( !sqlite3Isdigit(zNum[0]) ) return 0;
while( zNum[0]=='0' ) zNum++;
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
v = v*10 + c;
}
@@ -29481,151 +29547,153 @@
/* 18 */ "Jump" OpHelp(""),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
/* 20 */ "Once" OpHelp(""),
/* 21 */ "If" OpHelp(""),
/* 22 */ "IfNot" OpHelp(""),
- /* 23 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 24 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 25 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 26 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
- /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 31 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 32 */ "SeekRowid" OpHelp("intkey=r[P3]"),
- /* 33 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 36 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
- /* 37 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
- /* 38 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
- /* 39 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
- /* 40 */ "Lt" OpHelp("IF r[P3]=r[P1]"),
- /* 42 */ "ElseNotEq" OpHelp(""),
- /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"),
- /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 53 */ "Last" OpHelp(""),
- /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
- /* 55 */ "IfSmaller" OpHelp(""),
- /* 56 */ "SorterSort" OpHelp(""),
- /* 57 */ "Sort" OpHelp(""),
- /* 58 */ "Rewind" OpHelp(""),
- /* 59 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 60 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 61 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 62 */ "IdxGE" OpHelp("key=r[P3@P4]"),
- /* 63 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 64 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 65 */ "Program" OpHelp(""),
- /* 66 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 67 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
- /* 68 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
- /* 69 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 70 */ "IncrVacuum" OpHelp(""),
- /* 71 */ "VNext" OpHelp(""),
- /* 72 */ "Init" OpHelp("Start at P2"),
- /* 73 */ "Return" OpHelp(""),
- /* 74 */ "EndCoroutine" OpHelp(""),
- /* 75 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
- /* 76 */ "Halt" OpHelp(""),
- /* 77 */ "Integer" OpHelp("r[P2]=P1"),
- /* 78 */ "Int64" OpHelp("r[P2]=P4"),
- /* 79 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
- /* 80 */ "Null" OpHelp("r[P2..P3]=NULL"),
- /* 81 */ "SoftNull" OpHelp("r[P1]=NULL"),
- /* 82 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 83 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
- /* 84 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
- /* 85 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
- /* 86 */ "SCopy" OpHelp("r[P2]=r[P1]"),
- /* 87 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
- /* 88 */ "ResultRow" OpHelp("output=r[P1@P2]"),
- /* 89 */ "CollSeq" OpHelp(""),
- /* 90 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 91 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 92 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
- /* 93 */ "RealAffinity" OpHelp(""),
+ /* 23 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 24 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 25 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 26 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 27 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 30 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"),
+ /* 32 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 33 */ "Last" OpHelp(""),
+ /* 34 */ "IfSmaller" OpHelp(""),
+ /* 35 */ "SorterSort" OpHelp(""),
+ /* 36 */ "Sort" OpHelp(""),
+ /* 37 */ "Rewind" OpHelp(""),
+ /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"),
+ /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 43 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 44 */ "Program" OpHelp(""),
+ /* 45 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
+ /* 46 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 47 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+ /* 48 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 49 */ "IncrVacuum" OpHelp(""),
+ /* 50 */ "VNext" OpHelp(""),
+ /* 51 */ "Init" OpHelp("Start at P2"),
+ /* 52 */ "Return" OpHelp(""),
+ /* 53 */ "EndCoroutine" OpHelp(""),
+ /* 54 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
+ /* 55 */ "Halt" OpHelp(""),
+ /* 56 */ "Integer" OpHelp("r[P2]=P1"),
+ /* 57 */ "Int64" OpHelp("r[P2]=P4"),
+ /* 58 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
+ /* 59 */ "Null" OpHelp("r[P2..P3]=NULL"),
+ /* 60 */ "SoftNull" OpHelp("r[P1]=NULL"),
+ /* 61 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
+ /* 62 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 63 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
+ /* 64 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
+ /* 65 */ "SCopy" OpHelp("r[P2]=r[P1]"),
+ /* 66 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
+ /* 67 */ "ResultRow" OpHelp("output=r[P1@P2]"),
+ /* 68 */ "CollSeq" OpHelp(""),
+ /* 69 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"),
+ /* 70 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
+ /* 71 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
+ /* 72 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
+ /* 73 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
+ /* 74 */ "RealAffinity" OpHelp(""),
+ /* 75 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 76 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 77 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
+ /* 78 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 79 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 80 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
+ /* 81 */ "Lt" OpHelp("IF r[P3]=r[P1]"),
+ /* 83 */ "ElseNotEq" OpHelp(""),
+ /* 84 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 85 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 86 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"),
+ /* 88 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 89 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 90 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 91 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 92 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 93 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
/* 94 */ "Cast" OpHelp("affinity(r[P1])"),
- /* 95 */ "Permutation" OpHelp(""),
- /* 96 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
+ /* 95 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
+ /* 96 */ "Permutation" OpHelp(""),
/* 97 */ "String8" OpHelp("r[P2]='P4'"),
- /* 98 */ "Column" OpHelp("r[P3]=PX"),
- /* 99 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
- /* 100 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
- /* 101 */ "Count" OpHelp("r[P2]=count()"),
- /* 102 */ "ReadCookie" OpHelp(""),
- /* 103 */ "SetCookie" OpHelp(""),
- /* 104 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 105 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
- /* 106 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 107 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 108 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 109 */ "SorterOpen" OpHelp(""),
- /* 110 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
- /* 111 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 112 */ "Close" OpHelp(""),
- /* 113 */ "ColumnsUsed" OpHelp(""),
- /* 114 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 115 */ "NewRowid" OpHelp("r[P2]=rowid"),
- /* 116 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
- /* 117 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 118 */ "Delete" OpHelp(""),
- /* 119 */ "ResetCount" OpHelp(""),
- /* 120 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
- /* 121 */ "SorterData" OpHelp("r[P2]=data"),
- /* 122 */ "RowData" OpHelp("r[P2]=data"),
- /* 123 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 124 */ "NullRow" OpHelp(""),
- /* 125 */ "SorterInsert" OpHelp("key=r[P2]"),
- /* 126 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 127 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
- /* 128 */ "Seek" OpHelp("Move P3 to P1.rowid"),
- /* 129 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 130 */ "Destroy" OpHelp(""),
- /* 131 */ "Clear" OpHelp(""),
+ /* 98 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
+ /* 99 */ "Column" OpHelp("r[P3]=PX"),
+ /* 100 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
+ /* 101 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
+ /* 102 */ "Count" OpHelp("r[P2]=count()"),
+ /* 103 */ "ReadCookie" OpHelp(""),
+ /* 104 */ "SetCookie" OpHelp(""),
+ /* 105 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
+ /* 106 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 107 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
+ /* 108 */ "OpenDup" OpHelp(""),
+ /* 109 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 110 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 111 */ "SorterOpen" OpHelp(""),
+ /* 112 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
+ /* 113 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 114 */ "Close" OpHelp(""),
+ /* 115 */ "ColumnsUsed" OpHelp(""),
+ /* 116 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 117 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 118 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 119 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
+ /* 120 */ "Delete" OpHelp(""),
+ /* 121 */ "ResetCount" OpHelp(""),
+ /* 122 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 123 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 124 */ "RowData" OpHelp("r[P2]=data"),
+ /* 125 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 126 */ "NullRow" OpHelp(""),
+ /* 127 */ "SorterInsert" OpHelp("key=r[P2]"),
+ /* 128 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 129 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
+ /* 130 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
+ /* 131 */ "IdxRowid" OpHelp("r[P2]=rowid"),
/* 132 */ "Real" OpHelp("r[P2]=P4"),
- /* 133 */ "ResetSorter" OpHelp(""),
- /* 134 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 135 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
- /* 136 */ "SqlExec" OpHelp(""),
- /* 137 */ "ParseSchema" OpHelp(""),
- /* 138 */ "LoadAnalysis" OpHelp(""),
- /* 139 */ "DropTable" OpHelp(""),
- /* 140 */ "DropIndex" OpHelp(""),
- /* 141 */ "DropTrigger" OpHelp(""),
- /* 142 */ "IntegrityCk" OpHelp(""),
- /* 143 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 144 */ "Param" OpHelp(""),
- /* 145 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 146 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 147 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
- /* 148 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 149 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 150 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 151 */ "Expire" OpHelp(""),
- /* 152 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 153 */ "VBegin" OpHelp(""),
- /* 154 */ "VCreate" OpHelp(""),
- /* 155 */ "VDestroy" OpHelp(""),
- /* 156 */ "VOpen" OpHelp(""),
- /* 157 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 158 */ "VRename" OpHelp(""),
- /* 159 */ "Pagecount" OpHelp(""),
- /* 160 */ "MaxPgcnt" OpHelp(""),
- /* 161 */ "CursorHint" OpHelp(""),
- /* 162 */ "Noop" OpHelp(""),
- /* 163 */ "Explain" OpHelp(""),
+ /* 133 */ "Destroy" OpHelp(""),
+ /* 134 */ "Clear" OpHelp(""),
+ /* 135 */ "ResetSorter" OpHelp(""),
+ /* 136 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
+ /* 137 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
+ /* 138 */ "SqlExec" OpHelp(""),
+ /* 139 */ "ParseSchema" OpHelp(""),
+ /* 140 */ "LoadAnalysis" OpHelp(""),
+ /* 141 */ "DropTable" OpHelp(""),
+ /* 142 */ "DropIndex" OpHelp(""),
+ /* 143 */ "DropTrigger" OpHelp(""),
+ /* 144 */ "IntegrityCk" OpHelp(""),
+ /* 145 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 146 */ "Param" OpHelp(""),
+ /* 147 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 148 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 149 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+ /* 150 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 151 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 152 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 153 */ "Expire" OpHelp(""),
+ /* 154 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 155 */ "VBegin" OpHelp(""),
+ /* 156 */ "VCreate" OpHelp(""),
+ /* 157 */ "VDestroy" OpHelp(""),
+ /* 158 */ "VOpen" OpHelp(""),
+ /* 159 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 160 */ "VRename" OpHelp(""),
+ /* 161 */ "Pagecount" OpHelp(""),
+ /* 162 */ "MaxPgcnt" OpHelp(""),
+ /* 163 */ "CursorHint" OpHelp(""),
+ /* 164 */ "Noop" OpHelp(""),
+ /* 165 */ "Explain" OpHelp(""),
};
return azName[i];
}
#endif
@@ -45236,21 +45304,20 @@
}
zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
sqlite3EndBenignMalloc();
if( zBulk ){
int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
- int i;
- for(i=0; iszPage];
pX->page.pBuf = zBulk;
pX->page.pExtra = &pX[1];
pX->isBulkLocal = 1;
pX->isAnchor = 0;
pX->pNext = pCache->pFree;
pCache->pFree = pX;
zBulk += pCache->szAlloc;
- }
+ }while( --nBulk );
}
return pCache->pFree!=0;
}
/*
@@ -46162,11 +46229,11 @@
*/
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
assert( sqlite3_mutex_notheld(pcache1.mutex) );
- if( sqlite3GlobalConfig.nPage==0 ){
+ if( sqlite3GlobalConfig.pPage==0 ){
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
while( (nReq<0 || nFreeisAnchor==0
@@ -49122,10 +49189,15 @@
Pgno pgno; /* The page number of a page in journal */
u32 cksum; /* Checksum used for sanity checking */
char *aData; /* Temporary storage for the page */
sqlite3_file *jfd; /* The file descriptor for the journal file */
int isSynced; /* True if journal page is synced */
+#ifdef SQLITE_HAS_CODEC
+ /* The jrnlEnc flag is true if Journal pages should be passed through
+ ** the codec. It is false for pure in-memory journals. */
+ const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
+#endif
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */
assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */
@@ -49245,18 +49317,38 @@
&& isSynced
){
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
assert( !pagerUseWal(pPager) );
+
+ /* Write the data read from the journal back into the database file.
+ ** This is usually safe even for an encrypted database - as the data
+ ** was encrypted before it was written to the journal file. The exception
+ ** is if the data was just read from an in-memory sub-journal. In that
+ ** case it must be encrypted here before it is copied into the database
+ ** file. */
+#ifdef SQLITE_HAS_CODEC
+ if( !jrnlEnc ){
+ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
+ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
+ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
+ }else
+#endif
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
+
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
if( pPager->pBackup ){
- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
+#ifdef SQLITE_HAS_CODEC
+ if( jrnlEnc ){
+ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
+ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
+ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
+ }else
+#endif
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
}
}else if( !isMainJrnl && pPg==0 ){
/* If this is a rollback of a savepoint and data was not written to
** the database and the page is not in-memory, there is a potential
** problem. When the page is next fetched by the b-tree layer, it
@@ -49304,11 +49396,13 @@
if( pgno==1 ){
memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
}
/* Decode the page just read from disk */
- CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
+#if SQLITE_HAS_CODEC
+ if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
+#endif
sqlite3PcacheRelease(pPg);
}
return rc;
}
@@ -50090,11 +50184,11 @@
assert( isOpen(pPager->fd) );
assert( pPager->tempFile==0 );
nPage = sqlite3WalDbsize(pPager->pWal);
/* If the number of pages in the database is not available from the
- ** WAL sub-system, determine the page counte based on the size of
+ ** WAL sub-system, determine the page count based on the size of
** the database file. If the size of the database file is not an
** integer multiple of the page-size, round up the result.
*/
if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
i64 n = 0; /* Size of db file in bytes */
@@ -50141,27 +50235,25 @@
assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK );
if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */
- Pgno nPage; /* Size of the database file */
-
- rc = pagerPagecount(pPager, &nPage);
- if( rc ) return rc;
- if( nPage==0 ){
- rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
- if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
- isWal = 0;
- }else{
- rc = sqlite3OsAccess(
- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
- );
- }
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
+ );
if( rc==SQLITE_OK ){
if( isWal ){
- testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
- rc = sqlite3PagerOpenWal(pPager, 0);
+ Pgno nPage; /* Size of the database file */
+
+ rc = pagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ if( nPage==0 ){
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ }else{
+ testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
+ rc = sqlite3PagerOpenWal(pPager, 0);
+ }
}else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
pPager->journalMode = PAGER_JOURNALMODE_DELETE;
}
}
}
@@ -51316,12 +51408,17 @@
** write the journal record into the file. */
if( rc==SQLITE_OK ){
void *pData = pPg->pData;
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2;
-
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
+
+#if SQLITE_HAS_CODEC
+ if( !pPager->subjInMemory ){
+ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
+ }else
+#endif
+ pData2 = pData;
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
}
@@ -52095,23 +52192,18 @@
**
** There is a vanishingly small chance that a change will not be
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
- Pgno nPage = 0;
char dbFileVers[sizeof(pPager->dbFileVers)];
- rc = pagerPagecount(pPager, &nPage);
- if( rc ) goto failed;
-
- if( nPage>0 ){
- IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
- rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
- if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
+ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
+ if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_IOERR_SHORT_READ ){
goto failed;
}
- }else{
memset(dbFileVers, 0, sizeof(dbFileVers));
}
if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
pager_reset(pPager);
@@ -58469,14 +58561,14 @@
/* All fields above are zeroed when the cursor is allocated. See
** sqlite3BtreeCursorZero(). Fields that follow must be manually
** initialized. */
i8 iPage; /* Index of current page in apPage */
u8 curIntKey; /* Value of apPage[0]->intKey */
- struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
- void *padding1; /* Make object size a multiple of 16 */
- u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
+ u16 ix; /* Current index for apPage[iPage] */
+ u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
+ struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
+ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
};
/*
** Legal values for BtCursor.curFlags
*/
@@ -59448,10 +59540,11 @@
** rowid iRow is being replaced or deleted. In this case invalidate
** only those incrblob cursors open on that specific row.
*/
static void invalidateIncrblobCursors(
Btree *pBtree, /* The database file to check */
+ Pgno pgnoRoot, /* The table that might be changing */
i64 iRow, /* The rowid that might be changing */
int isClearTable /* True if all rows are being deleted */
){
BtCursor *p;
if( pBtree->hasIncrblobCur==0 ) return;
@@ -59458,20 +59551,20 @@
assert( sqlite3BtreeHoldsMutex(pBtree) );
pBtree->hasIncrblobCur = 0;
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
if( (p->curFlags & BTCF_Incrblob)!=0 ){
pBtree->hasIncrblobCur = 1;
- if( isClearTable || p->info.nKey==iRow ){
+ if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
p->eState = CURSOR_INVALID;
}
}
}
}
#else
/* Stub function when INCRBLOB is omitted */
- #define invalidateIncrblobCursors(x,y,z)
+ #define invalidateIncrblobCursors(w,x,y,z)
#endif /* SQLITE_OMIT_INCRBLOB */
/*
** Set bit pgno of the BtShared.pHasContent bitvec. This is called
** when a page that previously contained data becomes a free-list leaf
@@ -59719,11 +59812,11 @@
assert( nKey==(i64)(int)nKey );
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo);
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
goto moveto_done;
}
}else{
pIdxKey = 0;
}
@@ -59948,11 +60041,11 @@
assert( pEType!=0 );
*pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3PagerUnref(pDbPage);
- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
+ if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap);
return SQLITE_OK;
}
#else /* if defined SQLITE_OMIT_AUTOVACUUM */
#define ptrmapPut(w,x,y,z,rc)
@@ -60333,11 +60426,11 @@
u8 *pAddr;
int sz2 = 0;
int sz = get2byte(&data[iFree+2]);
int top = get2byte(&data[hdr+5]);
if( iFree2 ){
- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_BKPT;
+ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
sz2 = get2byte(&data[iFree2+2]);
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
}
@@ -60364,17 +60457,17 @@
testcase( pc==iCellLast );
/* These conditions have already been verified in btreeInitPage()
** if PRAGMA cell_size_check=ON.
*/
if( pciCellLast ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
assert( pc>=iCellFirst && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrkusableSize ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
testcase( cbrk+size==usableSize );
testcase( pc+size==usableSize );
put2byte(pAddr, cbrk);
@@ -60390,11 +60483,11 @@
}
data[hdr+7] = 0;
defragment_out:
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
data[hdr+1] = 0;
data[hdr+2] = 0;
@@ -60429,11 +60522,11 @@
do{
int size; /* Size of the free slot */
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
** increasing offset. */
if( pc>usableSize-4 || pcpgno);
return 0;
}
/* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
** freeblock form a big-endian integer which is the size of the freeblock
** in bytes, including the 4-byte header. */
@@ -60440,11 +60533,11 @@
size = get2byte(&aData[pc+2]);
if( (x = size - nByte)>=0 ){
testcase( x==4 );
testcase( x==3 );
if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
- *pRc = SQLITE_CORRUPT_BKPT;
+ *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
return 0;
}else if( x<4 ){
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
** number of bytes in fragments may not exceed 60. */
if( aData[hdr+7]>57 ) return 0;
@@ -60507,11 +60600,11 @@
assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
}
/* If there is enough space between gap and top for one more cell pointer
** array entry offset, and if the freelist is not empty, then search the
@@ -60603,15 +60696,15 @@
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))pgno);
}
iPtr = iFreeBlk;
}
- if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
+ if( iFreeBlk>iLast ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
assert( iFreeBlk>iPtr || iFreeBlk==0 );
/* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none
** iPtr: The address of a pointer to iFreeBlk
@@ -60618,13 +60711,15 @@
**
** Check to see if iFreeBlk should be coalesced onto the end of iStart.
*/
if( iFreeBlk && iEnd+3>=iFreeBlk ){
nFrag = iFreeBlk - iEnd;
- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
+ if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
+ if( iEnd > pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
}
/* If iPtr is another freeblock (that is, if iPtr is not the freelist
@@ -60632,24 +60727,24 @@
** coalesced onto the end of iPtr.
*/
if( iPtr>hdr+1 ){
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
if( iPtrEnd+3>=iStart ){
- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT;
+ if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
nFrag += iStart - iPtrEnd;
iSize = iEnd - iPtr;
iStart = iPtr;
}
}
- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT;
+ if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
data[hdr+7] -= nFrag;
}
if( iStart==get2byte(&data[hdr+5]) ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
** freelist entry */
- if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT;
+ if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
@@ -60713,11 +60808,11 @@
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
** an error. */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
@@ -60729,138 +60824,140 @@
** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
** guarantee that the page is well-formed. It only shows that
** we failed to detect any corruption.
*/
static int btreeInitPage(MemPage *pPage){
+ int pc; /* Address of a freeblock within pPage->aData[] */
+ u8 hdr; /* Offset to beginning of page header */
+ u8 *data; /* Equal to pPage->aData */
+ BtShared *pBt; /* The main btree structure */
+ int usableSize; /* Amount of usable space on each page */
+ u16 cellOffset; /* Offset from start of page to first cell pointer */
+ int nFree; /* Number of unused bytes on the page */
+ int top; /* First byte of the cell content area */
+ int iCellFirst; /* First allowable cell or freeblock offset */
+ int iCellLast; /* Last possible cell or freeblock offset */
assert( pPage->pBt!=0 );
assert( pPage->pBt->db!=0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
-
- if( !pPage->isInit ){
- int pc; /* Address of a freeblock within pPage->aData[] */
- u8 hdr; /* Offset to beginning of page header */
- u8 *data; /* Equal to pPage->aData */
- BtShared *pBt; /* The main btree structure */
- int usableSize; /* Amount of usable space on each page */
- u16 cellOffset; /* Offset from start of page to first cell pointer */
- int nFree; /* Number of unused bytes on the page */
- int top; /* First byte of the cell content area */
- int iCellFirst; /* First allowable cell or freeblock offset */
- int iCellLast; /* Last possible cell or freeblock offset */
-
- pBt = pPage->pBt;
-
- hdr = pPage->hdrOffset;
- data = pPage->aData;
- /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
- ** the b-tree page type. */
- if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
- assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
- pPage->maskPage = (u16)(pBt->pageSize - 1);
- pPage->nOverflow = 0;
- usableSize = pBt->usableSize;
- pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
- pPage->aDataEnd = &data[usableSize];
- pPage->aCellIdx = &data[cellOffset];
- pPage->aDataOfst = &data[pPage->childPtrSize];
- /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
- ** the start of the cell content area. A zero value for this integer is
- ** interpreted as 65536. */
- top = get2byteNotZero(&data[hdr+5]);
- /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
- ** number of cells on the page. */
- pPage->nCell = get2byte(&data[hdr+3]);
- if( pPage->nCell>MX_CELL(pBt) ){
- /* To many cells for a single page. The page must be corrupt */
- return SQLITE_CORRUPT_BKPT;
- }
- testcase( pPage->nCell==MX_CELL(pBt) );
- /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
- ** possible for a root page of a table that contains no rows) then the
- ** offset to the cell content area will equal the page size minus the
- ** bytes of reserved space. */
- assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
-
- /* A malformed database page might cause us to read past the end
- ** of page when parsing a cell.
- **
- ** The following block of code checks early to see if a cell extends
- ** past the end of a page boundary and causes SQLITE_CORRUPT to be
- ** returned if it does.
- */
- iCellFirst = cellOffset + 2*pPage->nCell;
- iCellLast = usableSize - 4;
- if( pBt->db->flags & SQLITE_CellSizeCk ){
- int i; /* Index into the cell pointer array */
- int sz; /* Size of a cell */
-
- if( !pPage->leaf ) iCellLast--;
- for(i=0; inCell; i++){
- pc = get2byteAligned(&data[cellOffset+i*2]);
- testcase( pc==iCellFirst );
- testcase( pc==iCellLast );
- if( pciCellLast ){
- return SQLITE_CORRUPT_BKPT;
- }
- sz = pPage->xCellSize(pPage, &data[pc]);
- testcase( pc+sz==usableSize );
- if( pc+sz>usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }
- }
- if( !pPage->leaf ) iCellLast++;
- }
-
- /* Compute the total free space on the page
- ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
- ** start of the first freeblock on the page, or is zero if there are no
- ** freeblocks. */
- pc = get2byte(&data[hdr+1]);
- nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
- if( pc>0 ){
- u32 next, size;
- if( pciCellLast ){
- return SQLITE_CORRUPT_BKPT; /* Freeblock off the end of the page */
- }
- next = get2byte(&data[pc]);
- size = get2byte(&data[pc+2]);
- nFree = nFree + size;
- if( next<=pc+size+3 ) break;
- pc = next;
- }
- if( next>0 ){
- return SQLITE_CORRUPT_BKPT; /* Freeblock not in ascending order */
- }
- if( pc+size>(unsigned int)usableSize ){
- return SQLITE_CORRUPT_BKPT; /* Last freeblock extends past page end */
- }
- }
-
- /* At this point, nFree contains the sum of the offset to the start
- ** of the cell-content area plus the number of free bytes within
- ** the cell-content area. If this is greater than the usable-size
- ** of the page, then the page must be corrupted. This check also
- ** serves to verify that the offset to the start of the cell-content
- ** area, according to the page header, lies within the page.
- */
- if( nFree>usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }
- pPage->nFree = (u16)(nFree - iCellFirst);
- pPage->isInit = 1;
- }
+ assert( pPage->isInit==0 );
+
+ pBt = pPage->pBt;
+ hdr = pPage->hdrOffset;
+ data = pPage->aData;
+ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
+ ** the b-tree page type. */
+ if( decodeFlags(pPage, data[hdr]) ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
+ pPage->maskPage = (u16)(pBt->pageSize - 1);
+ pPage->nOverflow = 0;
+ usableSize = pBt->usableSize;
+ pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
+ pPage->aDataEnd = &data[usableSize];
+ pPage->aCellIdx = &data[cellOffset];
+ pPage->aDataOfst = &data[pPage->childPtrSize];
+ /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
+ ** the start of the cell content area. A zero value for this integer is
+ ** interpreted as 65536. */
+ top = get2byteNotZero(&data[hdr+5]);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
+ pPage->nCell = get2byte(&data[hdr+3]);
+ if( pPage->nCell>MX_CELL(pBt) ){
+ /* To many cells for a single page. The page must be corrupt */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ testcase( pPage->nCell==MX_CELL(pBt) );
+ /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
+ ** possible for a root page of a table that contains no rows) then the
+ ** offset to the cell content area will equal the page size minus the
+ ** bytes of reserved space. */
+ assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
+
+ /* A malformed database page might cause us to read past the end
+ ** of page when parsing a cell.
+ **
+ ** The following block of code checks early to see if a cell extends
+ ** past the end of a page boundary and causes SQLITE_CORRUPT to be
+ ** returned if it does.
+ */
+ iCellFirst = cellOffset + 2*pPage->nCell;
+ iCellLast = usableSize - 4;
+ if( pBt->db->flags & SQLITE_CellSizeCk ){
+ int i; /* Index into the cell pointer array */
+ int sz; /* Size of a cell */
+
+ if( !pPage->leaf ) iCellLast--;
+ for(i=0; inCell; i++){
+ pc = get2byteAligned(&data[cellOffset+i*2]);
+ testcase( pc==iCellFirst );
+ testcase( pc==iCellLast );
+ if( pciCellLast ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ sz = pPage->xCellSize(pPage, &data[pc]);
+ testcase( pc+sz==usableSize );
+ if( pc+sz>usableSize ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ }
+ if( !pPage->leaf ) iCellLast++;
+ }
+
+ /* Compute the total free space on the page
+ ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
+ ** start of the first freeblock on the page, or is zero if there are no
+ ** freeblocks. */
+ pc = get2byte(&data[hdr+1]);
+ nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
+ if( pc>0 ){
+ u32 next, size;
+ if( pcpgno);
+ }
+ while( 1 ){
+ if( pc>iCellLast ){
+ /* Freeblock off the end of the page */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ next = get2byte(&data[pc]);
+ size = get2byte(&data[pc+2]);
+ nFree = nFree + size;
+ if( next<=pc+size+3 ) break;
+ pc = next;
+ }
+ if( next>0 ){
+ /* Freeblock not in ascending order */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ if( pc+size>(unsigned int)usableSize ){
+ /* Last freeblock extends past page end */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ }
+
+ /* At this point, nFree contains the sum of the offset to the start
+ ** of the cell-content area plus the number of free bytes within
+ ** the cell-content area. If this is greater than the usable-size
+ ** of the page, then the page must be corrupted. This check also
+ ** serves to verify that the offset to the start of the cell-content
+ ** area, according to the page header, lies within the page.
+ */
+ if( nFree>usableSize ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ pPage->nFree = (u16)(nFree - iCellFirst);
+ pPage->isInit = 1;
return SQLITE_OK;
}
/*
** Set up a raw page so that it looks like a database page holding
@@ -61020,11 +61117,11 @@
assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
/* If obtaining a child page for a cursor, we must verify that the page is
** compatible with the root page. */
if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pgno);
releasePage(*ppPage);
goto getAndInitPage_error;
}
return SQLITE_OK;
@@ -61810,10 +61907,35 @@
sqlite3BtreeLeave(p);
return rc;
#endif
}
+/*
+** If the user has not set the safety-level for this database connection
+** using "PRAGMA synchronous", and if the safety-level is not already
+** set to the value passed to this function as the second parameter,
+** set it so.
+*/
+#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
+static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
+ sqlite3 *db;
+ Db *pDb;
+ if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
+ while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
+ if( pDb->bSyncSet==0
+ && pDb->safety_level!=safety_level
+ && pDb!=&db->aDb[1]
+ ){
+ pDb->safety_level = safety_level;
+ sqlite3PagerSetFlags(pBt->pPager,
+ pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
+ }
+ }
+}
+#else
+# define setDefaultSyncFlag(pBt,safety_level)
+#endif
/*
** Get a reference to pPage1 of the database file. This will
** also acquire a readlock on that file.
**
@@ -61883,30 +62005,19 @@
int isOpen = 0;
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
}else{
-#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
- sqlite3 *db;
- Db *pDb;
- if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
- while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
- if( pDb->bSyncSet==0
- && pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
- ){
- pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
- sqlite3PagerSetFlags(pBt->pPager,
- pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
- }
- }
-#endif
+ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}
}
rc = SQLITE_NOTADB;
+ }else{
+ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1);
}
#endif
/* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload
** fractions and the leaf payload fraction values must be 64, 32, and 32.
@@ -62294,11 +62405,11 @@
int rc; /* Return code */
BtShared *pBt = pPage->pBt;
Pgno pgno = pPage->pgno;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- rc = btreeInitPage(pPage);
+ rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
if( rc!=SQLITE_OK ) return rc;
nCell = pPage->nCell;
for(i=0; ipBt->mutex) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
if( eType==PTRMAP_OVERFLOW2 ){
/* The pointer is always the first 4 bytes of the page in this case. */
if( get4byte(pPage->aData)!=iFrom ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
put4byte(pPage->aData, iTo);
}else{
int i;
int nCell;
int rc;
- rc = btreeInitPage(pPage);
+ rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
if( rc ) return rc;
nCell = pPage->nCell;
for(i=0; ixParseCell(pPage, pCell, &info);
if( info.nLocal pPage->aData+pPage->pBt->usableSize ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
if( iFrom==get4byte(pCell+info.nSize-4) ){
put4byte(pCell+info.nSize-4, iTo);
break;
}
@@ -62374,11 +62485,11 @@
}
if( i==nCell ){
if( eType!=PTRMAP_BTREE ||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
}
}
return SQLITE_OK;
@@ -63251,21 +63362,21 @@
#ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){
CellInfo info;
int iPage = pCur->iPage;
memset(&info, 0, sizeof(info));
- btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
+ btreeParseCell(pCur->apPage[iPage], pCur->ix, &info);
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
}
#else
#define assertCellInfo(x)
#endif
static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
int iPage = pCur->iPage;
pCur->curFlags |= BTCF_ValidNKey;
- btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
+ btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info);
}else{
assertCellInfo(pCur);
}
}
@@ -63468,11 +63579,11 @@
#endif
assert( pPage );
assert( eOp==0 || eOp==1 );
assert( pCur->eState==CURSOR_VALID );
- assert( pCur->aiIdx[pCur->iPage]nCell );
+ assert( pCur->ixnCell );
assert( cursorHoldsMutex(pCur) );
getCellInfo(pCur);
aPayload = pCur->info.pPayload;
assert( offset+amt <= pCur->info.nPayload );
@@ -63482,11 +63593,11 @@
/* Trying to read or write past the end of the data is an error. The
** conditional above is really:
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
** but is recast into its current form to avoid integer overflow problems
*/
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
/* Check if data must be read/written to/from the btree page itself. */
if( offsetinfo.nLocal ){
int a = amt;
@@ -63629,11 +63740,12 @@
iIdx++;
}
}
if( rc==SQLITE_OK && amt>0 ){
- return SQLITE_CORRUPT_BKPT; /* Overflow chain ends prematurely */
+ /* Overflow chain ends prematurely */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
return rc;
}
/*
@@ -63655,11 +63767,11 @@
*/
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
- assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell );
+ assert( pCur->ixapPage[pCur->iPage]->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
/*
** This variant of sqlite3BtreePayload() works even if the cursor has not
@@ -63717,11 +63829,11 @@
u32 amt;
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorOwnsBtShared(pCur) );
- assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell );
+ assert( pCur->ixapPage[pCur->iPage]->nCell );
assert( pCur->info.nSize>0 );
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
if( pCur->info.nLocalinfo.nLocal;
@@ -63768,12 +63880,12 @@
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- pCur->iPage++;
- pCur->aiIdx[pCur->iPage] = 0;
+ pCur->aiIdx[pCur->iPage++] = pCur->ix;
+ pCur->ix = 0;
return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
pCur, pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
@@ -63817,10 +63929,11 @@
pCur->apPage[pCur->iPage]->pgno
);
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ pCur->ix = pCur->aiIdx[pCur->iPage-1];
releasePageNotNull(pCur->apPage[pCur->iPage--]);
}
/*
** Move the cursor to point to the root page of its b-tree structure.
@@ -63894,15 +64007,15 @@
** if pCur->iPage>=0). But this is not so if the database is corrupted
** in such a way that page pRoot is linked into a second b-tree table
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
}
skip_init:
- pCur->aiIdx[0] = 0;
+ pCur->ix = 0;
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
pRoot = pCur->apPage[0];
if( pRoot->nCell>0 ){
@@ -63932,12 +64045,12 @@
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
- assert( pCur->aiIdx[pCur->iPage]nCell );
- pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
+ assert( pCur->ixnCell );
+ pgno = get4byte(findCell(pPage, pCur->ix));
rc = moveToChild(pCur, pgno);
}
return rc;
}
@@ -63958,15 +64071,15 @@
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- pCur->aiIdx[pCur->iPage] = pPage->nCell;
+ pCur->ix = pPage->nCell;
rc = moveToChild(pCur, pgno);
if( rc ) return rc;
}
- pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
+ pCur->ix = pPage->nCell-1;
assert( pCur->info.nSize==0 );
assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
return SQLITE_OK;
}
@@ -64010,11 +64123,11 @@
** to the last entry in the b-tree. */
int ii;
for(ii=0; iiiPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
- assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
+ assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 );
assert( pCur->apPage[pCur->iPage]->leaf );
#endif
return SQLITE_OK;
}
@@ -64099,20 +64212,23 @@
return SQLITE_OK;
}
/* If the requested key is one more than the previous key, then
** try to get there using sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
- ** is still obtained without this ase, only a little more slowely */
+ ** is still obtained without this case, only a little more slowely */
if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
*pRes = 0;
- rc = sqlite3BtreeNext(pCur, pRes);
- if( rc ) return rc;
- if( *pRes==0 ){
+ rc = sqlite3BtreeNext(pCur, 0);
+ if( rc==SQLITE_OK ){
getCellInfo(pCur);
if( pCur->info.nKey==intKey ){
return SQLITE_OK;
}
+ }else if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ }else{
+ return rc;
}
}
}
}
@@ -64157,18 +64273,20 @@
assert( pPage->intKey==(pIdxKey==0) );
lwr = 0;
upr = pPage->nCell-1;
assert( biasRight==0 || biasRight==1 );
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ pCur->ix = (u16)idx;
if( xRecordCompare==0 ){
for(;;){
i64 nCellKey;
pCell = findCellPastPtr(pPage, idx);
if( pPage->intKeyLeaf ){
while( 0x80 <= *(pCell++) ){
- if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
+ if( pCell>=pPage->aDataEnd ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
}
}
getVarint(pCell, (u64*)&nCellKey);
if( nCellKeyintKey ){
upr = idx-1;
if( lwr>upr ){ c = +1; break; }
}else{
assert( nCellKey==intKey );
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ pCur->ix = (u16)idx;
if( !pPage->leaf ){
lwr = idx;
goto moveto_next_layer;
}else{
pCur->curFlags |= BTCF_ValidNKey;
@@ -64237,19 +64355,19 @@
testcase( nCell<0 ); /* True if key size is 2^32 or more */
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
testcase( nCell==2 ); /* Minimum legal index key size */
if( nCell<2 ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pPage->pgno);
goto moveto_finish;
}
pCellKey = sqlite3Malloc( nCell+18 );
if( pCellKey==0 ){
rc = SQLITE_NOMEM_BKPT;
goto moveto_finish;
}
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ pCur->ix = (u16)idx;
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
pCur->curFlags &= ~BTCF_ValidOvfl;
if( rc ){
sqlite3_free(pCellKey);
goto moveto_finish;
@@ -64267,11 +64385,11 @@
upr = idx-1;
}else{
assert( c==0 );
*pRes = 0;
rc = SQLITE_OK;
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ pCur->ix = (u16)idx;
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
goto moveto_finish;
}
if( lwr>upr ) break;
assert( lwr+upr>=0 );
@@ -64279,12 +64397,12 @@
}
}
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
- assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell );
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ assert( pCur->ixapPage[pCur->iPage]->nCell );
+ pCur->ix = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
goto moveto_finish;
}
moveto_next_layer:
@@ -64291,11 +64409,11 @@
if( lwr>=pPage->nCell ){
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
}else{
chldPg = get4byte(findCell(pPage, lwr));
}
- pCur->aiIdx[pCur->iPage] = (u16)lwr;
+ pCur->ix = (u16)lwr;
rc = moveToChild(pCur, chldPg);
if( rc ) break;
}
moveto_finish:
pCur->info.nSize = 0;
@@ -64342,47 +64460,44 @@
}
return n;
}
/*
-** Advance the cursor to the next entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the last entry in the database before
-** this routine was called, then set *pRes=1.
+** Advance the cursor to the next entry in the database.
+** Return value:
+**
+** SQLITE_OK success
+** SQLITE_DONE cursor is already pointing at the last element
+** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreeNext(). That routine is optimized
** for the common case of merely incrementing the cell counter BtCursor.aiIdx
** to the next cell on the current page. The (slower) btreeNext() helper
** routine is called when it is necessary to move to a different page or
** to restore the cursor.
**
-** The calling function will set *pRes to 0 or 1. The initial *pRes value
-** will be 1 if the cursor being stepped corresponds to an SQL index and
-** if this routine could have been skipped if that SQL index had been
-** a unique index. Otherwise the caller will have set *pRes to zero.
-** Zero is the common case. The btree implementation is free to use the
-** initial *pRes value as a hint to improve performance, but the current
-** SQLite btree implementation does not. (Note that the comdb2 btree
-** implementation does use this hint, however.)
+** If bit 0x01 of the flags argument is 1, then the cursor corresponds to
+** an SQL index and this routine could have been skipped if the SQL index
+** had been a unique index. The flags argument is a hint to the implement.
+** SQLite btree implementation does not use this hint, but COMDB2 does.
*/
-static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int flags){
int rc;
int idx;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- assert( *pRes==0 );
+ assert( flags==0 );
if( pCur->eState!=CURSOR_VALID ){
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
pCur->eState = CURSOR_VALID;
if( pCur->skipNext>0 ){
@@ -64392,11 +64507,11 @@
pCur->skipNext = 0;
}
}
pPage = pCur->apPage[pCur->iPage];
- idx = ++pCur->aiIdx[pCur->iPage];
+ idx = ++pCur->ix;
assert( pPage->isInit );
/* If the database file is corrupt, it is possible for the value of idx
** to be invalid here. This can only occur if a second cursor modifies
** the page while cursor pCur is holding a reference to it. Which can
@@ -64410,19 +64525,18 @@
if( rc ) return rc;
return moveToLeftmost(pCur);
}
do{
if( pCur->iPage==0 ){
- *pRes = 1;
pCur->eState = CURSOR_INVALID;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
moveToParent(pCur);
pPage = pCur->apPage[pCur->iPage];
- }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
+ }while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
- return sqlite3BtreeNext(pCur, pRes);
+ return sqlite3BtreeNext(pCur, flags);
}else{
return SQLITE_OK;
}
}
if( pPage->leaf ){
@@ -64429,71 +64543,66 @@
return SQLITE_OK;
}else{
return moveToLeftmost(pCur);
}
}
-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
+ assert( flags==0 || flags==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- *pRes = 0;
- if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
+ if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, 0);
pPage = pCur->apPage[pCur->iPage];
- if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
- pCur->aiIdx[pCur->iPage]--;
- return btreeNext(pCur, pRes);
+ if( (++pCur->ix)>=pPage->nCell ){
+ pCur->ix--;
+ return btreeNext(pCur, 0);
}
if( pPage->leaf ){
return SQLITE_OK;
}else{
return moveToLeftmost(pCur);
}
}
/*
-** Step the cursor to the back to the previous entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the first entry in the database before
-** this routine was called, then set *pRes=1.
+** Step the cursor to the back to the previous entry in the database.
+** Return values:
+**
+** SQLITE_OK success
+** SQLITE_DONE the cursor is already on the first element of the table
+** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreePrevious(). That routine is optimized
** for the common case of merely decrementing the cell counter BtCursor.aiIdx
** to the previous cell on the current page. The (slower) btreePrevious()
** helper routine is called when it is necessary to move to a different page
** or to restore the cursor.
**
-** The calling function will set *pRes to 0 or 1. The initial *pRes value
-** will be 1 if the cursor being stepped corresponds to an SQL index and
-** if this routine could have been skipped if that SQL index had been
-** a unique index. Otherwise the caller will have set *pRes to zero.
-** Zero is the common case. The btree implementation is free to use the
-** initial *pRes value as a hint to improve performance, but the current
-** SQLite btree implementation does not. (Note that the comdb2 btree
-** implementation does use this hint, however.)
+**
+** If bit 0x01 of the flags argument is 1, then the cursor corresponds to
+** an SQL index and this routine could have been skipped if the SQL index
+** had been a unique index. The flags argument is a hint to the implement.
+** SQLite btree implementation does not use this hint, but COMDB2 does.
*/
-static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int flags){
int rc;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 );
+ assert( flags==0 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
assert( pCur->info.nSize==0 );
if( pCur->eState!=CURSOR_VALID ){
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
pCur->eState = CURSOR_VALID;
if( pCur->skipNext<0 ){
@@ -64505,51 +64614,48 @@
}
pPage = pCur->apPage[pCur->iPage];
assert( pPage->isInit );
if( !pPage->leaf ){
- int idx = pCur->aiIdx[pCur->iPage];
+ int idx = pCur->ix;
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
if( rc ) return rc;
rc = moveToRightmost(pCur);
}else{
- while( pCur->aiIdx[pCur->iPage]==0 ){
+ while( pCur->ix==0 ){
if( pCur->iPage==0 ){
pCur->eState = CURSOR_INVALID;
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
moveToParent(pCur);
}
assert( pCur->info.nSize==0 );
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
- pCur->aiIdx[pCur->iPage]--;
+ pCur->ix--;
pPage = pCur->apPage[pCur->iPage];
if( pPage->intKey && !pPage->leaf ){
- rc = sqlite3BtreePrevious(pCur, pRes);
+ rc = sqlite3BtreePrevious(pCur, flags);
}else{
rc = SQLITE_OK;
}
}
return rc;
}
-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
+ assert( flags==0 || flags==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- *pRes = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
- || pCur->aiIdx[pCur->iPage]==0
+ || pCur->ix==0
|| pCur->apPage[pCur->iPage]->leaf==0
){
- return btreePrevious(pCur, pRes);
+ return btreePrevious(pCur, 0);
}
- pCur->aiIdx[pCur->iPage]--;
+ pCur->ix--;
return SQLITE_OK;
}
/*
** Allocate a new page from the database file.
@@ -64651,11 +64757,11 @@
** the freelist is empty. */
iTrunk = get4byte(&pPage1->aData[32]);
}
testcase( iTrunk==mxPage );
if( iTrunk>mxPage || nSearch++ > n ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1);
}else{
rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
}
if( rc ){
pTrunk = 0;
@@ -64680,11 +64786,11 @@
*ppPage = pTrunk;
pTrunk = 0;
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList
&& (nearby==iTrunk || (iTrunkaData[8]);
if( iNewTrunk>mxPage ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
rc = btreeGetUnusedPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){
@@ -64779,11 +64885,11 @@
}
iPage = get4byte(&aData[8+closest*4]);
testcase( iPage==mxPage );
if( iPage>mxPage ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
}
testcase( iPage==mxPage );
if( !searchList
|| (iPage==nearby || (iPagexParseCell(pPage, pCell, pInfo);
if( pInfo->nLocal==pInfo->nPayload ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
- return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
+ /* Cell extends past end of page */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
@@ -66867,12 +66974,12 @@
assert( balance_deeper_called==0 );
VVA_ONLY( balance_deeper_called++ );
rc = balance_deeper(pPage, &pCur->apPage[1]);
if( rc==SQLITE_OK ){
pCur->iPage = 1;
+ pCur->ix = 0;
pCur->aiIdx[0] = 0;
- pCur->aiIdx[1] = 0;
assert( pCur->apPage[1]->nOverflow );
}
}else{
break;
}
@@ -67045,11 +67152,11 @@
if( pCur->pKeyInfo==0 ){
assert( pX->pKey==0 );
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
- invalidateIncrblobCursors(p, pX->nKey, 0);
+ invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
/* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
** to a row with the same key as the new entry being inserted. */
assert( (flags & BTREE_SAVEPOSITION)==0 ||
((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) );
@@ -67057,13 +67164,10 @@
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary
** btreeMoveto() call */
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
loc = 0;
- }else if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
- && pCur->info.nKey==pX->nKey-1 ){
- loc = -1;
}else if( loc==0 ){
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
if( rc ) return rc;
}
}else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){
@@ -67097,11 +67201,11 @@
assert( newCell!=0 );
rc = fillInCell(pPage, newCell, pX, &szNew);
if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) );
- idx = pCur->aiIdx[pCur->iPage];
+ idx = pCur->ix;
if( loc==0 ){
CellInfo info;
assert( idxnCell );
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ){
@@ -67110,26 +67214,33 @@
oldCell = findCell(pPage, idx);
if( !pPage->leaf ){
memcpy(newCell, oldCell, 4);
}
rc = clearCell(pPage, oldCell, &info);
- if( info.nSize==szNew && info.nLocal==info.nPayload ){
+ if( info.nSize==szNew && info.nLocal==info.nPayload
+ && (!ISAUTOVACUUM || szNewminLocal)
+ ){
/* Overwrite the old cell with the new if they are the same size.
** We could also try to do this if the old cell is smaller, then add
** the leftover space to the free list. But experiments show that
** doing that is no faster then skipping this optimization and just
- ** calling dropCell() and insertCell(). */
+ ** calling dropCell() and insertCell().
+ **
+ ** This optimization cannot be used on an autovacuum database if the
+ ** new entry uses overflow pages, as the insertCell() call below is
+ ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */
assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
memcpy(oldCell, newCell, szNew);
return SQLITE_OK;
}
dropCell(pPage, idx, info.nSize, &rc);
if( rc ) goto end_insert;
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
- idx = ++pCur->aiIdx[pCur->iPage];
+ idx = ++pCur->ix;
+ pCur->curFlags &= ~BTCF_ValidNKey;
}else{
assert( pPage->leaf );
}
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
@@ -67221,16 +67332,16 @@
assert( pBt->inTransaction==TRANS_WRITE );
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
- assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell );
+ assert( pCur->ixapPage[pCur->iPage]->nCell );
assert( pCur->eState==CURSOR_VALID );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
iCellDepth = pCur->iPage;
- iCellIdx = pCur->aiIdx[iCellDepth];
+ iCellIdx = pCur->ix;
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
@@ -67260,12 +67371,12 @@
** from the internal node. The 'previous' entry is used for this instead
** of the 'next' entry, as the previous entry is always a part of the
** sub-tree headed by the child page of the cell being deleted. This makes
** balancing the tree following the delete operation easier. */
if( !pPage->leaf ){
- int notUsed = 0;
- rc = sqlite3BtreePrevious(pCur, ¬Used);
+ rc = sqlite3BtreePrevious(pCur, 0);
+ assert( rc!=SQLITE_DONE );
if( rc ) return rc;
}
/* Save the positions of any other cursors open on this table before
** making any modifications. */
@@ -67275,11 +67386,11 @@
}
/* If this is a delete operation to remove a row from a table b-tree,
** invalidate any incrblob cursors open on the row being deleted. */
if( pCur->pKeyInfo==0 ){
- invalidateIncrblobCursors(p, pCur->info.nKey, 0);
+ invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
}
/* Make the page containing the entry to be deleted writable. Then free any
** overflow pages associated with the entry and finally remove the cell
** itself from within the page. */
@@ -67343,11 +67454,11 @@
assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
if( iCellIdx>=pPage->nCell ){
pCur->skipNext = -1;
- pCur->aiIdx[iCellDepth] = pPage->nCell-1;
+ pCur->ix = pPage->nCell-1;
}else{
pCur->skipNext = 1;
}
}else{
rc = moveToRoot(pCur);
@@ -67602,11 +67713,11 @@
if( SQLITE_OK==rc ){
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
** is the root of a table b-tree - if it is not, the following call is
** a no-op). */
- invalidateIncrblobCursors(p, 0, 1);
+ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
}
sqlite3BtreeLeave(p);
return rc;
}
@@ -67856,20 +67967,20 @@
/* All pages of the b-tree have been visited. Return successfully. */
*pnEntry = nEntry;
return moveToRoot(pCur);
}
moveToParent(pCur);
- }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
+ }while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell );
- pCur->aiIdx[pCur->iPage]++;
+ pCur->ix++;
pPage = pCur->apPage[pCur->iPage];
}
/* Descend to the child node of the cell that the cursor currently
** points at. This is the right-child if (iIdx==pPage->nCell).
*/
- iIdx = pCur->aiIdx[pCur->iPage];
+ iIdx = pCur->ix;
if( iIdx==pPage->nCell ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
}else{
rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx)));
}
@@ -68250,10 +68361,11 @@
if( pPage->intKey ){
if( keyCanBeEqual ? (info.nKey > maxKey) : (info.nKey >= maxKey) ){
checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
}
maxKey = info.nKey;
+ keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */
}
/* Check the content overflow list */
if( info.nPayload>info.nLocal ){
int nPage; /* Number of pages on the overflow chain */
@@ -69635,10 +69747,14 @@
assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );
/* Cannot be both MEM_Int and MEM_Real at the same time */
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
+ /* Cannot be both MEM_Null and some other type */
+ assert( (p->flags & MEM_Null)==0 ||
+ (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 );
+
/* The szMalloc field holds the correct memory allocation size */
assert( p->szMalloc==0
|| p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
/* If p holds a string or blob, the Mem.z must point to exactly
@@ -69720,30 +69836,28 @@
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->szMallocszMalloc>0 && pMem->z==pMem->zMalloc ){
- pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
- bPreserve = 0;
- }else{
- if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
- pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
- }
- if( pMem->zMalloc==0 ){
- sqlite3VdbeMemSetNull(pMem);
- pMem->z = 0;
- pMem->szMalloc = 0;
- return SQLITE_NOMEM_BKPT;
- }else{
- pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
- }
- }
-
- if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
+ if( n<32 ) n = 32;
+ if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
+ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
+ bPreserve = 0;
+ }else{
+ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
+ pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
+ }
+ if( pMem->zMalloc==0 ){
+ sqlite3VdbeMemSetNull(pMem);
+ pMem->z = 0;
+ pMem->szMalloc = 0;
+ return SQLITE_NOMEM_BKPT;
+ }else{
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
+ }
+
+ if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){
assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC );
pMem->xDel((void *)(pMem->z));
@@ -69936,11 +70050,11 @@
ctx.pOut = &t;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
assert( (pMem->flags & MEM_Dyn)==0 );
- if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
+ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
memcpy(pMem, &t, sizeof(t));
rc = ctx.isError;
}
return rc;
}
@@ -69987,11 +70101,11 @@
static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
if( VdbeMemDynamic(p) ){
vdbeMemClearExternAndSetNull(p);
}
if( p->szMalloc ){
- sqlite3DbFree(p->db, p->zMalloc);
+ sqlite3DbFreeNN(p->db, p->zMalloc);
p->szMalloc = 0;
}
p->z = 0;
}
@@ -70015,11 +70129,11 @@
/*
** Convert a 64-bit IEEE double into a 64-bit signed integer.
** If the double is out of range of a 64-bit signed integer then
** return the closest available 64-bit signed integer.
*/
-static i64 doubleToInt64(double r){
+static SQLITE_NOINLINE i64 doubleToInt64(double r){
#ifdef SQLITE_OMIT_FLOATING_POINT
/* When floating-point is omitted, double and int64 are the same thing */
return r;
#else
/*
@@ -70051,10 +70165,15 @@
** it into an integer and return that. If pMem represents an
** an SQL-NULL value, return 0.
**
** If pMem represents a string value, its encoding might be changed.
*/
+static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
+ i64 value = 0;
+ sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
+ return value;
+}
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
int flags;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
flags = pMem->flags;
@@ -70061,14 +70180,12 @@
if( flags & MEM_Int ){
return pMem->u.i;
}else if( flags & MEM_Real ){
return doubleToInt64(pMem->u.r);
}else if( flags & (MEM_Str|MEM_Blob) ){
- i64 value = 0;
assert( pMem->z || pMem->n==0 );
- sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
- return value;
+ return memIntValue(pMem);
}else{
return 0;
}
}
@@ -70076,22 +70193,25 @@
** Return the best representation of pMem that we can get into a
** double. If pMem is already a double or an integer, return its
** value. If it is a string or blob, try to convert it to a double.
** If it is a NULL, return 0.0.
*/
+static SQLITE_NOINLINE double memRealValue(Mem *pMem){
+ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
+ double val = (double)0;
+ sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
+ return val;
+}
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( pMem->flags & MEM_Real ){
return pMem->u.r;
}else if( pMem->flags & MEM_Int ){
return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- double val = (double)0;
- sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
- return val;
+ return memRealValue(pMem);
}else{
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
return (double)0;
}
}
@@ -70712,11 +70832,11 @@
for(i=0; iaMem[i].flags = MEM_Null;
pRec->aMem[i].db = db;
}
}else{
- sqlite3DbFree(db, pRec);
+ sqlite3DbFreeNN(db, pRec);
pRec = 0;
}
}
if( pRec==0 ) return 0;
p->ppRec[0] = pRec;
@@ -70824,11 +70944,11 @@
}
if( apVal ){
for(i=0; ipLeft,enc,affinity,&pVal)
+ if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx)
&& pVal!=0
){
sqlite3VdbeMemNumerify(pVal);
if( pVal->flags & MEM_Real ){
pVal->u.r = -pVal->u.r;
@@ -71023,11 +71143,11 @@
}else{
aRet[0] = nSerial+1;
putVarint32(&aRet[1], iSerial);
sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
- sqlite3DbFree(db, aRet);
+ sqlite3DbFreeNN(db, aRet);
}
}
/*
** Register built-in functions used to help read ANALYZE data.
@@ -71250,11 +71370,11 @@
sqlite3 *db = aMem[0].db;
for(i=0; ipKeyInfo);
- sqlite3DbFree(db, pRec);
+ sqlite3DbFreeNN(db, pRec);
}
}
#endif /* ifdef SQLITE_ENABLE_STAT4 */
/*
@@ -71274,11 +71394,11 @@
** Free an sqlite3_value object
*/
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){
if( !v ) return;
sqlite3VdbeMemRelease((Mem *)v);
- sqlite3DbFree(((Mem*)v)->db, v);
+ sqlite3DbFreeNN(((Mem*)v)->db, v);
}
/*
** The sqlite3ValueBytes() routine returns the number of bytes in the
** sqlite3_value object assuming that it uses the encoding "enc".
@@ -71422,10 +71542,16 @@
int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp);
#else
int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
UNUSED_PARAMETER(nOp);
#endif
+
+ /* Ensure that the size of a VDBE does not grow too large */
+ if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){
+ sqlite3OomFault(p->db);
+ return SQLITE_NOMEM;
+ }
assert( nOp<=(1024/sizeof(Op)) );
assert( nNew>=(p->nOpAlloc+nOp) );
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
if( pNew ){
@@ -72111,11 +72237,11 @@
** If the input FuncDef structure is ephemeral, then free it. If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
- sqlite3DbFree(db, pDef);
+ sqlite3DbFreeNN(db, pDef);
}
}
static void vdbeFreeOpArray(sqlite3 *, Op *, int);
@@ -72122,15 +72248,15 @@
/*
** Delete a P4 value if necessary.
*/
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
freeEphemeralFunction(db, p->pFunc);
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
switch( p4type ){
case P4_FUNCCTX: {
@@ -72179,18 +72305,18 @@
** nOp entries.
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( aOp ){
Op *pOp;
- for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
+ for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);
#endif
}
+ sqlite3DbFreeNN(db, aOp);
}
- sqlite3DbFree(db, aOp);
}
/*
** Link the SubProgram object passed as the second argument into the linked
** list at Vdbe.pSubProgram. This list is used to delete all sub-program
@@ -72859,11 +72985,11 @@
testcase( p->flags & MEM_Frame );
testcase( p->flags & MEM_RowSet );
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
sqlite3VdbeMemRelease(p);
}else if( p->szMalloc ){
- sqlite3DbFree(db, p->zMalloc);
+ sqlite3DbFreeNN(db, p->zMalloc);
p->szMalloc = 0;
}
p->flags = MEM_Undefined;
}while( (++p)db, pCx);
break;
}
case CURTYPE_BTREE: {
- if( pCx->pBtx ){
- sqlite3BtreeClose(pCx->pBtx);
+ if( pCx->isEphemeral ){
+ if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
/* The pCx->pCursor will be close automatically, if it exists, by
** the call above. */
}else{
assert( pCx->uc.pCursor!=0 );
sqlite3BtreeCloseCursor(pCx->uc.pCursor);
@@ -73460,21 +73586,22 @@
** statement. This is now set at compile time, rather than during
** execution of the vdbe program so that sqlite3_column_count() can
** be called on an SQL statement before sqlite3_step().
*/
SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
- Mem *pColName;
int n;
sqlite3 *db = p->db;
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqlite3DbFree(db, p->aColName);
+ if( p->nResColumn ){
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ sqlite3DbFree(db, p->aColName);
+ }
n = nResColumn*COLNAME_N;
p->nResColumn = (u16)nResColumn;
- p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
+ p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
- initMemArray(p->aColName, n, p->db, MEM_Null);
+ initMemArray(p->aColName, n, db, MEM_Null);
}
/*
** Set the name of the idx'th column to be returned by the SQL statement.
** zName must be a pointer to a nul terminated string.
@@ -74120,14 +74247,14 @@
sqlite3BeginBenignMalloc();
if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
db->bBenignMalloc--;
- db->errCode = rc;
- }else{
- sqlite3Error(db, rc);
+ }else if( db->pErr ){
+ sqlite3ValueSetNull(db->pErr);
}
+ db->errCode = rc;
return rc;
}
#ifdef SQLITE_ENABLE_SQLLOG
/*
@@ -74230,11 +74357,10 @@
}
fclose(out);
}
}
#endif
- p->iCurrentTime = 0;
p->magic = VDBE_MAGIC_RESET;
return p->rc & db->errMask;
}
/*
@@ -74269,20 +74395,22 @@
*/
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
while( *pp ){
AuxData *pAux = *pp;
if( (iOp<0)
- || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
+ || (pAux->iAuxOp==iOp
+ && pAux->iAuxArg>=0
+ && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg))))
){
- testcase( pAux->iArg==31 );
- if( pAux->xDelete ){
- pAux->xDelete(pAux->pAux);
+ testcase( pAux->iAuxArg==31 );
+ if( pAux->xDeleteAux ){
+ pAux->xDeleteAux(pAux->pAux);
}
- *pp = pAux->pNext;
+ *pp = pAux->pNextAux;
sqlite3DbFree(db, pAux);
}else{
- pp= &pAux->pNext;
+ pp= &pAux->pNextAux;
}
}
}
/*
@@ -74340,11 +74468,11 @@
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
}
p->magic = VDBE_MAGIC_DEAD;
p->db = 0;
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
/*
** The cursor "p" has a pending seek operation that has not yet been
** carried out. Seek the cursor now. If an error occurs, return
@@ -75030,23 +75158,24 @@
** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
int rc;
const void *v1, *v2;
- int n1, n2;
Mem c1;
Mem c2;
sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null);
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
- n1 = v1==0 ? 0 : c1.n;
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
- n2 = v2==0 ? 0 : c2.n;
- rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
+ if( (v1==0 || v2==0) ){
+ if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
+ rc = 0;
+ }else{
+ rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
+ }
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
return rc;
}
}
@@ -75899,11 +76028,11 @@
int i;
for(i=0; iaMem[i];
if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
}
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@@ -75966,11 +76095,11 @@
if( preupdate.aNew ){
int i;
for(i=0; inField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
- sqlite3DbFree(db, preupdate.aNew);
+ sqlite3DbFreeNN(db, preupdate.aNew);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
/************** End of vdbeaux.c *********************************************/
@@ -76779,10 +76908,16 @@
}
/*
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
+**
+** The left-most argument is 0.
+**
+** Undocumented behavior: If iArg is negative then access a cache of
+** auxiliary data pointers that is available to all functions within a
+** single prepared statement. The iArg values must match.
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
@@ -76789,21 +76924,28 @@
#if SQLITE_ENABLE_STAT3_OR_STAT4
if( pCtx->pVdbe==0 ) return 0;
#else
assert( pCtx->pVdbe!=0 );
#endif
- for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
- if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
+ for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
+ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
+ return pAuxData->pAux;
+ }
}
-
- return (pAuxData ? pAuxData->pAux : 0);
+ return 0;
}
/*
** Set the auxiliary data pointer and delete function, for the iArg'th
** argument to the user-function defined by pCtx. Any previous value is
** deleted by calling the delete function specified when it was set.
+**
+** The left-most argument is 0.
+**
+** Undocumented behavior: If iArg is negative then make the data available
+** to all functions within the current prepared statement using iArg as an
+** access code.
*/
SQLITE_API void sqlite3_set_auxdata(
sqlite3_context *pCtx,
int iArg,
void *pAux,
@@ -76811,37 +76953,38 @@
){
AuxData *pAuxData;
Vdbe *pVdbe = pCtx->pVdbe;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- if( iArg<0 ) goto failed;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( pVdbe==0 ) goto failed;
#else
assert( pVdbe!=0 );
#endif
- for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
- if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
+ for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
+ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
+ break;
+ }
}
if( pAuxData==0 ){
pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
if( !pAuxData ) goto failed;
- pAuxData->iOp = pCtx->iOp;
- pAuxData->iArg = iArg;
- pAuxData->pNext = pVdbe->pAuxData;
+ pAuxData->iAuxOp = pCtx->iOp;
+ pAuxData->iAuxArg = iArg;
+ pAuxData->pNextAux = pVdbe->pAuxData;
pVdbe->pAuxData = pAuxData;
if( pCtx->fErrorOrAux==0 ){
pCtx->isError = 0;
pCtx->fErrorOrAux = 1;
}
- }else if( pAuxData->xDelete ){
- pAuxData->xDelete(pAuxData->pAux);
+ }else if( pAuxData->xDeleteAux ){
+ pAuxData->xDeleteAux(pAuxData->pAux);
}
pAuxData->pAux = pAux;
- pAuxData->xDelete = xDelete;
+ pAuxData->xDeleteAux = xDelete;
return;
failed:
if( xDelete ){
xDelete(pAux);
@@ -77264,12 +77407,14 @@
pVar = &p->aVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
if( rc==SQLITE_OK && encoding!=0 ){
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
- sqlite3Error(p->db, rc);
- rc = sqlite3ApiExit(p->db, rc);
+ if( rc ){
+ sqlite3Error(p->db, rc);
+ rc = sqlite3ApiExit(p->db, rc);
+ }
}
sqlite3_mutex_leave(p->db->mutex);
}else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
xDel((void*)zData);
}
@@ -77572,12 +77717,23 @@
if( !pStmt ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- v = pVdbe->aCounter[op];
- if( resetFlag ) pVdbe->aCounter[op] = 0;
+ if( op==SQLITE_STMTSTATUS_MEMUSED ){
+ sqlite3 *db = pVdbe->db;
+ sqlite3_mutex_enter(db->mutex);
+ v = 0;
+ db->pnBytesFreed = (int*)&v;
+ sqlite3VdbeClearObject(db, pVdbe);
+ sqlite3DbFree(db, pVdbe);
+ db->pnBytesFreed = 0;
+ sqlite3_mutex_leave(db->mutex);
+ }else{
+ v = pVdbe->aCounter[op];
+ if( resetFlag ) pVdbe->aCounter[op] = 0;
+ }
return (int)v;
}
/*
** Return the SQL associated with a prepared statement
@@ -78469,13 +78625,11 @@
c = 'e';
assert( (f & (MEM_Static|MEM_Dyn))==0 );
}else{
c = 's';
}
-
- sqlite3_snprintf(100, zCsr, "%c", c);
- zCsr += sqlite3Strlen30(zCsr);
+ *(zCsr++) = c;
sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
zCsr += sqlite3Strlen30(zCsr);
for(i=0; i<16 && in; i++){
sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
zCsr += sqlite3Strlen30(zCsr);
@@ -78483,13 +78637,11 @@
for(i=0; i<16 && in; i++){
char z = pMem->z[i];
if( z<32 || z>126 ) *zCsr++ = '.';
else *zCsr++ = z;
}
-
- sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]);
- zCsr += sqlite3Strlen30(zCsr);
+ *(zCsr++) = ']';
if( f & MEM_Zero ){
sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
zCsr += sqlite3Strlen30(zCsr);
}
*zCsr = '\0';
@@ -78556,10 +78708,11 @@
}
static void registerTrace(int iReg, Mem *p){
printf("REG[%d] = ", iReg);
memTracePrint(p);
printf("\n");
+ sqlite3VdbeCheckMemInvariants(p);
}
#endif
#ifdef SQLITE_DEBUG
# define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M)
@@ -78731,11 +78884,11 @@
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
int iCompare = 0; /* Result of last comparison */
unsigned nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
+ unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
@@ -78763,10 +78916,12 @@
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
assert( 0 < db->nProgressOps );
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
+ }else{
+ nProgressLimit = 0xffffffff;
}
#endif
#ifdef SQLITE_DEBUG
sqlite3BeginBenignMalloc();
if( p->pc==0
@@ -78922,11 +79077,11 @@
case OP_Goto: { /* jump */
jump_to_p2_and_check_for_interrupt:
pOp = &aOp[pOp->p2 - 1];
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
- ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
+ ** OP_VNext, or OP_SorterNext) all jump here upon
** completion. Check to see if sqlite3_interrupt() has been called
** or if the progress callback needs to be invoked.
**
** This code uses unstructured "goto" statements and does not look clean.
** But that is not due to sloppy coding habits. The code is written this
@@ -78940,11 +79095,11 @@
** of VDBE ops have been executed (either since this invocation of
** sqlite3VdbeExec() or since last time the progress callback was called).
** If the progress callback returns non-zero, exit the virtual machine with
** a return code SQLITE_ABORT.
*/
- if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
+ if( nVmStep>=nProgressLimit && db->xProgress!=0 ){
assert( db->nProgressOps!=0 );
nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
if( db->xProgress(db->pProgressArg) ){
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
@@ -79310,11 +79465,11 @@
** previously copied using OP_SCopy, the copies will continue to be valid.
*/
case OP_SoftNull: {
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
pOut = &aMem[pOp->p1];
- pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
+ pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null;
break;
}
/* Opcode: Blob P1 P2 * P4 *
** Synopsis: r[P2]=P4 (len=P1)
@@ -79482,11 +79637,11 @@
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
/* Run the progress counter just before returning.
*/
if( db->xProgress!=0
- && nVmStep>=nProgressLimit
+ && nVmStep>=nProgressLimit
&& db->xProgress(db->pProgressArg)!=0
){
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -79653,11 +79808,10 @@
type1 = numericType(pIn1);
pIn2 = &aMem[pOp->p2];
type2 = numericType(pIn2);
pOut = &aMem[pOp->p3];
flags = pIn1->flags | pIn2->flags;
- if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (type1 & type2 & MEM_Int)!=0 ){
iA = pIn1->u.i;
iB = pIn2->u.i;
bIntint = 1;
switch( pOp->opcode ){
@@ -79677,10 +79831,12 @@
break;
}
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
+ }else if( (flags & MEM_Null)!=0 ){
+ goto arithmetic_result_is_null;
}else{
bIntint = 0;
fp_math:
rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2);
@@ -79724,11 +79880,11 @@
break;
}
/* Opcode: CollSeq P1 * * P4
**
-** P4 is a pointer to a CollSeq struct. If the next call to a user function
+** P4 is a pointer to a CollSeq object. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** functions.
**
** If P1 is not zero, then it is a register that a subsequent min() or
@@ -80005,15 +80161,15 @@
** Synopsis: affinity(r[P1])
**
** Force the value in register P1 to be the type defined by P2.
**
**
-** - TEXT
-**
- BLOB
-**
- NUMERIC
-**
- INTEGER
-**
- REAL
+**
- P2=='A' → BLOB
+**
- P2=='B' → TEXT
+**
- P2=='C' → NUMERIC
+**
- P2=='D' → INTEGER
+**
- P2=='E' → REAL
**
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_Cast: { /* in1 */
@@ -80491,23 +80647,43 @@
break;
}
/* Opcode: Once P1 P2 * * *
**
-** If the P1 value is equal to the P1 value on the OP_Init opcode at
-** instruction 0, then jump to P2. If the two P1 values differ, then
-** set the P1 value on this opcode to equal the P1 value on the OP_Init
-** and fall through.
+** Fall through to the next instruction the first time this opcode is
+** encountered on each invocation of the byte-code program. Jump to P2
+** on the second and all subsequent encounters during the same invocation.
+**
+** Top-level programs determine first invocation by comparing the P1
+** operand against the P1 operand on the OP_Init opcode at the beginning
+** of the program. If the P1 values differ, then fall through and make
+** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are
+** the same then take the jump.
+**
+** For subprograms, there is a bitmask in the VdbeFrame that determines
+** whether or not the jump should be taken. The bitmask is necessary
+** because the self-altering code trick does not work for recursive
+** triggers.
*/
case OP_Once: { /* jump */
+ u32 iAddr; /* Address of this instruction */
assert( p->aOp[0].opcode==OP_Init );
- VdbeBranchTaken(p->aOp[0].p1==pOp->p1, 2);
- if( p->aOp[0].p1==pOp->p1 ){
- goto jump_to_p2;
+ if( p->pFrame ){
+ iAddr = (int)(pOp - p->aOp);
+ if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){
+ VdbeBranchTaken(1, 2);
+ goto jump_to_p2;
+ }
+ p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7);
}else{
- pOp->p1 = p->aOp[0].p1;
+ if( p->aOp[0].p1==pOp->p1 ){
+ VdbeBranchTaken(1, 2);
+ goto jump_to_p2;
+ }
}
+ VdbeBranchTaken(0, 2);
+ pOp->p1 = p->aOp[0].p1;
break;
}
/* Opcode: If P1 P2 P3 * *
**
@@ -80567,10 +80743,28 @@
if( (pIn1->flags & MEM_Null)==0 ){
goto jump_to_p2;
}
break;
}
+
+/* Opcode: IfNullRow P1 P2 P3 * *
+** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
+**
+** Check the cursor P1 to see if it is currently pointing at a NULL row.
+** If it is, then set register P3 to NULL and jump immediately to P2.
+** If P1 is not on a NULL row, then fall through without making any
+** changes.
+*/
+case OP_IfNullRow: { /* jump */
+ assert( pOp->p1>=0 && pOp->p1nCursor );
+ assert( p->apCsr[pOp->p1]!=0 );
+ if( p->apCsr[pOp->p1]->nullRow ){
+ sqlite3VdbeMemSetNull(aMem + pOp->p3);
+ goto jump_to_p2;
+ }
+ break;
+}
/* Opcode: Column P1 P2 P3 P4 P5
** Synopsis: r[P3]=PX
**
** Interpret the data that cursor P1 points to as a structure built using
@@ -80579,20 +80773,20 @@
** from this record. If there are less that (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
**
-** If the column contains fewer than P2 fields, then extract a NULL. Or,
+** If the record contains fewer than P2 fields, then extract a NULL. Or,
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor,
** then the cache of the cursor is reset prior to extracting the column.
** The first OP_Column against a pseudo-table after the value of the content
** register has changed should have this bit set.
**
-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
+** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
** the result is guaranteed to only be used as the argument of a length()
** or typeof() function, respectively. The loading of large blobs can be
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
@@ -80614,11 +80808,13 @@
Mem *pReg; /* PseudoTable input register */
pC = p->apCsr[pOp->p1];
p2 = pOp->p2;
- /* If the cursor cache is stale, bring it up-to-date */
+ /* If the cursor cache is stale (meaning it is not currently point at
+ ** the correct row) then bring it up-to-date by doing the necessary
+ ** B-Tree seek. */
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
if( rc ) goto abort_due_to_error;
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pDest = &aMem[pOp->p3];
@@ -80816,12 +81012,17 @@
/* Content is irrelevant for
** 1. the typeof() function,
** 2. the length(X) function if X is a blob, and
** 3. if the content length is zero.
** So we might as well use bogus content rather than reading
- ** content from disk. */
- static u8 aZero[8]; /* This is the bogus content */
+ ** content from disk.
+ **
+ ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
+ ** buffer passed to it, debugging function VdbeMemPrettyPrint() may
+ ** read up to 16. So 16 bytes of bogus content is supplied.
+ */
+ static u8 aZero[16]; /* This is the bogus content */
sqlite3VdbeSerialGet(aZero, t, pDest);
}else{
rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
@@ -80838,28 +81039,28 @@
/* Opcode: Affinity P1 P2 * P4 *
** Synopsis: affinity(r[P1@P2])
**
** Apply affinities to a range of P2 registers starting with P1.
**
-** P4 is a string that is P2 characters long. The nth character of the
-** string indicates the column affinity that should be used for the nth
+** P4 is a string that is P2 characters long. The N-th character of the
+** string indicates the column affinity that should be used for the N-th
** memory cell in the range.
*/
case OP_Affinity: {
const char *zAffinity; /* The affinity to be applied */
- char cAff; /* A single character of affinity */
zAffinity = pOp->p4.z;
assert( zAffinity!=0 );
+ assert( pOp->p2>0 );
assert( zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
- while( (cAff = *(zAffinity++))!=0 ){
+ do{
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
assert( memIsValid(pIn1) );
- applyAffinity(pIn1, cAff, encoding);
+ applyAffinity(pIn1, *(zAffinity++), encoding);
pIn1++;
- }
+ }while( zAffinity[0] );
break;
}
/* Opcode: MakeRecord P1 P2 P3 P4 *
** Synopsis: r[P3]=mkrec(r[P1@P2])
@@ -80866,12 +81067,12 @@
**
** Convert P2 registers beginning with P1 into the [record format]
** use as a data record in a database table or as a key
** in an index. The OP_Column opcode can decode the record later.
**
-** P4 may be a string that is P2 characters long. The nth character of the
-** string indicates the column affinity that should be used for the nth
+** P4 may be a string that is P2 characters long. The N-th character of the
+** string indicates the column affinity that should be used for the N-th
** field of the index key.
**
** The mapping from character to affinity is given by the SQLITE_AFF_
** macros defined in sqliteInt.h.
**
@@ -81026,11 +81227,10 @@
pOut->flags = MEM_Blob;
if( nZero ){
pOut->u.nZero = nZero;
pOut->flags |= MEM_Zero;
}
- pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
REGISTER_TRACE(pOp->p3, pOut);
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -81655,10 +81855,41 @@
sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
(pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
if( rc ) goto abort_due_to_error;
break;
}
+
+/* Opcode: OpenDup P1 P2 * * *
+**
+** Open a new cursor P1 that points to the same ephemeral table as
+** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral
+** opcode. Only ephemeral cursors may be duplicated.
+**
+** Duplicate ephemeral cursors are used for self-joins of materialized views.
+*/
+case OP_OpenDup: {
+ VdbeCursor *pOrig; /* The original cursor to be duplicated */
+ VdbeCursor *pCx; /* The new cursor */
+
+ pOrig = p->apCsr[pOp->p2];
+ assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
+
+ pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
+ if( pCx==0 ) goto no_mem;
+ pCx->nullRow = 1;
+ pCx->isEphemeral = 1;
+ pCx->pKeyInfo = pOrig->pKeyInfo;
+ pCx->isTable = pOrig->isTable;
+ rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
+ pCx->pKeyInfo, pCx->uc.pCursor);
+ /* The sqlite3BtreeCursor() routine can only fail for the first cursor
+ ** opened for a database. Since there is already an open cursor when this
+ ** opcode is run, the sqlite3BtreeCursor() cannot fail */
+ assert( rc==SQLITE_OK );
+ break;
+}
+
/* Opcode: OpenEphemeral P1 P2 * P4 P5
** Synopsis: nColumn=P2
**
** Open a new cursor P1 to a transient table.
@@ -82061,21 +82292,35 @@
sqlite3_search_count++;
#endif
if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
if( res<0 || (res==0 && oc==OP_SeekGT) ){
res = 0;
- rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ res = 1;
+ }else{
+ goto abort_due_to_error;
+ }
+ }
}else{
res = 0;
}
}else{
assert( oc==OP_SeekLT || oc==OP_SeekLE );
if( res>0 || (res==0 && oc==OP_SeekLT) ){
res = 0;
- rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3BtreePrevious(pC->uc.pCursor, 0);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ res = 1;
+ }else{
+ goto abort_due_to_error;
+ }
+ }
}else{
/* res might be negative because the table is empty. Check to
** see if this is the case.
*/
res = sqlite3BtreeEof(pC->uc.pCursor);
@@ -82191,14 +82436,16 @@
}
#endif
pIdxKey = &r;
pFree = 0;
}else{
+ assert( pIn3->flags & MEM_Blob );
+ rc = ExpandBlob(pIn3);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc ) goto no_mem;
pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
if( pIdxKey==0 ) goto no_mem;
- assert( pIn3->flags & MEM_Blob );
- (void)ExpandBlob(pIn3);
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
}
pIdxKey->default_rc = 0;
takeJump = 0;
if( pOp->opcode==OP_NoConflict ){
@@ -82211,11 +82458,11 @@
break;
}
}
}
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
- if( pFree ) sqlite3DbFree(db, pFree);
+ if( pFree ) sqlite3DbFreeNN(db, pFree);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
pC->seekResult = res;
alreadyExists = (res==0);
@@ -83175,16 +83422,14 @@
** invoked. This opcode advances the cursor to the next sorted
** record, or jumps to P2 if there are no more sorted records.
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
- int res;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
- res = 0;
- rc = sqlite3VdbeSorterNext(db, pC, &res);
+ rc = sqlite3VdbeSorterNext(db, pC);
goto next_tail;
case OP_PrevIfOpen: /* jump */
case OP_NextIfOpen: /* jump */
if( p->apCsr[pOp->p1]==0 ) break;
/* Fall through */
@@ -83191,16 +83436,13 @@
case OP_Prev: /* jump */
case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1nCursor );
assert( pOp->p5aCounter) );
pC = p->apCsr[pOp->p1];
- res = pOp->p3;
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
assert( pC->eCurType==CURTYPE_BTREE );
- assert( res==0 || (res==1 && pC->isTable==0) );
- testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
@@ -83211,25 +83453,25 @@
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found);
assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last );
- rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
+ rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
next_tail:
pC->cacheStatus = CACHE_STALE;
- VdbeBranchTaken(res==0,2);
- if( rc ) goto abort_due_to_error;
- if( res==0 ){
+ VdbeBranchTaken(rc==SQLITE_OK,2);
+ if( rc==SQLITE_OK ){
pC->nullRow = 0;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
goto jump_to_p2_and_check_for_interrupt;
- }else{
- pC->nullRow = 1;
}
+ if( rc!=SQLITE_DONE ) goto abort_due_to_error;
+ rc = SQLITE_OK;
+ pC->nullRow = 1;
goto check_for_interrupt;
}
/* Opcode: IdxInsert P1 P2 P3 P4 P5
** Synopsis: key=r[P2]
@@ -83336,12 +83578,12 @@
pC->cacheStatus = CACHE_STALE;
pC->seekResult = 0;
break;
}
-/* Opcode: Seek P1 * P3 P4 *
-** Synopsis: Move P3 to P1.rowid
+/* Opcode: DeferredSeek P1 * P3 P4 *
+** Synopsis: Move P3 to P1.rowid if needed
**
** P1 is an open index cursor and P3 is a cursor on the corresponding
** table. This opcode does a deferred seek of the P3 table cursor
** to the row that corresponds to the current row of P1.
**
@@ -83364,15 +83606,15 @@
** the end of the index key pointed to by cursor P1. This integer should be
** the rowid of the table entry to which this index entry points.
**
** See also: Rowid, MakeRecord.
*/
-case OP_Seek:
-case OP_IdxRowid: { /* out2 */
- VdbeCursor *pC; /* The P1 index cursor */
- VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */
- i64 rowid; /* Rowid that P1 current points to */
+case OP_DeferredSeek:
+case OP_IdxRowid: { /* out2 */
+ VdbeCursor *pC; /* The P1 index cursor */
+ VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */
+ i64 rowid; /* Rowid that P1 current points to */
assert( pOp->p1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
@@ -83394,11 +83636,11 @@
rowid = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( pOp->opcode==OP_Seek ){
+ if( pOp->opcode==OP_DeferredSeek ){
assert( pOp->p3>=0 && pOp->p3nCursor );
pTabCur = p->apCsr[pOp->p3];
assert( pTabCur!=0 );
assert( pTabCur->eCurType==CURTYPE_BTREE );
assert( pTabCur->uc.pCursor!=0 );
@@ -83521,14 +83763,21 @@
**
** If AUTOVACUUM is enabled then it is possible that another root page
** might be moved into the newly deleted root page in order to keep all
** root pages contiguous at the beginning of the database. The former
** value of the root page that moved - its value before the move occurred -
-** is stored in register P2. If no page
-** movement was required (because the table being dropped was already
-** the last one in the database) then a zero is stored in register P2.
-** If AUTOVACUUM is disabled then a zero is stored in register P2.
+** is stored in register P2. If no page movement was required (because the
+** table being dropped was already the last one in the database) then a
+** zero is stored in register P2. If AUTOVACUUM is disabled then a zero
+** is stored in register P2.
+**
+** This opcode throws an error if there are any active reader VMs when
+** it is invoked. This is done to avoid the difficulty associated with
+** updating existing cursors when a root page is moved in an AUTOVACUUM
+** database. This error is thrown even if the database is not an AUTOVACUUM
+** db in order to avoid introducing an incompatibility between autovacuum
+** and non-autovacuum modes.
**
** See also: Clear
*/
case OP_Destroy: { /* out2 */
int iMoved;
@@ -83729,11 +83978,11 @@
db->init.busy = 1;
initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_OK ) rc = initData.rc;
- sqlite3DbFree(db, zSql);
+ sqlite3DbFreeNN(db, zSql);
db->init.busy = 0;
}
}
if( rc ){
sqlite3ResetAllSchemasOfConnection(db);
@@ -83857,11 +84106,11 @@
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/* Opcode: RowSetAdd P1 P2 * * *
** Synopsis: rowset(P1)=r[P2]
**
-** Insert the integer value held by register P2 into a boolean index
+** Insert the integer value held by register P2 into a RowSet object
** held in register P1.
**
** An assertion fails if P2 is not an integer.
*/
case OP_RowSetAdd: { /* in1, in2 */
@@ -83877,12 +84126,13 @@
}
/* Opcode: RowSetRead P1 P2 P3 * *
** Synopsis: r[P3]=rowset(P1)
**
-** Extract the smallest value from boolean index P1 and put that value into
-** register P3. Or, if boolean index P1 is initially empty, leave P3
+** Extract the smallest value from the RowSet object in P1
+** and put that value into register P3.
+** Or, if RowSet object P1 is initially empty, leave P3
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: { /* jump, in1, out3 */
i64 val;
@@ -83909,19 +84159,18 @@
** contains a RowSet object and that RowSet object contains
** the value held in P3, jump to register P2. Otherwise, insert the
** integer in P3 into the RowSet and continue on to the
** next opcode.
**
-** The RowSet object is optimized for the case where successive sets
-** of integers, where each set contains no duplicates. Each set
-** of values is identified by a unique P4 value. The first set
-** must have P4==0, the final set P4=-1. P4 must be either -1 or
-** non-negative. For non-negative values of P4 only the lower 4
-** bits are significant.
+** The RowSet object is optimized for the case where sets of integers
+** are inserted in distinct phases, which each set contains no duplicates.
+** Each set is identified by a unique P4 value. The first set
+** must have P4==0, the final set must have P4==-1, and for all other sets
+** must have P4>0.
**
** This allows optimizations: (a) when P4==0 there is no need to test
-** the rowset object for P3, as it is guaranteed not to contain it,
+** the RowSet object for P3, as it is guaranteed not to contain it,
** (b) when P4==-1 there is no need to insert the value, as it will
** never be tested for, and (c) when a value that is part of set X is
** inserted, there is no need to search to see if the same value was
** previously inserted as part of set X (only if it was previously
** inserted as part of some other set).
@@ -84024,11 +84273,12 @@
nMem = pProgram->nMem + pProgram->nCsr;
assert( nMem>0 );
if( pProgram->nCsr==0 ) nMem++;
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
- + pProgram->nCsr * sizeof(VdbeCursor *);
+ + pProgram->nCsr * sizeof(VdbeCursor*)
+ + (pProgram->nOp + 7)/8;
pFrame = sqlite3DbMallocZero(db, nByte);
if( !pFrame ){
goto no_mem;
}
sqlite3VdbeMemRelease(pRt);
@@ -84075,10 +84325,12 @@
p->pFrame = pFrame;
p->aMem = aMem = VdbeFrameMem(pFrame);
p->nMem = pFrame->nChildMem;
p->nCursor = (u16)pFrame->nChildCsr;
p->apCsr = (VdbeCursor **)&aMem[p->nMem];
+ pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr];
+ memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
p->anExec = 0;
#endif
@@ -85104,11 +85356,15 @@
char *z = sqlite3VdbeExpandSql(p, zTrace);
x(db->pTraceArg, z);
sqlite3_free(z);
}else
#endif
- {
+ if( db->nVdbeExec>1 ){
+ char *z = sqlite3MPrintf(db, "-- %s", zTrace);
+ (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
+ sqlite3DbFree(db, z);
+ }else{
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
}
}
#ifdef SQLITE_USE_FCNTL_TRACE
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
@@ -86607,13 +86863,13 @@
int n1;
int n2;
int res;
- getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
- getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
- res = memcmp(v1, v2, MIN(n1, n2));
+ getVarint32(&p1[1], n1);
+ getVarint32(&p2[1], n2);
+ res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
if( res==0 ){
res = n1 - n2;
}
if( res==0 ){
@@ -86650,41 +86906,40 @@
int res; /* Return value */
assert( (s1>0 && s1<7) || s1==8 || s1==9 );
assert( (s2>0 && s2<7) || s2==8 || s2==9 );
- if( s1>7 && s2>7 ){
- res = s1 - s2;
- }else{
- if( s1==s2 ){
- if( (*v1 ^ *v2) & 0x80 ){
- /* The two values have different signs */
- res = (*v1 & 0x80) ? -1 : +1;
- }else{
- /* The two values have the same sign. Compare using memcmp(). */
- static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
- int i;
- res = 0;
- for(i=0; i7 ){
- res = +1;
- }else if( s1>7 ){
- res = -1;
- }else{
- res = s1 - s2;
- }
- assert( res!=0 );
-
- if( res>0 ){
- if( *v1 & 0x80 ) res = -1;
- }else{
- if( *v2 & 0x80 ) res = +1;
- }
+ if( s1==s2 ){
+ /* The two values have the same sign. Compare using memcmp(). */
+ static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 };
+ const u8 n = aLen[s1];
+ int i;
+ res = 0;
+ for(i=0; i7 && s2>7 ){
+ res = s1 - s2;
+ }else{
+ if( s2>7 ){
+ res = +1;
+ }else if( s1>7 ){
+ res = -1;
+ }else{
+ res = s1 - s2;
+ }
+ assert( res!=0 );
+
+ if( res>0 ){
+ if( *v1 & 0x80 ) res = -1;
+ }else{
+ if( *v2 & 0x80 ) res = +1;
}
}
if( res==0 ){
if( pTask->pSorter->pKeyInfo->nField>1 ){
@@ -88405,13 +88660,17 @@
vdbeSorterRewindDebug("rewinddone");
return rc;
}
/*
-** Advance to the next element in the sorter.
+** Advance to the next element in the sorter. Return value:
+**
+** SQLITE_OK success
+** SQLITE_DONE end of data
+** otherwise some kind of error.
*/
-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
+SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
VdbeSorter *pSorter;
int rc; /* Return code */
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
@@ -88421,25 +88680,26 @@
assert( pSorter->bUseThreads==0 || pSorter->pReader );
assert( pSorter->bUseThreads==1 || pSorter->pMerger );
#if SQLITE_MAX_WORKER_THREADS>0
if( pSorter->bUseThreads ){
rc = vdbePmaReaderNext(pSorter->pReader);
- *pbEof = (pSorter->pReader->pFd==0);
+ if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE;
}else
#endif
/*if( !pSorter->bUseThreads )*/ {
+ int res = 0;
assert( pSorter->pMerger!=0 );
assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
- rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
+ rc = vdbeMergeEngineStep(pSorter->pMerger, &res);
+ if( rc==SQLITE_OK && res ) rc = SQLITE_DONE;
}
}else{
SorterRecord *pFree = pSorter->list.pList;
pSorter->list.pList = pFree->u.pNext;
pFree->u.pNext = 0;
if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
- *pbEof = !pSorter->list.pList;
- rc = SQLITE_OK;
+ rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE;
}
return rc;
}
/*
@@ -89089,44 +89349,37 @@
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
** on the compound select chain, p->pPrior.
**
** If it is not NULL, the xSelectCallback() callback is invoked before
** the walk of the expressions and FROM clause. The xSelectCallback2()
-** method, if it is not NULL, is invoked following the walk of the
-** expressions and FROM clause.
+** method is invoked following the walk of the expressions and FROM clause,
+** but only if both xSelectCallback and xSelectCallback2 are both non-NULL
+** and if the expressions and FROM clause both return WRC_Continue;
**
** Return WRC_Continue under normal conditions. Return WRC_Abort if
** there is an abort request.
**
** If the Walker does not have an xSelectCallback() then this routine
** is a no-op returning WRC_Continue.
*/
SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
int rc;
- if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
- return WRC_Continue;
- }
- rc = WRC_Continue;
- pWalker->walkerDepth++;
- while( p ){
- if( pWalker->xSelectCallback ){
- rc = pWalker->xSelectCallback(pWalker, p);
- if( rc ) break;
- }
+ if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue;
+ do{
+ rc = pWalker->xSelectCallback(pWalker, p);
+ if( rc ) return rc & WRC_Abort;
if( sqlite3WalkSelectExpr(pWalker, p)
|| sqlite3WalkSelectFrom(pWalker, p)
){
- pWalker->walkerDepth--;
return WRC_Abort;
}
if( pWalker->xSelectCallback2 ){
pWalker->xSelectCallback2(pWalker, p);
}
p = p->pPrior;
- }
- pWalker->walkerDepth--;
- return rc & WRC_Abort;
+ }while( p!=0 );
+ return WRC_Continue;
}
/************** End of walker.c **********************************************/
/************** Begin file resolve.c *****************************************/
/*
@@ -90559,41 +90812,33 @@
Expr *pExpr /* The expression to be analyzed. */
){
u16 savedHasAgg;
Walker w;
- if( pExpr==0 ) return 0;
-#if SQLITE_MAX_EXPR_DEPTH>0
- {
- Parse *pParse = pNC->pParse;
- if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){
- return 1;
- }
- pParse->nHeight += pExpr->nHeight;
- }
-#endif
+ if( pExpr==0 ) return SQLITE_OK;
savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
w.pParse = pNC->pParse;
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
w.xSelectCallback2 = 0;
- w.walkerDepth = 0;
- w.eCode = 0;
w.u.pNC = pNC;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ w.pParse->nHeight += pExpr->nHeight;
+ if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
+ return SQLITE_ERROR;
+ }
+#endif
sqlite3WalkExpr(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
- pNC->pParse->nHeight -= pExpr->nHeight;
+ w.pParse->nHeight -= pExpr->nHeight;
#endif
- if( pNC->nErr>0 || w.pParse->nErr>0 ){
- ExprSetProperty(pExpr, EP_Error);
- }
if( pNC->ncFlags & NC_HasAgg ){
ExprSetProperty(pExpr, EP_Agg);
}
pNC->ncFlags |= savedHasAgg;
- return ExprHasProperty(pExpr, EP_Error);
+ return pNC->nErr>0 || w.pParse->nErr>0;
}
/*
** Resolve all names for all expression in an expression list. This is
** just like sqlite3ResolveExprNames() except that it works for an expression
@@ -90630,13 +90875,13 @@
NameContext *pOuterNC /* Name context for parent SELECT statement */
){
Walker w;
assert( p!=0 );
- memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
+ w.xSelectCallback2 = 0;
w.pParse = pParse;
w.u.pNC = pOuterNC;
sqlite3WalkSelect(&w, p);
}
@@ -90735,11 +90980,11 @@
if( op==TK_CAST ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
return sqlite3AffinityType(pExpr->u.zToken, 0);
}
#endif
- if( op==TK_AGG_COLUMN || op==TK_COLUMN ){
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){
return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
}
if( op==TK_SELECT_COLUMN ){
assert( pExpr->pLeft->flags&EP_xIsSelect );
return sqlite3ExprAffinity(
@@ -91029,11 +91274,10 @@
}else{
return 1;
}
}
-#ifndef SQLITE_OMIT_SUBQUERY
/*
** Return a pointer to a subexpression of pVector that is the i-th
** column of the vector (numbered starting with 0). The caller must
** ensure that i is within range.
**
@@ -91057,13 +91301,11 @@
return pVector->x.pList->a[i].pExpr;
}
}
return pVector;
}
-#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
-#ifndef SQLITE_OMIT_SUBQUERY
/*
** Compute and return a new Expr object which when passed to
** sqlite3ExprCode() will generate all necessary code to compute
** the iField-th column of the vector expression pVector.
**
@@ -91117,11 +91359,10 @@
if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
pRet = sqlite3ExprDup(pParse->db, pVector, 0);
}
return pRet;
}
-#endif /* !define(SQLITE_OMIT_SUBQUERY) */
/*
** If expression pExpr is of type TK_SELECT, generate code to evaluate
** it. Return the register in which the result is stored (or, if the
** sub-select returns more than one column, the first in an array
@@ -91633,11 +91874,11 @@
if( pExpr==0 ) return;
assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
z = pExpr->u.zToken;
assert( z!=0 );
assert( z[0]!=0 );
- assert( n==sqlite3Strlen30(z) );
+ assert( n==(u32)sqlite3Strlen30(z) );
if( z[1]==0 ){
/* Wildcard of the form "?". Assign the next variable number */
assert( z[0]=='?' );
x = (ynVar)(++pParse->nVar);
}else{
@@ -91715,11 +91956,11 @@
sqlite3ExprListDelete(db, p->x.pList);
}
}
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
if( !ExprHasProperty(p, EP_Static) ){
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
}
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p ) sqlite3ExprDeleteNN(db, p);
}
@@ -91982,19 +92223,15 @@
struct ExprList_item *pItem, *pOldItem;
int i;
Expr *pPriorSelectCol = 0;
assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pNew = sqlite3DbMallocRawNN(db,
+ sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) );
if( pNew==0 ) return 0;
- pNew->nExpr = i = p->nExpr;
- if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){}
- pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) );
- if( pItem==0 ){
- sqlite3DbFree(db, pNew);
- return 0;
- }
+ pNew->nAlloc = pNew->nExpr = p->nExpr;
+ pItem = pNew->a;
pOldItem = p->a;
for(i=0; inExpr; i++, pItem++, pOldItem++){
Expr *pOldExpr = pOldItem->pExpr;
Expr *pNewExpr;
pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
@@ -92081,11 +92318,11 @@
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nId = p->nId;
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
- sqlite3DbFree(db, pNew);
+ sqlite3DbFreeNN(db, pNew);
return 0;
}
/* Note that because the size of the allocation for p->a[] is not
** necessarily a power of two, sqlite3IdListAppend() may not be called
** on the duplicate created by this function. */
@@ -92152,35 +92389,35 @@
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List to which to append. Might be NULL */
Expr *pExpr /* Expression to be appended. Might be NULL */
){
+ struct ExprList_item *pItem;
sqlite3 *db = pParse->db;
assert( db!=0 );
if( pList==0 ){
pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) );
if( pList==0 ){
goto no_mem;
}
pList->nExpr = 0;
- pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0]));
- if( pList->a==0 ) goto no_mem;
- }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
- struct ExprList_item *a;
- assert( pList->nExpr>0 );
- a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
- if( a==0 ){
+ pList->nAlloc = 1;
+ }else if( pList->nExpr==pList->nAlloc ){
+ ExprList *pNew;
+ pNew = sqlite3DbRealloc(db, pList,
+ sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0]));
+ if( pNew==0 ){
goto no_mem;
}
- pList->a = a;
- }
- assert( pList->a!=0 );
- if( 1 ){
- struct ExprList_item *pItem = &pList->a[pList->nExpr++];
- memset(pItem, 0, sizeof(*pItem));
- pItem->pExpr = pExpr;
- }
+ pList = pNew;
+ pList->nAlloc *= 2;
+ }
+ pItem = &pList->a[pList->nExpr++];
+ assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
+ assert( offsetof(struct ExprList_item,pExpr)==0 );
+ memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName));
+ pItem->pExpr = pExpr;
return pList;
no_mem:
/* Avoid leaking memory if malloc has failed. */
sqlite3ExprDelete(db, pExpr);
@@ -92233,24 +92470,23 @@
pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
pColumns->a[i].zName = 0;
}
}
- if( pExpr->op==TK_SELECT ){
- if( pList && pList->a[iFirst].pExpr ){
- Expr *pFirst = pList->a[iFirst].pExpr;
- assert( pFirst->op==TK_SELECT_COLUMN );
-
- /* Store the SELECT statement in pRight so it will be deleted when
- ** sqlite3ExprListDelete() is called */
- pFirst->pRight = pExpr;
- pExpr = 0;
-
- /* Remember the size of the LHS in iTable so that we can check that
- ** the RHS and LHS sizes match during code generation. */
- pFirst->iTable = pColumns->nId;
- }
+ if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
+ Expr *pFirst = pList->a[iFirst].pExpr;
+ assert( pFirst!=0 );
+ assert( pFirst->op==TK_SELECT_COLUMN );
+
+ /* Store the SELECT statement in pRight so it will be deleted when
+ ** sqlite3ExprListDelete() is called */
+ pFirst->pRight = pExpr;
+ pExpr = 0;
+
+ /* Remember the size of the LHS in iTable so that we can check that
+ ** the RHS and LHS sizes match during code generation. */
+ pFirst->iTable = pColumns->nId;
}
vector_append_error:
sqlite3ExprDelete(db, pExpr);
sqlite3IdListDelete(db, pColumns);
@@ -92340,20 +92576,20 @@
/*
** Delete an entire expression list.
*/
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
- int i;
- struct ExprList_item *pItem;
- assert( pList->a!=0 || pList->nExpr==0 );
- for(pItem=pList->a, i=0; inExpr; i++, pItem++){
+ int i = pList->nExpr;
+ struct ExprList_item *pItem = pList->a;
+ assert( pList->nExpr>0 );
+ do{
sqlite3ExprDelete(db, pItem->pExpr);
sqlite3DbFree(db, pItem->zName);
sqlite3DbFree(db, pItem->zSpan);
- }
- sqlite3DbFree(db, pList->a);
- sqlite3DbFree(db, pList);
+ pItem++;
+ }while( --i>0 );
+ sqlite3DbFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
}
@@ -92428,14 +92664,16 @@
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
testcase( pExpr->op==TK_AGG_COLUMN );
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
return WRC_Continue;
- }else{
- pWalker->eCode = 0;
- return WRC_Abort;
}
+ /* Fall through */
+ case TK_IF_NULL_ROW:
+ testcase( pExpr->op==TK_IF_NULL_ROW );
+ pWalker->eCode = 0;
+ return WRC_Abort;
case TK_VARIABLE:
if( pWalker->eCode==5 ){
/* Silently convert bound parameters that appear inside of CREATE
** statements into a NULL when parsing the CREATE statement text out
** of the sqlite_master table */
@@ -92458,14 +92696,16 @@
pWalker->eCode = 0;
return WRC_Abort;
}
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlite3SelectWalkAssert2;
+#endif
w.u.iCur = iCur;
sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -92499,10 +92739,69 @@
*/
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
return exprIsConst(p, 3, iCur);
}
+
+/*
+** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
+*/
+static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
+ ExprList *pGroupBy = pWalker->u.pGroupBy;
+ int i;
+
+ /* Check if pExpr is identical to any GROUP BY term. If so, consider
+ ** it constant. */
+ for(i=0; inExpr; i++){
+ Expr *p = pGroupBy->a[i].pExpr;
+ if( sqlite3ExprCompare(pExpr, p, -1)<2 ){
+ CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
+ if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
+ return WRC_Prune;
+ }
+ }
+ }
+
+ /* Check if pExpr is a sub-select. If so, consider it variable. */
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+
+ return exprNodeIsConstant(pWalker, pExpr);
+}
+
+/*
+** Walk the expression tree passed as the first argument. Return non-zero
+** if the expression consists entirely of constants or copies of terms
+** in pGroupBy that sort with the BINARY collation sequence.
+**
+** This routine is used to determine if a term of the HAVING clause can
+** be promoted into the WHERE clause. In order for such a promotion to work,
+** the value of the HAVING clause term must be the same for all members of
+** a "group". The requirement that the GROUP BY term must be BINARY
+** assumes that no other collating sequence will have a finer-grained
+** grouping than binary. In other words (A=B COLLATE binary) implies
+** A=B in every other collating sequence. The requirement that the
+** GROUP BY be BINARY is stricter than necessary. It would also work
+** to promote HAVING clauses that use the same alternative collating
+** sequence as the GROUP BY term, but that is much harder to check,
+** alternative collating sequences are uncommon, and this is only an
+** optimization, so we take the easy way out and simply require the
+** GROUP BY to use the BINARY collating sequence.
+*/
+SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
+ Walker w;
+ w.eCode = 1;
+ w.xExprCallback = exprNodeIsConstantOrGroupBy;
+ w.xSelectCallback = 0;
+ w.u.pGroupBy = pGroupBy;
+ w.pParse = pParse;
+ sqlite3WalkExpr(&w, p);
+ return w.eCode;
+}
+
/*
** Walk an expression tree. Return non-zero if the expression is constant
** or a function call with constant arguments. Return and 0 if there
** are any variables.
**
@@ -92520,14 +92819,16 @@
** Walk an expression tree. Return 1 if the expression contains a
** subquery of some kind. Return 0 if there are no subqueries.
*/
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = 1;
w.xExprCallback = sqlite3ExprWalkNoop;
w.xSelectCallback = selectNodeIsConstant;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlite3SelectWalkAssert2;
+#endif
sqlite3WalkExpr(&w, p);
return w.eCode==0;
}
#endif
@@ -92537,10 +92838,11 @@
** in *pValue. If the expression is not an integer or if it is too big
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
*/
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
int rc = 0;
+ if( p==0 ) return 0; /* Can only happen following on OOM */
/* If an expression is an integer literal that fits in a signed 32-bit
** integer, then the EP_IntValue flag will have already been set */
assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0
|| sqlite3GetInt32(p->u.zToken, &rc)==0 );
@@ -93209,11 +93511,10 @@
if( ALWAYS(pEList->nExpr==nVal) ){
SelectDest dest;
int i;
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.zAffSdst = exprINAffinity(pParse, pExpr);
- assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
pSelect->iLimit = 0;
testcase( pSelect->selFlags & SF_Distinct );
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
if( sqlite3Select(pParse, pSelect, &dest) ){
sqlite3DbFree(pParse->db, dest.zAffSdst);
@@ -93876,10 +94177,14 @@
Table *pTab, /* The table containing the value */
int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */
int iCol, /* Index of the column to extract */
int regOut /* Extract the value into this register */
){
+ if( pTab==0 ){
+ sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
+ return;
+ }
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
}else{
int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
int x = iCol;
@@ -94032,11 +94337,15 @@
if( nResult==1 ){
iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable);
}else{
*piFreeable = 0;
if( p->op==TK_SELECT ){
+#if SQLITE_OMIT_SUBQUERY
+ iResult = 0;
+#else
iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
+#endif
}else{
int i;
iResult = pParse->nMem+1;
pParse->nMem += nResult;
for(i=0; iiTable);
+ sqlite3ExprCachePush(pParse);
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ sqlite3ExprCachePop(pParse);
+ sqlite3VdbeJumpHere(v, addrINR);
+ sqlite3VdbeChangeP3(v, addrINR, inReg);
+ break;
+ }
/*
** Form A:
** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
**
@@ -95509,12 +95829,12 @@
*/
SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
Walker w;
struct SrcCount cnt;
assert( pExpr->op==TK_AGG_FUNCTION );
- memset(&w, 0, sizeof(w));
w.xExprCallback = exprSrcCount;
+ w.xSelectCallback = 0;
w.u.pSrcCount = &cnt;
cnt.pSrc = pSrcList;
cnt.nThis = 0;
cnt.nOther = 0;
sqlite3WalkExprList(&w, pExpr->x.pList);
@@ -95682,13 +96002,17 @@
}
}
return WRC_Continue;
}
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
- UNUSED_PARAMETER(pWalker);
+ UNUSED_PARAMETER(pSelect);
+ pWalker->walkerDepth++;
+ return WRC_Continue;
+}
+static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
UNUSED_PARAMETER(pSelect);
- return WRC_Continue;
+ pWalker->walkerDepth--;
}
/*
** Analyze the pExpr expression looking for aggregate functions and
** for variables that need to be added to AggInfo object that pNC->pAggInfo
@@ -95698,13 +96022,14 @@
** This routine should only be called after the expression has been
** analyzed by sqlite3ResolveExprNames().
*/
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
Walker w;
- memset(&w, 0, sizeof(w));
w.xExprCallback = analyzeAggregate;
w.xSelectCallback = analyzeAggregatesInSelect;
+ w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
+ w.walkerDepth = 0;
w.u.pNC = pNC;
assert( pNC->pSrcList!=0 );
sqlite3WalkExpr(&w, pExpr);
}
@@ -97834,11 +98159,11 @@
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
int j, k, regKey;
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; jnKeyCol; j++){
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
- assert( k>=0 && knCol );
+ assert( k>=0 && knColumn );
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
@@ -99346,10 +99671,22 @@
}
if( db->xAuth==0 ){
return SQLITE_OK;
}
+
+ /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the
+ ** callback are either NULL pointers or zero-terminated strings that
+ ** contain additional details about the action to be authorized.
+ **
+ ** The following testcase() macros show that any of the 3rd through 6th
+ ** parameters can be either NULL or a string. */
+ testcase( zArg1==0 );
+ testcase( zArg2==0 );
+ testcase( zArg3==0 );
+ testcase( pParse->zAuthContext==0 );
+
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
#ifdef SQLITE_USER_AUTHENTICATION
,db->auth.zAuthUser
#endif
);
@@ -100333,11 +100670,15 @@
}
pTable->zName = zName;
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nTabRef = 1;
+#ifdef SQLITE_DEFAULT_ROWEST
+ pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST);
+#else
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
+#endif
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
/* If this is the magic sqlite_sequence table used by autoincrement,
** then record a pointer to this table in the main database structure
@@ -103017,11 +103358,11 @@
if( pList==0 ) return;
for(i=0; inId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
sqlite3DbFree(db, pList->a);
- sqlite3DbFree(db, pList);
+ sqlite3DbFreeNN(db, pList);
}
/*
** Return the index in pList of the identifier named zId. Return -1
** if not found.
@@ -103207,11 +103548,11 @@
sqlite3DeleteTable(db, pItem->pTab);
sqlite3SelectDelete(db, pItem->pSelect);
sqlite3ExprDelete(db, pItem->pOn);
sqlite3IdListDelete(db, pItem->pUsing);
}
- sqlite3DbFree(db, pList);
+ sqlite3DbFreeNN(db, pList);
}
/*
** This routine is called by the parser to add a new term to the
** end of a growing FROM clause. The "p" parameter is the part of
@@ -104681,11 +105022,18 @@
#ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
/* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to erase the whole table. Prior to version 3.6.5,
** this optimization caused the row change count (the value returned by
- ** API function sqlite3_count_changes) to be set incorrectly. */
+ ** API function sqlite3_count_changes) to be set incorrectly.
+ **
+ ** The "rcauth==SQLITE_OK" terms is the
+ ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and
+ ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but
+ ** the truncate optimization is disabled and all rows are deleted
+ ** individually.
+ */
if( rcauth==SQLITE_OK
&& pWhere==0
&& !bComplex
&& !IsVirtual(pTab)
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@@ -104783,11 +105131,11 @@
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
}else{
/* Add the rowid of the row to be deleted to the RowSet */
- nKey = 1; /* OP_Seek always uses a single rowid */
+ nKey = 1; /* OP_DeferredSeek always uses a single rowid */
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
}
}
/* If this DELETE cannot use the ONEPASS strategy, this is the
@@ -105435,19 +105783,17 @@
nNeedle = sqlite3_value_bytes(argv[1]);
if( nNeedle>0 ){
if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
zHaystack = sqlite3_value_blob(argv[0]);
zNeedle = sqlite3_value_blob(argv[1]);
- assert( zNeedle!=0 );
- assert( zHaystack!=0 || nHaystack==0 );
isText = 0;
}else{
zHaystack = sqlite3_value_text(argv[0]);
zNeedle = sqlite3_value_text(argv[1]);
isText = 1;
- if( zHaystack==0 || zNeedle==0 ) return;
}
+ if( zNeedle==0 || (nHaystack && zHaystack==0) ) return;
while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
N++;
do{
nHaystack--;
zHaystack++;
@@ -108193,42 +108539,57 @@
** entry in the aChange[] array is set to -1. If the column is modified,
** the value is 0 or greater. Parameter chngRowid is set to true if the
** UPDATE statement modifies the rowid fields of the table.
**
** If any foreign key processing will be required, this function returns
-** true. If there is no foreign key related processing, this function
-** returns false.
+** non-zero. If there is no foreign key related processing, this function
+** returns zero.
+**
+** For an UPDATE, this function returns 2 if:
+**
+** * There are any FKs for which pTab is the child and the parent table, or
+** * the UPDATE modifies one or more parent keys for which the action is
+** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
+**
+** Or, assuming some other foreign key processing is required, 1.
*/
SQLITE_PRIVATE int sqlite3FkRequired(
Parse *pParse, /* Parse context */
Table *pTab, /* Table being modified */
int *aChange, /* Non-NULL for UPDATE operations */
int chngRowid /* True for UPDATE that affects rowid */
){
+ int eRet = 0;
if( pParse->db->flags&SQLITE_ForeignKeys ){
if( !aChange ){
/* A DELETE operation. Foreign key processing is required if the
** table in question is either the child or parent table for any
** foreign key constraint. */
- return (sqlite3FkReferences(pTab) || pTab->pFKey);
+ eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
}else{
/* This is an UPDATE. Foreign key processing is only required if the
** operation modifies one or more child or parent key columns. */
FKey *p;
/* Check if any child key columns are being modified. */
for(p=pTab->pFKey; p; p=p->pNextFrom){
- if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
+ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
+ if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
+ eRet = 1;
+ }
}
/* Check if any parent key columns are being modified. */
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
- if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
+ if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
+ if( p->aAction[1]!=OE_None ) return 2;
+ eRet = 1;
+ }
}
}
}
- return 0;
+ return eRet;
}
/*
** This function is called when an UPDATE or DELETE operation is being
** compiled on table pTab, which is the parent table of foreign-key pFKey.
@@ -109034,14 +109395,14 @@
Trigger *pTrigger; /* List of triggers on pTab, if required */
int tmask; /* Mask of trigger times */
#endif
db = pParse->db;
- memset(&dest, 0, sizeof(dest));
if( pParse->nErr || db->mallocFailed ){
goto insert_cleanup;
}
+ dest.iSDParm = 0; /* Suppress a harmless compiler warning */
/* If the Select object is really just a simple VALUES() list with a
** single row (the common case) then keep that one row of values
** and discard the other (unused) parts of the pSelect object
*/
@@ -110740,12 +111101,10 @@
** might change the definition of a collation sequence and then run
** a VACUUM command. In that case keys may not be written in strictly
** sorted order. */
for(i=0; inColumn; i++){
const char *zColl = pSrcIdx->azColl[i];
- assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0
- || sqlite3StrBINARY==zColl );
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
}
if( i==pSrcIdx->nColumn ){
idxInsFlags = OPFLAG_USESEEKRESULT;
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
@@ -111228,10 +111587,12 @@
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
+ /* Version 3.18.0 and later */
+ void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
@@ -111486,10 +111847,12 @@
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
+/* Version 3.18.0 and later */
+#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
@@ -111911,11 +112274,13 @@
sqlite3_db_cacheflush,
/* Version 3.12.0 and later */
sqlite3_system_errno,
/* Version 3.14.0 and later */
sqlite3_trace_v2,
- sqlite3_expanded_sql
+ sqlite3_expanded_sql,
+ /* Version 3.18.0 and later */
+ sqlite3_set_last_insert_rowid
};
/*
** Attempt to load an SQLite extension library contained in the file
** zFile. The entry point is zProc. zProc may be 0 in which case a
@@ -112730,11 +113095,11 @@
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
{/* zName: */ "optimize",
/* ePragTyp: */ PragTyp_OPTIMIZE,
- /* ePragFlg: */ PragFlg_Result1,
+ /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "page_count",
/* ePragTyp: */ PragTyp_PAGE_COUNT,
@@ -113916,11 +114281,11 @@
returnSingleInt(v, pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
- }else{
+ }else if( iDb!=1 ){
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
if( iLevel==0 ) iLevel = 1;
pDb->safety_level = iLevel;
pDb->bSyncSet = 1;
setAllPagerFlags(db);
@@ -114230,37 +114595,41 @@
if( pParent ){
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
assert( x==0 );
}
addrOk = sqlite3VdbeMakeLabel(v);
- if( pParent && pIdx==0 ){
- int iKey = pFK->aCol[0].iFrom;
- assert( iKey>=0 && iKeynCol );
- if( iKey!=pTab->iPKey ){
- sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
- sqlite3ColumnDefault(v, pTab, iKey, regRow);
- sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
- }else{
- sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
- }
- sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
+
+ /* Generate code to read the child key values into registers
+ ** regRow..regRow+n. If any of the child key values are NULL, this
+ ** row cannot cause an FK violation. Jump directly to addrOk in
+ ** this case. */
+ for(j=0; jnCol; j++){
+ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
+ }
+
+ /* Generate code to query the parent index for a matching parent
+ ** key. If a match is found, jump to addrOk. */
+ if( pIdx ){
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
+ sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
+ sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
+ VdbeCoverage(v);
+ }else if( pParent ){
+ int jmp = sqlite3VdbeCurrentAddr(v)+2;
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
sqlite3VdbeGoto(v, addrOk);
- sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+ assert( pFK->nCol==1 );
+ }
+
+ /* Generate code to report an FK violation to the caller. */
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
}else{
- for(j=0; jnCol; j++){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
- aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
- sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
- }
- if( pParent ){
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
- sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
- sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
- VdbeCoverage(v);
- }
- }
- sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
+ }
sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
sqlite3VdbeResolveLabel(v, addrOk);
sqlite3DbFree(db, aiCols);
}
@@ -114406,10 +114775,11 @@
Index *pPrior = 0;
int loopTop;
int iDataCur, iIdxCur;
int r1 = -1;
+ if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
if( pTab->pCheck==0
&& (pTab->tabFlags & TF_HasNotNull)==0
&& (pTab->pIndex==0 || isQuick)
){
continue; /* No additional checks needed for this table */
@@ -114441,29 +114811,32 @@
integrityCheckResultRow(v, 3);
sqlite3VdbeJumpHere(v, jmp2);
}
/* Verify CHECK constraints */
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
- int addrCkFault = sqlite3VdbeMakeLabel(v);
- int addrCkOk = sqlite3VdbeMakeLabel(v);
- ExprList *pCheck = pTab->pCheck;
- char *zErr;
- int k;
- pParse->iSelfTab = iDataCur;
- sqlite3ExprCachePush(pParse);
- for(k=pCheck->nExpr-1; k>0; k--){
- sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
- }
- sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
- SQLITE_JUMPIFNULL);
- sqlite3VdbeResolveLabel(v, addrCkFault);
- zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
- pTab->zName);
- sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- integrityCheckResultRow(v, 3);
- sqlite3VdbeResolveLabel(v, addrCkOk);
- sqlite3ExprCachePop(pParse);
+ ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
+ if( db->mallocFailed==0 ){
+ int addrCkFault = sqlite3VdbeMakeLabel(v);
+ int addrCkOk = sqlite3VdbeMakeLabel(v);
+ char *zErr;
+ int k;
+ pParse->iSelfTab = iDataCur;
+ sqlite3ExprCachePush(pParse);
+ for(k=pCheck->nExpr-1; k>0; k--){
+ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
+ }
+ sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
+ SQLITE_JUMPIFNULL);
+ sqlite3VdbeResolveLabel(v, addrCkFault);
+ zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
+ pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ integrityCheckResultRow(v, 3);
+ sqlite3VdbeResolveLabel(v, addrCkOk);
+ sqlite3ExprCachePop(pParse);
+ }
+ sqlite3ExprListDelete(db, pCheck);
}
/* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
int jmp2, jmp3, jmp4, jmp5;
int ckUniq = sqlite3VdbeMakeLabel(v);
@@ -116263,11 +116636,11 @@
sqlite3ExprDelete(db, p->pHaving);
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
if( p->pWith ) sqlite3WithDelete(db, p->pWith);
- if( bFree ) sqlite3DbFree(db, p);
+ if( bFree ) sqlite3DbFreeNN(db, p);
p = pPrior;
bFree = 1;
}
}
@@ -116299,18 +116672,17 @@
Expr *pLimit, /* LIMIT value. NULL means not used */
Expr *pOffset /* OFFSET value. NULL means no offset */
){
Select *pNew;
Select standin;
- sqlite3 *db = pParse->db;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
if( pNew==0 ){
- assert( db->mallocFailed );
+ assert( pParse->db->mallocFailed );
pNew = &standin;
}
if( pEList==0 ){
- pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
+ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0));
}
pNew->pEList = pEList;
pNew->op = TK_SELECT;
pNew->selFlags = selFlags;
pNew->iLimit = 0;
@@ -116319,11 +116691,11 @@
pNew->zSelName[0] = 0;
#endif
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = 0;
- if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
+ if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy;
@@ -116330,13 +116702,13 @@
pNew->pPrior = 0;
pNew->pNext = 0;
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
pNew->pWith = 0;
- assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
- if( db->mallocFailed ) {
- clearSelect(db, pNew, pNew!=&standin);
+ assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 );
+ if( pParse->db->mallocFailed ) {
+ clearSelect(pParse->db, pNew, pNew!=&standin);
pNew = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
}
assert( pNew!=&standin );
@@ -117219,11 +117591,11 @@
/*
** Allocate a KeyInfo object sufficient for an index of N key columns and
** X extra columns.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
- int nExtra = (N+X)*(sizeof(CollSeq*)+1);
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
p->nField = (u16)N;
p->nXField = (u16)X;
@@ -117242,11 +117614,11 @@
*/
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
assert( p->nRef>0 );
p->nRef--;
- if( p->nRef==0 ) sqlite3DbFree(p->db, p);
+ if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
}
}
/*
** Make a new pointer to a KeyInfo object
@@ -117717,10 +118089,11 @@
Vdbe *v = pParse->pVdbe;
int i;
NameContext sNC;
sNC.pSrcList = pTabList;
sNC.pParse = pParse;
+ sNC.pNext = 0;
for(i=0; inExpr; i++){
Expr *p = pEList->a[i].pExpr;
const char *zType;
#ifdef SQLITE_ENABLE_COLUMN_METADATA
const char *zOrigDb = 0;
@@ -117740,10 +118113,23 @@
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
}
+
+/*
+** Return the Table objecct in the SrcList that has cursor iCursor.
+** Or return NULL if no such Table object exists in the SrcList.
+*/
+static Table *tableWithCursor(SrcList *pList, int iCursor){
+ int j;
+ for(j=0; jnSrc; j++){
+ if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab;
+ }
+ return 0;
+}
+
/*
** Generate code that will tell the VDBE the names of columns
** in the result set. This information is used to provide the
** azCol[] values in the callback.
@@ -117752,11 +118138,12 @@
Parse *pParse, /* Parser context */
SrcList *pTabList, /* List of tables */
ExprList *pEList /* Expressions defining the result set */
){
Vdbe *v = pParse->pVdbe;
- int i, j;
+ int i;
+ Table *pTab;
sqlite3 *db = pParse->db;
int fullNames, shortNames;
#ifndef SQLITE_OMIT_EXPLAIN
/* If this is an EXPLAIN, skip this step */
@@ -117777,19 +118164,15 @@
p = pEList->a[i].pExpr;
if( NEVER(p==0) ) continue;
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
- }else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
- Table *pTab;
+ }else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
+ && (pTab = tableWithCursor(pTabList, p->iTable))!=0
+ ){
char *zCol;
int iCol = p->iColumn;
- for(j=0; ALWAYS(jnSrc); j++){
- if( pTabList->a[j].iCursor==p->iTable ) break;
- }
- assert( jnSrc );
- pTab = pTabList->a[j].pTab;
if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iColnCol) );
if( iCol<0 ){
zCol = "rowid";
}else{
@@ -117867,11 +118250,11 @@
Table *pTab; /* Table associated with this expression */
while( pColExpr->op==TK_DOT ){
pColExpr = pColExpr->pRight;
assert( pColExpr!=0 );
}
- if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
+ if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
pTab = pColExpr->pTab;
if( iCol<0 ) iCol = pTab->iPKey;
zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
@@ -119087,11 +119470,11 @@
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
- pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
+ p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
}
}
}
@@ -119321,13 +119704,28 @@
return pParse->nErr!=0;
}
#endif
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+
+/* An instance of the SubstContext object describes an substitution edit
+** to be performed on a parse tree.
+**
+** All references to columns in table iTable are to be replaced by corresponding
+** expressions in pEList.
+*/
+typedef struct SubstContext {
+ Parse *pParse; /* The parsing context */
+ int iTable; /* Replace references to this table */
+ int iNewTable; /* New table number */
+ int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
+ ExprList *pEList; /* Replacement expressions */
+} SubstContext;
+
/* Forward Declarations */
-static void substExprList(Parse*, ExprList*, int, ExprList*);
-static void substSelect(Parse*, Select *, int, ExprList*, int);
+static void substExprList(SubstContext*, ExprList*);
+static void substSelect(SubstContext*, Select*, int);
/*
** Scan through the expression pExpr. Replace every reference to
** a column in table number iTable with a copy of the iColumn-th
** entry in pEList. (But leave references to the ROWID column
@@ -119334,33 +119732,42 @@
** unchanged.)
**
** This routine is part of the flattening procedure. A subquery
** whose result set is defined by pEList appears as entry in the
** FROM clause of a SELECT such that the VDBE cursor assigned to that
-** FORM clause entry is iTable. This routine make the necessary
+** FORM clause entry is iTable. This routine makes the necessary
** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery.
*/
static Expr *substExpr(
- Parse *pParse, /* Report errors here */
- Expr *pExpr, /* Expr in which substitution occurs */
- int iTable, /* Table to be substituted */
- ExprList *pEList /* Substitute expressions */
+ SubstContext *pSubst, /* Description of the substitution */
+ Expr *pExpr /* Expr in which substitution occurs */
){
- sqlite3 *db = pParse->db;
if( pExpr==0 ) return 0;
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
+ if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){
+ pExpr->iRightJoinTable = pSubst->iNewTable;
+ }
+ if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
}else{
Expr *pNew;
- Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
- assert( pEList!=0 && pExpr->iColumnnExpr );
+ Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
+ Expr ifNullRow;
+ assert( pSubst->pEList!=0 && pExpr->iColumnpEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
if( sqlite3ExprIsVector(pCopy) ){
- sqlite3VectorErrorMsg(pParse, pCopy);
+ sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
+ sqlite3 *db = pSubst->pParse->db;
+ if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
+ memset(&ifNullRow, 0, sizeof(ifNullRow));
+ ifNullRow.op = TK_IF_NULL_ROW;
+ ifNullRow.pLeft = pCopy;
+ ifNullRow.iTable = pSubst->iNewTable;
+ pCopy = &ifNullRow;
+ }
pNew = sqlite3ExprDup(db, pCopy, 0);
if( pNew && (pExpr->flags & EP_FromJoin) ){
pNew->iRightJoinTable = pExpr->iRightJoinTable;
pNew->flags |= EP_FromJoin;
}
@@ -119367,55 +119774,54 @@
sqlite3ExprDelete(db, pExpr);
pExpr = pNew;
}
}
}else{
- pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
- pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList);
+ if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
+ pExpr->iTable = pSubst->iNewTable;
+ }
+ pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
+ pExpr->pRight = substExpr(pSubst, pExpr->pRight);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1);
+ substSelect(pSubst, pExpr->x.pSelect, 1);
}else{
- substExprList(pParse, pExpr->x.pList, iTable, pEList);
+ substExprList(pSubst, pExpr->x.pList);
}
}
return pExpr;
}
static void substExprList(
- Parse *pParse, /* Report errors here */
- ExprList *pList, /* List to scan and in which to make substitutes */
- int iTable, /* Table to be substituted */
- ExprList *pEList /* Substitute values */
+ SubstContext *pSubst, /* Description of the substitution */
+ ExprList *pList /* List to scan and in which to make substitutes */
){
int i;
if( pList==0 ) return;
for(i=0; inExpr; i++){
- pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
+ pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
}
}
static void substSelect(
- Parse *pParse, /* Report errors here */
- Select *p, /* SELECT statement in which to make substitutions */
- int iTable, /* Table to be replaced */
- ExprList *pEList, /* Substitute values */
- int doPrior /* Do substitutes on p->pPrior too */
+ SubstContext *pSubst, /* Description of the substitution */
+ Select *p, /* SELECT statement in which to make substitutions */
+ int doPrior /* Do substitutes on p->pPrior too */
){
SrcList *pSrc;
struct SrcList_item *pItem;
int i;
if( !p ) return;
do{
- substExprList(pParse, p->pEList, iTable, pEList);
- substExprList(pParse, p->pGroupBy, iTable, pEList);
- substExprList(pParse, p->pOrderBy, iTable, pEList);
- p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
- p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
+ substExprList(pSubst, p->pEList);
+ substExprList(pSubst, p->pGroupBy);
+ substExprList(pSubst, p->pOrderBy);
+ p->pHaving = substExpr(pSubst, p->pHaving);
+ p->pWhere = substExpr(pSubst, p->pWhere);
pSrc = p->pSrc;
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
+ substSelect(pSubst, pItem->pSelect, 1);
if( pItem->fg.isTabFunc ){
- substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList);
+ substExprList(pSubst, pItem->u1.pFuncArg);
}
}
}while( doPrior && (p = p->pPrior)!=0 );
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
@@ -119454,12 +119860,13 @@
** (2) The subquery is not an aggregate or (2a) the outer query is not a join
** and (2b) the outer query does not use subqueries other than the one
** FROM-clause subquery that is a candidate for flattening. (2b is
** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
**
-** (3) The subquery is not the right operand of a left outer join
-** (Originally ticket #306. Strengthened by ticket #3300)
+** (3) The subquery is not the right operand of a LEFT JOIN
+** or the subquery is not itself a join and the outer query is not
+** an aggregate.
**
** (4) The subquery is not DISTINCT.
**
** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
** sub-queries that were excluded from this optimization. Restriction
@@ -119467,11 +119874,11 @@
**
** (6) The subquery does not use aggregates or the outer query is not
** DISTINCT.
**
** (7) The subquery has a FROM clause. TODO: For subqueries without
-** A FROM clause, consider adding a FROM close with the special
+** A FROM clause, consider adding a FROM clause with the special
** table sqlite_once that consists of a single row containing a
** single NULL.
**
** (8) The subquery does not use LIMIT or the outer query is not a join.
**
@@ -119573,10 +119980,12 @@
Select *pSub1; /* Pointer to the rightmost select in sub-query */
SrcList *pSrc; /* The FROM clause of the outer query */
SrcList *pSubSrc; /* The FROM clause of the subquery */
ExprList *pList; /* The result set of the outer query */
int iParent; /* VDBE cursor number of the pSub result set temp table */
+ int iNewParent = -1;/* Replacement table for iParent */
+ int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
int i; /* Loop counter */
Expr *pWhere; /* The WHERE clause */
struct SrcList_item *pSubitem; /* The subquery */
sqlite3 *db = pParse->db;
@@ -119599,11 +120008,11 @@
|| (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
){
return 0; /* Restriction (2b) */
}
}
-
+
pSubSrc = pSub->pSrc;
assert( pSubSrc );
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET
** because they could be computed at compile-time. But when LIMIT and OFFSET
@@ -119637,45 +120046,43 @@
}
if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
return 0; /* Restriction (23) */
}
- /* OBSOLETE COMMENT 1:
- ** Restriction 3: If the subquery is a join, make sure the subquery is
- ** not used as the right operand of an outer join. Examples of why this
- ** is not allowed:
+ /*
+ ** If the subquery is the right operand of a LEFT JOIN, then the
+ ** subquery may not be a join itself. Example of why this is not allowed:
**
** t1 LEFT OUTER JOIN (t2 JOIN t3)
**
** If we flatten the above, we would get
**
** (t1 LEFT OUTER JOIN t2) JOIN t3
**
** which is not at all the same thing.
**
- ** OBSOLETE COMMENT 2:
- ** Restriction 12: If the subquery is the right operand of a left outer
- ** join, make sure the subquery has no WHERE clause.
- ** An examples of why this is not allowed:
- **
- ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
- **
- ** If we flatten the above, we would get
- **
- ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
- **
- ** But the t2.x>0 test will always fail on a NULL row of t2, which
- ** effectively converts the OUTER JOIN into an INNER JOIN.
- **
- ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
- ** Ticket #3300 shows that flattening the right term of a LEFT JOIN
- ** is fraught with danger. Best to avoid the whole thing. If the
- ** subquery is the right term of a LEFT JOIN, then do not flatten.
+ ** If the subquery is the right operand of a LEFT JOIN, then the outer
+ ** query cannot be an aggregate. This is an artifact of the way aggregates
+ ** are processed - there is not mechanism to determine if the LEFT JOIN
+ ** table should be all-NULL.
+ **
+ ** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
- return 0;
+ isLeftJoin = 1;
+ if( pSubSrc->nSrc>1 || isAgg ){
+ return 0; /* Restriction (3) */
+ }
}
+#ifdef SQLITE_EXTRA_IFNULLROW
+ else if( iFrom>0 && !isAgg ){
+ /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
+ ** every reference to any result column from subquery in a join, even though
+ ** they are not necessary. This will stress-test the OP_IfNullRow opcode. */
+ isLeftJoin = -1;
+ }
+#endif
/* Restriction 17: If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
@@ -119879,10 +120286,11 @@
*/
for(i=0; ia[i+iFrom].pUsing);
assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
pSrc->a[i+iFrom] = pSubSrc->a[i];
+ iNewParent = pSubSrc->a[i].iCursor;
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
pSrc->a[iFrom].fg.jointype = jointype;
/* Now begin substituting subquery result set expressions for
@@ -119924,10 +120332,13 @@
assert( pSub->pPrior==0 );
pParent->pOrderBy = pOrderBy;
pSub->pOrderBy = 0;
}
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
+ if( isLeftJoin>0 ){
+ setJoinExpr(pWhere, iNewParent);
+ }
if( subqueryIsAgg ){
assert( pParent->pHaving==0 );
pParent->pHaving = pParent->pWhere;
pParent->pWhere = pWhere;
pParent->pHaving = sqlite3ExprAnd(db,
@@ -119936,11 +120347,19 @@
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
}
- substSelect(pParse, pParent, iParent, pSub->pEList, 0);
+ if( db->mallocFailed==0 ){
+ SubstContext x;
+ x.pParse = pParse;
+ x.iTable = iParent;
+ x.iNewTable = iNewParent;
+ x.isLeftJoin = isLeftJoin;
+ x.pEList = pSub->pEList;
+ substSelect(&x, pParent, 0);
+ }
/* The flattened query is distinct if either the inner or the
** outer query is distinct.
*/
pParent->selFlags |= pSub->selFlags & SF_Distinct;
@@ -120038,12 +120457,18 @@
}
if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
nChng++;
while( pSubq ){
+ SubstContext x;
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
- pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
+ x.pParse = pParse;
+ x.iTable = iCursor;
+ x.iNewTable = iCursor;
+ x.isLeftJoin = 0;
+ x.pEList = pSubq->pEList;
+ pNew = substExpr(&x, pNew);
pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
pSubq = pSubq->pPrior;
}
}
return nChng;
@@ -120745,10 +121170,29 @@
SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return WRC_Continue;
}
+/*
+** No-op routine for the parse-tree walker for SELECT statements.
+** subquery in the parser tree.
+*/
+SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return WRC_Continue;
+}
+
+#if SQLITE_DEBUG
+/*
+** Always assert. This xSelectCallback2 implementation proves that the
+** xSelectCallback2 is never invoked.
+*/
+SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ assert( 0 );
+}
+#endif
/*
** This routine "expands" a SELECT statement and all of its subqueries.
** For additional information on what it means to "expand" a SELECT
** statement, see the comment on the selectExpand worker callback above.
**
@@ -120760,15 +121204,15 @@
** The calling function can detect the problem by looking at pParse->nErr
** and/or pParse->db->mallocFailed.
*/
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
- memset(&w, 0, sizeof(w));
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
if( pParse->hasCompound ){
w.xSelectCallback = convertCompoundSelectToSubquery;
+ w.xSelectCallback2 = 0;
sqlite3WalkSelect(&w, pSelect);
}
w.xSelectCallback = selectExpander;
w.xSelectCallback2 = selectPopWith;
sqlite3WalkSelect(&w, pSelect);
@@ -120824,11 +121268,11 @@
** Use this routine after name resolution.
*/
static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
#ifndef SQLITE_OMIT_SUBQUERY
Walker w;
- memset(&w, 0, sizeof(w));
+ w.xSelectCallback = sqlite3SelectWalkNoop;
w.xSelectCallback2 = selectAddSubqueryTypeInfo;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
sqlite3WalkSelect(&w, pSelect);
#endif
@@ -121030,10 +121474,107 @@
}
}
#else
# define explainSimpleCount(a,b,c)
#endif
+
+/*
+** Context object for havingToWhereExprCb().
+*/
+struct HavingToWhereCtx {
+ Expr **ppWhere;
+ ExprList *pGroupBy;
+};
+
+/*
+** sqlite3WalkExpr() callback used by havingToWhere().
+**
+** If the node passed to the callback is a TK_AND node, return
+** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
+**
+** Otherwise, return WRC_Prune. In this case, also check if the
+** sub-expression matches the criteria for being moved to the WHERE
+** clause. If so, add it to the WHERE clause and replace the sub-expression
+** within the HAVING expression with a constant "1".
+*/
+static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op!=TK_AND ){
+ struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
+ if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
+ sqlite3 *db = pWalker->pParse->db;
+ Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
+ if( pNew ){
+ Expr *pWhere = *(p->ppWhere);
+ SWAP(Expr, *pNew, *pExpr);
+ pNew = sqlite3ExprAnd(db, pWhere, pNew);
+ *(p->ppWhere) = pNew;
+ }
+ }
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Transfer eligible terms from the HAVING clause of a query, which is
+** processed after grouping, to the WHERE clause, which is processed before
+** grouping. For example, the query:
+**
+** SELECT * FROM WHERE a=? GROUP BY b HAVING b=? AND c=?
+**
+** can be rewritten as:
+**
+** SELECT * FROM WHERE a=? AND b=? GROUP BY b HAVING c=?
+**
+** A term of the HAVING expression is eligible for transfer if it consists
+** entirely of constants and expressions that are also GROUP BY terms that
+** use the "BINARY" collation sequence.
+*/
+static void havingToWhere(
+ Parse *pParse,
+ ExprList *pGroupBy,
+ Expr *pHaving,
+ Expr **ppWhere
+){
+ struct HavingToWhereCtx sCtx;
+ Walker sWalker;
+
+ sCtx.ppWhere = ppWhere;
+ sCtx.pGroupBy = pGroupBy;
+
+ memset(&sWalker, 0, sizeof(sWalker));
+ sWalker.pParse = pParse;
+ sWalker.xExprCallback = havingToWhereExprCb;
+ sWalker.u.pHavingCtx = &sCtx;
+ sqlite3WalkExpr(&sWalker, pHaving);
+}
+
+/*
+** Check to see if the pThis entry of pTabList is a self-join of a prior view.
+** If it is, then return the SrcList_item for the prior view. If it is not,
+** then return 0.
+*/
+static struct SrcList_item *isSelfJoinView(
+ SrcList *pTabList, /* Search for self-joins in this FROM clause */
+ struct SrcList_item *pThis /* Search for prior reference to this subquery */
+){
+ struct SrcList_item *pItem;
+ for(pItem = pTabList->a; pItempSelect==0 ) continue;
+ if( pItem->fg.viaCoroutine ) continue;
+ if( pItem->zName==0 ) continue;
+ if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
+ if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
+ if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){
+ /* The view was modified by some other optimization such as
+ ** pushDownWhereTerms() */
+ continue;
+ }
+ return pItem;
+ }
+ return 0;
+}
/*
** Generate code for the SELECT statement given in the p argument.
**
** The results are returned according to the SelectDest structure.
@@ -121170,17 +121711,42 @@
#endif
return rc;
}
#endif
- /* Generate code for all sub-queries in the FROM clause
+ /* For each term in the FROM clause, do two things:
+ ** (1) Authorized unreferenced tables
+ ** (2) Generate code for all sub-queries
*/
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; inSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest;
- Select *pSub = pItem->pSelect;
+ Select *pSub;
+
+ /* Issue SQLITE_READ authorizations with a fake column name for any tables that
+ ** are referenced but from which no values are extracted. Examples of where these
+ ** kinds of null SQLITE_READ authorizations would occur:
+ **
+ ** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
+ ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
+ **
+ ** The fake column name is an empty string. It is possible for a table to
+ ** have a column named by the empty string, in which case there is no way to
+ ** distinguish between an unreferenced table and an actual reference to the
+ ** "" column. The original design was for the fake column name to be a NULL,
+ ** which would be unambiguous. But legacy authorization callbacks might
+ ** assume the column name is non-NULL and segfault. The use of an empty string
+ ** for the fake column name seems safer.
+ */
+ if( pItem->colUsed==0 ){
+ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
+ }
+
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+ /* Generate code for all sub-queries in the FROM clause
+ */
+ pSub = pItem->pSelect;
if( pSub==0 ) continue;
/* Sometimes the code for a subquery will be generated more than
** once, if the subquery is part of the WHERE clause in a LEFT JOIN,
** for example. In that case, do not regenerate the code to manifest
@@ -121187,10 +121753,14 @@
** a view or the co-routine to implement a view. The first instance
** is sufficient, though the subroutine to manifest the view does need
** to be invoked again. */
if( pItem->addrFillSub ){
if( pItem->fg.viaCoroutine==0 ){
+ /* The subroutine that manifests the view might be a one-time routine,
+ ** or it might need to be rerun on each iteration because it
+ ** encodes a correlated subquery. */
+ testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once );
sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
}
continue;
}
@@ -121261,10 +121831,12 @@
** is a register allocated to hold the subroutine return address
*/
int topAddr;
int onceAddr = 0;
int retAddr;
+ struct SrcList_item *pPrior;
+
assert( pItem->addrFillSub==0 );
pItem->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
pItem->addrFillSub = topAddr+1;
if( pItem->fg.isCorrelated==0 ){
@@ -121274,24 +121846,32 @@
onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
}else{
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
}
- sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
- explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
- sqlite3Select(pParse, pSub, &dest);
+ pPrior = isSelfJoinView(pTabList, pItem);
+ if( pPrior ){
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
+ explainSetInteger(pItem->iSelectId, pPrior->iSelectId);
+ assert( pPrior->pSelect!=0 );
+ pSub->nSelectRow = pPrior->pSelect->nSelectRow;
+ }else{
+ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
+ explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
+ sqlite3Select(pParse, pSub, &dest);
+ }
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
sqlite3VdbeChangeP1(v, topAddr, retAddr);
sqlite3ClearTempRegCache(pParse);
}
if( db->mallocFailed ) goto select_end;
pParse->nHeight -= sqlite3SelectExprHeight(p);
+#endif
}
-#endif
/* Various elements of the SELECT copied into local variables for
** convenience */
pEList = p->pEList;
pWhere = p->pWhere;
@@ -121495,10 +122075,15 @@
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
if( pHaving ){
+ if( pGroupBy ){
+ assert( pWhere==p->pWhere );
+ havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere);
+ pWhere = p->pWhere;
+ }
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; iz, pAll->n);
+ testcase( z==0 );
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
db->aDb[iDb].zDbSName, MASTER_NAME, zName,
pTrig->table, z);
sqlite3DbFree(db, z);
@@ -123507,11 +124093,11 @@
**
** FIXME: Be smarter about omitting indexes that use expressions.
*/
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
- if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
+ if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){
reg = ++pParse->nMem;
pParse->nMem += pIdx->nColumn;
}else{
reg = 0;
for(i=0; inKeyCol; i++){
@@ -123862,11 +124448,11 @@
** is the column index supplied by the user.
*/
assert( regNew==regNewRowid+1 );
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
- OPFLAG_ISUPDATE | ((hasFK || chngKey) ? 0 : OPFLAG_ISNOOP),
+ OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP),
regNewRowid
);
if( eOnePass==ONEPASS_MULTI ){
assert( hasFK==0 && chngKey==0 );
sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
@@ -123873,11 +124459,11 @@
}
if( !pParse->nested ){
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
#else
- if( hasFK || chngKey ){
+ if( hasFK>1 || chngKey ){
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
}
#endif
if( bReplace || chngKey ){
sqlite3VdbeJumpHere(v, addr1);
@@ -125516,11 +126102,11 @@
/* Check to see the left operand is a column in a virtual table */
if( NEVER(pExpr==0) ) return pDef;
if( pExpr->op!=TK_COLUMN ) return pDef;
pTab = pExpr->pTab;
- if( NEVER(pTab==0) ) return pDef;
+ if( pTab==0 ) return pDef;
if( !IsVirtual(pTab) ) return pDef;
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
@@ -125851,10 +126437,11 @@
union {
struct { /* Information for internal btree tables */
u16 nEq; /* Number of equality constraints */
u16 nBtm; /* Size of BTM vector */
u16 nTop; /* Size of TOP vector */
+ u16 nIdxCol; /* Index column used for ORDER BY */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
int idxNum; /* Index number */
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
@@ -126144,10 +126731,11 @@
struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
+ Expr *pWhere; /* The complete WHERE clause */
LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
@@ -127231,14 +127819,14 @@
** function generates code to do a deferred seek of cursor iCur to the
** rowid stored in register iRowid.
**
** Normally, this is just:
**
-** OP_Seek $iCur $iRowid
+** OP_DeferredSeek $iCur $iRowid
**
** However, if the scan currently being coded is a branch of an OR-loop and
-** the statement currently being coded is a SELECT, then P3 of the OP_Seek
+** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek
** is set to iIdxCur and P4 is set to point to an array of integers
** containing one entry for each column of the table cursor iCur is open
** on. For each table column, if the column is the i'th column of the
** index, then the corresponding array entry is set to (i+1). If the column
** does not appear in the index at all, the array entry is set to 0.
@@ -127253,11 +127841,11 @@
Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */
assert( iIdxCur>0 );
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
- sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
+ sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
){
int i;
Table *pTab = pIdx->pTable;
@@ -127303,10 +127891,73 @@
}else{
assert( nReg==1 );
sqlite3ExprCode(pParse, p, iReg);
}
}
+
+/* An instance of the IdxExprTrans object carries information about a
+** mapping from an expression on table columns into a column in an index
+** down through the Walker.
+*/
+typedef struct IdxExprTrans {
+ Expr *pIdxExpr; /* The index expression */
+ int iTabCur; /* The cursor of the corresponding table */
+ int iIdxCur; /* The cursor for the index */
+ int iIdxCol; /* The column for the index */
+} IdxExprTrans;
+
+/* The walker node callback used to transform matching expressions into
+** a reference to an index column for an index on an expression.
+**
+** If pExpr matches, then transform it into a reference to the index column
+** that contains the value of pExpr.
+*/
+static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
+ IdxExprTrans *pX = p->u.pIdxTrans;
+ if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
+ pExpr->op = TK_COLUMN;
+ pExpr->iTable = pX->iIdxCur;
+ pExpr->iColumn = pX->iIdxCol;
+ pExpr->pTab = 0;
+ return WRC_Prune;
+ }else{
+ return WRC_Continue;
+ }
+}
+
+/*
+** For an indexes on expression X, locate every instance of expression X in pExpr
+** and change that subexpression into a reference to the appropriate column of
+** the index.
+*/
+static void whereIndexExprTrans(
+ Index *pIdx, /* The Index */
+ int iTabCur, /* Cursor of the table that is being indexed */
+ int iIdxCur, /* Cursor of the index itself */
+ WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
+){
+ int iIdxCol; /* Column number of the index */
+ ExprList *aColExpr; /* Expressions that are indexed */
+ Walker w;
+ IdxExprTrans x;
+ aColExpr = pIdx->aColExpr;
+ if( aColExpr==0 ) return; /* Not an index on expressions */
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = whereIndexExprTransNode;
+ w.u.pIdxTrans = &x;
+ x.iTabCur = iTabCur;
+ x.iIdxCur = iIdxCur;
+ for(iIdxCol=0; iIdxColnExpr; iIdxCol++){
+ if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
+ assert( aColExpr->a[iIdxCol].pExpr!=0 );
+ x.iIdxCol = iIdxCol;
+ x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
+ sqlite3WalkExpr(&w, pWInfo->pWhere);
+ sqlite3WalkExprList(&w, pWInfo->pOrderBy);
+ sqlite3WalkExprList(&w, pWInfo->pResultSet);
+ }
+}
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
@@ -127331,10 +127982,12 @@
int addrBrk; /* Jump here to break out of the loop */
int addrHalt; /* addrBrk for the outermost loop */
int addrCont; /* Jump here to continue with next cycle */
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
int iReleaseReg = 0; /* Temp register to free before returning */
+ Index *pIdx = 0; /* Index used by loop (if any) */
+ int loopAgain; /* True if constraint generator loop should repeat */
pParse = pWInfo->pParse;
v = pParse->pVdbe;
pWC = &pWInfo->sWC;
db = pParse->db;
@@ -127656,11 +128309,10 @@
WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */
int startEq; /* True if range start uses ==, >= or <= */
int endEq; /* True if range end uses ==, >= or <= */
int start_constraints; /* Start of range is constrained */
int nConstraint; /* Number of constraint terms */
- Index *pIdx; /* The index we will be using */
int iIdxCur; /* The VDBE cursor for the index */
int nExtraReg = 0; /* Number of extra registers needed */
int op; /* Instruction opcode */
char *zStartAff; /* Affinity for start of range constraint */
char *zEndAff = 0; /* Affinity for end of range constraint */
@@ -127884,10 +128536,17 @@
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
}
sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
+
+ /* If pIdx is an index on one or more expressions, then look through
+ ** all the expressions in pWInfo and try to transform matching expressions
+ ** into reference to index columns.
+ */
+ whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
+
/* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;
}else if( bRev ){
@@ -127900,10 +128559,11 @@
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}else{
assert( pLevel->p5==0 );
}
+ if( omitTable ) pIdx = 0;
}else
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
if( pLoop->wsFlags & WHERE_MULTI_OR ){
/* Case 5: Two or more separately indexed terms connected by OR
@@ -128217,47 +128877,60 @@
pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
#endif
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
+ **
+ ** This loop may run either once (pIdx==0) or twice (pIdx!=0). If
+ ** it is run twice, then the first iteration codes those sub-expressions
+ ** that can be computed using columns from pIdx only (without seeking
+ ** the main table cursor).
*/
- for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
- Expr *pE;
- int skipLikeAddr = 0;
- testcase( pTerm->wtFlags & TERM_VIRTUAL );
- testcase( pTerm->wtFlags & TERM_CODED );
- if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
- testcase( pWInfo->untestedTerms==0
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
- pWInfo->untestedTerms = 1;
- continue;
- }
- pE = pTerm->pExpr;
- assert( pE!=0 );
- if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
- continue;
- }
- if( pTerm->wtFlags & TERM_LIKECOND ){
- /* If the TERM_LIKECOND flag is set, that means that the range search
- ** is sufficient to guarantee that the LIKE operator is true, so we
- ** can skip the call to the like(A,B) function. But this only works
- ** for strings. So do not skip the call to the function on the pass
- ** that compares BLOBs. */
+ do{
+ loopAgain = 0;
+ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ Expr *pE;
+ int skipLikeAddr = 0;
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ testcase( pTerm->wtFlags & TERM_CODED );
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
+ testcase( pWInfo->untestedTerms==0
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
+ pWInfo->untestedTerms = 1;
+ continue;
+ }
+ pE = pTerm->pExpr;
+ assert( pE!=0 );
+ if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
+ continue;
+ }
+ if( pIdx && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
+ loopAgain = 1;
+ continue;
+ }
+ if( pTerm->wtFlags & TERM_LIKECOND ){
+ /* If the TERM_LIKECOND flag is set, that means that the range search
+ ** is sufficient to guarantee that the LIKE operator is true, so we
+ ** can skip the call to the like(A,B) function. But this only works
+ ** for strings. So do not skip the call to the function on the pass
+ ** that compares BLOBs. */
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- continue;
+ continue;
#else
- u32 x = pLevel->iLikeRepCntr;
- assert( x>0 );
- skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
- VdbeCoverage(v);
+ u32 x = pLevel->iLikeRepCntr;
+ assert( x>0 );
+ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1));
+ VdbeCoverage(v);
#endif
+ }
+ sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
+ if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
+ pTerm->wtFlags |= TERM_CODED;
}
- sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
- if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
- pTerm->wtFlags |= TERM_CODED;
- }
+ pIdx = 0;
+ }while( loopAgain );
/* Insert code to test for implied constraints based on transitivity
** of the "==" operator.
**
** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123"
@@ -129146,31 +129819,50 @@
/*
** Expression pExpr is one operand of a comparison operator that might
** be useful for indexing. This routine checks to see if pExpr appears
** in any index. Return TRUE (1) if pExpr is an indexed term and return
-** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
-** number of the table that is indexed and *piColumn to the column number
+** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor
+** number of the table that is indexed and aiCurCol[1] to the column number
** of the column that is indexed, or XN_EXPR (-2) if an expression is being
** indexed.
**
** If pExpr is a TK_COLUMN column reference, then this routine always returns
** true even if that particular column is not indexed, because the column
** might be added to an automatic index later.
*/
-static int exprMightBeIndexed(
+static SQLITE_NOINLINE int exprMightBeIndexed2(
SrcList *pFrom, /* The FROM clause */
- int op, /* The specific comparison operator */
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
- Expr *pExpr, /* An operand of a comparison operator */
- int *piCur, /* Write the referenced table cursor number here */
- int *piColumn /* Write the referenced table column number here */
+ int *aiCurCol, /* Write the referenced table cursor and column here */
+ Expr *pExpr /* An operand of a comparison operator */
){
Index *pIdx;
int i;
int iCur;
-
+ for(i=0; mPrereq>1; i++, mPrereq>>=1){}
+ iCur = pFrom->a[i].iCursor;
+ for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->aColExpr==0 ) continue;
+ for(i=0; inKeyCol; i++){
+ if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
+ if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
+ aiCurCol[0] = iCur;
+ aiCurCol[1] = XN_EXPR;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+static int exprMightBeIndexed(
+ SrcList *pFrom, /* The FROM clause */
+ Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
+ int *aiCurCol, /* Write the referenced table cursor & column here */
+ Expr *pExpr, /* An operand of a comparison operator */
+ int op /* The specific comparison operator */
+){
/* If this expression is a vector to the left or right of a
** inequality constraint (>, <, >= or <=), perform the processing
** on the first element of the vector. */
assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
pExpr = pExpr->x.pList->a[0].pExpr;
}
if( pExpr->op==TK_COLUMN ){
- *piCur = pExpr->iTable;
- *piColumn = pExpr->iColumn;
+ aiCurCol[0] = pExpr->iTable;
+ aiCurCol[1] = pExpr->iColumn;
return 1;
}
if( mPrereq==0 ) return 0; /* No table references */
if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
- for(i=0; mPrereq>1; i++, mPrereq>>=1){}
- iCur = pFrom->a[i].iCursor;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->aColExpr==0 ) continue;
- for(i=0; inKeyCol; i++){
- if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
- if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
- *piCur = iCur;
- *piColumn = XN_EXPR;
- return 1;
- }
- }
- }
- return 0;
+ return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
}
/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in. The job of this routine is to analyze the
@@ -129277,11 +129956,11 @@
pTerm->prereqAll = prereqAll;
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
if( allowedOp(op) ){
- int iCur, iColumn;
+ int aiCurCol[2];
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
if( pTerm->iField>0 ){
@@ -129288,18 +129967,18 @@
assert( op==TK_IN );
assert( pLeft->op==TK_VECTOR );
pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
}
- if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
- pTerm->leftCursor = iCur;
- pTerm->u.leftColumn = iColumn;
+ if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
+ pTerm->leftCursor = aiCurCol[0];
+ pTerm->u.leftColumn = aiCurCol[1];
pTerm->eOperator = operatorMask(op) & opMask;
}
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
if( pRight
- && exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn)
+ && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
){
WhereTerm *pNew;
Expr *pDup;
u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
assert( pTerm->iField==0 );
@@ -129325,12 +130004,12 @@
}else{
pDup = pExpr;
pNew = pTerm;
}
exprCommute(pParse, pDup);
- pNew->leftCursor = iCur;
- pNew->u.leftColumn = iColumn;
+ pNew->leftCursor = aiCurCol[0];
+ pNew->u.leftColumn = aiCurCol[1];
testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
}
@@ -129685,15 +130364,15 @@
*/
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
Bitmask mask;
if( p==0 ) return 0;
if( p->op==TK_COLUMN ){
- mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
- return mask;
+ return sqlite3WhereGetMask(pMaskSet, p->iTable);
}
+ mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
assert( !ExprHasProperty(p, EP_TokenOnly) );
- mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0;
+ if( p->pRight ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight);
if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
if( ExprHasProperty(p, EP_xIsSelect) ){
mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
}else if( p->x.pList ){
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
@@ -130289,18 +130968,20 @@
** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero,
** then each OP_Rowid is transformed into an instruction to increment the
** value stored in its output register.
*/
static void translateColumnToCopy(
- Vdbe *v, /* The VDBE containing code to translate */
+ Parse *pParse, /* Parsing context */
int iStart, /* Translate from this opcode to the end */
int iTabCur, /* OP_Column/OP_Rowid references to this table */
int iRegister, /* The first column is in this register */
int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */
){
+ Vdbe *v = pParse->pVdbe;
VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
int iEnd = sqlite3VdbeCurrentAddr(v);
+ if( pParse->db->mallocFailed ) return;
for(; iStartp1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + iRegister;
@@ -130574,11 +131255,13 @@
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
if( pTabItem->fg.viaCoroutine ){
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
- translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
+ testcase( pParse->db->mallocFailed );
+ translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
+ pTabItem->regResult, 1);
sqlite3VdbeGoto(v, addrTop);
pTabItem->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
}
@@ -130960,11 +131643,11 @@
iGap = (iGap*2)/3;
}else{
iGap = iGap/3;
}
aStat[0] = iLower + iGap;
- aStat[1] = pIdx->aAvgEq[iCol];
+ aStat[1] = pIdx->aAvgEq[nField-1];
}
/* Restore the pRec->nField value before returning. */
pRec->nField = nField;
return i;
@@ -131554,21 +132237,21 @@
sqlite3_free(p->u.vtab.idxStr);
p->u.vtab.needFree = 0;
p->u.vtab.idxStr = 0;
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
- sqlite3DbFree(db, p->u.btree.pIndex);
+ sqlite3DbFreeNN(db, p->u.btree.pIndex);
p->u.btree.pIndex = 0;
}
}
}
/*
** Deallocate internal memory used by a WhereLoop object
*/
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
whereLoopClearUnion(db, p);
whereLoopInit(p);
}
/*
@@ -131579,11 +132262,11 @@
if( p->nLSlot>=n ) return SQLITE_OK;
n = (n+7)&~7;
paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
if( paNew==0 ) return SQLITE_NOMEM_BKPT;
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
p->aLTerm = paNew;
p->nLSlot = n;
return SQLITE_OK;
}
@@ -131609,11 +132292,11 @@
/*
** Delete a WhereLoop object
*/
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
whereLoopClear(db, p);
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
/*
** Free a WhereInfo structure
*/
@@ -131630,11 +132313,11 @@
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
- sqlite3DbFree(db, pWInfo);
+ sqlite3DbFreeNN(db, pWInfo);
}
}
/*
** Return TRUE if all of the following are true:
@@ -131713,20 +132396,21 @@
}
}
/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
-** supplanted by pTemplate.
+** replaced by pTemplate.
**
-** Return NULL if the WhereLoop list contains an entry that can supplant
-** pTemplate, in other words if pTemplate does not belong on the list.
+** Return NULL if pTemplate does not belong on the WhereLoop list.
+** In other words if pTemplate ought to be dropped from further consideration.
**
-** If pX is a WhereLoop that pTemplate can supplant, then return the
+** If pX is a WhereLoop that pTemplate can replace, then return the
** link that points to pX.
**
-** If pTemplate cannot supplant any existing element of the list but needs
-** to be added to the list, then return a pointer to the tail of the list.
+** If pTemplate cannot replace any existing element of the list but needs
+** to be added to the list as a new entry, then return a pointer to the
+** tail of the list.
*/
static WhereLoop **whereLoopFindLesser(
WhereLoop **ppPrev,
const WhereLoop *pTemplate
){
@@ -131867,12 +132551,14 @@
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
if( p!=0 ){
sqlite3DebugPrintf("replace: ");
whereLoopPrint(p, pBuilder->pWC);
+ sqlite3DebugPrintf(" with: ");
+ }else{
+ sqlite3DebugPrintf(" add: ");
}
- sqlite3DebugPrintf(" add: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
if( p==0 ){
/* Allocate a new WhereLoop to add to the end of the list */
@@ -133021,11 +133707,11 @@
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn);
}
}
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
- sqlite3DbFree(pParse->db, p);
+ sqlite3DbFreeNN(pParse->db, p);
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/*
@@ -133205,11 +133891,11 @@
whereLoopClear(db, pNew);
return rc;
}
/*
-** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
+** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
** parameters) to see if it outputs rows in the requested ORDER BY
** (or GROUP BY) without requiring a separate sort operation. Return N:
**
** N>0: N terms of the ORDER BY clause are satisfied
** N==0: No terms of the ORDER BY clause are satisfied
@@ -133300,10 +133986,12 @@
pLoop = pLast;
}
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
break;
+ }else{
+ pLoop->u.btree.nIdxCol = 0;
}
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
/* Mark off any ORDER BY term X that is a column in the table of
** the current loop for which there is term in the WHERE
@@ -133445,10 +134133,11 @@
if( iColumn>=0 ){
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( !pColl ) pColl = db->pDfltColl;
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
}
+ pLoop->u.btree.nIdxCol = j+1;
isMatch = 1;
break;
}
if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause.
@@ -133765,12 +134454,12 @@
/* The current candidate is no better than any of the mxChoice
** paths currently in the best-so-far buffer. So discard
** this candidate as not viable. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
- sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
continue;
}
@@ -133784,30 +134473,40 @@
jj = mxI;
}
pTo = &aTo[jj];
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
- sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
}else{
/* Control reaches here if best-so-far path pTo=aTo[jj] covers the
- ** same set of loops and has the sam isOrdered setting as the
+ ** same set of loops and has the same isOrdered setting as the
** candidate path. Check to see if the candidate should replace
- ** pTo or if the candidate should be skipped */
- if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){
+ ** pTo or if the candidate should be skipped.
+ **
+ ** The conditional is an expanded vector comparison equivalent to:
+ ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
+ */
+ if( pTo->rCostrCost==rCost
+ && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted)
+ )
+ )
+ ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
- "Skip %s cost=%-3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ "Skip %s cost=%-3d,%3d,%3d order=%c",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
- sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
+ sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
/* Discard the candidate path from further consideration */
testcase( pTo->rCost==rCost );
continue;
@@ -133816,16 +134515,16 @@
/* Control reaches here if the candidate path is better than the
** pTo path. Replace pTo with the candidate. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
- "Update %s cost=%-3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ "Update %s cost=%-3d,%3d,%3d order=%c",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
- sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
+ sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
/* pWLoop is a winner. Add it to the set of best so far */
pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
@@ -133876,11 +134575,11 @@
nFrom = nTo;
}
if( nFrom==0 ){
sqlite3ErrorMsg(pParse, "no query solution");
- sqlite3DbFree(db, pSpace);
+ sqlite3DbFreeNN(db, pSpace);
return SQLITE_ERROR;
}
/* Find the lowest cost path. pFrom will be left pointing to that path */
pFrom = aFrom;
@@ -133952,11 +134651,11 @@
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
- sqlite3DbFree(db, pSpace);
+ sqlite3DbFreeNN(db, pSpace);
return SQLITE_OK;
}
/*
** Most queries use only a single table (they are not joins) and have
@@ -134030,11 +134729,12 @@
}
}
if( pLoop->wsFlags ){
pLoop->nOut = (LogEst)1;
pWInfo->a[0].pWLoop = pLoop;
- pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
+ assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] );
+ pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
pWInfo->a[0].iTabCur = iCur;
pWInfo->nRowOut = 1;
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
@@ -134214,10 +134914,11 @@
goto whereBeginError;
}
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
+ pWInfo->pWhere = pWhere;
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
pWInfo->wctrlFlags = wctrlFlags;
@@ -134327,11 +135028,11 @@
WhereLoop *p;
int i;
static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
"ABCDEFGHIJKLMNOPQRSTUVWYXZ";
for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
- p->cId = zLabel[i%sizeof(zLabel)];
+ p->cId = zLabel[i%(sizeof(zLabel)-1)];
whereLoopPrint(p, sWLB.pWC);
}
}
#endif
@@ -134524,10 +135225,11 @@
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
+ && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
){
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
}
VdbeComment((v, "%s", pIx->zName));
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
@@ -134612,18 +135314,47 @@
sqlite3ExprCacheClear(pParse);
for(i=pWInfo->nLevel-1; i>=0; i--){
int addr;
pLevel = &pWInfo->a[i];
pLoop = pLevel->pWLoop;
- sqlite3VdbeResolveLabel(v, pLevel->addrCont);
if( pLevel->op!=OP_Noop ){
+#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ int addrSeek = 0;
+ Index *pIdx;
+ int n;
+ if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
+ && (pLoop->wsFlags & WHERE_INDEXED)!=0
+ && (pIdx = pLoop->u.btree.pIndex)->hasStat1
+ && (n = pLoop->u.btree.nIdxCol)>0
+ && pIdx->aiRowLogEst[n]>=36
+ ){
+ int r1 = pParse->nMem+1;
+ int j, op;
+ for(j=0; jiIdxCur, j, r1+j);
+ }
+ pParse->nMem += n+1;
+ op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT;
+ addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n);
+ VdbeCoverageIf(v, op==OP_SeekLT);
+ VdbeCoverageIf(v, op==OP_SeekGT);
+ sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
+ }
+#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
+ /* The common case: Advance to the next row */
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
sqlite3VdbeChangeP5(v, pLevel->p5);
VdbeCoverage(v);
VdbeCoverageIf(v, pLevel->op==OP_Next);
VdbeCoverageIf(v, pLevel->op==OP_Prev);
VdbeCoverageIf(v, pLevel->op==OP_VNext);
+#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
+#endif
+ }else{
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
}
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
struct InLoop *pIn;
int j;
sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
@@ -134692,12 +135423,13 @@
/* For a co-routine, change all OP_Column references to the table of
** the co-routine into OP_Copy of result contained in a register.
** OP_Rowid becomes OP_Null.
*/
- if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
- translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
+ if( pTabItem->fg.viaCoroutine ){
+ testcase( pParse->db->mallocFailed );
+ translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult, 0);
continue;
}
/* If this scan uses an index, make VDBE code substitutions to read data
@@ -134741,10 +135473,12 @@
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0
|| pWInfo->eOnePass );
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
pOp->opcode = OP_IdxRowid;
+ }else if( pOp->opcode==OP_IfNullRow ){
+ pOp->p1 = pLevel->iIdxCur;
}
}
}
}
@@ -135050,11 +135784,11 @@
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
#define YYNOCODE 252
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 96
+#define YYWILDCARD 69
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
Expr* yy72;
@@ -135157,419 +135891,419 @@
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1567)
+#define YY_ACTTAB_COUNT (1566)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 325, 832, 351, 825, 5, 203, 203, 819, 99, 100,
- /* 10 */ 90, 978, 978, 853, 856, 845, 845, 97, 97, 98,
- /* 20 */ 98, 98, 98, 301, 96, 96, 96, 96, 95, 95,
- /* 30 */ 94, 94, 94, 93, 351, 325, 976, 976, 824, 824,
- /* 40 */ 826, 946, 354, 99, 100, 90, 978, 978, 853, 856,
- /* 50 */ 845, 845, 97, 97, 98, 98, 98, 98, 338, 96,
- /* 60 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
- /* 70 */ 95, 95, 94, 94, 94, 93, 351, 791, 976, 976,
- /* 80 */ 325, 94, 94, 94, 93, 351, 792, 75, 99, 100,
- /* 90 */ 90, 978, 978, 853, 856, 845, 845, 97, 97, 98,
- /* 100 */ 98, 98, 98, 450, 96, 96, 96, 96, 95, 95,
- /* 110 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 325,
- /* 120 */ 275, 146, 132, 52, 52, 93, 351, 99, 100, 90,
- /* 130 */ 978, 978, 853, 856, 845, 845, 97, 97, 98, 98,
- /* 140 */ 98, 98, 101, 96, 96, 96, 96, 95, 95, 94,
- /* 150 */ 94, 94, 93, 351, 957, 957, 325, 268, 428, 413,
- /* 160 */ 411, 61, 752, 752, 99, 100, 90, 978, 978, 853,
- /* 170 */ 856, 845, 845, 97, 97, 98, 98, 98, 98, 60,
- /* 180 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 190 */ 351, 325, 270, 329, 273, 277, 958, 959, 250, 99,
- /* 200 */ 100, 90, 978, 978, 853, 856, 845, 845, 97, 97,
- /* 210 */ 98, 98, 98, 98, 301, 96, 96, 96, 96, 95,
- /* 220 */ 95, 94, 94, 94, 93, 351, 325, 937, 1326, 698,
- /* 230 */ 706, 1326, 242, 412, 99, 100, 90, 978, 978, 853,
- /* 240 */ 856, 845, 845, 97, 97, 98, 98, 98, 98, 347,
- /* 250 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 260 */ 351, 325, 937, 1327, 384, 699, 1327, 381, 379, 99,
- /* 270 */ 100, 90, 978, 978, 853, 856, 845, 845, 97, 97,
- /* 280 */ 98, 98, 98, 98, 701, 96, 96, 96, 96, 95,
- /* 290 */ 95, 94, 94, 94, 93, 351, 325, 92, 89, 178,
- /* 300 */ 833, 935, 373, 700, 99, 100, 90, 978, 978, 853,
- /* 310 */ 856, 845, 845, 97, 97, 98, 98, 98, 98, 375,
- /* 320 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 330 */ 351, 325, 1275, 946, 354, 818, 935, 739, 739, 99,
- /* 340 */ 100, 90, 978, 978, 853, 856, 845, 845, 97, 97,
- /* 350 */ 98, 98, 98, 98, 230, 96, 96, 96, 96, 95,
- /* 360 */ 95, 94, 94, 94, 93, 351, 325, 968, 227, 92,
- /* 370 */ 89, 178, 373, 300, 99, 100, 90, 978, 978, 853,
- /* 380 */ 856, 845, 845, 97, 97, 98, 98, 98, 98, 920,
- /* 390 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 400 */ 351, 325, 449, 447, 447, 447, 147, 737, 737, 99,
- /* 410 */ 100, 90, 978, 978, 853, 856, 845, 845, 97, 97,
- /* 420 */ 98, 98, 98, 98, 296, 96, 96, 96, 96, 95,
- /* 430 */ 95, 94, 94, 94, 93, 351, 325, 419, 231, 957,
- /* 440 */ 957, 158, 25, 422, 99, 100, 90, 978, 978, 853,
- /* 450 */ 856, 845, 845, 97, 97, 98, 98, 98, 98, 450,
- /* 460 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 470 */ 351, 443, 224, 224, 420, 957, 957, 961, 325, 52,
- /* 480 */ 52, 958, 959, 176, 415, 78, 99, 100, 90, 978,
- /* 490 */ 978, 853, 856, 845, 845, 97, 97, 98, 98, 98,
- /* 500 */ 98, 379, 96, 96, 96, 96, 95, 95, 94, 94,
- /* 510 */ 94, 93, 351, 325, 428, 418, 298, 958, 959, 961,
- /* 520 */ 81, 99, 88, 90, 978, 978, 853, 856, 845, 845,
- /* 530 */ 97, 97, 98, 98, 98, 98, 717, 96, 96, 96,
- /* 540 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 842,
- /* 550 */ 842, 854, 857, 996, 318, 343, 379, 100, 90, 978,
- /* 560 */ 978, 853, 856, 845, 845, 97, 97, 98, 98, 98,
- /* 570 */ 98, 450, 96, 96, 96, 96, 95, 95, 94, 94,
- /* 580 */ 94, 93, 351, 325, 350, 350, 350, 260, 377, 340,
- /* 590 */ 928, 52, 52, 90, 978, 978, 853, 856, 845, 845,
- /* 600 */ 97, 97, 98, 98, 98, 98, 361, 96, 96, 96,
- /* 610 */ 96, 95, 95, 94, 94, 94, 93, 351, 86, 445,
- /* 620 */ 846, 3, 1202, 361, 360, 378, 344, 813, 957, 957,
- /* 630 */ 1299, 86, 445, 729, 3, 212, 169, 287, 405, 282,
- /* 640 */ 404, 199, 232, 450, 300, 760, 83, 84, 280, 245,
- /* 650 */ 262, 365, 251, 85, 352, 352, 92, 89, 178, 83,
- /* 660 */ 84, 242, 412, 52, 52, 448, 85, 352, 352, 246,
- /* 670 */ 958, 959, 194, 455, 670, 402, 399, 398, 448, 243,
- /* 680 */ 221, 114, 434, 776, 361, 450, 397, 268, 747, 224,
- /* 690 */ 224, 132, 132, 198, 832, 434, 452, 451, 428, 427,
- /* 700 */ 819, 415, 734, 713, 132, 52, 52, 832, 268, 452,
- /* 710 */ 451, 734, 194, 819, 363, 402, 399, 398, 450, 1270,
- /* 720 */ 1270, 23, 957, 957, 86, 445, 397, 3, 228, 429,
- /* 730 */ 894, 824, 824, 826, 827, 19, 203, 720, 52, 52,
- /* 740 */ 428, 408, 439, 249, 824, 824, 826, 827, 19, 229,
- /* 750 */ 403, 153, 83, 84, 761, 177, 241, 450, 721, 85,
- /* 760 */ 352, 352, 120, 157, 958, 959, 58, 976, 409, 355,
- /* 770 */ 330, 448, 268, 428, 430, 320, 790, 32, 32, 86,
- /* 780 */ 445, 776, 3, 341, 98, 98, 98, 98, 434, 96,
- /* 790 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
- /* 800 */ 832, 120, 452, 451, 813, 886, 819, 83, 84, 976,
- /* 810 */ 813, 132, 410, 919, 85, 352, 352, 132, 407, 789,
- /* 820 */ 957, 957, 92, 89, 178, 916, 448, 262, 370, 261,
- /* 830 */ 82, 913, 80, 262, 370, 261, 776, 824, 824, 826,
- /* 840 */ 827, 19, 933, 434, 96, 96, 96, 96, 95, 95,
- /* 850 */ 94, 94, 94, 93, 351, 832, 74, 452, 451, 957,
- /* 860 */ 957, 819, 958, 959, 120, 92, 89, 178, 944, 2,
- /* 870 */ 917, 964, 268, 1, 975, 76, 445, 762, 3, 708,
- /* 880 */ 900, 900, 387, 957, 957, 757, 918, 371, 740, 778,
- /* 890 */ 756, 257, 824, 824, 826, 827, 19, 417, 741, 450,
- /* 900 */ 24, 958, 959, 83, 84, 369, 957, 957, 177, 226,
- /* 910 */ 85, 352, 352, 884, 315, 314, 313, 215, 311, 10,
- /* 920 */ 10, 683, 448, 349, 348, 958, 959, 908, 777, 157,
- /* 930 */ 120, 957, 957, 337, 776, 416, 711, 310, 450, 434,
- /* 940 */ 450, 321, 450, 791, 103, 200, 175, 450, 958, 959,
- /* 950 */ 907, 832, 792, 452, 451, 9, 9, 819, 10, 10,
- /* 960 */ 52, 52, 51, 51, 180, 716, 248, 10, 10, 171,
- /* 970 */ 170, 167, 339, 958, 959, 247, 984, 702, 702, 450,
- /* 980 */ 715, 233, 686, 982, 888, 983, 182, 913, 824, 824,
- /* 990 */ 826, 827, 19, 183, 256, 423, 132, 181, 394, 10,
- /* 1000 */ 10, 888, 890, 749, 957, 957, 916, 268, 985, 198,
- /* 1010 */ 985, 349, 348, 425, 415, 299, 817, 832, 326, 825,
- /* 1020 */ 120, 332, 133, 819, 268, 98, 98, 98, 98, 91,
- /* 1030 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 1040 */ 351, 157, 810, 371, 382, 359, 958, 959, 358, 268,
- /* 1050 */ 450, 917, 368, 324, 824, 824, 826, 450, 709, 450,
- /* 1060 */ 264, 380, 888, 450, 876, 746, 253, 918, 255, 433,
- /* 1070 */ 36, 36, 234, 450, 234, 120, 269, 37, 37, 12,
- /* 1080 */ 12, 334, 272, 27, 27, 450, 330, 118, 450, 162,
- /* 1090 */ 742, 280, 450, 38, 38, 450, 985, 356, 985, 450,
- /* 1100 */ 709, 1209, 450, 132, 450, 39, 39, 450, 40, 40,
- /* 1110 */ 450, 362, 41, 41, 450, 42, 42, 450, 254, 28,
- /* 1120 */ 28, 450, 29, 29, 31, 31, 450, 43, 43, 450,
- /* 1130 */ 44, 44, 450, 714, 45, 45, 450, 11, 11, 767,
- /* 1140 */ 450, 46, 46, 450, 268, 450, 105, 105, 450, 47,
- /* 1150 */ 47, 450, 48, 48, 450, 237, 33, 33, 450, 172,
- /* 1160 */ 49, 49, 450, 50, 50, 34, 34, 274, 122, 122,
- /* 1170 */ 450, 123, 123, 450, 124, 124, 450, 897, 56, 56,
- /* 1180 */ 450, 896, 35, 35, 450, 267, 450, 817, 450, 817,
- /* 1190 */ 106, 106, 450, 53, 53, 385, 107, 107, 450, 817,
- /* 1200 */ 108, 108, 817, 450, 104, 104, 121, 121, 119, 119,
- /* 1210 */ 450, 117, 112, 112, 450, 276, 450, 225, 111, 111,
- /* 1220 */ 450, 730, 450, 109, 109, 450, 673, 674, 675, 911,
- /* 1230 */ 110, 110, 317, 998, 55, 55, 57, 57, 692, 331,
- /* 1240 */ 54, 54, 26, 26, 696, 30, 30, 317, 936, 197,
- /* 1250 */ 196, 195, 335, 281, 336, 446, 331, 745, 689, 436,
- /* 1260 */ 440, 444, 120, 72, 386, 223, 175, 345, 757, 932,
- /* 1270 */ 20, 286, 319, 756, 815, 372, 374, 202, 202, 202,
- /* 1280 */ 263, 395, 285, 74, 208, 21, 696, 719, 718, 883,
- /* 1290 */ 120, 120, 120, 120, 120, 754, 278, 828, 77, 74,
- /* 1300 */ 726, 727, 785, 783, 879, 202, 999, 208, 893, 892,
- /* 1310 */ 893, 892, 694, 816, 763, 116, 774, 1289, 431, 432,
- /* 1320 */ 302, 999, 390, 303, 823, 697, 691, 680, 159, 289,
- /* 1330 */ 679, 883, 681, 951, 291, 218, 293, 7, 316, 828,
- /* 1340 */ 173, 805, 259, 364, 252, 910, 376, 713, 295, 435,
- /* 1350 */ 308, 168, 954, 993, 135, 400, 990, 284, 881, 880,
- /* 1360 */ 205, 927, 925, 59, 333, 62, 144, 156, 130, 72,
- /* 1370 */ 802, 366, 367, 393, 137, 185, 189, 160, 139, 383,
- /* 1380 */ 67, 895, 140, 141, 142, 148, 389, 812, 775, 266,
- /* 1390 */ 219, 190, 154, 391, 912, 875, 271, 406, 191, 322,
- /* 1400 */ 682, 733, 192, 342, 732, 724, 731, 711, 723, 421,
- /* 1410 */ 705, 71, 323, 6, 204, 771, 288, 79, 297, 346,
- /* 1420 */ 772, 704, 290, 283, 703, 770, 292, 294, 966, 239,
- /* 1430 */ 769, 102, 861, 438, 426, 240, 424, 442, 73, 213,
- /* 1440 */ 688, 238, 22, 453, 952, 214, 217, 216, 454, 677,
- /* 1450 */ 676, 671, 753, 125, 115, 235, 126, 669, 353, 166,
- /* 1460 */ 127, 244, 179, 357, 306, 304, 305, 307, 113, 891,
- /* 1470 */ 327, 889, 811, 328, 134, 128, 136, 138, 743, 258,
- /* 1480 */ 906, 184, 143, 129, 909, 186, 63, 64, 145, 187,
- /* 1490 */ 905, 65, 8, 66, 13, 188, 202, 898, 265, 149,
- /* 1500 */ 987, 388, 150, 685, 161, 392, 285, 193, 279, 396,
- /* 1510 */ 151, 401, 68, 14, 15, 722, 69, 236, 831, 131,
- /* 1520 */ 830, 859, 70, 751, 16, 414, 755, 4, 174, 220,
- /* 1530 */ 222, 784, 201, 152, 779, 77, 74, 17, 18, 874,
- /* 1540 */ 860, 858, 915, 863, 914, 207, 206, 941, 163, 437,
- /* 1550 */ 947, 942, 164, 209, 1002, 441, 862, 165, 210, 829,
- /* 1560 */ 695, 87, 312, 211, 1291, 1290, 309,
+ /* 0 */ 325, 411, 343, 752, 752, 203, 946, 354, 976, 98,
+ /* 10 */ 98, 98, 98, 91, 96, 96, 96, 96, 95, 95,
+ /* 20 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 813,
+ /* 30 */ 978, 978, 98, 98, 98, 98, 20, 96, 96, 96,
+ /* 40 */ 96, 95, 95, 94, 94, 94, 93, 351, 92, 89,
+ /* 50 */ 178, 99, 100, 90, 853, 856, 845, 845, 97, 97,
+ /* 60 */ 98, 98, 98, 98, 351, 96, 96, 96, 96, 95,
+ /* 70 */ 95, 94, 94, 94, 93, 351, 325, 340, 976, 262,
+ /* 80 */ 365, 251, 212, 169, 287, 405, 282, 404, 199, 791,
+ /* 90 */ 242, 412, 21, 957, 379, 280, 93, 351, 792, 95,
+ /* 100 */ 95, 94, 94, 94, 93, 351, 978, 978, 96, 96,
+ /* 110 */ 96, 96, 95, 95, 94, 94, 94, 93, 351, 813,
+ /* 120 */ 329, 242, 412, 913, 832, 913, 132, 99, 100, 90,
+ /* 130 */ 853, 856, 845, 845, 97, 97, 98, 98, 98, 98,
+ /* 140 */ 450, 96, 96, 96, 96, 95, 95, 94, 94, 94,
+ /* 150 */ 93, 351, 325, 825, 349, 348, 120, 819, 120, 75,
+ /* 160 */ 52, 52, 957, 958, 959, 760, 984, 146, 361, 262,
+ /* 170 */ 370, 261, 957, 982, 961, 983, 92, 89, 178, 371,
+ /* 180 */ 230, 371, 978, 978, 817, 361, 360, 101, 824, 824,
+ /* 190 */ 826, 384, 24, 964, 381, 428, 413, 369, 985, 380,
+ /* 200 */ 985, 708, 325, 99, 100, 90, 853, 856, 845, 845,
+ /* 210 */ 97, 97, 98, 98, 98, 98, 373, 96, 96, 96,
+ /* 220 */ 96, 95, 95, 94, 94, 94, 93, 351, 957, 132,
+ /* 230 */ 897, 450, 978, 978, 896, 60, 94, 94, 94, 93,
+ /* 240 */ 351, 957, 958, 959, 961, 103, 361, 957, 385, 334,
+ /* 250 */ 702, 52, 52, 99, 100, 90, 853, 856, 845, 845,
+ /* 260 */ 97, 97, 98, 98, 98, 98, 698, 96, 96, 96,
+ /* 270 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 455,
+ /* 280 */ 670, 450, 227, 61, 157, 243, 344, 114, 701, 888,
+ /* 290 */ 147, 832, 957, 373, 747, 957, 320, 957, 958, 959,
+ /* 300 */ 194, 10, 10, 402, 399, 398, 888, 890, 978, 978,
+ /* 310 */ 762, 171, 170, 157, 397, 337, 957, 958, 959, 702,
+ /* 320 */ 825, 310, 153, 957, 819, 321, 82, 23, 80, 99,
+ /* 330 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98,
+ /* 340 */ 98, 98, 894, 96, 96, 96, 96, 95, 95, 94,
+ /* 350 */ 94, 94, 93, 351, 325, 824, 824, 826, 277, 231,
+ /* 360 */ 300, 957, 958, 959, 957, 958, 959, 888, 194, 25,
+ /* 370 */ 450, 402, 399, 398, 957, 355, 300, 450, 957, 74,
+ /* 380 */ 450, 1, 397, 132, 978, 978, 957, 224, 224, 813,
+ /* 390 */ 10, 10, 957, 958, 959, 968, 132, 52, 52, 415,
+ /* 400 */ 52, 52, 739, 739, 339, 99, 100, 90, 853, 856,
+ /* 410 */ 845, 845, 97, 97, 98, 98, 98, 98, 790, 96,
+ /* 420 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
+ /* 430 */ 325, 789, 428, 418, 706, 428, 427, 1270, 1270, 262,
+ /* 440 */ 370, 261, 957, 957, 958, 959, 757, 957, 958, 959,
+ /* 450 */ 450, 756, 450, 734, 713, 957, 958, 959, 443, 711,
+ /* 460 */ 978, 978, 734, 394, 92, 89, 178, 447, 447, 447,
+ /* 470 */ 51, 51, 52, 52, 439, 778, 700, 92, 89, 178,
+ /* 480 */ 172, 99, 100, 90, 853, 856, 845, 845, 97, 97,
+ /* 490 */ 98, 98, 98, 98, 198, 96, 96, 96, 96, 95,
+ /* 500 */ 95, 94, 94, 94, 93, 351, 325, 428, 408, 916,
+ /* 510 */ 699, 957, 958, 959, 92, 89, 178, 224, 224, 157,
+ /* 520 */ 241, 221, 419, 299, 776, 917, 416, 375, 450, 415,
+ /* 530 */ 58, 324, 737, 737, 920, 379, 978, 978, 379, 777,
+ /* 540 */ 449, 918, 363, 740, 296, 686, 9, 9, 52, 52,
+ /* 550 */ 234, 330, 234, 256, 417, 741, 280, 99, 100, 90,
+ /* 560 */ 853, 856, 845, 845, 97, 97, 98, 98, 98, 98,
+ /* 570 */ 450, 96, 96, 96, 96, 95, 95, 94, 94, 94,
+ /* 580 */ 93, 351, 325, 423, 72, 450, 833, 120, 368, 450,
+ /* 590 */ 10, 10, 5, 301, 203, 450, 177, 976, 253, 420,
+ /* 600 */ 255, 776, 200, 175, 233, 10, 10, 842, 842, 36,
+ /* 610 */ 36, 1299, 978, 978, 729, 37, 37, 349, 348, 425,
+ /* 620 */ 203, 260, 776, 976, 232, 937, 1326, 876, 338, 1326,
+ /* 630 */ 422, 854, 857, 99, 100, 90, 853, 856, 845, 845,
+ /* 640 */ 97, 97, 98, 98, 98, 98, 268, 96, 96, 96,
+ /* 650 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 846,
+ /* 660 */ 450, 985, 818, 985, 1209, 450, 916, 976, 720, 350,
+ /* 670 */ 350, 350, 935, 177, 450, 937, 1327, 254, 198, 1327,
+ /* 680 */ 12, 12, 917, 403, 450, 27, 27, 250, 978, 978,
+ /* 690 */ 118, 721, 162, 976, 38, 38, 268, 176, 918, 776,
+ /* 700 */ 433, 1275, 946, 354, 39, 39, 317, 998, 325, 99,
+ /* 710 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98,
+ /* 720 */ 98, 98, 935, 96, 96, 96, 96, 95, 95, 94,
+ /* 730 */ 94, 94, 93, 351, 450, 330, 450, 358, 978, 978,
+ /* 740 */ 717, 317, 936, 341, 900, 900, 387, 673, 674, 675,
+ /* 750 */ 275, 996, 318, 999, 40, 40, 41, 41, 268, 99,
+ /* 760 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98,
+ /* 770 */ 98, 98, 450, 96, 96, 96, 96, 95, 95, 94,
+ /* 780 */ 94, 94, 93, 351, 325, 450, 356, 450, 999, 450,
+ /* 790 */ 692, 331, 42, 42, 791, 270, 450, 273, 450, 228,
+ /* 800 */ 450, 298, 450, 792, 450, 28, 28, 29, 29, 31,
+ /* 810 */ 31, 450, 817, 450, 978, 978, 43, 43, 44, 44,
+ /* 820 */ 45, 45, 11, 11, 46, 46, 893, 78, 893, 268,
+ /* 830 */ 268, 105, 105, 47, 47, 99, 100, 90, 853, 856,
+ /* 840 */ 845, 845, 97, 97, 98, 98, 98, 98, 450, 96,
+ /* 850 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
+ /* 860 */ 325, 450, 117, 450, 749, 158, 450, 696, 48, 48,
+ /* 870 */ 229, 919, 450, 928, 450, 415, 450, 335, 450, 245,
+ /* 880 */ 450, 33, 33, 49, 49, 450, 50, 50, 246, 817,
+ /* 890 */ 978, 978, 34, 34, 122, 122, 123, 123, 124, 124,
+ /* 900 */ 56, 56, 268, 81, 249, 35, 35, 197, 196, 195,
+ /* 910 */ 325, 99, 100, 90, 853, 856, 845, 845, 97, 97,
+ /* 920 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95,
+ /* 930 */ 95, 94, 94, 94, 93, 351, 450, 696, 450, 817,
+ /* 940 */ 978, 978, 975, 884, 106, 106, 268, 886, 268, 944,
+ /* 950 */ 2, 892, 268, 892, 336, 716, 53, 53, 107, 107,
+ /* 960 */ 325, 99, 100, 90, 853, 856, 845, 845, 97, 97,
+ /* 970 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95,
+ /* 980 */ 95, 94, 94, 94, 93, 351, 450, 746, 450, 742,
+ /* 990 */ 978, 978, 715, 267, 108, 108, 446, 331, 332, 133,
+ /* 1000 */ 223, 175, 301, 225, 386, 933, 104, 104, 121, 121,
+ /* 1010 */ 325, 99, 88, 90, 853, 856, 845, 845, 97, 97,
+ /* 1020 */ 98, 98, 98, 98, 817, 96, 96, 96, 96, 95,
+ /* 1030 */ 95, 94, 94, 94, 93, 351, 450, 347, 450, 167,
+ /* 1040 */ 978, 978, 932, 815, 372, 319, 202, 202, 374, 263,
+ /* 1050 */ 395, 202, 74, 208, 726, 727, 119, 119, 112, 112,
+ /* 1060 */ 325, 407, 100, 90, 853, 856, 845, 845, 97, 97,
+ /* 1070 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95,
+ /* 1080 */ 95, 94, 94, 94, 93, 351, 450, 757, 450, 345,
+ /* 1090 */ 978, 978, 756, 278, 111, 111, 74, 719, 718, 709,
+ /* 1100 */ 286, 883, 754, 1289, 257, 77, 109, 109, 110, 110,
+ /* 1110 */ 908, 285, 810, 90, 853, 856, 845, 845, 97, 97,
+ /* 1120 */ 98, 98, 98, 98, 911, 96, 96, 96, 96, 95,
+ /* 1130 */ 95, 94, 94, 94, 93, 351, 86, 445, 450, 3,
+ /* 1140 */ 1202, 450, 745, 132, 352, 120, 689, 86, 445, 785,
+ /* 1150 */ 3, 767, 202, 377, 448, 352, 907, 120, 55, 55,
+ /* 1160 */ 450, 57, 57, 828, 879, 448, 450, 208, 450, 709,
+ /* 1170 */ 450, 883, 237, 434, 436, 120, 440, 429, 362, 120,
+ /* 1180 */ 54, 54, 132, 450, 434, 832, 52, 52, 26, 26,
+ /* 1190 */ 30, 30, 382, 132, 409, 444, 832, 694, 264, 390,
+ /* 1200 */ 116, 269, 272, 32, 32, 83, 84, 120, 274, 120,
+ /* 1210 */ 120, 276, 85, 352, 452, 451, 83, 84, 819, 730,
+ /* 1220 */ 714, 428, 430, 85, 352, 452, 451, 120, 120, 819,
+ /* 1230 */ 378, 218, 281, 828, 783, 816, 86, 445, 410, 3,
+ /* 1240 */ 763, 774, 431, 432, 352, 302, 303, 823, 697, 824,
+ /* 1250 */ 824, 826, 827, 19, 448, 691, 680, 679, 681, 951,
+ /* 1260 */ 824, 824, 826, 827, 19, 289, 159, 291, 293, 7,
+ /* 1270 */ 316, 173, 259, 434, 805, 364, 252, 910, 376, 713,
+ /* 1280 */ 295, 435, 168, 993, 400, 832, 284, 881, 880, 205,
+ /* 1290 */ 954, 308, 927, 86, 445, 990, 3, 925, 333, 144,
+ /* 1300 */ 130, 352, 72, 135, 59, 83, 84, 761, 137, 366,
+ /* 1310 */ 802, 448, 85, 352, 452, 451, 139, 226, 819, 140,
+ /* 1320 */ 156, 62, 315, 314, 313, 215, 311, 367, 393, 683,
+ /* 1330 */ 434, 185, 141, 912, 142, 160, 148, 812, 875, 383,
+ /* 1340 */ 189, 67, 832, 180, 389, 248, 895, 775, 219, 824,
+ /* 1350 */ 824, 826, 827, 19, 247, 190, 266, 154, 391, 271,
+ /* 1360 */ 191, 192, 83, 84, 682, 406, 733, 182, 322, 85,
+ /* 1370 */ 352, 452, 451, 732, 183, 819, 342, 132, 181, 711,
+ /* 1380 */ 731, 421, 76, 445, 705, 3, 323, 704, 283, 724,
+ /* 1390 */ 352, 771, 703, 966, 723, 71, 204, 6, 288, 290,
+ /* 1400 */ 448, 772, 770, 769, 79, 292, 824, 824, 826, 827,
+ /* 1410 */ 19, 294, 297, 438, 346, 442, 102, 861, 753, 434,
+ /* 1420 */ 238, 426, 73, 305, 239, 304, 326, 240, 424, 306,
+ /* 1430 */ 307, 832, 213, 688, 22, 952, 453, 214, 216, 217,
+ /* 1440 */ 454, 677, 115, 676, 671, 125, 126, 235, 127, 669,
+ /* 1450 */ 327, 83, 84, 359, 353, 244, 166, 328, 85, 352,
+ /* 1460 */ 452, 451, 134, 179, 819, 357, 113, 891, 811, 889,
+ /* 1470 */ 136, 128, 138, 743, 258, 184, 906, 143, 145, 63,
+ /* 1480 */ 64, 65, 66, 129, 909, 905, 187, 186, 8, 13,
+ /* 1490 */ 188, 265, 898, 149, 202, 824, 824, 826, 827, 19,
+ /* 1500 */ 388, 987, 150, 161, 285, 685, 392, 396, 151, 722,
+ /* 1510 */ 193, 68, 14, 401, 279, 15, 69, 236, 831, 830,
+ /* 1520 */ 131, 859, 751, 70, 16, 414, 755, 4, 784, 220,
+ /* 1530 */ 222, 174, 152, 437, 779, 201, 17, 77, 74, 18,
+ /* 1540 */ 874, 860, 858, 915, 863, 914, 207, 206, 941, 163,
+ /* 1550 */ 210, 942, 209, 164, 441, 862, 165, 211, 829, 695,
+ /* 1560 */ 87, 312, 309, 947, 1291, 1290,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28,
- /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
- /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133,
- /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33,
- /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 187, 43,
- /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97,
- /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28,
- /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
- /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19,
- /* 120 */ 16, 22, 92, 172, 173, 52, 53, 27, 28, 29,
- /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49,
- /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208,
- /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32,
- /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79,
- /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 190 */ 53, 19, 88, 157, 90, 23, 97, 98, 193, 27,
- /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172,
- /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32,
- /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187,
- /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 260 */ 53, 19, 22, 23, 228, 23, 26, 231, 152, 27,
- /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 280 */ 38, 39, 40, 41, 172, 43, 44, 45, 46, 47,
- /* 290 */ 48, 49, 50, 51, 52, 53, 19, 221, 222, 223,
- /* 300 */ 23, 96, 152, 172, 27, 28, 29, 30, 31, 32,
- /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152,
- /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 330 */ 53, 19, 0, 1, 2, 23, 96, 190, 191, 27,
- /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 350 */ 38, 39, 40, 41, 238, 43, 44, 45, 46, 47,
- /* 360 */ 48, 49, 50, 51, 52, 53, 19, 185, 218, 221,
- /* 370 */ 222, 223, 152, 152, 27, 28, 29, 30, 31, 32,
- /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 241,
- /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 400 */ 53, 19, 152, 168, 169, 170, 22, 190, 191, 27,
- /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 430 */ 48, 49, 50, 51, 52, 53, 19, 19, 218, 55,
- /* 440 */ 56, 24, 22, 152, 27, 28, 29, 30, 31, 32,
- /* 450 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152,
- /* 460 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 470 */ 53, 250, 194, 195, 56, 55, 56, 55, 19, 172,
- /* 480 */ 173, 97, 98, 152, 206, 138, 27, 28, 29, 30,
- /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 500 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 510 */ 51, 52, 53, 19, 207, 208, 152, 97, 98, 97,
- /* 520 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- /* 530 */ 36, 37, 38, 39, 40, 41, 181, 43, 44, 45,
- /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 30,
- /* 550 */ 31, 32, 33, 247, 248, 19, 152, 28, 29, 30,
- /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 580 */ 51, 52, 53, 19, 168, 169, 170, 238, 19, 53,
- /* 590 */ 152, 172, 173, 29, 30, 31, 32, 33, 34, 35,
- /* 600 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45,
- /* 610 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 20,
- /* 620 */ 101, 22, 23, 169, 170, 56, 207, 85, 55, 56,
- /* 630 */ 23, 19, 20, 26, 22, 99, 100, 101, 102, 103,
- /* 640 */ 104, 105, 238, 152, 152, 210, 47, 48, 112, 152,
- /* 650 */ 108, 109, 110, 54, 55, 56, 221, 222, 223, 47,
- /* 660 */ 48, 119, 120, 172, 173, 66, 54, 55, 56, 152,
- /* 670 */ 97, 98, 99, 148, 149, 102, 103, 104, 66, 154,
- /* 680 */ 23, 156, 83, 26, 230, 152, 113, 152, 163, 194,
- /* 690 */ 195, 92, 92, 30, 95, 83, 97, 98, 207, 208,
- /* 700 */ 101, 206, 179, 180, 92, 172, 173, 95, 152, 97,
- /* 710 */ 98, 188, 99, 101, 219, 102, 103, 104, 152, 119,
- /* 720 */ 120, 196, 55, 56, 19, 20, 113, 22, 193, 163,
- /* 730 */ 11, 132, 133, 134, 135, 136, 24, 65, 172, 173,
- /* 740 */ 207, 208, 250, 152, 132, 133, 134, 135, 136, 193,
- /* 750 */ 78, 84, 47, 48, 49, 98, 199, 152, 86, 54,
- /* 760 */ 55, 56, 196, 152, 97, 98, 209, 55, 163, 244,
- /* 770 */ 107, 66, 152, 207, 208, 164, 175, 172, 173, 19,
- /* 780 */ 20, 124, 22, 111, 38, 39, 40, 41, 83, 43,
- /* 790 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 800 */ 95, 196, 97, 98, 85, 152, 101, 47, 48, 97,
- /* 810 */ 85, 92, 207, 193, 54, 55, 56, 92, 49, 175,
- /* 820 */ 55, 56, 221, 222, 223, 12, 66, 108, 109, 110,
- /* 830 */ 137, 163, 139, 108, 109, 110, 26, 132, 133, 134,
- /* 840 */ 135, 136, 152, 83, 43, 44, 45, 46, 47, 48,
- /* 850 */ 49, 50, 51, 52, 53, 95, 26, 97, 98, 55,
- /* 860 */ 56, 101, 97, 98, 196, 221, 222, 223, 146, 147,
- /* 870 */ 57, 171, 152, 22, 26, 19, 20, 49, 22, 179,
- /* 880 */ 108, 109, 110, 55, 56, 116, 73, 219, 75, 124,
- /* 890 */ 121, 152, 132, 133, 134, 135, 136, 163, 85, 152,
- /* 900 */ 232, 97, 98, 47, 48, 237, 55, 56, 98, 5,
- /* 910 */ 54, 55, 56, 193, 10, 11, 12, 13, 14, 172,
- /* 920 */ 173, 17, 66, 47, 48, 97, 98, 152, 124, 152,
- /* 930 */ 196, 55, 56, 186, 124, 152, 106, 160, 152, 83,
- /* 940 */ 152, 164, 152, 61, 22, 211, 212, 152, 97, 98,
- /* 950 */ 152, 95, 70, 97, 98, 172, 173, 101, 172, 173,
- /* 960 */ 172, 173, 172, 173, 60, 181, 62, 172, 173, 47,
- /* 970 */ 48, 123, 186, 97, 98, 71, 100, 55, 56, 152,
- /* 980 */ 181, 186, 21, 107, 152, 109, 82, 163, 132, 133,
- /* 990 */ 134, 135, 136, 89, 16, 207, 92, 93, 19, 172,
- /* 1000 */ 173, 169, 170, 195, 55, 56, 12, 152, 132, 30,
- /* 1010 */ 134, 47, 48, 186, 206, 225, 152, 95, 114, 97,
- /* 1020 */ 196, 245, 246, 101, 152, 38, 39, 40, 41, 42,
- /* 1030 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 1040 */ 53, 152, 163, 219, 152, 141, 97, 98, 193, 152,
- /* 1050 */ 152, 57, 91, 164, 132, 133, 134, 152, 55, 152,
- /* 1060 */ 152, 237, 230, 152, 103, 193, 88, 73, 90, 75,
- /* 1070 */ 172, 173, 183, 152, 185, 196, 152, 172, 173, 172,
- /* 1080 */ 173, 217, 152, 172, 173, 152, 107, 22, 152, 24,
- /* 1090 */ 193, 112, 152, 172, 173, 152, 132, 242, 134, 152,
- /* 1100 */ 97, 140, 152, 92, 152, 172, 173, 152, 172, 173,
- /* 1110 */ 152, 100, 172, 173, 152, 172, 173, 152, 140, 172,
- /* 1120 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152,
- /* 1130 */ 172, 173, 152, 152, 172, 173, 152, 172, 173, 213,
- /* 1140 */ 152, 172, 173, 152, 152, 152, 172, 173, 152, 172,
- /* 1150 */ 173, 152, 172, 173, 152, 210, 172, 173, 152, 26,
- /* 1160 */ 172, 173, 152, 172, 173, 172, 173, 152, 172, 173,
- /* 1170 */ 152, 172, 173, 152, 172, 173, 152, 59, 172, 173,
- /* 1180 */ 152, 63, 172, 173, 152, 193, 152, 152, 152, 152,
- /* 1190 */ 172, 173, 152, 172, 173, 77, 172, 173, 152, 152,
- /* 1200 */ 172, 173, 152, 152, 172, 173, 172, 173, 172, 173,
- /* 1210 */ 152, 22, 172, 173, 152, 152, 152, 22, 172, 173,
- /* 1220 */ 152, 152, 152, 172, 173, 152, 7, 8, 9, 163,
- /* 1230 */ 172, 173, 22, 23, 172, 173, 172, 173, 166, 167,
- /* 1240 */ 172, 173, 172, 173, 55, 172, 173, 22, 23, 108,
- /* 1250 */ 109, 110, 217, 152, 217, 166, 167, 163, 163, 163,
- /* 1260 */ 163, 163, 196, 130, 217, 211, 212, 217, 116, 23,
- /* 1270 */ 22, 101, 26, 121, 23, 23, 23, 26, 26, 26,
- /* 1280 */ 23, 23, 112, 26, 26, 37, 97, 100, 101, 55,
- /* 1290 */ 196, 196, 196, 196, 196, 23, 23, 55, 26, 26,
- /* 1300 */ 7, 8, 23, 152, 23, 26, 96, 26, 132, 132,
- /* 1310 */ 134, 134, 23, 152, 152, 26, 152, 122, 152, 191,
- /* 1320 */ 152, 96, 234, 152, 152, 152, 152, 152, 197, 210,
- /* 1330 */ 152, 97, 152, 152, 210, 233, 210, 198, 150, 97,
- /* 1340 */ 184, 201, 239, 214, 214, 201, 239, 180, 214, 227,
- /* 1350 */ 200, 198, 155, 67, 243, 176, 69, 175, 175, 175,
- /* 1360 */ 122, 159, 159, 240, 159, 240, 22, 220, 27, 130,
- /* 1370 */ 201, 18, 159, 18, 189, 158, 158, 220, 192, 159,
- /* 1380 */ 137, 236, 192, 192, 192, 189, 74, 189, 159, 235,
- /* 1390 */ 159, 158, 22, 177, 201, 201, 159, 107, 158, 177,
- /* 1400 */ 159, 174, 158, 76, 174, 182, 174, 106, 182, 125,
- /* 1410 */ 174, 107, 177, 22, 159, 216, 215, 137, 159, 53,
- /* 1420 */ 216, 176, 215, 174, 174, 216, 215, 215, 174, 229,
- /* 1430 */ 216, 129, 224, 177, 126, 229, 127, 177, 128, 25,
- /* 1440 */ 162, 226, 26, 161, 13, 153, 6, 153, 151, 151,
- /* 1450 */ 151, 151, 205, 165, 178, 178, 165, 4, 3, 22,
- /* 1460 */ 165, 142, 15, 94, 202, 204, 203, 201, 16, 23,
- /* 1470 */ 249, 23, 120, 249, 246, 111, 131, 123, 20, 16,
- /* 1480 */ 1, 125, 123, 111, 56, 64, 37, 37, 131, 122,
- /* 1490 */ 1, 37, 5, 37, 22, 107, 26, 80, 140, 80,
- /* 1500 */ 87, 72, 107, 20, 24, 19, 112, 105, 23, 79,
- /* 1510 */ 22, 79, 22, 22, 22, 58, 22, 79, 23, 68,
- /* 1520 */ 23, 23, 26, 116, 22, 26, 23, 22, 122, 23,
- /* 1530 */ 23, 56, 64, 22, 124, 26, 26, 64, 64, 23,
- /* 1540 */ 23, 23, 23, 11, 23, 22, 26, 23, 22, 24,
- /* 1550 */ 1, 23, 22, 26, 251, 24, 23, 22, 122, 23,
- /* 1560 */ 23, 22, 15, 122, 122, 122, 23,
-};
-#define YY_SHIFT_USE_DFLT (1567)
+ /* 0 */ 19, 115, 19, 117, 118, 24, 1, 2, 27, 79,
+ /* 10 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ /* 20 */ 90, 91, 92, 93, 94, 144, 145, 146, 147, 58,
+ /* 30 */ 49, 50, 79, 80, 81, 82, 22, 84, 85, 86,
+ /* 40 */ 87, 88, 89, 90, 91, 92, 93, 94, 221, 222,
+ /* 50 */ 223, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 60 */ 79, 80, 81, 82, 94, 84, 85, 86, 87, 88,
+ /* 70 */ 89, 90, 91, 92, 93, 94, 19, 94, 97, 108,
+ /* 80 */ 109, 110, 99, 100, 101, 102, 103, 104, 105, 32,
+ /* 90 */ 119, 120, 78, 27, 152, 112, 93, 94, 41, 88,
+ /* 100 */ 89, 90, 91, 92, 93, 94, 49, 50, 84, 85,
+ /* 110 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 58,
+ /* 120 */ 157, 119, 120, 163, 68, 163, 65, 70, 71, 72,
+ /* 130 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ /* 140 */ 152, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ /* 150 */ 93, 94, 19, 97, 88, 89, 196, 101, 196, 26,
+ /* 160 */ 172, 173, 96, 97, 98, 210, 100, 22, 152, 108,
+ /* 170 */ 109, 110, 27, 107, 27, 109, 221, 222, 223, 219,
+ /* 180 */ 238, 219, 49, 50, 152, 169, 170, 54, 132, 133,
+ /* 190 */ 134, 228, 232, 171, 231, 207, 208, 237, 132, 237,
+ /* 200 */ 134, 179, 19, 70, 71, 72, 73, 74, 75, 76,
+ /* 210 */ 77, 78, 79, 80, 81, 82, 152, 84, 85, 86,
+ /* 220 */ 87, 88, 89, 90, 91, 92, 93, 94, 27, 65,
+ /* 230 */ 30, 152, 49, 50, 34, 52, 90, 91, 92, 93,
+ /* 240 */ 94, 96, 97, 98, 97, 22, 230, 27, 48, 217,
+ /* 250 */ 27, 172, 173, 70, 71, 72, 73, 74, 75, 76,
+ /* 260 */ 77, 78, 79, 80, 81, 82, 172, 84, 85, 86,
+ /* 270 */ 87, 88, 89, 90, 91, 92, 93, 94, 19, 148,
+ /* 280 */ 149, 152, 218, 24, 152, 154, 207, 156, 172, 152,
+ /* 290 */ 22, 68, 27, 152, 163, 27, 164, 96, 97, 98,
+ /* 300 */ 99, 172, 173, 102, 103, 104, 169, 170, 49, 50,
+ /* 310 */ 90, 88, 89, 152, 113, 186, 96, 97, 98, 96,
+ /* 320 */ 97, 160, 57, 27, 101, 164, 137, 196, 139, 70,
+ /* 330 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ /* 340 */ 81, 82, 11, 84, 85, 86, 87, 88, 89, 90,
+ /* 350 */ 91, 92, 93, 94, 19, 132, 133, 134, 23, 218,
+ /* 360 */ 152, 96, 97, 98, 96, 97, 98, 230, 99, 22,
+ /* 370 */ 152, 102, 103, 104, 27, 244, 152, 152, 27, 26,
+ /* 380 */ 152, 22, 113, 65, 49, 50, 27, 194, 195, 58,
+ /* 390 */ 172, 173, 96, 97, 98, 185, 65, 172, 173, 206,
+ /* 400 */ 172, 173, 190, 191, 186, 70, 71, 72, 73, 74,
+ /* 410 */ 75, 76, 77, 78, 79, 80, 81, 82, 175, 84,
+ /* 420 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ /* 430 */ 19, 175, 207, 208, 23, 207, 208, 119, 120, 108,
+ /* 440 */ 109, 110, 27, 96, 97, 98, 116, 96, 97, 98,
+ /* 450 */ 152, 121, 152, 179, 180, 96, 97, 98, 250, 106,
+ /* 460 */ 49, 50, 188, 19, 221, 222, 223, 168, 169, 170,
+ /* 470 */ 172, 173, 172, 173, 250, 124, 172, 221, 222, 223,
+ /* 480 */ 26, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 490 */ 79, 80, 81, 82, 50, 84, 85, 86, 87, 88,
+ /* 500 */ 89, 90, 91, 92, 93, 94, 19, 207, 208, 12,
+ /* 510 */ 23, 96, 97, 98, 221, 222, 223, 194, 195, 152,
+ /* 520 */ 199, 23, 19, 225, 26, 28, 152, 152, 152, 206,
+ /* 530 */ 209, 164, 190, 191, 241, 152, 49, 50, 152, 124,
+ /* 540 */ 152, 44, 219, 46, 152, 21, 172, 173, 172, 173,
+ /* 550 */ 183, 107, 185, 16, 163, 58, 112, 70, 71, 72,
+ /* 560 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ /* 570 */ 152, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ /* 580 */ 93, 94, 19, 207, 130, 152, 23, 196, 64, 152,
+ /* 590 */ 172, 173, 22, 152, 24, 152, 98, 27, 61, 96,
+ /* 600 */ 63, 26, 211, 212, 186, 172, 173, 49, 50, 172,
+ /* 610 */ 173, 23, 49, 50, 26, 172, 173, 88, 89, 186,
+ /* 620 */ 24, 238, 124, 27, 238, 22, 23, 103, 187, 26,
+ /* 630 */ 152, 73, 74, 70, 71, 72, 73, 74, 75, 76,
+ /* 640 */ 77, 78, 79, 80, 81, 82, 152, 84, 85, 86,
+ /* 650 */ 87, 88, 89, 90, 91, 92, 93, 94, 19, 101,
+ /* 660 */ 152, 132, 23, 134, 140, 152, 12, 97, 36, 168,
+ /* 670 */ 169, 170, 69, 98, 152, 22, 23, 140, 50, 26,
+ /* 680 */ 172, 173, 28, 51, 152, 172, 173, 193, 49, 50,
+ /* 690 */ 22, 59, 24, 97, 172, 173, 152, 152, 44, 124,
+ /* 700 */ 46, 0, 1, 2, 172, 173, 22, 23, 19, 70,
+ /* 710 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ /* 720 */ 81, 82, 69, 84, 85, 86, 87, 88, 89, 90,
+ /* 730 */ 91, 92, 93, 94, 152, 107, 152, 193, 49, 50,
+ /* 740 */ 181, 22, 23, 111, 108, 109, 110, 7, 8, 9,
+ /* 750 */ 16, 247, 248, 69, 172, 173, 172, 173, 152, 70,
+ /* 760 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ /* 770 */ 81, 82, 152, 84, 85, 86, 87, 88, 89, 90,
+ /* 780 */ 91, 92, 93, 94, 19, 152, 242, 152, 69, 152,
+ /* 790 */ 166, 167, 172, 173, 32, 61, 152, 63, 152, 193,
+ /* 800 */ 152, 152, 152, 41, 152, 172, 173, 172, 173, 172,
+ /* 810 */ 173, 152, 152, 152, 49, 50, 172, 173, 172, 173,
+ /* 820 */ 172, 173, 172, 173, 172, 173, 132, 138, 134, 152,
+ /* 830 */ 152, 172, 173, 172, 173, 70, 71, 72, 73, 74,
+ /* 840 */ 75, 76, 77, 78, 79, 80, 81, 82, 152, 84,
+ /* 850 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ /* 860 */ 19, 152, 22, 152, 195, 24, 152, 27, 172, 173,
+ /* 870 */ 193, 193, 152, 152, 152, 206, 152, 217, 152, 152,
+ /* 880 */ 152, 172, 173, 172, 173, 152, 172, 173, 152, 152,
+ /* 890 */ 49, 50, 172, 173, 172, 173, 172, 173, 172, 173,
+ /* 900 */ 172, 173, 152, 138, 152, 172, 173, 108, 109, 110,
+ /* 910 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 920 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
+ /* 930 */ 89, 90, 91, 92, 93, 94, 152, 97, 152, 152,
+ /* 940 */ 49, 50, 26, 193, 172, 173, 152, 152, 152, 146,
+ /* 950 */ 147, 132, 152, 134, 217, 181, 172, 173, 172, 173,
+ /* 960 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 970 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
+ /* 980 */ 89, 90, 91, 92, 93, 94, 152, 193, 152, 193,
+ /* 990 */ 49, 50, 181, 193, 172, 173, 166, 167, 245, 246,
+ /* 1000 */ 211, 212, 152, 22, 217, 152, 172, 173, 172, 173,
+ /* 1010 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 1020 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
+ /* 1030 */ 89, 90, 91, 92, 93, 94, 152, 187, 152, 123,
+ /* 1040 */ 49, 50, 23, 23, 23, 26, 26, 26, 23, 23,
+ /* 1050 */ 23, 26, 26, 26, 7, 8, 172, 173, 172, 173,
+ /* 1060 */ 19, 90, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 1070 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
+ /* 1080 */ 89, 90, 91, 92, 93, 94, 152, 116, 152, 217,
+ /* 1090 */ 49, 50, 121, 23, 172, 173, 26, 100, 101, 27,
+ /* 1100 */ 101, 27, 23, 122, 152, 26, 172, 173, 172, 173,
+ /* 1110 */ 152, 112, 163, 72, 73, 74, 75, 76, 77, 78,
+ /* 1120 */ 79, 80, 81, 82, 163, 84, 85, 86, 87, 88,
+ /* 1130 */ 89, 90, 91, 92, 93, 94, 19, 20, 152, 22,
+ /* 1140 */ 23, 152, 163, 65, 27, 196, 163, 19, 20, 23,
+ /* 1150 */ 22, 213, 26, 19, 37, 27, 152, 196, 172, 173,
+ /* 1160 */ 152, 172, 173, 27, 23, 37, 152, 26, 152, 97,
+ /* 1170 */ 152, 97, 210, 56, 163, 196, 163, 163, 100, 196,
+ /* 1180 */ 172, 173, 65, 152, 56, 68, 172, 173, 172, 173,
+ /* 1190 */ 172, 173, 152, 65, 163, 163, 68, 23, 152, 234,
+ /* 1200 */ 26, 152, 152, 172, 173, 88, 89, 196, 152, 196,
+ /* 1210 */ 196, 152, 95, 96, 97, 98, 88, 89, 101, 152,
+ /* 1220 */ 152, 207, 208, 95, 96, 97, 98, 196, 196, 101,
+ /* 1230 */ 96, 233, 152, 97, 152, 152, 19, 20, 207, 22,
+ /* 1240 */ 152, 152, 152, 191, 27, 152, 152, 152, 152, 132,
+ /* 1250 */ 133, 134, 135, 136, 37, 152, 152, 152, 152, 152,
+ /* 1260 */ 132, 133, 134, 135, 136, 210, 197, 210, 210, 198,
+ /* 1270 */ 150, 184, 239, 56, 201, 214, 214, 201, 239, 180,
+ /* 1280 */ 214, 227, 198, 38, 176, 68, 175, 175, 175, 122,
+ /* 1290 */ 155, 200, 159, 19, 20, 40, 22, 159, 159, 22,
+ /* 1300 */ 70, 27, 130, 243, 240, 88, 89, 90, 189, 18,
+ /* 1310 */ 201, 37, 95, 96, 97, 98, 192, 5, 101, 192,
+ /* 1320 */ 220, 240, 10, 11, 12, 13, 14, 159, 18, 17,
+ /* 1330 */ 56, 158, 192, 201, 192, 220, 189, 189, 201, 159,
+ /* 1340 */ 158, 137, 68, 31, 45, 33, 236, 159, 159, 132,
+ /* 1350 */ 133, 134, 135, 136, 42, 158, 235, 22, 177, 159,
+ /* 1360 */ 158, 158, 88, 89, 159, 107, 174, 55, 177, 95,
+ /* 1370 */ 96, 97, 98, 174, 62, 101, 47, 65, 66, 106,
+ /* 1380 */ 174, 125, 19, 20, 174, 22, 177, 176, 174, 182,
+ /* 1390 */ 27, 216, 174, 174, 182, 107, 159, 22, 215, 215,
+ /* 1400 */ 37, 216, 216, 216, 137, 215, 132, 133, 134, 135,
+ /* 1410 */ 136, 215, 159, 177, 94, 177, 129, 224, 205, 56,
+ /* 1420 */ 226, 126, 128, 203, 229, 204, 114, 229, 127, 202,
+ /* 1430 */ 201, 68, 25, 162, 26, 13, 161, 153, 153, 6,
+ /* 1440 */ 151, 151, 178, 151, 151, 165, 165, 178, 165, 4,
+ /* 1450 */ 249, 88, 89, 141, 3, 142, 22, 249, 95, 96,
+ /* 1460 */ 97, 98, 246, 15, 101, 67, 16, 23, 120, 23,
+ /* 1470 */ 131, 111, 123, 20, 16, 125, 1, 123, 131, 78,
+ /* 1480 */ 78, 78, 78, 111, 96, 1, 122, 35, 5, 22,
+ /* 1490 */ 107, 140, 53, 53, 26, 132, 133, 134, 135, 136,
+ /* 1500 */ 43, 60, 107, 24, 112, 20, 19, 52, 22, 29,
+ /* 1510 */ 105, 22, 22, 52, 23, 22, 22, 52, 23, 23,
+ /* 1520 */ 39, 23, 116, 26, 22, 26, 23, 22, 96, 23,
+ /* 1530 */ 23, 122, 22, 24, 124, 35, 35, 26, 26, 35,
+ /* 1540 */ 23, 23, 23, 23, 11, 23, 22, 26, 23, 22,
+ /* 1550 */ 122, 23, 26, 22, 24, 23, 22, 122, 23, 23,
+ /* 1560 */ 22, 15, 23, 1, 122, 122,
+};
+#define YY_SHIFT_USE_DFLT (1566)
#define YY_SHIFT_COUNT (455)
-#define YY_SHIFT_MIN (-94)
-#define YY_SHIFT_MAX (1549)
+#define YY_SHIFT_MIN (-114)
+#define YY_SHIFT_MAX (1562)
static const short yy_shift_ofst[] = {
- /* 0 */ 40, 599, 904, 612, 760, 760, 760, 760, 725, -19,
- /* 10 */ 16, 16, 100, 760, 760, 760, 760, 760, 760, 760,
- /* 20 */ 876, 876, 573, 542, 719, 600, 61, 137, 172, 207,
- /* 30 */ 242, 277, 312, 347, 382, 417, 459, 459, 459, 459,
- /* 40 */ 459, 459, 459, 459, 459, 459, 459, 459, 459, 459,
- /* 50 */ 459, 459, 459, 494, 459, 529, 564, 564, 705, 760,
- /* 60 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 70 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 80 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 90 */ 856, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 100 */ 760, 760, 760, 760, 987, 746, 746, 746, 746, 746,
- /* 110 */ 801, 23, 32, 949, 961, 979, 964, 964, 949, 73,
- /* 120 */ 113, -51, 1567, 1567, 1567, 536, 536, 536, 99, 99,
- /* 130 */ 813, 813, 667, 205, 240, 949, 949, 949, 949, 949,
- /* 140 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949,
- /* 150 */ 949, 949, 949, 949, 949, 332, 1011, 422, 422, 113,
- /* 160 */ 30, 30, 30, 30, 30, 30, 1567, 1567, 1567, 922,
- /* 170 */ -94, -94, 384, 613, 828, 420, 765, 804, 851, 949,
- /* 180 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949,
- /* 190 */ 949, 949, 949, 949, 949, 672, 672, 672, 949, 949,
- /* 200 */ 657, 949, 949, 949, -18, 949, 949, 994, 949, 949,
- /* 210 */ 949, 949, 949, 949, 949, 949, 949, 949, 772, 1118,
- /* 220 */ 712, 712, 712, 810, 45, 769, 1219, 1133, 418, 418,
- /* 230 */ 569, 1133, 569, 830, 607, 663, 882, 418, 693, 882,
- /* 240 */ 882, 848, 1152, 1065, 1286, 1238, 1238, 1287, 1287, 1238,
- /* 250 */ 1344, 1341, 1239, 1353, 1353, 1353, 1353, 1238, 1355, 1239,
- /* 260 */ 1344, 1341, 1341, 1239, 1238, 1355, 1243, 1312, 1238, 1238,
- /* 270 */ 1355, 1370, 1238, 1355, 1238, 1355, 1370, 1290, 1290, 1290,
- /* 280 */ 1327, 1370, 1290, 1301, 1290, 1327, 1290, 1290, 1284, 1304,
- /* 290 */ 1284, 1304, 1284, 1304, 1284, 1304, 1238, 1391, 1238, 1280,
- /* 300 */ 1370, 1366, 1366, 1370, 1302, 1308, 1310, 1309, 1239, 1414,
- /* 310 */ 1416, 1431, 1431, 1440, 1440, 1440, 1440, 1567, 1567, 1567,
- /* 320 */ 1567, 1567, 1567, 1567, 1567, 519, 978, 1210, 1225, 104,
- /* 330 */ 1141, 1189, 1246, 1248, 1251, 1252, 1253, 1257, 1258, 1273,
- /* 340 */ 1003, 1187, 1293, 1170, 1272, 1279, 1234, 1281, 1176, 1177,
- /* 350 */ 1289, 1242, 1195, 1453, 1455, 1437, 1319, 1447, 1369, 1452,
- /* 360 */ 1446, 1448, 1352, 1345, 1364, 1354, 1458, 1356, 1463, 1479,
- /* 370 */ 1359, 1357, 1449, 1450, 1454, 1456, 1372, 1428, 1421, 1367,
- /* 380 */ 1489, 1487, 1472, 1388, 1358, 1417, 1470, 1419, 1413, 1429,
- /* 390 */ 1395, 1480, 1483, 1486, 1394, 1402, 1488, 1430, 1490, 1491,
- /* 400 */ 1485, 1492, 1432, 1457, 1494, 1438, 1451, 1495, 1497, 1498,
- /* 410 */ 1496, 1407, 1502, 1503, 1505, 1499, 1406, 1506, 1507, 1475,
- /* 420 */ 1468, 1511, 1410, 1509, 1473, 1510, 1474, 1516, 1509, 1517,
- /* 430 */ 1518, 1519, 1520, 1521, 1523, 1532, 1524, 1526, 1525, 1527,
- /* 440 */ 1528, 1530, 1531, 1527, 1533, 1535, 1536, 1537, 1539, 1436,
- /* 450 */ 1441, 1442, 1443, 1543, 1547, 1549,
+ /* 0 */ 5, 1117, 1312, 1128, 1274, 1274, 1274, 1274, 61, -19,
+ /* 10 */ 57, 57, 183, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
+ /* 20 */ 66, 66, 201, -29, 331, 318, 133, 259, 335, 411,
+ /* 30 */ 487, 563, 639, 689, 765, 841, 891, 891, 891, 891,
+ /* 40 */ 891, 891, 891, 891, 891, 891, 891, 891, 891, 891,
+ /* 50 */ 891, 891, 891, 941, 891, 991, 1041, 1041, 1217, 1274,
+ /* 60 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
+ /* 70 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
+ /* 80 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
+ /* 90 */ 1363, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
+ /* 100 */ 1274, 1274, 1274, 1274, -70, -47, -47, -47, -47, -47,
+ /* 110 */ 24, 11, 146, 296, 524, 444, 529, 529, 296, 3,
+ /* 120 */ 2, -30, 1566, 1566, 1566, -17, -17, -17, 145, 145,
+ /* 130 */ 497, 497, 265, 603, 653, 296, 296, 296, 296, 296,
+ /* 140 */ 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
+ /* 150 */ 296, 296, 296, 296, 296, 701, 1078, 147, 147, 2,
+ /* 160 */ 164, 164, 164, 164, 164, 164, 1566, 1566, 1566, 223,
+ /* 170 */ 56, 56, 268, 269, 220, 347, 351, 415, 359, 296,
+ /* 180 */ 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
+ /* 190 */ 296, 296, 296, 296, 296, 632, 632, 632, 296, 296,
+ /* 200 */ 498, 296, 296, 296, 570, 296, 296, 654, 296, 296,
+ /* 210 */ 296, 296, 296, 296, 296, 296, 296, 296, 636, 200,
+ /* 220 */ 596, 596, 596, 575, -114, 971, 740, 454, 503, 503,
+ /* 230 */ 1134, 454, 1134, 353, 588, 628, 762, 503, 189, 762,
+ /* 240 */ 762, 916, 330, 668, 1245, 1167, 1167, 1255, 1255, 1167,
+ /* 250 */ 1277, 1230, 1172, 1291, 1291, 1291, 1291, 1167, 1310, 1172,
+ /* 260 */ 1277, 1230, 1230, 1172, 1167, 1310, 1204, 1299, 1167, 1167,
+ /* 270 */ 1310, 1335, 1167, 1310, 1167, 1310, 1335, 1258, 1258, 1258,
+ /* 280 */ 1329, 1335, 1258, 1273, 1258, 1329, 1258, 1258, 1256, 1288,
+ /* 290 */ 1256, 1288, 1256, 1288, 1256, 1288, 1167, 1375, 1167, 1267,
+ /* 300 */ 1335, 1320, 1320, 1335, 1287, 1295, 1294, 1301, 1172, 1407,
+ /* 310 */ 1408, 1422, 1422, 1433, 1433, 1433, 1433, 1566, 1566, 1566,
+ /* 320 */ 1566, 1566, 1566, 1566, 1566, 558, 537, 684, 719, 734,
+ /* 330 */ 799, 840, 1019, 14, 1020, 1021, 1025, 1026, 1027, 1070,
+ /* 340 */ 1072, 997, 1047, 999, 1079, 1126, 1074, 1141, 694, 819,
+ /* 350 */ 1174, 1136, 981, 1445, 1451, 1434, 1313, 1448, 1398, 1450,
+ /* 360 */ 1444, 1446, 1348, 1339, 1360, 1349, 1453, 1350, 1458, 1475,
+ /* 370 */ 1354, 1347, 1401, 1402, 1403, 1404, 1372, 1388, 1452, 1364,
+ /* 380 */ 1484, 1483, 1467, 1383, 1351, 1439, 1468, 1440, 1441, 1457,
+ /* 390 */ 1395, 1479, 1485, 1487, 1392, 1405, 1486, 1455, 1489, 1490,
+ /* 400 */ 1491, 1493, 1461, 1480, 1494, 1465, 1481, 1495, 1496, 1498,
+ /* 410 */ 1497, 1406, 1502, 1503, 1505, 1499, 1409, 1506, 1507, 1432,
+ /* 420 */ 1500, 1510, 1410, 1511, 1501, 1512, 1504, 1517, 1511, 1518,
+ /* 430 */ 1519, 1520, 1521, 1522, 1524, 1533, 1525, 1527, 1509, 1526,
+ /* 440 */ 1528, 1531, 1530, 1526, 1532, 1534, 1535, 1536, 1538, 1428,
+ /* 450 */ 1435, 1442, 1443, 1539, 1546, 1562,
};
-#define YY_REDUCE_USE_DFLT (-130)
+#define YY_REDUCE_USE_DFLT (-174)
#define YY_REDUCE_COUNT (324)
-#define YY_REDUCE_MIN (-129)
-#define YY_REDUCE_MAX (1300)
+#define YY_REDUCE_MIN (-173)
+#define YY_REDUCE_MAX (1293)
static const short yy_reduce_ofst[] = {
- /* 0 */ -29, 566, 525, 605, -49, 307, 491, 533, 668, 435,
- /* 10 */ 601, 644, 148, 747, 786, 795, 419, 788, 827, 790,
- /* 20 */ 454, 832, 889, 495, 824, 734, 76, 76, 76, 76,
- /* 30 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
- /* 40 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
- /* 50 */ 76, 76, 76, 76, 76, 76, 76, 76, 783, 898,
- /* 60 */ 905, 907, 911, 921, 933, 936, 940, 943, 947, 950,
- /* 70 */ 952, 955, 958, 962, 965, 969, 974, 977, 980, 984,
- /* 80 */ 988, 991, 993, 996, 999, 1002, 1006, 1010, 1018, 1021,
- /* 90 */ 1024, 1028, 1032, 1034, 1036, 1040, 1046, 1051, 1058, 1062,
- /* 100 */ 1064, 1068, 1070, 1073, 76, 76, 76, 76, 76, 76,
- /* 110 */ 76, 76, 76, 855, 36, 523, 235, 416, 777, 76,
- /* 120 */ 278, 76, 76, 76, 76, 700, 700, 700, 150, 220,
- /* 130 */ 147, 217, 221, 306, 306, 611, 5, 535, 556, 620,
- /* 140 */ 720, 872, 897, 116, 864, 349, 1035, 1037, 404, 1047,
- /* 150 */ 992, -129, 1050, 492, 62, 722, 879, 1072, 1089, 808,
- /* 160 */ 1066, 1094, 1095, 1096, 1097, 1098, 776, 1054, 557, 57,
- /* 170 */ 112, 131, 167, 182, 250, 272, 291, 331, 364, 438,
- /* 180 */ 497, 517, 591, 653, 690, 739, 775, 798, 892, 908,
- /* 190 */ 924, 930, 1015, 1063, 1069, 355, 784, 799, 981, 1101,
- /* 200 */ 926, 1151, 1161, 1162, 945, 1164, 1166, 1128, 1168, 1171,
- /* 210 */ 1172, 250, 1173, 1174, 1175, 1178, 1180, 1181, 1088, 1102,
- /* 220 */ 1119, 1124, 1126, 926, 1131, 1139, 1188, 1140, 1129, 1130,
- /* 230 */ 1103, 1144, 1107, 1179, 1156, 1167, 1182, 1134, 1122, 1183,
- /* 240 */ 1184, 1150, 1153, 1197, 1111, 1202, 1203, 1123, 1125, 1205,
- /* 250 */ 1147, 1185, 1169, 1186, 1190, 1191, 1192, 1213, 1217, 1193,
- /* 260 */ 1157, 1196, 1198, 1194, 1220, 1218, 1145, 1154, 1229, 1231,
- /* 270 */ 1233, 1216, 1237, 1240, 1241, 1244, 1222, 1227, 1230, 1232,
- /* 280 */ 1223, 1235, 1236, 1245, 1249, 1226, 1250, 1254, 1199, 1201,
- /* 290 */ 1204, 1207, 1209, 1211, 1214, 1212, 1255, 1208, 1259, 1215,
- /* 300 */ 1256, 1200, 1206, 1260, 1247, 1261, 1263, 1262, 1266, 1278,
- /* 310 */ 1282, 1292, 1294, 1297, 1298, 1299, 1300, 1221, 1224, 1228,
- /* 320 */ 1288, 1291, 1276, 1277, 1295,
+ /* 0 */ -119, 1014, 131, 1031, -12, 225, 228, 300, -40, -45,
+ /* 10 */ 243, 256, 293, 129, 218, 418, 79, 376, 433, 298,
+ /* 20 */ 16, 137, 367, 323, -38, 391, -173, -173, -173, -173,
+ /* 30 */ -173, -173, -173, -173, -173, -173, -173, -173, -173, -173,
+ /* 40 */ -173, -173, -173, -173, -173, -173, -173, -173, -173, -173,
+ /* 50 */ -173, -173, -173, -173, -173, -173, -173, -173, 374, 437,
+ /* 60 */ 443, 508, 513, 522, 532, 582, 584, 620, 633, 635,
+ /* 70 */ 637, 644, 646, 648, 650, 652, 659, 661, 696, 709,
+ /* 80 */ 711, 714, 720, 722, 724, 726, 728, 733, 772, 784,
+ /* 90 */ 786, 822, 834, 836, 884, 886, 922, 934, 936, 986,
+ /* 100 */ 989, 1008, 1016, 1018, -173, -173, -173, -173, -173, -173,
+ /* 110 */ -173, -173, -173, 544, -37, 274, 299, 501, 161, -173,
+ /* 120 */ 193, -173, -173, -173, -173, 22, 22, 22, 64, 141,
+ /* 130 */ 212, 342, 208, 504, 504, 132, 494, 606, 677, 678,
+ /* 140 */ 750, 794, 796, -58, 32, 383, 660, 737, 386, 787,
+ /* 150 */ 800, 441, 872, 224, 850, 803, 949, 624, 830, 669,
+ /* 160 */ 961, 979, 983, 1011, 1013, 1032, 753, 789, 321, 94,
+ /* 170 */ 116, 304, 375, 210, 388, 392, 478, 545, 649, 721,
+ /* 180 */ 727, 736, 752, 795, 853, 952, 958, 1004, 1040, 1046,
+ /* 190 */ 1049, 1050, 1056, 1059, 1067, 559, 774, 811, 1068, 1080,
+ /* 200 */ 938, 1082, 1083, 1088, 962, 1089, 1090, 1052, 1093, 1094,
+ /* 210 */ 1095, 388, 1096, 1103, 1104, 1105, 1106, 1107, 965, 998,
+ /* 220 */ 1055, 1057, 1058, 938, 1069, 1071, 1120, 1073, 1061, 1062,
+ /* 230 */ 1033, 1076, 1039, 1108, 1087, 1099, 1111, 1066, 1054, 1112,
+ /* 240 */ 1113, 1091, 1084, 1135, 1060, 1133, 1138, 1064, 1081, 1139,
+ /* 250 */ 1100, 1119, 1109, 1124, 1127, 1140, 1142, 1168, 1173, 1132,
+ /* 260 */ 1115, 1147, 1148, 1137, 1180, 1182, 1110, 1121, 1188, 1189,
+ /* 270 */ 1197, 1181, 1200, 1202, 1205, 1203, 1191, 1192, 1199, 1206,
+ /* 280 */ 1207, 1209, 1210, 1211, 1214, 1212, 1218, 1219, 1175, 1183,
+ /* 290 */ 1185, 1184, 1186, 1190, 1187, 1196, 1237, 1193, 1253, 1194,
+ /* 300 */ 1236, 1195, 1198, 1238, 1213, 1221, 1220, 1227, 1229, 1271,
+ /* 310 */ 1275, 1284, 1285, 1289, 1290, 1292, 1293, 1201, 1208, 1216,
+ /* 320 */ 1280, 1281, 1264, 1269, 1283,
};
static const YYACTIONTYPE yy_default[] = {
/* 0 */ 1280, 1270, 1270, 1270, 1202, 1202, 1202, 1202, 1270, 1096,
/* 10 */ 1125, 1125, 1254, 1332, 1332, 1332, 1332, 1332, 1332, 1201,
/* 20 */ 1332, 1332, 1332, 1332, 1270, 1100, 1131, 1332, 1332, 1332,
@@ -135635,104 +136369,77 @@
*/
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 55, /* EXPLAIN => ID */
- 55, /* QUERY => ID */
- 55, /* PLAN => ID */
- 55, /* BEGIN => ID */
+ 27, /* EXPLAIN => ID */
+ 27, /* QUERY => ID */
+ 27, /* PLAN => ID */
+ 27, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 55, /* DEFERRED => ID */
- 55, /* IMMEDIATE => ID */
- 55, /* EXCLUSIVE => ID */
+ 27, /* DEFERRED => ID */
+ 27, /* IMMEDIATE => ID */
+ 27, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 55, /* END => ID */
- 55, /* ROLLBACK => ID */
- 55, /* SAVEPOINT => ID */
- 55, /* RELEASE => ID */
+ 27, /* END => ID */
+ 27, /* ROLLBACK => ID */
+ 27, /* SAVEPOINT => ID */
+ 27, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 55, /* IF => ID */
+ 27, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 55, /* TEMP => ID */
+ 27, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
- 55, /* WITHOUT => ID */
+ 27, /* WITHOUT => ID */
0, /* COMMA => nothing */
- 0, /* OR => nothing */
- 0, /* AND => nothing */
- 0, /* IS => nothing */
- 55, /* MATCH => ID */
- 55, /* LIKE_KW => ID */
- 0, /* BETWEEN => nothing */
- 0, /* IN => nothing */
- 0, /* ISNULL => nothing */
- 0, /* NOTNULL => nothing */
- 0, /* NE => nothing */
- 0, /* EQ => nothing */
- 0, /* GT => nothing */
- 0, /* LE => nothing */
- 0, /* LT => nothing */
- 0, /* GE => nothing */
- 0, /* ESCAPE => nothing */
- 0, /* BITAND => nothing */
- 0, /* BITOR => nothing */
- 0, /* LSHIFT => nothing */
- 0, /* RSHIFT => nothing */
- 0, /* PLUS => nothing */
- 0, /* MINUS => nothing */
- 0, /* STAR => nothing */
- 0, /* SLASH => nothing */
- 0, /* REM => nothing */
- 0, /* CONCAT => nothing */
- 0, /* COLLATE => nothing */
- 0, /* BITNOT => nothing */
0, /* ID => nothing */
- 0, /* INDEXED => nothing */
- 55, /* ABORT => ID */
- 55, /* ACTION => ID */
- 55, /* AFTER => ID */
- 55, /* ANALYZE => ID */
- 55, /* ASC => ID */
- 55, /* ATTACH => ID */
- 55, /* BEFORE => ID */
- 55, /* BY => ID */
- 55, /* CASCADE => ID */
- 55, /* CAST => ID */
- 55, /* COLUMNKW => ID */
- 55, /* CONFLICT => ID */
- 55, /* DATABASE => ID */
- 55, /* DESC => ID */
- 55, /* DETACH => ID */
- 55, /* EACH => ID */
- 55, /* FAIL => ID */
- 55, /* FOR => ID */
- 55, /* IGNORE => ID */
- 55, /* INITIALLY => ID */
- 55, /* INSTEAD => ID */
- 55, /* NO => ID */
- 55, /* KEY => ID */
- 55, /* OF => ID */
- 55, /* OFFSET => ID */
- 55, /* PRAGMA => ID */
- 55, /* RAISE => ID */
- 55, /* RECURSIVE => ID */
- 55, /* REPLACE => ID */
- 55, /* RESTRICT => ID */
- 55, /* ROW => ID */
- 55, /* TRIGGER => ID */
- 55, /* VACUUM => ID */
- 55, /* VIEW => ID */
- 55, /* VIRTUAL => ID */
- 55, /* WITH => ID */
- 55, /* REINDEX => ID */
- 55, /* RENAME => ID */
- 55, /* CTIME_KW => ID */
+ 27, /* ABORT => ID */
+ 27, /* ACTION => ID */
+ 27, /* AFTER => ID */
+ 27, /* ANALYZE => ID */
+ 27, /* ASC => ID */
+ 27, /* ATTACH => ID */
+ 27, /* BEFORE => ID */
+ 27, /* BY => ID */
+ 27, /* CASCADE => ID */
+ 27, /* CAST => ID */
+ 27, /* COLUMNKW => ID */
+ 27, /* CONFLICT => ID */
+ 27, /* DATABASE => ID */
+ 27, /* DESC => ID */
+ 27, /* DETACH => ID */
+ 27, /* EACH => ID */
+ 27, /* FAIL => ID */
+ 27, /* FOR => ID */
+ 27, /* IGNORE => ID */
+ 27, /* INITIALLY => ID */
+ 27, /* INSTEAD => ID */
+ 27, /* LIKE_KW => ID */
+ 27, /* MATCH => ID */
+ 27, /* NO => ID */
+ 27, /* KEY => ID */
+ 27, /* OF => ID */
+ 27, /* OFFSET => ID */
+ 27, /* PRAGMA => ID */
+ 27, /* RAISE => ID */
+ 27, /* RECURSIVE => ID */
+ 27, /* REPLACE => ID */
+ 27, /* RESTRICT => ID */
+ 27, /* ROW => ID */
+ 27, /* TRIGGER => ID */
+ 27, /* VACUUM => ID */
+ 27, /* VIEW => ID */
+ 27, /* VIRTUAL => ID */
+ 27, /* WITH => ID */
+ 27, /* REINDEX => ID */
+ 27, /* RENAME => ID */
+ 27, /* CTIME_KW => ID */
};
#endif /* YYFALLBACK */
/* The following structure represents a single element of the
** parser's stack. Information stored includes:
@@ -135820,29 +136527,29 @@
"PLAN", "BEGIN", "TRANSACTION", "DEFERRED",
"IMMEDIATE", "EXCLUSIVE", "COMMIT", "END",
"ROLLBACK", "SAVEPOINT", "RELEASE", "TO",
"TABLE", "CREATE", "IF", "NOT",
"EXISTS", "TEMP", "LP", "RP",
- "AS", "WITHOUT", "COMMA", "OR",
- "AND", "IS", "MATCH", "LIKE_KW",
- "BETWEEN", "IN", "ISNULL", "NOTNULL",
- "NE", "EQ", "GT", "LE",
- "LT", "GE", "ESCAPE", "BITAND",
- "BITOR", "LSHIFT", "RSHIFT", "PLUS",
- "MINUS", "STAR", "SLASH", "REM",
- "CONCAT", "COLLATE", "BITNOT", "ID",
- "INDEXED", "ABORT", "ACTION", "AFTER",
- "ANALYZE", "ASC", "ATTACH", "BEFORE",
- "BY", "CASCADE", "CAST", "COLUMNKW",
- "CONFLICT", "DATABASE", "DESC", "DETACH",
- "EACH", "FAIL", "FOR", "IGNORE",
- "INITIALLY", "INSTEAD", "NO", "KEY",
- "OF", "OFFSET", "PRAGMA", "RAISE",
- "RECURSIVE", "REPLACE", "RESTRICT", "ROW",
- "TRIGGER", "VACUUM", "VIEW", "VIRTUAL",
- "WITH", "REINDEX", "RENAME", "CTIME_KW",
- "ANY", "STRING", "JOIN_KW", "CONSTRAINT",
+ "AS", "WITHOUT", "COMMA", "ID",
+ "ABORT", "ACTION", "AFTER", "ANALYZE",
+ "ASC", "ATTACH", "BEFORE", "BY",
+ "CASCADE", "CAST", "COLUMNKW", "CONFLICT",
+ "DATABASE", "DESC", "DETACH", "EACH",
+ "FAIL", "FOR", "IGNORE", "INITIALLY",
+ "INSTEAD", "LIKE_KW", "MATCH", "NO",
+ "KEY", "OF", "OFFSET", "PRAGMA",
+ "RAISE", "RECURSIVE", "REPLACE", "RESTRICT",
+ "ROW", "TRIGGER", "VACUUM", "VIEW",
+ "VIRTUAL", "WITH", "REINDEX", "RENAME",
+ "CTIME_KW", "ANY", "OR", "AND",
+ "IS", "BETWEEN", "IN", "ISNULL",
+ "NOTNULL", "NE", "EQ", "GT",
+ "LE", "LT", "GE", "ESCAPE",
+ "BITAND", "BITOR", "LSHIFT", "RSHIFT",
+ "PLUS", "MINUS", "STAR", "SLASH",
+ "REM", "CONCAT", "COLLATE", "BITNOT",
+ "INDEXED", "STRING", "JOIN_KW", "CONSTRAINT",
"DEFAULT", "NULL", "PRIMARY", "UNIQUE",
"CHECK", "REFERENCES", "AUTOINCR", "ON",
"INSERT", "DELETE", "UPDATE", "SET",
"DEFERRABLE", "FOREIGN", "DROP", "UNION",
"ALL", "EXCEPT", "INTERSECT", "SELECT",
@@ -139315,11 +140022,11 @@
int tokenType; /* type of the next token */
int lastTokenParsed = -1; /* type of the previous token */
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
- unsigned char zSpace[sizeof(yyParser)]; /* Space for parser engine object */
+ yyParser sEngine; /* Space to hold the Lemon-generated Parser object */
#endif
assert( zSql!=0 );
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->nVdbeActive==0 ){
@@ -139328,11 +140035,11 @@
pParse->rc = SQLITE_OK;
pParse->zTail = zSql;
assert( pzErrMsg!=0 );
/* sqlite3ParserTrace(stdout, "parser: "); */
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
- pEngine = zSpace;
+ pEngine = &sEngine;
sqlite3ParserInit(pEngine);
#else
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
if( pEngine==0 ){
sqlite3OomFault(db);
@@ -139437,11 +140144,11 @@
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->pVList);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
pParse->pAinc = p->pNext;
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
while( pParse->pZombieTab ){
Table *p = pParse->pZombieTab;
pParse->pZombieTab = p->pNextZombie;
sqlite3DeleteTable(db, p);
@@ -140703,10 +141410,11 @@
int rc, n;
n = nKey1=0 );
return 5;
}
/*
** Return the number of bytes required to encode v as a varint
@@ -146391,69 +147110,70 @@
struct Fts4Option *pOp = &aFts4Opt[iOpt];
if( nKey==pOp->nOpt && !sqlite3_strnicmp(z, pOp->zOpt, pOp->nOpt) ){
break;
}
}
- if( iOpt==SizeofArray(aFts4Opt) ){
- sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
- rc = SQLITE_ERROR;
- }else{
- switch( iOpt ){
- case 0: /* MATCHINFO */
- if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
- sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
- rc = SQLITE_ERROR;
- }
- bNoDocsize = 1;
- break;
-
- case 1: /* PREFIX */
- sqlite3_free(zPrefix);
- zPrefix = zVal;
- zVal = 0;
- break;
-
- case 2: /* COMPRESS */
- sqlite3_free(zCompress);
- zCompress = zVal;
- zVal = 0;
- break;
-
- case 3: /* UNCOMPRESS */
- sqlite3_free(zUncompress);
- zUncompress = zVal;
- zVal = 0;
- break;
-
- case 4: /* ORDER */
- if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
- && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
- ){
- sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
- rc = SQLITE_ERROR;
- }
- bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
- break;
-
- case 5: /* CONTENT */
- sqlite3_free(zContent);
- zContent = zVal;
- zVal = 0;
- break;
-
- case 6: /* LANGUAGEID */
- assert( iOpt==6 );
- sqlite3_free(zLanguageid);
- zLanguageid = zVal;
- zVal = 0;
- break;
-
- case 7: /* NOTINDEXED */
- azNotindexed[nNotindexed++] = zVal;
- zVal = 0;
- break;
- }
+ switch( iOpt ){
+ case 0: /* MATCHINFO */
+ if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
+ rc = SQLITE_ERROR;
+ }
+ bNoDocsize = 1;
+ break;
+
+ case 1: /* PREFIX */
+ sqlite3_free(zPrefix);
+ zPrefix = zVal;
+ zVal = 0;
+ break;
+
+ case 2: /* COMPRESS */
+ sqlite3_free(zCompress);
+ zCompress = zVal;
+ zVal = 0;
+ break;
+
+ case 3: /* UNCOMPRESS */
+ sqlite3_free(zUncompress);
+ zUncompress = zVal;
+ zVal = 0;
+ break;
+
+ case 4: /* ORDER */
+ if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
+ && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
+ ){
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
+ rc = SQLITE_ERROR;
+ }
+ bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
+ break;
+
+ case 5: /* CONTENT */
+ sqlite3_free(zContent);
+ zContent = zVal;
+ zVal = 0;
+ break;
+
+ case 6: /* LANGUAGEID */
+ assert( iOpt==6 );
+ sqlite3_free(zLanguageid);
+ zLanguageid = zVal;
+ zVal = 0;
+ break;
+
+ case 7: /* NOTINDEXED */
+ azNotindexed[nNotindexed++] = zVal;
+ zVal = 0;
+ break;
+
+ default:
+ assert( iOpt==SizeofArray(aFts4Opt) );
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
+ rc = SQLITE_ERROR;
+ break;
}
sqlite3_free(zVal);
}
}
@@ -146570,11 +147290,13 @@
/* Fill in the azColumn array */
for(iCol=0; iCol0 ){
+ memcpy(zCsr, z, n);
+ }
zCsr[n] = '\0';
sqlite3Fts3Dequote(zCsr);
p->azColumn[iCol] = zCsr;
zCsr += n+1;
assert( zCsr <= &((char *)p)[nByte] );
@@ -147016,11 +147738,12 @@
zCsr += fts3GetVarint32(zCsr, &nPrefix);
}
isFirstTerm = 0;
zCsr += fts3GetVarint32(zCsr, &nSuffix);
- if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
+ assert( nPrefix>=0 && nSuffix>=0 );
+ if( &zCsr[nSuffix]>zEnd ){
rc = FTS_CORRUPT_VTAB;
goto finish_scan;
}
if( nPrefix+nSuffix>nAlloc ){
char *zNew;
@@ -147826,11 +148549,11 @@
bWritten = 1;
}
fts3ColumnlistCopy(0, &p);
}
- while( ppVtab;
/* The column value supplied by SQLite must be in range. */
assert( iCol>=0 && iCol<=p->nColumn+2 );
- if( iCol==p->nColumn+1 ){
- /* This call is a request for the "docid" column. Since "docid" is an
- ** alias for "rowid", use the xRowid() method to obtain the value.
- */
- sqlite3_result_int64(pCtx, pCsr->iPrevId);
- }else if( iCol==p->nColumn ){
- /* The extra column whose name is the same as the table.
- ** Return a blob which is a pointer to the cursor. */
- sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
- }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
- sqlite3_result_int64(pCtx, pCsr->iLangid);
- }else{
- /* The requested column is either a user column (one that contains
- ** indexed data), or the language-id column. */
- rc = fts3CursorSeek(0, pCsr);
-
- if( rc==SQLITE_OK ){
- if( iCol==p->nColumn+2 ){
- int iLangid = 0;
- if( p->zLanguageid ){
- iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
- }
- sqlite3_result_int(pCtx, iLangid);
- }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
+ switch( iCol-p->nColumn ){
+ case 0:
+ /* The special 'table-name' column */
+ sqlite3_result_blob(pCtx, &pCsr, sizeof(Fts3Cursor*), SQLITE_TRANSIENT);
+ sqlite3_result_subtype(pCtx, SQLITE_BLOB);
+ break;
+
+ case 1:
+ /* The docid column */
+ sqlite3_result_int64(pCtx, pCsr->iPrevId);
+ break;
+
+ case 2:
+ if( pCsr->pExpr ){
+ sqlite3_result_int64(pCtx, pCsr->iLangid);
+ break;
+ }else if( p->zLanguageid==0 ){
+ sqlite3_result_int(pCtx, 0);
+ break;
+ }else{
+ iCol = p->nColumn;
+ /* fall-through */
+ }
+
+ default:
+ /* A user column. Or, if this is a full-table scan, possibly the
+ ** language-id column. Seek the cursor. */
+ rc = fts3CursorSeek(0, pCsr);
+ if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
}
- }
+ break;
}
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
return rc;
}
@@ -148612,21 +149340,15 @@
** if an error occurs.
*/
static int fts3SetHasStat(Fts3Table *p){
int rc = SQLITE_OK;
if( p->bHasStat==2 ){
- const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
- char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
- if( zSql ){
- sqlite3_stmt *pStmt = 0;
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- if( rc==SQLITE_OK ){
- int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
- rc = sqlite3_finalize(pStmt);
- if( rc==SQLITE_OK ) p->bHasStat = (u8)bHasStat;
- }
- sqlite3_free(zSql);
+ char *zTbl = sqlite3_mprintf("%s_stat", p->zName);
+ if( zTbl ){
+ int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0);
+ sqlite3_free(zTbl);
+ p->bHasStat = (res==SQLITE_OK);
}else{
rc = SQLITE_NOMEM;
}
}
return rc;
@@ -148729,22 +149451,20 @@
sqlite3_context *pContext, /* SQL function call context */
const char *zFunc, /* Function name */
sqlite3_value *pVal, /* argv[0] passed to function */
Fts3Cursor **ppCsr /* OUT: Store cursor handle here */
){
- Fts3Cursor *pRet;
- if( sqlite3_value_type(pVal)!=SQLITE_BLOB
- || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
- ){
+ int rc = SQLITE_OK;
+ if( sqlite3_value_subtype(pVal)==SQLITE_BLOB ){
+ *ppCsr = *(Fts3Cursor**)sqlite3_value_blob(pVal);
+ }else{
char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
sqlite3_result_error(pContext, zErr, -1);
sqlite3_free(zErr);
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
}
- memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
- *ppCsr = pRet;
- return SQLITE_OK;
+ return rc;
}
/*
** Implementation of the snippet() function for FTS3
*/
@@ -149127,11 +149847,11 @@
rc = sqlite3Fts3ExprInitTestInterface(db);
}
#endif
/* Create the virtual table wrapper around the hash-table and overload
- ** the two scalar functions. If this is successful, register the
+ ** the four scalar functions. If this is successful, register the
** module with sqlite.
*/
if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
@@ -149710,11 +150430,11 @@
/* This is only called if it is guaranteed that the phrase has at least
** one incremental token. In which case the bIncr flag is set. */
assert( p->bIncr==1 );
- if( p->nToken==1 && p->bIncr ){
+ if( p->nToken==1 ){
rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
&pDL->iDocid, &pDL->pList, &pDL->nList
);
if( pDL->pList==0 ) bEof = 1;
}else{
@@ -149943,10 +150663,11 @@
** of data that will fit on a single leaf page of an intkey table in
** this database, then the average docsize is 1. Otherwise, it is 1 plus
** the number of overflow pages consumed by a record B bytes in size.
*/
static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
+ int rc = SQLITE_OK;
if( pCsr->nRowAvg==0 ){
/* The average document size, which is required to calculate the cost
** of each doclist, has not yet been determined. Read the required
** data from the %_stat table to calculate it.
**
@@ -149955,11 +150676,10 @@
** The first varint is the number of documents currently stored in
** the table. The following nCol varints contain the total amount of
** data stored in all rows of each column of the table, from left
** to right.
*/
- int rc;
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
sqlite3_stmt *pStmt;
sqlite3_int64 nDoc = 0;
sqlite3_int64 nByte = 0;
const char *pEnd;
@@ -149982,15 +150702,14 @@
pCsr->nDoc = nDoc;
pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
assert( pCsr->nRowAvg>0 );
rc = sqlite3_reset(pStmt);
- if( rc!=SQLITE_OK ) return rc;
}
*pnPage = pCsr->nRowAvg;
- return SQLITE_OK;
+ return rc;
}
/*
** This function is called to select the tokens (if any) that will be
** deferred. The array aTC[] has already been populated when this is
@@ -150336,11 +151055,12 @@
}
}
pExpr->iDocid = pLeft->iDocid;
pExpr->bEof = (pLeft->bEof || pRight->bEof);
if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
- if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
+ assert( pRight->eType==FTSQUERY_PHRASE );
+ if( pRight->pPhrase->doclist.aAll ){
Fts3Doclist *pDl = &pRight->pPhrase->doclist;
while( *pRc==SQLITE_OK && pRight->bEof==0 ){
memset(pDl->pList, 0, pDl->nList);
fts3EvalNextRow(pCsr, pRight, pRc);
}
@@ -150365,11 +151085,11 @@
assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid );
assert( pRight->bStart || pLeft->iDocid==pRight->iDocid );
if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
fts3EvalNextRow(pCsr, pLeft, pRc);
- }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
+ }else if( pLeft->bEof || iCmp>0 ){
fts3EvalNextRow(pCsr, pRight, pRc);
}else{
fts3EvalNextRow(pCsr, pLeft, pRc);
fts3EvalNextRow(pCsr, pRight, pRc);
}
@@ -150457,55 +151177,51 @@
** left-hand child may be either a phrase or a NEAR node. There are
** no exceptions to this - it's the way the parser in fts3_expr.c works.
*/
if( *pRc==SQLITE_OK
&& pExpr->eType==FTSQUERY_NEAR
- && pExpr->bEof==0
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
){
Fts3Expr *p;
int nTmp = 0; /* Bytes of temp space */
char *aTmp; /* Temp space for PoslistNearMerge() */
/* Allocate temporary working space. */
for(p=pExpr; p->pLeft; p=p->pLeft){
+ assert( p->pRight->pPhrase->doclist.nList>0 );
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- if( nTmp==0 ){
- res = 0;
- }else{
- aTmp = sqlite3_malloc(nTmp*2);
- if( !aTmp ){
- *pRc = SQLITE_NOMEM;
- res = 0;
- }else{
- char *aPoslist = p->pPhrase->doclist.pList;
- int nToken = p->pPhrase->nToken;
-
- for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
- Fts3Phrase *pPhrase = p->pRight->pPhrase;
- int nNear = p->nNear;
- res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
- }
-
- aPoslist = pExpr->pRight->pPhrase->doclist.pList;
- nToken = pExpr->pRight->pPhrase->nToken;
- for(p=pExpr->pLeft; p && res; p=p->pLeft){
- int nNear;
- Fts3Phrase *pPhrase;
- assert( p->pParent && p->pParent->pLeft==p );
- nNear = p->pParent->nNear;
- pPhrase = (
- p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
- );
- res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
- }
- }
-
- sqlite3_free(aTmp);
- }
+ aTmp = sqlite3_malloc(nTmp*2);
+ if( !aTmp ){
+ *pRc = SQLITE_NOMEM;
+ res = 0;
+ }else{
+ char *aPoslist = p->pPhrase->doclist.pList;
+ int nToken = p->pPhrase->nToken;
+
+ for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
+ Fts3Phrase *pPhrase = p->pRight->pPhrase;
+ int nNear = p->nNear;
+ res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+ }
+
+ aPoslist = pExpr->pRight->pPhrase->doclist.pList;
+ nToken = pExpr->pRight->pPhrase->nToken;
+ for(p=pExpr->pLeft; p && res; p=p->pLeft){
+ int nNear;
+ Fts3Phrase *pPhrase;
+ assert( p->pParent && p->pParent->pLeft==p );
+ nNear = p->pParent->nNear;
+ pPhrase = (
+ p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
+ );
+ res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+ }
+ }
+
+ sqlite3_free(aTmp);
}
return res;
}
@@ -160210,15 +160926,18 @@
/*
** Convert the text beginning at *pz into an integer and return
** its value. Advance *pz to point to the first character past
** the integer.
+**
+** This function used for parameters to merge= and incrmerge=
+** commands.
*/
static int fts3Getint(const char **pz){
const char *z = *pz;
int i = 0;
- while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
+ while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0';
*pz = z;
return i;
}
/*
@@ -162780,20 +163499,20 @@
const char *zIn, /* Array of characters to make exceptions */
int nIn /* Length of z in bytes */
){
const unsigned char *z = (const unsigned char *)zIn;
const unsigned char *zTerm = &z[nIn];
- int iCode;
+ unsigned int iCode;
int nEntry = 0;
assert( bAlnum==0 || bAlnum==1 );
while( znException;
z = (const unsigned char *)zIn;
while( zi; j--) aNew[j] = aNew[j-1];
- aNew[i] = iCode;
+ aNew[i] = (int)iCode;
nNew++;
}
}
p->aiException = aNew;
p->nException = nNew;
@@ -162962,11 +163681,11 @@
int *piEnd, /* OUT: Ending offset of token */
int *piPos /* OUT: Position integer of token */
){
unicode_cursor *pCsr = (unicode_cursor *)pC;
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
- int iCode = 0;
+ unsigned int iCode = 0;
char *zOut;
const unsigned char *z = &pCsr->aInput[pCsr->iOff];
const unsigned char *zStart = z;
const unsigned char *zEnd;
const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput];
@@ -162974,11 +163693,11 @@
/* Scan past any delimiter characters before the start of the next token.
** Return SQLITE_DONE early if this takes us all the way to the end of
** the input. */
while( z=zTerm ) return SQLITE_DONE;
zOut = pCsr->zToken;
@@ -162994,20 +163713,20 @@
pCsr->nAlloc += 64;
}
/* Write the folded case of the last character read to the output */
zEnd = z;
- iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic);
+ iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic);
if( iOut ){
WRITE_UTF8(zOut, iOut);
}
/* If the cursor is not at EOF, read the next character */
if( z>=zTerm ) break;
READ_UTF8(z, zTerm, iCode);
- }while( unicodeIsAlnum(p, iCode)
- || sqlite3FtsUnicodeIsdiacritic(iCode)
+ }while( unicodeIsAlnum(p, (int)iCode)
+ || sqlite3FtsUnicodeIsdiacritic((int)iCode)
);
/* Set the output variables and return. */
pCsr->iOff = (int)(z - pCsr->aInput);
*paToken = pCsr->zToken;
@@ -163167,13 +163886,13 @@
};
static const unsigned int aAscii[4] = {
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
- if( c<128 ){
- return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
- }else if( c<(1<<22) ){
+ if( (unsigned int)c<128 ){
+ return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
+ }else if( (unsigned int)c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
@@ -163362,20 +164081,21 @@
65514, 65521, 65527, 65528, 65529,
};
int ret = c;
- assert( c>=0 );
assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
if( c<128 ){
if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
}else if( c<65536 ){
+ const struct TableEntry *p;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
int iRes = -1;
+ assert( c>aEntry[0].iCode );
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
int cmp = (c - aEntry[iTest].iCode);
if( cmp>=0 ){
iRes = iTest;
@@ -163382,18 +164102,16 @@
iLo = iTest+1;
}else{
iHi = iTest-1;
}
}
- assert( iRes<0 || c>=aEntry[iRes].iCode );
-
- if( iRes>=0 ){
- const struct TableEntry *p = &aEntry[iRes];
- if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
- ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
- assert( ret>0 );
- }
+
+ assert( iRes>=0 && c>=aEntry[iRes].iCode );
+ p = &aEntry[iRes];
+ if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
+ ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
+ assert( ret>0 );
}
if( bRemoveDiacritic ) ret = remove_diacritic(ret);
}
@@ -163866,19 +164584,19 @@
#elif SQLITE_BYTEORDER==4321
i64 x;
memcpy(&x, p, 8);
return x;
#else
- return (
- (((i64)p[0]) << 56) +
- (((i64)p[1]) << 48) +
- (((i64)p[2]) << 40) +
- (((i64)p[3]) << 32) +
- (((i64)p[4]) << 24) +
- (((i64)p[5]) << 16) +
- (((i64)p[6]) << 8) +
- (((i64)p[7]) << 0)
+ return (i64)(
+ (((u64)p[0]) << 56) +
+ (((u64)p[1]) << 48) +
+ (((u64)p[2]) << 40) +
+ (((u64)p[3]) << 32) +
+ (((u64)p[4]) << 24) +
+ (((u64)p[5]) << 16) +
+ (((u64)p[6]) << 8) +
+ (((u64)p[7]) << 0)
);
#endif
}
/*
@@ -166606,16 +167324,40 @@
, pRtree->zDb, pRtree->zName, zNewName
, pRtree->zDb, pRtree->zName, zNewName
, pRtree->zDb, pRtree->zName, zNewName
);
if( zSql ){
+ nodeBlobReset(pRtree);
rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
return rc;
}
+/*
+** The xSavepoint method.
+**
+** This module does not need to do anything to support savepoints. However,
+** it uses this hook to close any open blob handle. This is done because a
+** DROP TABLE command - which fortunately always opens a savepoint - cannot
+** succeed if there are any open blob handles. i.e. if the blob handle were
+** not closed here, the following would fail:
+**
+** BEGIN;
+** INSERT INTO rtree...
+** DROP TABLE ; -- Would fail with SQLITE_LOCKED
+** COMMIT;
+*/
+static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
+ Rtree *pRtree = (Rtree *)pVtab;
+ int iwt = pRtree->inWrTrans;
+ UNUSED_PARAMETER(iSavepoint);
+ pRtree->inWrTrans = 0;
+ nodeBlobReset(pRtree);
+ pRtree->inWrTrans = iwt;
+ return SQLITE_OK;
+}
/*
** This function populates the pRtree->nRowEst variable with an estimate
** of the number of rows in the virtual table. If possible, this is based
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
@@ -166658,11 +167400,11 @@
return rc;
}
static sqlite3_module rtreeModule = {
- 0, /* iVersion */
+ 2, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
rtreeDisconnect, /* xDisconnect - Disconnect from a table */
rtreeDestroy, /* xDestroy - Drop a table */
@@ -166678,11 +167420,11 @@
rtreeEndTransaction, /* xSync - sync transaction */
rtreeEndTransaction, /* xCommit - commit transaction */
rtreeEndTransaction, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
rtreeRename, /* xRename - rename the table */
- 0, /* xSavepoint */
+ rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
};
static int rtreeSqlInit(
@@ -168507,14 +169249,14 @@
** as fully applied. Otherwise, assuming no error has occurred, save the
** current state of the RBU update appliation to the RBU database.
**
** If an error has already occurred as part of an sqlite3rbu_step()
** or sqlite3rbu_open() call, or if one occurs within this function, an
-** SQLite error code is returned. Additionally, *pzErrmsg may be set to
-** point to a buffer containing a utf-8 formatted English language error
-** message. It is the responsibility of the caller to eventually free any
-** such buffer using sqlite3_free().
+** SQLite error code is returned. Additionally, if pzErrmsg is not NULL,
+** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted
+** English language error message. It is the responsibility of the caller to
+** eventually free any such buffer using sqlite3_free().
**
** Otherwise, if no error occurs, this function returns SQLITE_OK if the
** update has been partially applied, or SQLITE_DONE if it has been
** completely applied.
*/
@@ -172366,11 +173108,15 @@
sqlite3_free(p->aBuf);
sqlite3_free(p->aFrame);
rbuEditErrmsg(p);
rc = p->rc;
- *pzErrmsg = p->zErrmsg;
+ if( pzErrmsg ){
+ *pzErrmsg = p->zErrmsg;
+ }else{
+ sqlite3_free(p->zErrmsg);
+ }
sqlite3_free(p->zState);
sqlite3_free(p);
}else{
rc = SQLITE_NOMEM;
*pzErrmsg = 0;
@@ -176924,15 +177670,16 @@
sessionDiscardData(&p->in);
p->in.iCurrent = p->in.iNext;
op = p->in.aData[p->in.iNext++];
- if( op=='T' || op=='P' ){
+ while( op=='T' || op=='P' ){
p->bPatchset = (op=='P');
if( sessionChangesetReadTblhdr(p) ) return p->rc;
if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
p->in.iCurrent = p->in.iNext;
+ if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
op = p->in.aData[p->in.iNext++];
}
p->op = op;
p->bIndirect = p->in.aData[p->in.iNext++];
@@ -178835,10 +179582,11 @@
#ifndef SQLITE_AMALGAMATION
/* Unsigned integer types. These are already defined in the sqliteInt.h,
** but the definitions need to be repeated for separate compilation. */
typedef sqlite3_uint64 u64;
typedef unsigned int u32;
+ typedef unsigned short int u16;
typedef unsigned char u8;
#endif
/* Objects */
typedef struct JsonString JsonString;
@@ -178883,26 +179631,28 @@
/* Bit values for the JsonNode.jnFlag field
*/
#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */
-#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x20 /* Is a label of an object */
+#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
+#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
+#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
+#define JNODE_LABEL 0x40 /* Is a label of an object */
/* A single node of parsed JSON
*/
struct JsonNode {
u8 eType; /* One of the JSON_ type values */
u8 jnFlags; /* JNODE flags */
- u8 iVal; /* Replacement value when JNODE_REPLACE */
u32 n; /* Bytes of content, or number of sub-nodes */
union {
const char *zJContent; /* Content for INT, REAL, and STRING */
u32 iAppend; /* More terms for ARRAY and OBJECT */
u32 iKey; /* Key for ARRAY objects in json_tree() */
+ u32 iReplace; /* Replacement content for JNODE_REPLACE */
+ JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */
} u;
};
/* A completely parsed JSON string
*/
@@ -178912,12 +179662,23 @@
JsonNode *aNode; /* Array of nodes containing the parse */
const char *zJson; /* Original JSON string */
u32 *aUp; /* Index of parent of each node */
u8 oom; /* Set to true if out of memory */
u8 nErr; /* Number of errors seen */
+ u16 iDepth; /* Nesting depth */
+ int nJson; /* Length of the zJson string in bytes */
};
+/*
+** Maximum nesting depth of JSON for this implementation.
+**
+** This limit is needed to avoid a stack overflow in the recursive
+** descent parser. A depth of 2000 is far deeper than any sane JSON
+** should go.
+*/
+#define JSON_MAX_DEPTH 2000
+
/**************************************************************************
** Utility routines for dealing with JsonString objects
**************************************************************************/
/* Set the JsonString object to an empty string
@@ -179144,10 +179905,18 @@
pParse->nNode = 0;
pParse->nAlloc = 0;
sqlite3_free(pParse->aUp);
pParse->aUp = 0;
}
+
+/*
+** Free a JsonParse object that was obtained from sqlite3_malloc().
+*/
+static void jsonParseFree(JsonParse *pParse){
+ jsonParseReset(pParse);
+ sqlite3_free(pParse);
+}
/*
** Convert the JsonNode pNode into a pure JSON string and
** append to pOut. Subsubstructure is also included. Return
** the number of JsonNode objects that are encoded.
@@ -179155,10 +179924,17 @@
static void jsonRenderNode(
JsonNode *pNode, /* The node to render */
JsonString *pOut, /* Write JSON here */
sqlite3_value **aReplace /* Replacement values */
){
+ if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
+ if( pNode->jnFlags & JNODE_REPLACE ){
+ jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
+ return;
+ }
+ pNode = pNode->u.pPatch;
+ }
switch( pNode->eType ){
default: {
assert( pNode->eType==JSON_NULL );
jsonAppendRaw(pOut, "null", 4);
break;
@@ -179186,16 +179962,11 @@
case JSON_ARRAY: {
u32 j = 1;
jsonAppendChar(pOut, '[');
for(;;){
while( j<=pNode->n ){
- if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
- if( pNode[j].jnFlags & JNODE_REPLACE ){
- jsonAppendSeparator(pOut);
- jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
- }
- }else{
+ if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
jsonAppendSeparator(pOut);
jsonRenderNode(&pNode[j], pOut, aReplace);
}
j += jsonNodeSize(&pNode[j]);
}
@@ -179213,15 +179984,11 @@
while( j<=pNode->n ){
if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
jsonAppendSeparator(pOut);
jsonRenderNode(&pNode[j], pOut, aReplace);
jsonAppendChar(pOut, ':');
- if( pNode[j+1].jnFlags & JNODE_REPLACE ){
- jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
- }else{
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
- }
+ jsonRenderNode(&pNode[j+1], pOut, aReplace);
}
j += 1 + jsonNodeSize(&pNode[j+1]);
}
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
pNode = &pNode[pNode->u.iAppend];
@@ -179444,11 +180211,10 @@
return jsonParseAddNodeExpand(pParse, eType, n, zContent);
}
p = &pParse->aNode[pParse->nNode];
p->eType = (u8)eType;
p->jnFlags = 0;
- p->iVal = 0;
p->n = n;
p->u.zJContent = zContent;
return pParse->nNode++;
}
@@ -179473,35 +180239,39 @@
char c;
u32 j;
int iThis;
int x;
JsonNode *pNode;
- while( safe_isspace(pParse->zJson[i]) ){ i++; }
- if( (c = pParse->zJson[i])=='{' ){
+ const char *z = pParse->zJson;
+ while( safe_isspace(z[i]) ){ i++; }
+ if( (c = z[i])=='{' ){
/* Parse object */
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
if( iThis<0 ) return -1;
for(j=i+1;;j++){
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
+ while( safe_isspace(z[j]) ){ j++; }
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
if( x<0 ){
+ pParse->iDepth--;
if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
return -1;
}
if( pParse->oom ) return -1;
pNode = &pParse->aNode[pParse->nNode-1];
if( pNode->eType!=JSON_STRING ) return -1;
pNode->jnFlags |= JNODE_LABEL;
j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- if( pParse->zJson[j]!=':' ) return -1;
+ while( safe_isspace(z[j]) ){ j++; }
+ if( z[j]!=':' ) return -1;
j++;
x = jsonParseValue(pParse, j);
+ pParse->iDepth--;
if( x<0 ) return -1;
j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- c = pParse->zJson[j];
+ while( safe_isspace(z[j]) ){ j++; }
+ c = z[j];
if( c==',' ) continue;
if( c!='}' ) return -1;
break;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
@@ -179509,19 +180279,21 @@
}else if( c=='[' ){
/* Parse array */
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
if( iThis<0 ) return -1;
for(j=i+1;;j++){
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
+ while( safe_isspace(z[j]) ){ j++; }
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
+ pParse->iDepth--;
if( x<0 ){
if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
return -1;
}
j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- c = pParse->zJson[j];
+ while( safe_isspace(z[j]) ){ j++; }
+ c = z[j];
if( c==',' ) continue;
if( c!=']' ) return -1;
break;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
@@ -179529,75 +180301,83 @@
}else if( c=='"' ){
/* Parse string */
u8 jnFlags = 0;
j = i+1;
for(;;){
- c = pParse->zJson[j];
- if( c==0 ) return -1;
+ c = z[j];
+ if( (c & ~0x1f)==0 ){
+ /* Control characters are not allowed in strings */
+ return -1;
+ }
if( c=='\\' ){
- c = pParse->zJson[++j];
+ c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
- || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){
+ || (c=='u' && jsonIs4Hex(z+j+1)) ){
jnFlags = JNODE_ESCAPE;
}else{
return -1;
}
}else if( c=='"' ){
break;
}
j++;
}
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
+ jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
return j+1;
}else if( c=='n'
- && strncmp(pParse->zJson+i,"null",4)==0
- && !safe_isalnum(pParse->zJson[i+4]) ){
+ && strncmp(z+i,"null",4)==0
+ && !safe_isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
return i+4;
}else if( c=='t'
- && strncmp(pParse->zJson+i,"true",4)==0
- && !safe_isalnum(pParse->zJson[i+4]) ){
+ && strncmp(z+i,"true",4)==0
+ && !safe_isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
return i+4;
}else if( c=='f'
- && strncmp(pParse->zJson+i,"false",5)==0
- && !safe_isalnum(pParse->zJson[i+5]) ){
+ && strncmp(z+i,"false",5)==0
+ && !safe_isalnum(z[i+5]) ){
jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
return i+5;
}else if( c=='-' || (c>='0' && c<='9') ){
/* Parse number */
u8 seenDP = 0;
u8 seenE = 0;
+ assert( '-' < '0' );
+ if( c<='0' ){
+ j = c=='-' ? i+1 : i;
+ if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ }
j = i+1;
for(;; j++){
- c = pParse->zJson[j];
+ c = z[j];
if( c>='0' && c<='9' ) continue;
if( c=='.' ){
- if( pParse->zJson[j-1]=='-' ) return -1;
+ if( z[j-1]=='-' ) return -1;
if( seenDP ) return -1;
seenDP = 1;
continue;
}
if( c=='e' || c=='E' ){
- if( pParse->zJson[j-1]<'0' ) return -1;
+ if( z[j-1]<'0' ) return -1;
if( seenE ) return -1;
seenDP = seenE = 1;
- c = pParse->zJson[j+1];
+ c = z[j+1];
if( c=='+' || c=='-' ){
j++;
- c = pParse->zJson[j+1];
+ c = z[j+1];
}
if( c<'0' || c>'9' ) return -1;
continue;
}
break;
}
- if( pParse->zJson[j-1]<'0' ) return -1;
+ if( z[j-1]<'0' ) return -1;
jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &pParse->zJson[i]);
+ j - i, &z[i]);
return j;
}else if( c=='}' ){
return -2; /* End of {...} */
}else if( c==']' ){
return -3; /* End of [...] */
@@ -179625,10 +180405,11 @@
if( zJson==0 ) return 1;
pParse->zJson = zJson;
i = jsonParseValue(pParse, 0);
if( pParse->oom ) i = -1;
if( i>0 ){
+ assert( pParse->iDepth==0 );
while( safe_isspace(zJson[i]) ) i++;
if( zJson[i] ) i = -1;
}
if( i<=0 ){
if( pCtx!=0 ){
@@ -179683,10 +180464,53 @@
return SQLITE_NOMEM;
}
jsonParseFillInParentage(pParse, 0, 0);
return SQLITE_OK;
}
+
+/*
+** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID (-429938)
+
+/*
+** Obtain a complete parse of the JSON found in the first argument
+** of the argv array. Use the sqlite3_get_auxdata() cache for this
+** parse if it is available. If the cache is not available or if it
+** is no longer valid, parse the JSON again and return the new parse,
+** and also register the new parse so that it will be available for
+** future sqlite3_get_auxdata() calls.
+*/
+static JsonParse *jsonParseCached(
+ sqlite3_context *pCtx,
+ sqlite3_value **argv
+){
+ const char *zJson = (const char*)sqlite3_value_text(argv[0]);
+ int nJson = sqlite3_value_bytes(argv[0]);
+ JsonParse *p;
+ if( zJson==0 ) return 0;
+ p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
+ if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){
+ p->nErr = 0;
+ return p; /* The cached entry matches, so return it */
+ }
+ p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
+ if( p==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return 0;
+ }
+ memset(p, 0, sizeof(*p));
+ p->zJson = (char*)&p[1];
+ memcpy((char*)p->zJson, zJson, nJson+1);
+ if( jsonParse(p, pCtx, p->zJson) ){
+ sqlite3_free(p);
+ return 0;
+ }
+ p->nJson = nJson;
+ sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree);
+ return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
+}
/*
** Compare the OBJECT label at pNode against zKey,nKey. Return true on
** a match.
*/
@@ -179910,10 +180734,29 @@
zFuncName);
sqlite3_result_error(pCtx, zMsg, -1);
sqlite3_free(zMsg);
}
+/*
+** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+*/
+static void jsonRemoveAllNulls(JsonNode *pNode){
+ int i, n;
+ assert( pNode->eType==JSON_OBJECT );
+ n = pNode->n;
+ for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
+ switch( pNode[i].eType ){
+ case JSON_NULL:
+ pNode[i].jnFlags |= JNODE_REMOVE;
+ break;
+ case JSON_OBJECT:
+ jsonRemoveAllNulls(&pNode[i]);
+ break;
+ }
+ }
+}
+
/****************************************************************************
** SQL functions used for testing and debugging
****************************************************************************/
@@ -180030,33 +180873,34 @@
static void jsonArrayLengthFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
+ JsonParse *p; /* The parse */
sqlite3_int64 n = 0;
u32 i;
JsonNode *pNode;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
+ p = jsonParseCached(ctx, argv);
+ if( p==0 ) return;
+ assert( p->nNode );
if( argc==2 ){
const char *zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
+ pNode = jsonLookup(p, zPath, 0, ctx);
}else{
- pNode = x.aNode;
+ pNode = p->aNode;
}
if( pNode==0 ){
- x.nErr = 1;
- }else if( pNode->eType==JSON_ARRAY ){
+ return;
+ }
+ if( pNode->eType==JSON_ARRAY ){
assert( (pNode->jnFlags & JNODE_APPEND)==0 );
for(i=1; i<=pNode->n; n++){
i += jsonNodeSize(&pNode[i]);
}
}
- if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
- jsonParseReset(&x);
+ sqlite3_result_int64(ctx, n);
}
/*
** json_extract(JSON, PATH, ...)
**
@@ -180068,24 +180912,25 @@
static void jsonExtractFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
+ JsonParse *p; /* The parse */
JsonNode *pNode;
const char *zPath;
JsonString jx;
int i;
if( argc<2 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ p = jsonParseCached(ctx, argv);
+ if( p==0 ) return;
jsonInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=1; inErr ) break;
if( argc>2 ){
jsonAppendSeparator(&jx);
if( pNode ){
jsonRenderNode(pNode, &jx, 0);
}else{
@@ -180099,12 +180944,110 @@
jsonAppendChar(&jx, ']');
jsonResult(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
jsonReset(&jx);
+}
+
+/* This is the RFC 7396 MergePatch algorithm.
+*/
+static JsonNode *jsonMergePatch(
+ JsonParse *pParse, /* The JSON parser that contains the TARGET */
+ u32 iTarget, /* Node of the TARGET in pParse */
+ JsonNode *pPatch /* The PATCH */
+){
+ u32 i, j;
+ u32 iRoot;
+ JsonNode *pTarget;
+ if( pPatch->eType!=JSON_OBJECT ){
+ return pPatch;
+ }
+ assert( iTarget>=0 && iTargetnNode );
+ pTarget = &pParse->aNode[iTarget];
+ assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
+ if( pTarget->eType!=JSON_OBJECT ){
+ jsonRemoveAllNulls(pPatch);
+ return pPatch;
+ }
+ iRoot = iTarget;
+ for(i=1; in; i += jsonNodeSize(&pPatch[i+1])+1){
+ u32 nKey;
+ const char *zKey;
+ assert( pPatch[i].eType==JSON_STRING );
+ assert( pPatch[i].jnFlags & JNODE_LABEL );
+ nKey = pPatch[i].n;
+ zKey = pPatch[i].u.zJContent;
+ assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+ for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){
+ assert( pTarget[j].eType==JSON_STRING );
+ assert( pTarget[j].jnFlags & JNODE_LABEL );
+ assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+ if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
+ if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
+ if( pPatch[i+1].eType==JSON_NULL ){
+ pTarget[j+1].jnFlags |= JNODE_REMOVE;
+ }else{
+ JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
+ if( pNew==0 ) return 0;
+ pTarget = &pParse->aNode[iTarget];
+ if( pNew!=&pTarget[j+1] ){
+ pTarget[j+1].u.pPatch = pNew;
+ pTarget[j+1].jnFlags |= JNODE_PATCH;
+ }
+ }
+ break;
+ }
+ }
+ if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
+ int iStart, iPatch;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+ iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ if( pParse->oom ) return 0;
+ jsonRemoveAllNulls(pPatch);
+ pTarget = &pParse->aNode[iTarget];
+ pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
+ pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
+ iRoot = iStart;
+ pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
+ pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
+ }
+ }
+ return pTarget;
+}
+
+/*
+** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
+** object that is the result of running the RFC 7396 MergePatch() algorithm
+** on the two arguments.
+*/
+static void jsonPatchFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The JSON that is being patched */
+ JsonParse y; /* The patch */
+ JsonNode *pResult; /* The result of the merge */
+
+ UNUSED_PARAM(argc);
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
+ jsonParseReset(&x);
+ return;
+ }
+ pResult = jsonMergePatch(&x, 0, y.aNode);
+ assert( pResult!=0 || x.oom );
+ if( pResult ){
+ jsonReturnJson(pResult, ctx, 0);
+ }else{
+ sqlite3_result_error_nomem(ctx);
+ }
jsonParseReset(&x);
+ jsonParseReset(&y);
}
+
/*
** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON
** object that contains all name/value given in arguments. Or if any name
** is not a string or if any value is a BLOB, throw an error.
@@ -180205,15 +181148,15 @@
zPath = (const char*)sqlite3_value_text(argv[i]);
pNode = jsonLookup(&x, zPath, 0, ctx);
if( x.nErr ) goto replace_err;
if( pNode ){
pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->iVal = (u8)(i+1);
+ pNode->u.iReplace = i + 1;
}
}
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
+ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
}else{
jsonReturnJson(x.aNode, ctx, argv);
}
replace_err:
jsonParseReset(&x);
@@ -180259,15 +181202,15 @@
goto jsonSetDone;
}else if( x.nErr ){
goto jsonSetDone;
}else if( pNode && (bApnd || bIsSet) ){
pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->iVal = (u8)(i+1);
+ pNode->u.iReplace = i + 1;
}
}
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
+ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
}else{
jsonReturnJson(x.aNode, ctx, argv);
}
jsonSetDone:
jsonParseReset(&x);
@@ -180906,10 +181849,11 @@
{ "json_array_length", 1, 0, jsonArrayLengthFunc },
{ "json_array_length", 2, 0, jsonArrayLengthFunc },
{ "json_extract", -1, 0, jsonExtractFunc },
{ "json_insert", -1, 0, jsonSetFunc },
{ "json_object", -1, 0, jsonObjectFunc },
+ { "json_patch", 2, 0, jsonPatchFunc },
{ "json_quote", 1, 0, jsonQuoteFunc },
{ "json_remove", -1, 0, jsonRemoveFunc },
{ "json_replace", -1, 0, jsonReplaceFunc },
{ "json_set", -1, 1, jsonSetFunc },
{ "json_type", 1, 0, jsonTypeFunc },
@@ -182015,13 +182959,13 @@
i64 iDocid /* Docid to add or remove data from */
);
/*
** Flush any data stored in the in-memory hash tables to the database.
-** If the bCommit flag is true, also close any open blob handles.
+** Also close any open blob handles.
*/
-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
+static int sqlite3Fts5IndexSync(Fts5Index *p);
/*
** Discard any data stored in the in-memory hash tables. Do not write it
** to the database. Additionally, assume that the contents of the %_data
** table may have changed on disk. So any in-memory caches of %_data
@@ -182187,11 +183131,11 @@
static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
+static int sqlite3Fts5StorageSync(Fts5Storage *p);
static int sqlite3Fts5StorageRollback(Fts5Storage *p);
static int sqlite3Fts5StorageConfigValue(
Fts5Storage *p, const char*, sqlite3_value*, int
);
@@ -182223,10 +183167,11 @@
};
/* Parse a MATCH expression. */
static int sqlite3Fts5ExprNew(
Fts5Config *pConfig,
+ int iCol, /* Column on LHS of MATCH operator */
const char *zExpr,
Fts5Expr **ppNew,
char **pzErr
);
@@ -182307,11 +183252,11 @@
static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*);
static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
-static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
+static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*);
static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
/*
@@ -182364,16 +183309,16 @@
#define FTS5_OR 1
#define FTS5_AND 2
#define FTS5_NOT 3
#define FTS5_TERM 4
#define FTS5_COLON 5
-#define FTS5_LP 6
-#define FTS5_RP 7
-#define FTS5_MINUS 8
-#define FTS5_LCP 9
-#define FTS5_RCP 10
-#define FTS5_STRING 11
+#define FTS5_MINUS 6
+#define FTS5_LCP 7
+#define FTS5_RCP 8
+#define FTS5_STRING 9
+#define FTS5_LP 10
+#define FTS5_RP 11
#define FTS5_COMMA 12
#define FTS5_PLUS 13
#define FTS5_STAR 14
/*
@@ -182505,20 +183450,20 @@
#endif
#define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse;
#define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
-#define fts5YYNSTATE 29
-#define fts5YYNRULE 26
-#define fts5YY_MAX_SHIFT 28
-#define fts5YY_MIN_SHIFTREDUCE 45
-#define fts5YY_MAX_SHIFTREDUCE 70
-#define fts5YY_MIN_REDUCE 71
-#define fts5YY_MAX_REDUCE 96
-#define fts5YY_ERROR_ACTION 97
-#define fts5YY_ACCEPT_ACTION 98
-#define fts5YY_NO_ACTION 99
+#define fts5YYNSTATE 33
+#define fts5YYNRULE 27
+#define fts5YY_MAX_SHIFT 32
+#define fts5YY_MIN_SHIFTREDUCE 50
+#define fts5YY_MAX_SHIFTREDUCE 76
+#define fts5YY_MIN_REDUCE 77
+#define fts5YY_MAX_REDUCE 103
+#define fts5YY_ERROR_ACTION 104
+#define fts5YY_ACCEPT_ACTION 105
+#define fts5YY_NO_ACTION 106
/************* End control #defines *******************************************/
/* Define the fts5yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
@@ -182586,54 +183531,58 @@
** fts5yy_reduce_ofst[] For each state, the offset into fts5yy_action for
** shifting non-terminals after a reduce.
** fts5yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define fts5YY_ACTTAB_COUNT (85)
+#define fts5YY_ACTTAB_COUNT (98)
static const fts5YYACTIONTYPE fts5yy_action[] = {
- /* 0 */ 98, 16, 51, 5, 53, 27, 83, 7, 26, 15,
- /* 10 */ 51, 5, 53, 27, 13, 69, 26, 48, 51, 5,
- /* 20 */ 53, 27, 19, 11, 26, 9, 20, 51, 5, 53,
- /* 30 */ 27, 13, 22, 26, 28, 51, 5, 53, 27, 68,
- /* 40 */ 1, 26, 19, 11, 17, 9, 52, 10, 53, 27,
- /* 50 */ 23, 24, 26, 54, 3, 4, 2, 26, 6, 21,
- /* 60 */ 49, 71, 3, 4, 2, 7, 56, 59, 55, 59,
- /* 70 */ 4, 2, 12, 69, 58, 60, 18, 67, 62, 69,
- /* 80 */ 25, 66, 8, 14, 2,
+ /* 0 */ 105, 19, 63, 6, 26, 66, 65, 24, 24, 17,
+ /* 10 */ 63, 6, 26, 16, 65, 54, 24, 18, 63, 6,
+ /* 20 */ 26, 10, 65, 12, 24, 75, 59, 63, 6, 26,
+ /* 30 */ 13, 65, 75, 24, 20, 63, 6, 26, 74, 65,
+ /* 40 */ 56, 24, 27, 63, 6, 26, 73, 65, 21, 24,
+ /* 50 */ 23, 15, 30, 11, 1, 64, 22, 25, 9, 65,
+ /* 60 */ 7, 24, 3, 4, 5, 3, 4, 5, 3, 77,
+ /* 70 */ 4, 5, 3, 61, 23, 15, 60, 11, 80, 12,
+ /* 80 */ 2, 13, 68, 10, 29, 52, 55, 75, 31, 32,
+ /* 90 */ 8, 28, 5, 3, 51, 55, 72, 14,
};
static const fts5YYCODETYPE fts5yy_lookahead[] = {
- /* 0 */ 16, 17, 18, 19, 20, 21, 5, 6, 24, 17,
- /* 10 */ 18, 19, 20, 21, 11, 14, 24, 17, 18, 19,
- /* 20 */ 20, 21, 8, 9, 24, 11, 17, 18, 19, 20,
- /* 30 */ 21, 11, 12, 24, 17, 18, 19, 20, 21, 26,
- /* 40 */ 6, 24, 8, 9, 22, 11, 18, 11, 20, 21,
- /* 50 */ 24, 25, 24, 20, 1, 2, 3, 24, 23, 24,
- /* 60 */ 7, 0, 1, 2, 3, 6, 10, 11, 10, 11,
- /* 70 */ 2, 3, 9, 14, 11, 11, 22, 26, 7, 14,
- /* 80 */ 13, 11, 5, 11, 3,
+ /* 0 */ 16, 17, 18, 19, 20, 22, 22, 24, 24, 17,
+ /* 10 */ 18, 19, 20, 7, 22, 9, 24, 17, 18, 19,
+ /* 20 */ 20, 10, 22, 9, 24, 14, 17, 18, 19, 20,
+ /* 30 */ 9, 22, 14, 24, 17, 18, 19, 20, 26, 22,
+ /* 40 */ 9, 24, 17, 18, 19, 20, 26, 22, 21, 24,
+ /* 50 */ 6, 7, 13, 9, 10, 18, 21, 20, 5, 22,
+ /* 60 */ 5, 24, 3, 1, 2, 3, 1, 2, 3, 0,
+ /* 70 */ 1, 2, 3, 11, 6, 7, 11, 9, 5, 9,
+ /* 80 */ 10, 9, 11, 10, 12, 8, 9, 14, 24, 25,
+ /* 90 */ 23, 24, 2, 3, 8, 9, 9, 9,
};
-#define fts5YY_SHIFT_USE_DFLT (85)
-#define fts5YY_SHIFT_COUNT (28)
+#define fts5YY_SHIFT_USE_DFLT (98)
+#define fts5YY_SHIFT_COUNT (32)
#define fts5YY_SHIFT_MIN (0)
-#define fts5YY_SHIFT_MAX (81)
+#define fts5YY_SHIFT_MAX (90)
static const unsigned char fts5yy_shift_ofst[] = {
- /* 0 */ 34, 34, 34, 34, 34, 14, 20, 3, 36, 1,
- /* 10 */ 59, 64, 64, 65, 65, 53, 61, 56, 58, 63,
- /* 20 */ 68, 67, 70, 67, 71, 72, 67, 77, 81,
+ /* 0 */ 44, 44, 44, 44, 44, 44, 68, 70, 72, 14,
+ /* 10 */ 21, 73, 11, 18, 18, 31, 31, 62, 65, 69,
+ /* 20 */ 90, 77, 86, 6, 39, 53, 55, 59, 39, 87,
+ /* 30 */ 88, 39, 71,
};
-#define fts5YY_REDUCE_USE_DFLT (-17)
-#define fts5YY_REDUCE_COUNT (14)
-#define fts5YY_REDUCE_MIN (-16)
-#define fts5YY_REDUCE_MAX (54)
+#define fts5YY_REDUCE_USE_DFLT (-18)
+#define fts5YY_REDUCE_COUNT (16)
+#define fts5YY_REDUCE_MIN (-17)
+#define fts5YY_REDUCE_MAX (67)
static const signed char fts5yy_reduce_ofst[] = {
- /* 0 */ -16, -8, 0, 9, 17, 28, 26, 35, 33, 13,
- /* 10 */ 13, 22, 54, 13, 51,
+ /* 0 */ -16, -8, 0, 9, 17, 25, 37, -17, 64, -17,
+ /* 10 */ 67, 12, 12, 12, 20, 27, 35,
};
static const fts5YYACTIONTYPE fts5yy_default[] = {
- /* 0 */ 97, 97, 97, 97, 97, 76, 91, 97, 97, 96,
- /* 10 */ 96, 97, 97, 96, 96, 97, 97, 97, 97, 97,
- /* 20 */ 73, 89, 97, 90, 97, 97, 87, 97, 72,
+ /* 0 */ 104, 104, 104, 104, 104, 104, 89, 104, 98, 104,
+ /* 10 */ 104, 103, 103, 103, 103, 104, 104, 104, 104, 104,
+ /* 20 */ 85, 104, 104, 104, 94, 104, 104, 84, 96, 104,
+ /* 30 */ 104, 97, 104,
};
/********** End of lemon-generated parsing tables *****************************/
/* The next table maps tokens (terminal symbols) into fallback tokens.
** If a construct like the following:
@@ -182735,49 +183684,50 @@
#ifndef NDEBUG
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
static const char *const fts5yyTokenName[] = {
"$", "OR", "AND", "NOT",
- "TERM", "COLON", "LP", "RP",
- "MINUS", "LCP", "RCP", "STRING",
+ "TERM", "COLON", "MINUS", "LCP",
+ "RCP", "STRING", "LP", "RP",
"COMMA", "PLUS", "STAR", "error",
"input", "expr", "cnearset", "exprlist",
- "nearset", "colset", "colsetlist", "nearphrases",
+ "colset", "colsetlist", "nearset", "nearphrases",
"phrase", "neardist_opt", "star_opt",
};
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const fts5yyRuleName[] = {
/* 0 */ "input ::= expr",
- /* 1 */ "expr ::= expr AND expr",
- /* 2 */ "expr ::= expr OR expr",
- /* 3 */ "expr ::= expr NOT expr",
- /* 4 */ "expr ::= LP expr RP",
- /* 5 */ "expr ::= exprlist",
- /* 6 */ "exprlist ::= cnearset",
- /* 7 */ "exprlist ::= exprlist cnearset",
- /* 8 */ "cnearset ::= nearset",
- /* 9 */ "cnearset ::= colset COLON nearset",
- /* 10 */ "colset ::= MINUS LCP colsetlist RCP",
- /* 11 */ "colset ::= LCP colsetlist RCP",
- /* 12 */ "colset ::= STRING",
- /* 13 */ "colset ::= MINUS STRING",
- /* 14 */ "colsetlist ::= colsetlist STRING",
- /* 15 */ "colsetlist ::= STRING",
- /* 16 */ "nearset ::= phrase",
- /* 17 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
- /* 18 */ "nearphrases ::= phrase",
- /* 19 */ "nearphrases ::= nearphrases phrase",
- /* 20 */ "neardist_opt ::=",
- /* 21 */ "neardist_opt ::= COMMA STRING",
- /* 22 */ "phrase ::= phrase PLUS STRING star_opt",
- /* 23 */ "phrase ::= STRING star_opt",
- /* 24 */ "star_opt ::= STAR",
- /* 25 */ "star_opt ::=",
+ /* 1 */ "colset ::= MINUS LCP colsetlist RCP",
+ /* 2 */ "colset ::= LCP colsetlist RCP",
+ /* 3 */ "colset ::= STRING",
+ /* 4 */ "colset ::= MINUS STRING",
+ /* 5 */ "colsetlist ::= colsetlist STRING",
+ /* 6 */ "colsetlist ::= STRING",
+ /* 7 */ "expr ::= expr AND expr",
+ /* 8 */ "expr ::= expr OR expr",
+ /* 9 */ "expr ::= expr NOT expr",
+ /* 10 */ "expr ::= colset COLON LP expr RP",
+ /* 11 */ "expr ::= LP expr RP",
+ /* 12 */ "expr ::= exprlist",
+ /* 13 */ "exprlist ::= cnearset",
+ /* 14 */ "exprlist ::= exprlist cnearset",
+ /* 15 */ "cnearset ::= nearset",
+ /* 16 */ "cnearset ::= colset COLON nearset",
+ /* 17 */ "nearset ::= phrase",
+ /* 18 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
+ /* 19 */ "nearphrases ::= phrase",
+ /* 20 */ "nearphrases ::= nearphrases phrase",
+ /* 21 */ "neardist_opt ::=",
+ /* 22 */ "neardist_opt ::= COMMA STRING",
+ /* 23 */ "phrase ::= phrase PLUS STRING star_opt",
+ /* 24 */ "phrase ::= STRING star_opt",
+ /* 25 */ "star_opt ::= STAR",
+ /* 26 */ "star_opt ::=",
};
#endif /* NDEBUG */
#if fts5YYSTACKDEPTH<=0
@@ -182903,21 +183853,21 @@
case 19: /* exprlist */
{
sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24));
}
break;
- case 20: /* nearset */
+ case 20: /* colset */
+ case 21: /* colsetlist */
+{
+ sqlite3_free((fts5yypminor->fts5yy11));
+}
+ break;
+ case 22: /* nearset */
case 23: /* nearphrases */
{
sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46));
}
- break;
- case 21: /* colset */
- case 22: /* colsetlist */
-{
- sqlite3_free((fts5yypminor->fts5yy11));
-}
break;
case 24: /* phrase */
{
sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53));
}
@@ -183172,27 +184122,28 @@
static const struct {
fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} fts5yyRuleInfo[] = {
{ 16, 1 },
+ { 20, 4 },
+ { 20, 3 },
+ { 20, 1 },
+ { 20, 2 },
+ { 21, 2 },
+ { 21, 1 },
{ 17, 3 },
{ 17, 3 },
{ 17, 3 },
+ { 17, 5 },
{ 17, 3 },
{ 17, 1 },
{ 19, 1 },
{ 19, 2 },
{ 18, 1 },
{ 18, 3 },
- { 21, 4 },
- { 21, 3 },
- { 21, 1 },
- { 21, 2 },
- { 22, 2 },
{ 22, 1 },
- { 20, 1 },
- { 20, 5 },
+ { 22, 5 },
{ 23, 1 },
{ 23, 2 },
{ 25, 0 },
{ 25, 2 },
{ 24, 4 },
@@ -183263,132 +184214,139 @@
/********** Begin reduce actions **********************************************/
fts5YYMINORTYPE fts5yylhsminor;
case 0: /* input ::= expr */
{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); }
break;
- case 1: /* expr ::= expr AND expr */
-{
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
-}
- fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 2: /* expr ::= expr OR expr */
-{
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
-}
- fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 3: /* expr ::= expr NOT expr */
-{
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
-}
- fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 4: /* expr ::= LP expr RP */
-{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;}
- break;
- case 5: /* expr ::= exprlist */
- case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
-{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;}
- fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 7: /* exprlist ::= exprlist cnearset */
-{
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24);
-}
- fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 8: /* cnearset ::= nearset */
-{
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
-}
- fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 9: /* cnearset ::= colset COLON nearset */
-{
- sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy46, fts5yymsp[-2].minor.fts5yy11);
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
-}
- fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
- break;
- case 10: /* colset ::= MINUS LCP colsetlist RCP */
-{
- fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
-}
- break;
- case 11: /* colset ::= LCP colsetlist RCP */
-{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; }
- break;
- case 12: /* colset ::= STRING */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
-}
- fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 13: /* colset ::= MINUS STRING */
-{
- fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
- fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
-}
- break;
- case 14: /* colsetlist ::= colsetlist STRING */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); }
- fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 15: /* colsetlist ::= STRING */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
-}
- fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 16: /* nearset ::= phrase */
-{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); }
- fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
- break;
- case 17: /* nearset ::= STRING LP nearphrases neardist_opt RP */
+ case 1: /* colset ::= MINUS LCP colsetlist RCP */
+{
+ fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
+}
+ break;
+ case 2: /* colset ::= LCP colsetlist RCP */
+{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; }
+ break;
+ case 3: /* colset ::= STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+}
+ fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ break;
+ case 4: /* colset ::= MINUS STRING */
+{
+ fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+ fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
+}
+ break;
+ case 5: /* colsetlist ::= colsetlist STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); }
+ fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ break;
+ case 6: /* colsetlist ::= STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+}
+ fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ break;
+ case 7: /* expr ::= expr AND expr */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
+}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 8: /* expr ::= expr OR expr */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
+}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 9: /* expr ::= expr NOT expr */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
+}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 10: /* expr ::= colset COLON LP expr RP */
+{
+ sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[-4].minor.fts5yy11);
+ fts5yylhsminor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;
+}
+ fts5yymsp[-4].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 11: /* expr ::= LP expr RP */
+{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;}
+ break;
+ case 12: /* expr ::= exprlist */
+ case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13);
+{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;}
+ fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 14: /* exprlist ::= exprlist cnearset */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24);
+}
+ fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 15: /* cnearset ::= nearset */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
+}
+ fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 16: /* cnearset ::= colset COLON nearset */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
+ sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy24, fts5yymsp[-2].minor.fts5yy11);
+}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 17: /* nearset ::= phrase */
+{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); }
+ fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
+ break;
+ case 18: /* nearset ::= STRING LP nearphrases neardist_opt RP */
{
sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0);
fts5yylhsminor.fts5yy46 = fts5yymsp[-2].minor.fts5yy46;
}
fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 18: /* nearphrases ::= phrase */
+ case 19: /* nearphrases ::= phrase */
{
fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
}
fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 19: /* nearphrases ::= nearphrases phrase */
+ case 20: /* nearphrases ::= nearphrases phrase */
{
fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53);
}
fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 20: /* neardist_opt ::= */
+ case 21: /* neardist_opt ::= */
{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; }
break;
- case 21: /* neardist_opt ::= COMMA STRING */
+ case 22: /* neardist_opt ::= COMMA STRING */
{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
break;
- case 22: /* phrase ::= phrase PLUS STRING star_opt */
+ case 23: /* phrase ::= phrase PLUS STRING star_opt */
{
fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
}
fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
break;
- case 23: /* phrase ::= STRING star_opt */
+ case 24: /* phrase ::= STRING star_opt */
{
fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
}
fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
break;
- case 24: /* star_opt ::= STAR */
+ case 25: /* star_opt ::= STAR */
{ fts5yymsp[0].minor.fts5yy4 = 1; }
break;
- case 25: /* star_opt ::= */
+ case 26: /* star_opt ::= */
{ fts5yymsp[1].minor.fts5yy4 = 0; }
break;
default:
break;
/********** End reduce actions ************************************************/
@@ -184426,13 +185384,15 @@
Fts5Buffer *pBuf,
u32 nData,
const u8 *pData
){
assert_nc( *pRc || nData>=0 );
- if( fts5BufferGrow(pRc, pBuf, nData) ) return;
- memcpy(&pBuf->p[pBuf->n], pData, nData);
- pBuf->n += nData;
+ if( nData ){
+ if( fts5BufferGrow(pRc, pBuf, nData) ) return;
+ memcpy(&pBuf->p[pBuf->n], pData, nData);
+ pBuf->n += nData;
+ }
}
/*
** Append the nul-terminated string zStr to the buffer pBuf. This function
** ensures that the byte following the buffer data is set to 0x00, even
@@ -184605,12 +185565,12 @@
static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
void *pRet = 0;
if( *pRc==SQLITE_OK ){
pRet = sqlite3_malloc(nByte);
- if( pRet==0 && nByte>0 ){
- *pRc = SQLITE_NOMEM;
+ if( pRet==0 ){
+ if( nByte>0 ) *pRc = SQLITE_NOMEM;
}else{
memset(pRet, 0, nByte);
}
}
return pRet;
@@ -185927,10 +186887,11 @@
static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
static void fts5ParseFree(void *p){ sqlite3_free(p); }
static int sqlite3Fts5ExprNew(
Fts5Config *pConfig, /* FTS5 Configuration */
+ int iCol,
const char *zExpr, /* Expression text */
Fts5Expr **ppNew,
char **pzErr
){
Fts5Parse sParse;
@@ -185950,10 +186911,22 @@
do {
t = fts5ExprGetToken(&sParse, &z, &token);
sqlite3Fts5Parser(pEngine, t, token, &sParse);
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+
+ /* If the LHS of the MATCH expression was a user column, apply the
+ ** implicit column-filter. */
+ if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
+ int n = sizeof(Fts5Colset);
+ Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
+ if( pColset ){
+ pColset->nCol = 1;
+ pColset->aiCol[0] = iCol;
+ sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
+ }
+ }
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
if( sParse.rc==SQLITE_OK ){
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
if( pNew==0 ){
@@ -187600,29 +188573,114 @@
}
return pRet;
}
+/*
+** If argument pOrig is NULL, or if (*pRc) is set to anything other than
+** SQLITE_OK when this function is called, NULL is returned.
+**
+** Otherwise, a copy of (*pOrig) is made into memory obtained from
+** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
+** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
+*/
+static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
+ Fts5Colset *pRet;
+ if( pOrig ){
+ int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
+ pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
+ if( pRet ){
+ memcpy(pRet, pOrig, nByte);
+ }
+ }else{
+ pRet = 0;
+ }
+ return pRet;
+}
+
+/*
+** Remove from colset pColset any columns that are not also in colset pMerge.
+*/
+static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
+ int iIn = 0; /* Next input in pColset */
+ int iMerge = 0; /* Next input in pMerge */
+ int iOut = 0; /* Next output slot in pColset */
+
+ while( iInnCol && iMergenCol ){
+ int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge];
+ if( iDiff==0 ){
+ pColset->aiCol[iOut++] = pMerge->aiCol[iMerge];
+ iMerge++;
+ iIn++;
+ }else if( iDiff>0 ){
+ iMerge++;
+ }else{
+ iIn++;
+ }
+ }
+ pColset->nCol = iOut;
+}
+
+/*
+** Recursively apply colset pColset to expression node pNode and all of
+** its decendents. If (*ppFree) is not NULL, it contains a spare copy
+** of pColset. This function may use the spare copy and set (*ppFree) to
+** zero, or it may create copies of pColset using fts5CloneColset().
+*/
+static void fts5ParseSetColset(
+ Fts5Parse *pParse,
+ Fts5ExprNode *pNode,
+ Fts5Colset *pColset,
+ Fts5Colset **ppFree
+){
+ if( pParse->rc==SQLITE_OK ){
+ assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING
+ || pNode->eType==FTS5_AND || pNode->eType==FTS5_OR
+ || pNode->eType==FTS5_NOT || pNode->eType==FTS5_EOF
+ );
+ if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
+ Fts5ExprNearset *pNear = pNode->pNear;
+ if( pNear->pColset ){
+ fts5MergeColset(pNear->pColset, pColset);
+ if( pNear->pColset->nCol==0 ){
+ pNode->eType = FTS5_EOF;
+ pNode->xNext = 0;
+ }
+ }else if( *ppFree ){
+ pNear->pColset = pColset;
+ *ppFree = 0;
+ }else{
+ pNear->pColset = fts5CloneColset(&pParse->rc, pColset);
+ }
+ }else{
+ int i;
+ assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 );
+ for(i=0; inChild; i++){
+ fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree);
+ }
+ }
+ }
+}
+
+/*
+** Apply colset pColset to expression node pExpr and all of its descendents.
+*/
static void sqlite3Fts5ParseSetColset(
Fts5Parse *pParse,
- Fts5ExprNearset *pNear,
+ Fts5ExprNode *pExpr,
Fts5Colset *pColset
){
+ Fts5Colset *pFree = pColset;
if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
pParse->rc = SQLITE_ERROR;
pParse->zErr = sqlite3_mprintf(
"fts5: column queries are not supported (detail=none)"
);
- sqlite3_free(pColset);
- return;
- }
-
- if( pNear ){
- pNear->pColset = pColset;
- }else{
- sqlite3_free(pColset);
- }
+ }else{
+ fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
+ }
+ sqlite3_free(pFree);
}
static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
switch( pNode->eType ){
case FTS5_STRING: {
@@ -188072,11 +189130,11 @@
zExpr = (const char*)sqlite3_value_text(apVal[0]);
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
+ rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
}
if( rc==SQLITE_OK ){
char *zText;
if( pExpr->pRoot->xNext==0 ){
zText = sqlite3_mprintf("");
@@ -188469,13 +189527,14 @@
Fts5HashEntry **aSlot; /* Array of hash slots */
};
/*
** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (zKey[]) and its current data
-** are stored in a single memory allocation. The position list data
-** immediately follows the key data in memory.
+** following type. Each object, its key (a nul-terminated string) and
+** its current data are stored in a single memory allocation. The
+** key immediately follows the object in memory. The position list
+** data immediately follows the key data in memory.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
**
** * Rowid, as a varint
@@ -188495,24 +189554,24 @@
Fts5HashEntry *pScanNext; /* Next entry in sorted order */
int nAlloc; /* Total size of allocation */
int iSzPoslist; /* Offset of space for 4-byte poslist size */
int nData; /* Total bytes of data (incl. structure) */
- int nKey; /* Length of zKey[] in bytes */
+ int nKey; /* Length of key in bytes */
u8 bDel; /* Set delete-flag @ iSzPoslist */
u8 bContent; /* Set content-flag (detail=none mode) */
i16 iCol; /* Column of last value written */
int iPos; /* Position of last value written */
i64 iRowid; /* Rowid of last value written */
- char zKey[8]; /* Nul-terminated entry key */
};
/*
-** Size of Fts5HashEntry without the zKey[] array.
+** Eqivalent to:
+**
+** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
*/
-#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8)
-
+#define fts5EntryKey(p) ( ((char *)(&(p)[1])) )
/*
** Allocate a new hash table.
*/
@@ -188603,14 +189662,15 @@
if( !apNew ) return SQLITE_NOMEM;
memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
for(i=0; inSlot; i++){
while( apOld[i] ){
- int iHash;
+ unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
+ (int)strlen(fts5EntryKey(p)));
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
}
@@ -188677,22 +189737,24 @@
bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
/* Attempt to locate an existing hash entry */
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
- if( p->zKey[0]==bByte
+ char *zKey = fts5EntryKey(p);
+ if( zKey[0]==bByte
&& p->nKey==nToken
- && memcmp(&p->zKey[1], pToken, nToken)==0
+ && memcmp(&zKey[1], pToken, nToken)==0
){
break;
}
}
/* If an existing hash entry cannot be found, create a new one. */
if( p==0 ){
/* Figure out how much space to allocate */
- int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
+ char *zKey;
+ int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
if( nByte<128 ) nByte = 128;
/* Grow the Fts5Hash.aSlot[] array if necessary. */
if( (pHash->nEntry*2)>=pHash->nSlot ){
int rc = fts5HashResize(pHash);
@@ -188701,18 +189763,19 @@
}
/* Allocate new Fts5HashEntry and add it to the hash table. */
p = (Fts5HashEntry*)sqlite3_malloc(nByte);
if( !p ) return SQLITE_NOMEM;
- memset(p, 0, FTS5_HASHENTRYSIZE);
+ memset(p, 0, sizeof(Fts5HashEntry));
p->nAlloc = nByte;
- p->zKey[0] = bByte;
- memcpy(&p->zKey[1], pToken, nToken);
- assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
+ zKey = fts5EntryKey(p);
+ zKey[0] = bByte;
+ memcpy(&zKey[1], pToken, nToken);
+ assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
p->nKey = nToken;
- p->zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
+ zKey[nToken+1] = '\0';
+ p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
p->pHashNext = pHash->aSlot[iHash];
pHash->aSlot[iHash] = p;
pHash->nEntry++;
/* Add the first rowid field to the hash-entry */
@@ -188826,13 +189889,15 @@
}else if( p2==0 ){
*ppOut = p1;
p1 = 0;
}else{
int i = 0;
- while( p1->zKey[i]==p2->zKey[i] ) i++;
+ char *zKey1 = fts5EntryKey(p1);
+ char *zKey2 = fts5EntryKey(p2);
+ while( zKey1[i]==zKey2[i] ) i++;
- if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){
+ if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
/* p2 is smaller */
*ppOut = p2;
ppOut = &p2->pScanNext;
p2 = p2->pScanNext;
}else{
@@ -188871,11 +189936,11 @@
memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
for(iSlot=0; iSlotnSlot; iSlot++){
Fts5HashEntry *pIter;
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
- if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){
+ if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){
Fts5HashEntry *pEntry = pIter;
pEntry->pScanNext = 0;
for(i=0; ap[i]; i++){
pEntry = fts5HashEntryMerge(pEntry, ap[i]);
ap[i] = 0;
@@ -188904,20 +189969,22 @@
const char *pTerm, int nTerm, /* Query term */
const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
int *pnDoclist /* OUT: Size of doclist in bytes */
){
unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
+ char *zKey = 0;
Fts5HashEntry *p;
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
- if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
+ zKey = fts5EntryKey(p);
+ if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break;
}
if( p ){
fts5HashAddPoslistSize(pHash, p);
- *ppDoclist = (const u8*)&p->zKey[nTerm+1];
- *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
+ *ppDoclist = (const u8*)&zKey[nTerm+1];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
}else{
*ppDoclist = 0;
*pnDoclist = 0;
}
@@ -188946,15 +190013,16 @@
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
){
Fts5HashEntry *p;
if( (p = pHash->pScan) ){
- int nTerm = (int)strlen(p->zKey);
+ char *zKey = fts5EntryKey(p);
+ int nTerm = (int)strlen(zKey);
fts5HashAddPoslistSize(pHash, p);
- *pzTerm = p->zKey;
- *ppDoclist = (const u8*)&p->zKey[nTerm+1];
- *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
+ *pzTerm = zKey;
+ *ppDoclist = (const u8*)&zKey[nTerm+1];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
}else{
*pzTerm = 0;
*ppDoclist = 0;
*pnDoclist = 0;
}
@@ -189588,11 +190656,10 @@
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
sqlite3_blob_close(pReader);
}
}
-
/*
** Retrieve a record from the %_data table.
**
** If an error occurs, NULL is returned and an error left in the
@@ -191840,11 +192907,12 @@
Fts5Iter *pIter,
int *pbNewTerm /* OUT: True if *might* be new term */
){
assert( pIter->bSkipEmpty );
if( p->rc==SQLITE_OK ){
- do {
+ *pbNewTerm = 0;
+ do{
int iFirst = pIter->aFirst[1].iFirst;
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
int bNewTerm = 0;
assert( p->rc==SQLITE_OK );
@@ -191853,12 +192921,10 @@
|| fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
){
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
fts5MultiIterSetEof(pIter);
*pbNewTerm = 1;
- }else{
- *pbNewTerm = 0;
}
fts5AssertMultiIterSetup(p, pIter);
}while( fts5MultiIterIsEmpty(p, pIter) );
}
@@ -192120,27 +193186,27 @@
}
return p - (*pa);
}
-static int fts5IndexExtractColset (
+static void fts5IndexExtractColset(
+ int *pRc,
Fts5Colset *pColset, /* Colset to filter on */
const u8 *pPos, int nPos, /* Position list */
Fts5Buffer *pBuf /* Output buffer */
){
- int rc = SQLITE_OK;
- int i;
-
- fts5BufferZero(pBuf);
- for(i=0; inCol; i++){
- const u8 *pSub = pPos;
- int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
- if( nSub ){
- fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
+ if( *pRc==SQLITE_OK ){
+ int i;
+ fts5BufferZero(pBuf);
+ for(i=0; inCol; i++){
+ const u8 *pSub = pPos;
+ int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
+ if( nSub ){
+ fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
+ }
}
}
- return rc;
}
/*
** xSetOutputs callback used by detail=none tables.
*/
@@ -192260,12 +193326,13 @@
const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
if( pColset->nCol==1 ){
pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
pIter->base.pData = a;
}else{
+ int *pRc = &pIter->pIndex->rc;
fts5BufferZero(&pIter->poslist);
- fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist);
+ fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
pIter->base.pData = pIter->poslist.p;
pIter->base.nData = pIter->poslist.n;
}
}else{
/* The data is distributed over two or more pages. Copy it into the
@@ -192806,13 +193873,10 @@
static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
static const u8 zero[] = { 0x00, 0x00, 0x00, 0x00 };
Fts5PageWriter *pPage = &pWriter->writer;
i64 iRowid;
-static int nCall = 0;
-nCall++;
-
assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
/* Set the szLeaf header field. */
assert( 0==fts5GetU16(&pPage->buf.p[2]) );
fts5PutU16(&pPage->buf.p[2], (u16)pPage->buf.n);
@@ -193157,10 +194221,11 @@
Fts5StructureSegment *pSeg; /* Output segment */
Fts5Buffer term;
int bOldest; /* True if the output segment is the oldest */
int eDetail = p->pConfig->eDetail;
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
+ int bTermWritten = 0; /* True if current term already output */
assert( iLvlnLevel );
assert( pLvl->nMerge<=pLvl->nSeg );
memset(&writer, 0, sizeof(Fts5SegWriter));
@@ -193210,22 +194275,26 @@
Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
int nPos; /* position-list size field value */
int nTerm;
const u8 *pTerm;
- /* Check for key annihilation. */
- if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
-
pTerm = fts5MultiIterTerm(pIter, &nTerm);
if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
if( pnRem && writer.nLeafWritten>nRem ){
break;
}
+ fts5BufferSet(&p->rc, &term, nTerm, pTerm);
+ bTermWritten =0;
+ }
+ /* Check for key annihilation. */
+ if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
+
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
/* This is a new term. Append a term to the output segment. */
fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
- fts5BufferSet(&p->rc, &term, nTerm, pTerm);
+ bTermWritten = 1;
}
/* Append the rowid to the output */
/* WRITEPOSLISTSIZE */
fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter));
@@ -194053,11 +195122,11 @@
pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
if( pData ){
pData->p = (u8*)&pData[1];
pData->nn = pData->szLeaf = doclist.n;
- memcpy(pData->p, doclist.p, doclist.n);
+ if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
fts5MultiIterNew2(p, pData, bDesc, ppIter);
}
fts5BufferFree(&doclist);
}
@@ -194092,14 +195161,14 @@
}
/*
** Commit data to disk.
*/
-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
+static int sqlite3Fts5IndexSync(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
- if( bCommit ) fts5CloseReader(p);
+ fts5CloseReader(p);
return fts5IndexReturn(p);
}
/*
** Discard any data stored in the in-memory hash tables. Do not write it
@@ -194292,11 +195361,11 @@
/* If the QUERY_SCAN flag is set, all other flags must be clear. */
assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN );
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
- memcpy(&buf.p[1], pToken, nToken);
+ if( nToken ) memcpy(&buf.p[1], pToken, nToken);
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
** greater than pConfig->nPrefix to indicate that the query will be
** satisfied by scanning multiple terms in the main index.
@@ -194341,11 +195410,11 @@
if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
}
}
if( p->rc ){
- sqlite3Fts5IterClose(&pRet->base);
+ sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
pRet = 0;
fts5CloseReader(p);
}
*ppIter = &pRet->base;
@@ -195959,10 +197028,11 @@
** Costs are not modified by the ORDER BY clause.
*/
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts5Table *pTab = (Fts5Table*)pVTab;
Fts5Config *pConfig = pTab->pConfig;
+ const int nCol = pConfig->nCol;
int idxFlags = 0; /* Parameter passed through to xFilter() */
int bHasMatch;
int iNext;
int i;
@@ -195984,28 +197054,38 @@
FTS5_BI_ROWID_GE, 0, 0, -1},
};
int aColMap[3];
aColMap[0] = -1;
- aColMap[1] = pConfig->nCol;
- aColMap[2] = pConfig->nCol+1;
+ aColMap[1] = nCol;
+ aColMap[2] = nCol+1;
/* Set idxFlags flags for all WHERE clause terms that will be used. */
for(i=0; inConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
- int j;
- for(j=0; jiColumn==aColMap[pC->iCol] && p->op & pC->op ){
- if( p->usable ){
+ int iCol = p->iColumn;
+
+ if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
+ || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
+ ){
+ /* A MATCH operator or equivalent */
+ if( p->usable ){
+ idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
+ aConstraint[0].iConsIndex = i;
+ }else{
+ /* As there exists an unusable MATCH constraint this is an
+ ** unusable plan. Set a prohibitively high cost. */
+ pInfo->estimatedCost = 1e50;
+ return SQLITE_OK;
+ }
+ }else{
+ int j;
+ for(j=1; jiCol] && p->op & pC->op && p->usable ){
pC->iConsIndex = i;
idxFlags |= pC->fts5op;
- }else if( j==0 ){
- /* As there exists an unusable MATCH constraint this is an
- ** unusable plan. Set a prohibitively high cost. */
- pInfo->estimatedCost = 1e50;
- return SQLITE_OK;
}
}
}
}
@@ -196576,10 +197656,11 @@
sqlite3_value *pMatch = 0; /* MATCH ? expression (or NULL) */
sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
+ int iCol; /* Column on LHS of MATCH operator */
char **pzErrmsg = pConfig->pzErrmsg;
UNUSED_PARAM(zUnused);
UNUSED_PARAM(nVal);
@@ -196606,10 +197687,12 @@
if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
+ iCol = (idxNum>>16);
+ assert( iCol>=0 && iCol<=pConfig->nCol );
assert( iVal==nVal );
bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
/* Set the cursor upper and lower rowid limits. Only some strategies
@@ -196652,11 +197735,11 @@
** indicates that the MATCH expression is not a full text query,
** but a request for an internal parameter. */
rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
}else{
char **pzErr = &pTab->base.zErrMsg;
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
+ rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
if( rc==SQLITE_OK ){
if( bOrderByRank ){
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
}else{
@@ -197032,11 +198115,11 @@
int rc;
Fts5Table *pTab = (Fts5Table*)pVtab;
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
fts5TripCursors(pTab);
- rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
+ rc = sqlite3Fts5StorageSync(pTab->pStorage);
pTab->pConfig->pzErrmsg = 0;
return rc;
}
/*
@@ -197843,11 +198926,11 @@
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
fts5TripCursors(pTab);
- return sqlite3Fts5StorageSync(pTab->pStorage, 0);
+ return sqlite3Fts5StorageSync(pTab->pStorage);
}
/*
** The xRelease() method.
**
@@ -197856,11 +198939,11 @@
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
fts5TripCursors(pTab);
- return sqlite3Fts5StorageSync(pTab->pStorage, 0);
+ return sqlite3Fts5StorageSync(pTab->pStorage);
}
/*
** The xRollbackTo() method.
**
@@ -198067,11 +199150,11 @@
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2017-03-10 17:03:11 f8560c60d10c0365b33342ab05b5a953987b0471", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2017-06-13 04:31:54 35b34bdf0843b49be39e13ed212e918c2d45afdb8374b5cd02ba6d2d5b16b3b9", -1, SQLITE_TRANSIENT);
}
static int fts5Init(sqlite3 *db){
static const sqlite3_module fts5Mod = {
/* iVersion */ 2,
@@ -198403,11 +199486,11 @@
}
}
static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
Fts5Config *pConfig = pStorage->pConfig;
- int rc = sqlite3Fts5StorageSync(pStorage, 1);
+ int rc = sqlite3Fts5StorageSync(pStorage);
fts5StorageRenameOne(pConfig, &rc, "data", zName);
fts5StorageRenameOne(pConfig, &rc, "idx", zName);
fts5StorageRenameOne(pConfig, &rc, "config", zName);
if( pConfig->bColumnsize ){
@@ -199266,19 +200349,19 @@
}
/*
** Flush any data currently held in-memory to disk.
*/
-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
+static int sqlite3Fts5StorageSync(Fts5Storage *p){
int rc = SQLITE_OK;
i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
if( p->bTotalsValid ){
rc = fts5StorageSaveTotals(p);
- if( bCommit ) p->bTotalsValid = 0;
+ p->bTotalsValid = 0;
}
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexSync(p->pIndex, bCommit);
+ rc = sqlite3Fts5IndexSync(p->pIndex);
}
sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
return rc;
}
Index: src/sqlite3.h
==================================================================
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -112,20 +112,20 @@
** SQLite source code has been stored in the
** Fossil configuration management
** system. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
-** string contains the date and time of the check-in (UTC) and an SHA1
-** hash of the entire source tree.
+** string contains the date and time of the check-in (UTC) and a SHA1
+** or SHA3-256 hash of the entire source tree.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.18.0"
-#define SQLITE_VERSION_NUMBER 3018000
-#define SQLITE_SOURCE_ID "2017-03-10 17:03:11 f8560c60d10c0365b33342ab05b5a953987b0471"
+#define SQLITE_VERSION "3.20.0"
+#define SQLITE_VERSION_NUMBER 3020000
+#define SQLITE_SOURCE_ID "2017-06-15 13:07:56 9afd7a2ffd3a39456190ad05e85ff6485298aae262d9e0698a58c1d73507a36f"
/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
@@ -855,11 +855,11 @@
** of 25 milliseconds before the first retry and with the delay increasing
** by an additional 25 milliseconds with each subsequent retry. This
** opcode allows these two values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
-** integers where the first integer i the new retry count and the second
+** integers where the first integer is the new retry count and the second
** integer is the delay. If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
** interrogated. The zDbName parameter is ignored.
**
@@ -2209,13 +2209,10 @@
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
-**
-** If the database connection closes while [sqlite3_interrupt()]
-** is running then bad things will likely happen.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2674,10 +2671,11 @@
SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
** METHOD: sqlite3
+** KEYWORDS: {authorizer callback}
**
** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
** ^The authorizer callback is invoked as SQL statements are being compiled
** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
@@ -2701,20 +2699,26 @@
**
** ^The first parameter to the authorizer callback is a copy of the third
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
** to the callback is an integer [SQLITE_COPY | action code] that specifies
** the particular action to be authorized. ^The third through sixth parameters
-** to the callback are zero-terminated strings that contain additional
-** details about the action to be authorized.
+** to the callback are either NULL pointers or zero-terminated strings
+** that contain additional details about the action to be authorized.
+** Applications must always be prepared to encounter a NULL pointer in any
+** of the third through the sixth parameters of the authorization callback.
**
** ^If the action code is [SQLITE_READ]
** and the callback returns [SQLITE_IGNORE] then the
** [prepared statement] statement is constructed to substitute
** a NULL value in place of the table column that would have
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
** return can be used to deny an untrusted user access to individual
** columns of a table.
+** ^When a table is referenced by a [SELECT] but no column values are
+** extracted from that table (for example in a query like
+** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
+** is invoked once for that table with a column name that is an empty string.
** ^If the action code is [SQLITE_DELETE] and the callback returns
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
** [truncate optimization] is disabled and all rows are deleted individually.
**
** An authorizer is used when [sqlite3_prepare | preparing]
@@ -3422,13 +3426,13 @@
** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(SQLITE_LIMIT_COMPOUND_SELECT
** The maximum number of terms in a compound SELECT statement.)^
**
** [[SQLITE_LIMIT_VDBE_OP]] ^(SQLITE_LIMIT_VDBE_OP
** The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement. This limit is not currently
-** enforced, though that might be added in some future release of
-** SQLite.)^
+** used to implement an SQL statement. If [sqlite3_prepare_v2()] or
+** the equivalent tries to allocate space for more than this many opcodes
+** in a single prepared statement, an SQLITE_NOMEM error is returned.)^
**
** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(SQLITE_LIMIT_FUNCTION_ARG
** The maximum number of arguments on a function.)^
**
** [[SQLITE_LIMIT_ATTACHED]] ^(SQLITE_LIMIT_ATTACHED
@@ -3461,10 +3465,11 @@
#define SQLITE_LIMIT_ATTACHED 7
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
#define SQLITE_LIMIT_WORKER_THREADS 11
+
/*
** CAPI3REF: Compiling An SQL Statement
** KEYWORDS: {SQL statement compiler}
** METHOD: sqlite3
@@ -3702,11 +3707,11 @@
** Unprotected sqlite3_value objects may only be used with
** [sqlite3_result_value()] and [sqlite3_bind_value()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
-typedef struct Mem sqlite3_value;
+typedef struct sqlite3_value sqlite3_value;
/*
** CAPI3REF: SQL Function Context Object
**
** The context in which an SQL function executes is stored in an
@@ -4756,14 +4761,15 @@
** metadata associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function. ^If there is no metadata
-** associated with the function argument, this sqlite3_get_auxdata() interface
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
+** value to the application-defined function. ^N is zero for the left-most
+** function argument. ^If there is no metadata
+** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
** argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
@@ -4789,10 +4795,14 @@
** sqlite3_set_auxdata() has been called.
**
** ^(In practice, metadata is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
+**
+** The value of the N parameter to these interfaces should be non-negative.
+** Future enhancements may make use of negative N values to define new
+** kinds of function caching behavior.
**
** These routines must be called from the same thread in which
** the SQL function is running.
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5608,11 +5618,13 @@
** column exists. ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
-** does not.
+** does not. If the table name parameter T in a call to
+** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
+** undefined behavior.
**
** ^The column is identified by the second, third and fourth parameters to
** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
** table or NULL.)^ ^If it is NULL, then all attached databases are searched
@@ -7121,17 +7133,24 @@
** by the prepared statement if that number is less than or equal
** to 2147483647. The number of virtual machine operations can be
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
+**
+** [[SQLITE_STMTSTATUS_MEMUSED]] SQLITE_STMTSTATUS_MEMUSED
+** ^This is the approximate number of bytes of heap memory
+** used to store the prepared statement. ^This value is not actually
+** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
+** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
**
**
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
#define SQLITE_STMTSTATUS_VM_STEP 4
+#define SQLITE_STMTSTATUS_MEMUSED 5
/*
** CAPI3REF: Custom Page Cache Object
**
** The sqlite3_pcache type is opaque. It is implemented by
@@ -9384,11 +9403,11 @@
**
** As well as the regular sqlite3changegroup_add() and
** sqlite3changegroup_output() functions, also available are the streaming
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
*/
-int sqlite3changegroup_new(sqlite3_changegroup **pp);
+SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add A Changeset To A Changegroup
**
** Add all changes within the changeset (or patchset) in buffer pData (size
@@ -9461,11 +9480,11 @@
** function returns SQLITE_NOMEM. In all cases, if an error occurs the
** final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
-int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
+SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
**
** Obtain a buffer containing a changeset (or patchset) representing the
@@ -9487,20 +9506,20 @@
** is returned and the output variables are set to the size of and a
** pointer to the output buffer, respectively. In this case it is the
** responsibility of the caller to eventually free the buffer using a
** call to sqlite3_free().
*/
-int sqlite3changegroup_output(
+SQLITE_API int sqlite3changegroup_output(
sqlite3_changegroup*,
int *pnData, /* OUT: Size of output buffer in bytes */
void **ppData /* OUT: Pointer to output buffer */
);
/*
** CAPI3REF: Delete A Changegroup Object
*/
-void sqlite3changegroup_delete(sqlite3_changegroup*);
+SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
/*
** CAPI3REF: Apply A Changeset To A Database
**
** Apply a changeset to a database. This function attempts to update the
@@ -9885,15 +9904,15 @@
SQLITE_API int sqlite3session_patchset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changegroup_add_strm(sqlite3_changegroup*,
+SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
-int sqlite3changegroup_output_strm(sqlite3_changegroup*,
+SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
Index: src/stat.c
==================================================================
--- src/stat.c
+++ src/stat.c
@@ -178,15 +178,15 @@
@ %h(p) %h(db_get("parent-project-name","")) |
}
/* @ Server ID: | %h(db_get("server-code","")) |
*/
@ Fossil Version: |
@ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
- @ (%h(RELEASE_VERSION)) (details)
+ @ (%h(RELEASE_VERSION)) (details)
@ |
@ SQLite Version: | %.19s(sqlite3_sourceid())
@ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))
- @ (details) |
+ @ (details)
if( g.eHashPolicy!=HPOLICY_AUTO ){
@ Schema Version: | %h(g.zAuxSchema),
@ %s(hpolicy_name()) |
}else{
@ Schema Version: | %h(g.zAuxSchema) |
@@ -341,10 +341,11 @@
** Show ways in which this repository has been accessed
*/
void urllist_page(void){
Stmt q;
int cnt;
+ char *zRemote;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
style_header("URLs and Checkouts");
style_adunit_config(ADUNIT_RIGHT_OK);
@@ -378,10 +379,22 @@
db_finalize(&q);
if( cnt==0 ){
@ (none) |
}
@
+ zRemote = db_text(0, "SELECT value FROM config WHERE name='last-sync-url'");
+ if( zRemote ){
+ @ Last Sync URL
+ if( sqlite3_strlike("http%", zRemote, 0)==0 ){
+ UrlData x;
+ url_parse_local(zRemote, URL_OMIT_USER, &x);
+ @ %h(zRemote)
+ }else{
+ @
%h(zRemote)
+ }
+ @
+ }
style_footer();
}
/*
** WEBPAGE: repo_schema
@@ -400,11 +413,11 @@
style_submenu_element("Stat", "stat");
style_submenu_element("URLs", "urllist");
if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){
style_submenu_element("Table Sizes", "repo-tabsize");
}
- blob_init(&sql,
+ blob_init(&sql,
"SELECT sql FROM repository.sqlite_master WHERE sql IS NOT NULL", -1);
if( zArg ){
style_submenu_element("All", "repo_schema");
blob_appendf(&sql, " AND (tbl_name=%Q OR name=%Q)", zArg, zArg);
}
Index: src/tag.c
==================================================================
--- src/tag.c
+++ src/tag.c
@@ -587,11 +587,11 @@
}
/*
** COMMAND: reparent*
**
-** Usage: %fossil reparent [OPTIONS] CHECK-IN PARENT ....
+** Usage: %fossil reparent [OPTIONS] CHECK-IN PARENT ...
**
** Create a "parent" tag that causes CHECK-IN to be interpreted as a
** child of PARENT. If multiple PARENTs are listed, then the first is
** the primary parent and others are merge ancestors.
**
@@ -619,11 +619,11 @@
if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
db_find_and_open_repository(0, 0);
verify_all_options();
if( g.argc<4 ){
- usage("reparent [OPTIONS] PARENT ...");
+ usage("[OPTIONS] CHECK-IN PARENT ...");
}
rid = name_to_typed_rid(g.argv[2], "ci");
blob_init(&value, 0, 0);
for(i=3; i10 ) zName[10] = 0;
Index: src/th_main.c
==================================================================
--- src/th_main.c
+++ src/th_main.c
@@ -1588,15 +1588,15 @@
}
zSql = argv[1];
nSql = argl[1];
while( res==TH_OK && nSql>0 ){
zErr = 0;
- sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)&zErr);
+ report_restrict_sql(&zErr);
g.dbIgnoreErrors++;
rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
g.dbIgnoreErrors--;
- sqlite3_set_authorizer(g.db, 0, 0);
+ report_unrestrict_sql();
if( rc!=0 || zErr!=0 ){
if( noComplain ) return TH_OK;
Th_ErrorMessage(interp, "SQL error: ",
zErr ? zErr : sqlite3_errmsg(g.db), -1);
return TH_ERROR;
Index: src/tkt.c
==================================================================
--- src/tkt.c
+++ src/tkt.c
@@ -749,24 +749,24 @@
cgi_redirectf("tktview?name=%T", zName);
}
style_header("Edit Ticket");
if( zName==0 || (nName = strlen(zName))<4 || nName>UUID_SIZE
|| !validate16(zName,nName) ){
- @ Not a valid ticket id: \"%h(zName)\"
+ @ Not a valid ticket id: "%h(zName)"
style_footer();
return;
}
nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'",
zName);
if( nRec==0 ){
- @ No such ticket: \"%h(zName)\"
+ @ No such ticket: "%h(zName)"
style_footer();
return;
}
if( nRec>1 ){
@ %d(nRec) tickets begin with:
- @ \"%h(zName)\"
+ @ "%h(zName)"
style_footer();
return;
}
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT
\n", -1);
ticket_init();
Index: src/unicode.c
==================================================================
--- src/unicode.c
+++ src/unicode.c
@@ -52,103 +52,105 @@
0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, 0x00206C09,
0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, 0x00217801,
0x00235030, 0x0024E803, 0x0024F812, 0x00254407, 0x00258804,
0x0025C001, 0x00260403, 0x0026F001, 0x0026F807, 0x00271C02,
0x00272C03, 0x00275C01, 0x00278802, 0x0027C802, 0x0027E802,
- 0x00280403, 0x0028F001, 0x0028F805, 0x00291C02, 0x00292C03,
- 0x00294401, 0x0029C002, 0x0029D401, 0x002A0403, 0x002AF001,
- 0x002AF808, 0x002B1C03, 0x002B2C03, 0x002B8802, 0x002BC002,
- 0x002C0403, 0x002CF001, 0x002CF807, 0x002D1C02, 0x002D2C03,
- 0x002D5802, 0x002D8802, 0x002DC001, 0x002E0801, 0x002EF805,
- 0x002F1803, 0x002F2804, 0x002F5C01, 0x002FCC08, 0x00300004,
- 0x0030F807, 0x00311803, 0x00312804, 0x00315402, 0x00318802,
- 0x0031FC01, 0x00320403, 0x0032F001, 0x0032F807, 0x00331803,
- 0x00332804, 0x00335402, 0x00338802, 0x00340403, 0x0034F807,
- 0x00351803, 0x00352804, 0x00353C01, 0x00355C01, 0x00358802,
- 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, 0x00375801,
- 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, 0x0038FC01,
- 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, 0x003AEC02,
- 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, 0x003E340B,
- 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, 0x00412806,
- 0x00415804, 0x00417803, 0x00418803, 0x00419C07, 0x0041C404,
- 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, 0x004D740C,
- 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, 0x005A6C02,
- 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, 0x005DC802,
- 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, 0x00621402,
- 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002,
- 0x00677822, 0x00685C05, 0x00687802, 0x0069540A, 0x0069801D,
- 0x0069FC01, 0x006A8007, 0x006AA006, 0x006AC00F, 0x006C0005,
- 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, 0x006F980E,
- 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, 0x00730008,
- 0x00734019, 0x0073B401, 0x0073C803, 0x0073E002, 0x00770036,
- 0x0077EC05, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403,
- 0x007FB403, 0x007FF402, 0x00800065, 0x0081980A, 0x0081E805,
- 0x00822805, 0x0082801F, 0x00834021, 0x00840002, 0x00840C04,
- 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401,
- 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005,
- 0x00852804, 0x00853C01, 0x00862802, 0x0086426F, 0x00900027,
- 0x0091000B, 0x0092704E, 0x00940276, 0x009E53E0, 0x00ADD820,
- 0x00AE6022, 0x00AEF40C, 0x00AF2808, 0x00AFB004, 0x00B39406,
- 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, 0x00B5FC01,
- 0x00B7804F, 0x00B8C015, 0x00BA001A, 0x00BA6C59, 0x00BC00D6,
- 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, 0x00C0D802,
- 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, 0x00C64002,
- 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, 0x00C94001,
- 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, 0x01370040,
- 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, 0x029A7802,
- 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, 0x02A00801,
- 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, 0x02A1D004,
- 0x02A20002, 0x02A2D012, 0x02A33802, 0x02A38012, 0x02A3E003,
- 0x02A3F001, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
- 0x02A6CC1B, 0x02A77802, 0x02A79401, 0x02A8A40E, 0x02A90C01,
- 0x02A93002, 0x02A97004, 0x02A9DC03, 0x02A9EC03, 0x02AAC001,
- 0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802,
- 0x02ABAC07, 0x02ABD402, 0x02AD6C01, 0x02AF8C0B, 0x03600001,
- 0x036DFC02, 0x036FFC02, 0x037FFC01, 0x03EC7801, 0x03ECA401,
- 0x03EEC810, 0x03F4F802, 0x03F7F002, 0x03F8001A, 0x03F88033,
- 0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807,
- 0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405,
- 0x04040003, 0x0404DC09, 0x0405E411, 0x04063003, 0x0406400C,
- 0x04068001, 0x0407402E, 0x040B8001, 0x040DD805, 0x040E7C01,
- 0x040F4001, 0x0415BC01, 0x04215C01, 0x0421DC02, 0x04247C01,
- 0x0424FC01, 0x04280403, 0x04281402, 0x04283004, 0x0428E003,
- 0x0428FC01, 0x04294009, 0x0429FC01, 0x042B2001, 0x042B9402,
- 0x042BC007, 0x042CE407, 0x042E6404, 0x04400003, 0x0440E016,
- 0x0441FC04, 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004,
- 0x0445CC03, 0x04460003, 0x0446CC0E, 0x04471409, 0x04476C01,
- 0x04477403, 0x0448B013, 0x044AA401, 0x044B7C0C, 0x044C0004,
- 0x044CF001, 0x044CF807, 0x044D1C02, 0x044D2C03, 0x044D5C01,
- 0x044D8802, 0x044D9807, 0x044DC005, 0x0450D412, 0x04512C05,
- 0x04516C01, 0x04517401, 0x0452C014, 0x04531801, 0x0456BC07,
- 0x0456E020, 0x04577002, 0x0458C014, 0x0459800D, 0x045AAC0D,
- 0x045C740F, 0x045CF004, 0x0470BC08, 0x0470E008, 0x04710405,
- 0x0471C002, 0x04724816, 0x0472A40E, 0x0491C005, 0x05A9B802,
- 0x05ABC006, 0x05ACC010, 0x05AD1002, 0x05BD442E, 0x05BE3C04,
- 0x06F27008, 0x074000F6, 0x07440027, 0x0744A4C0, 0x07480046,
- 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
- 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
- 0x075F0C01, 0x0760028C, 0x076A6C05, 0x076A840F, 0x07800007,
- 0x07802011, 0x07806C07, 0x07808C02, 0x07809805, 0x07A34007,
- 0x07A51007, 0x07A57802, 0x07BBC002, 0x07C0002C, 0x07C0C064,
- 0x07C2800F, 0x07C2C40F, 0x07C3040F, 0x07C34425, 0x07C4401F,
- 0x07C4C03C, 0x07C5C03D, 0x07C7981D, 0x07C8402C, 0x07C90009,
- 0x07C94002, 0x07CC03D3, 0x07DB800D, 0x07DBC007, 0x07DC0074,
- 0x07DE0055, 0x07E0000C, 0x07E04038, 0x07E1400A, 0x07E18028,
- 0x07E2401E, 0x07E4400F, 0x07E48008, 0x07E4C001, 0x07E4CC0C,
- 0x07E5000C, 0x07E5400F, 0x07E60012, 0x07E70001, 0x38000401,
- 0x38008060, 0x380400F0,
+ 0x0027F401, 0x00280403, 0x0028F001, 0x0028F805, 0x00291C02,
+ 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, 0x002A0403,
+ 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, 0x002B8802,
+ 0x002BC002, 0x002BE806, 0x002C0403, 0x002CF001, 0x002CF807,
+ 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001,
+ 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01,
+ 0x002FCC08, 0x00300004, 0x0030F807, 0x00311803, 0x00312804,
+ 0x00315402, 0x00318802, 0x0031FC01, 0x00320403, 0x0032F001,
+ 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802,
+ 0x00340004, 0x0034EC02, 0x0034F807, 0x00351803, 0x00352804,
+ 0x00353C01, 0x00355C01, 0x00358802, 0x0035E401, 0x00360802,
+ 0x00372801, 0x00373C06, 0x00375801, 0x00376008, 0x0037C803,
+ 0x0038C401, 0x0038D007, 0x0038FC01, 0x00391C09, 0x00396802,
+ 0x003AC401, 0x003AD006, 0x003AEC02, 0x003B2006, 0x003C041F,
+ 0x003CD00C, 0x003DC417, 0x003E340B, 0x003E6424, 0x003EF80F,
+ 0x003F380D, 0x0040AC14, 0x00412806, 0x00415804, 0x00417803,
+ 0x00418803, 0x00419C07, 0x0041C404, 0x0042080C, 0x00423C01,
+ 0x00426806, 0x0043EC01, 0x004D740C, 0x004E400A, 0x00500001,
+ 0x0059B402, 0x005A0001, 0x005A6C02, 0x005BAC03, 0x005C4803,
+ 0x005CC805, 0x005D4802, 0x005DC802, 0x005ED023, 0x005F6004,
+ 0x005F7401, 0x0060000F, 0x00621402, 0x0062A401, 0x0064800C,
+ 0x0064C00C, 0x00650001, 0x00651002, 0x00677822, 0x00685C05,
+ 0x00687802, 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007,
+ 0x006AA006, 0x006AC00F, 0x006C0005, 0x006CD011, 0x006D6823,
+ 0x006E0003, 0x006E840D, 0x006F980E, 0x006FF004, 0x00709014,
+ 0x0070EC05, 0x0071F802, 0x00730008, 0x00734019, 0x0073B401,
+ 0x0073C803, 0x0073DC03, 0x0077003A, 0x0077EC05, 0x007EF401,
+ 0x007EFC03, 0x007F3403, 0x007F7403, 0x007FB403, 0x007FF402,
+ 0x00800065, 0x0081980A, 0x0081E805, 0x00822805, 0x00828020,
+ 0x00834021, 0x00840002, 0x00840C04, 0x00842002, 0x00845001,
+ 0x00845803, 0x00847806, 0x00849401, 0x00849C01, 0x0084A401,
+ 0x0084B801, 0x0084E802, 0x00850005, 0x00852804, 0x00853C01,
+ 0x00862802, 0x00864297, 0x0091000B, 0x0092704E, 0x00940276,
+ 0x009E53E0, 0x00ADD820, 0x00AE6022, 0x00AEF40C, 0x00AF2809,
+ 0x00AFB004, 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802,
+ 0x00B5C001, 0x00B5FC01, 0x00B7804F, 0x00B8C01A, 0x00BA001A,
+ 0x00BA6C59, 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019,
+ 0x00C0A807, 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001,
+ 0x00C3EC01, 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F,
+ 0x00C8A81E, 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F,
+ 0x00CC0100, 0x01370040, 0x02924037, 0x0293F802, 0x02983403,
+ 0x0299BC10, 0x029A7802, 0x029BC008, 0x029C0017, 0x029C8002,
+ 0x029E2402, 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09,
+ 0x02A0D804, 0x02A1D004, 0x02A20002, 0x02A2D012, 0x02A33802,
+ 0x02A38012, 0x02A3E003, 0x02A3F001, 0x02A4980A, 0x02A51C0D,
+ 0x02A57C01, 0x02A60004, 0x02A6CC1B, 0x02A77802, 0x02A79401,
+ 0x02A8A40E, 0x02A90C01, 0x02A93002, 0x02A97004, 0x02A9DC03,
+ 0x02A9EC03, 0x02AAC001, 0x02AAC803, 0x02AADC02, 0x02AAF802,
+ 0x02AB0401, 0x02AB7802, 0x02ABAC07, 0x02ABD402, 0x02AD6C01,
+ 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, 0x037FFC01,
+ 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, 0x03F7F002,
+ 0x03F8001A, 0x03F88033, 0x03F95013, 0x03F9A004, 0x03FBFC01,
+ 0x03FC040F, 0x03FC6807, 0x03FCEC06, 0x03FD6C0B, 0x03FF8007,
+ 0x03FFA007, 0x03FFE405, 0x04040003, 0x0404DC09, 0x0405E411,
+ 0x04063003, 0x0406400C, 0x04068001, 0x0407402E, 0x040B8001,
+ 0x040DD805, 0x040E7C01, 0x040F4001, 0x0415BC01, 0x04215C01,
+ 0x0421DC02, 0x04247C01, 0x0424FC01, 0x04280403, 0x04281402,
+ 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, 0x0429FC01,
+ 0x042B2001, 0x042B9402, 0x042BC007, 0x042CE407, 0x042E6404,
+ 0x04400003, 0x0440E016, 0x0441FC04, 0x0442C012, 0x04440003,
+ 0x04449C0E, 0x04450004, 0x0445CC03, 0x04460003, 0x0446CC0E,
+ 0x04471409, 0x04476C01, 0x04477403, 0x0448B013, 0x044AA401,
+ 0x044B7C0C, 0x044C0004, 0x044CF001, 0x044CF807, 0x044D1C02,
+ 0x044D2C03, 0x044D5C01, 0x044D8802, 0x044D9807, 0x044DC005,
+ 0x0450D412, 0x04512C05, 0x04516C01, 0x04517401, 0x0452C014,
+ 0x04531801, 0x0456BC07, 0x0456E020, 0x04577002, 0x0458C014,
+ 0x0459800D, 0x045AAC0D, 0x045C740F, 0x045CF004, 0x0468040A,
+ 0x0468CC07, 0x0468EC0D, 0x0469440B, 0x046A2813, 0x046A7805,
+ 0x0470BC08, 0x0470E008, 0x04710405, 0x0471C002, 0x04724816,
+ 0x0472A40E, 0x0474C406, 0x0474E801, 0x0474F002, 0x0474FC07,
+ 0x04751C01, 0x0491C005, 0x05A9B802, 0x05ABC006, 0x05ACC010,
+ 0x05AD1002, 0x05BD442E, 0x05BE3C04, 0x06F27008, 0x074000F6,
+ 0x07440027, 0x0744A4C0, 0x07480046, 0x074C0057, 0x075B0401,
+ 0x075B6C01, 0x075BEC01, 0x075C5401, 0x075CD401, 0x075D3C01,
+ 0x075DBC01, 0x075E2401, 0x075EA401, 0x075F0C01, 0x0760028C,
+ 0x076A6C05, 0x076A840F, 0x07800007, 0x07802011, 0x07806C07,
+ 0x07808C02, 0x07809805, 0x07A34007, 0x07A51007, 0x07A57802,
+ 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, 0x07C2C40F,
+ 0x07C3040F, 0x07C34425, 0x07C4401F, 0x07C4C03C, 0x07C5C03D,
+ 0x07C7981D, 0x07C8402C, 0x07C90009, 0x07C94002, 0x07C98006,
+ 0x07CC03D5, 0x07DB800D, 0x07DBC009, 0x07DC0074, 0x07DE0055,
+ 0x07E0000C, 0x07E04038, 0x07E1400A, 0x07E18028, 0x07E2401E,
+ 0x07E4000C, 0x07E4402F, 0x07E5000D, 0x07E5401C, 0x07E60018,
+ 0x07E70001, 0x07E74017, 0x38000401, 0x38008060, 0x380400F0,
};
static const unsigned int aAscii[4] = {
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
if( (unsigned int)c<128 ){
- return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
+ return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
}else if( (unsigned int)c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
- int iHi = count(aEntry) - 1;
+ int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
if( key >= aEntry[iTest] ){
iRes = iTest;
@@ -201,11 +203,11 @@
'e', 'i', 'o', 'u', 'y',
};
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
int iRes = 0;
- int iHi = count(aDia) - 1;
+ int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
if( key >= aDia[iTest] ){
iRes = iTest;
@@ -348,11 +350,11 @@
if( c<128 ){
if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
}else if( c<65536 ){
const struct TableEntry *p;
- int iHi = count(aEntry) - 1;
+ int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
int iRes = -1;
assert( c>aEntry[0].iCode );
while( iHi>=iLo ){
Index: src/url.c
==================================================================
--- src/url.c
+++ src/url.c
@@ -38,10 +38,11 @@
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
+#define URL_OMIT_USER 0x020 /* Omit the user name from URL */
/*
** The URL related data used with this subsystem.
*/
struct UrlData {
@@ -153,11 +154,15 @@
dehttpize(pUrlData->passwd);
}
if( pUrlData->isSsh ){
urlFlags &= ~URL_ASK_REMEMBER_PW;
}
- zLogin = mprintf("%t@", pUrlData->user);
+ if( urlFlags & URL_OMIT_USER ){
+ zLogin = mprintf("");
+ }else{
+ zLogin = mprintf("%t@", pUrlData->user);
+ }
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
i = j;
}else{
int inSquare = 0;
Index: src/user.c
==================================================================
--- src/user.c
+++ src/user.c
@@ -53,10 +53,13 @@
static char *getpass(const char *prompt){
char *zPwd;
size_t nPwd;
size_t i;
+#if defined(_WIN32)
+ int useGetch = _isatty(_fileno(stderr));
+#endif
if( zPwdBuffer==0 ){
zPwdBuffer = fossil_secure_alloc_page(&nPwdBuffer);
assert( zPwdBuffer );
}else{
@@ -68,11 +71,11 @@
fflush(stderr);
assert( zPwd!=0 );
assert( nPwd>0 );
for(i=0; i0x7fffffff ){
+ nHeap = 0x7fffffff;
+ }
+ x.rlim_cur = (rlim_t)nHeap;
+ setrlimit(RLIMIT_DATA, &x);
+#endif /* defined(RLIMIT_DATA) */
+#if defined(RLIMIT_STACK)
+ getrlimit(RLIMIT_STACK, &x);
+ if( sizeof(x.rlim_cur)<8 && nStack>0x7fffffff ){
+ nStack = 0x7fffffff;
+ }
+ x.rlim_cur = (rlim_t)nStack;
+ setrlimit(RLIMIT_STACK, &x);
+#endif /* defined(RLIMIT_STACK) */
+#endif /* defined(__unix__) */
+}
Index: src/vfile.c
==================================================================
--- src/vfile.c
+++ src/vfile.c
@@ -796,11 +796,11 @@
/*
** Do a file-by-file comparison of the content of the repository and
** the working check-out on disk. Report any errors.
*/
void vfile_compare_repository_to_disk(int vid){
- int rc;
+ sqlite3_int64 rc;
Stmt q;
Blob disk, repo;
char *zOut;
db_must_be_within_tree();
Index: src/wikiformat.c
==================================================================
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1065,26 +1065,26 @@
/*
** If the input string corresponds to an existing baseline,
** return true.
*/
-static int is_valid_uuid(const char *z){
+static int is_valid_hname(const char *z){
int n = strlen(z);
if( n<4 || n>HNAME_MAX ) return 0;
if( !validate16(z, n) ) return 0;
return 1;
}
/*
-** Return TRUE if a UUID corresponds to an artifact in this
+** Return TRUE if a hash name corresponds to an artifact in this
** repository.
*/
static int in_this_repo(const char *zUuid){
static Stmt q;
int rc;
int n;
- char zU2[UUID_SIZE+1];
+ char zU2[HNAME_MAX+1];
db_static_prepare(&q,
"SELECT 1 FROM blob WHERE uuid>=:u AND uuid<:u2"
);
db_bind_text(&q, ":u", zUuid);
n = (int)strlen(zUuid);
@@ -1216,13 +1216,13 @@
&& (zTarget[1]=='/' || (zTarget[1]=='.' && zTarget[2]=='/'))
&& (p->state & WIKI_LINKSONLY)==0 ){
blob_appendf(p->pOut, "", zTarget);
}else if( zTarget[0]=='#' ){
blob_appendf(p->pOut, "", zTarget);
- }else if( is_valid_uuid(zTarget) ){
+ }else if( is_valid_hname(zTarget) ){
int isClosed = 0;
- if( is_ticket(zTarget, &isClosed) ){
+ if( strlen(zTarget)<=UUID_SIZE && is_ticket(zTarget, &isClosed) ){
/* Special display processing for tickets. Display the hyperlink
** as crossed out if the ticket is closed.
*/
if( isClosed ){
if( g.perm.Hyperlink ){
@@ -1839,11 +1839,11 @@
zTarget = &z[1];
for(i=0; zTarget[i] && zTarget[i]!='|' && zTarget[i]!=']'; i++){}
while(i>1 && zTarget[i-1]==' '){ i--; }
c = zTarget[i];
zTarget[i] = 0;
- if( is_valid_uuid(zTarget) ){
+ if( is_valid_hname(zTarget) ){
memcpy(zLink, zTarget, i+1);
canonical16(zLink, i);
db_multi_exec(
"REPLACE INTO backlink(target,srctype,srcid,mtime)"
"VALUES(%Q,%d,%d,%g)", zLink, srctype, srcid, mtime
Index: src/winhttp.c
==================================================================
--- src/winhttp.c
+++ src/winhttp.c
@@ -306,10 +306,11 @@
SOCKADDR_IN addr;
int idCnt = 0;
int iPort = mnPort;
Blob options;
wchar_t zTmpPath[MAX_PATH];
+ const char *zSkin;
#if USE_SEE
const char *zSavedKey = 0;
size_t savedKeySize = 0;
#endif
@@ -330,10 +331,14 @@
blob_appendf(&options, " --th-trace");
}
if( flags & HTTP_SERVER_REPOLIST ){
blob_appendf(&options, " --repolist");
}
+ zSkin = skin_in_use();
+ if( zSkin ){
+ blob_appendf(&options, " --skin %s", zSkin);
+ }
#if USE_SEE
zSavedKey = db_get_saved_encryption_key();
savedKeySize = db_get_saved_encryption_key_size();
if( zSavedKey!=0 && savedKeySize>0 ){
blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
Index: src/zip.c
==================================================================
--- src/zip.c
+++ src/zip.c
@@ -500,22 +500,26 @@
/*
** WEBPAGE: zip
** URL: /zip
**
-** Generate a ZIP archive for the check-in specified by the "uuid"
+** Generate a ZIP archive for the check-in specified by the "r"
** query parameter. Return that ZIP archive as the HTTP reply content.
**
** Query parameters:
**
** name=NAME[.zip] The base name of the output file. The default
** value is a configuration parameter in the project
** settings. A prefix of the name, omitting the
** extension, is used as the top-most directory name.
**
-** uuid=TAG The check-in that is turned into a ZIP archive.
-** Defaults to "trunk".
+** r=TAG The check-in that is turned into a ZIP archive.
+** Defaults to "trunk". This query parameter used to
+** be called "uuid" and the older "uuid" name is still
+** accepted for backwards compatibility. If this
+** query paramater is omitted, the latest "trunk"
+** check-in is used.
**
** in=PATTERN Only include files that match the comma-separate
** list of GLOB patterns in PATTERN, as with ex=
**
** ex=PATTERN Omit any file that match PATTERN. PATTERN is a
@@ -523,10 +527,11 @@
** pattern can optionally be quoted using ".." or '..'.
** Any file matching both ex= and in= is excluded.
*/
void baseline_zip_page(void){
int rid;
+ const char *z;
char *zName, *zRid, *zKey;
int nName, nRid;
const char *zInclude; /* The in= query parameter */
const char *zExclude; /* The ex= query parameter */
Blob cacheKey; /* The key to cache */
@@ -537,11 +542,14 @@
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
load_control();
zName = mprintf("%s", PD("name",""));
nName = strlen(zName);
- zRid = mprintf("%s", PD("uuid","trunk"));
+ z = P("r");
+ if( z==0 ) z = P("uuid");
+ if( z==0 ) z = "trunk";
+ zRid = fossil_strdup(z);
nRid = strlen(zRid);
zInclude = P("in");
if( zInclude ) pInclude = glob_create(zInclude);
zExclude = P("ex");
if( zExclude ) pExclude = glob_create(zExclude);
@@ -557,12 +565,13 @@
zName[nName] = 0;
break;
}
}
}
- rid = name_to_typed_rid(nRid?zRid:zName, "ci");
- if( rid==0 ){
+ rid = symbolic_name_to_rid(nRid?zRid:zName, "ci");
+ if( rid<=0 ){
+ cgi_set_status(404, "Not Found");
@ Not found
return;
}
if( nRid==0 && nName>10 ) zName[10] = 0;
Index: test/amend.test
==================================================================
--- test/amend.test
+++ test/amend.test
@@ -16,14 +16,10 @@
############################################################################
#
# Tests for the "amend" command.
#
-proc short_uuid {uuid {len 10}} {
- string range $uuid 0 $len-1
-}
-
proc artifact_from_timeline {res var} {
upvar $var artid
regexp {(?x)[0-9]{2}(?::[0-9]{2}){2}\s+\[([0-9a-f]+)]} $res m artid
}
@@ -31,16 +27,16 @@
string map [list { } {\\s} \n {\\n} \r {\\r}] $comment
}
proc uuid_from_commit {res var} {
upvar $var UUID
- regexp {^New_Version: ([0-9a-f]{40})$} $res m UUID
+ regexp {^New_Version: ([0-9a-f]{40})[0-9a-f]*$} $res m UUID
}
proc uuid_from_branch {res var} {
upvar $var UUID
- regexp {^New branch: ([0-9a-f]{40})$} $res m UUID
+ regexp {^New branch: ([0-9a-f]{40})[0-9a-f]*$} $res m UUID
}
proc uuid_from_checkout {var} {
global RESULT
upvar $var UUID
@@ -117,11 +113,11 @@
[string match "*Change*background*color*to*\"$result\"*" $RESULT]
}
if {[artifact_from_timeline $RESULT artid]} {
fossil artifact $artid
test amend-bgcolor-1.$tc.d {
- [string match "*T +bgcolor $UUID $result*" $RESULT]
+ [string match "*T +bgcolor $UUID* $result*" $RESULT]
}
} else {
if {$VERBOSE} { protOut "No artifact found in timeline output" }
test amend-bgcolor-1.$tc.d false
}
@@ -161,11 +157,11 @@
[string match {*Change*branch*background*color*to*"yellow".*} $RESULT]
}
if {[regexp {(?x)[0-9]{2}(?::[0-9]{2}){2}\s+\[([0-9a-f]+)]} $RESULT m artid]} {
fossil artifact $artid
test amend-branchcolor-1.4 {
- [string match "*T \*bgcolor $UUID2 yellow*" $RESULT]
+ [string match "*T \*bgcolor $UUID2* yellow*" $RESULT]
}
} else {
if {$VERBOSE} { protOut "No artifact found in timeline output" }
test amend-branchcolor-1.4 false
}
@@ -351,11 +347,11 @@
}
fossil timeline -n 1
if {[artifact_from_timeline $RESULT artid]} {
fossil artifact $artid
test amend-comment-$name.2 {
- [string match "*T +comment $UUID *[manifest_comment $comment]*" $RESULT]
+ [string match "*T +comment $UUID* *[manifest_comment $comment]*" $RESULT]
}
} else {
if {$VERBOSE} { protOut "No artifact found in timeline output: $RESULT" }
test amend-comment-$name.2 false
}
Index: test/commit-warning.test
==================================================================
--- test/commit-warning.test
+++ test/commit-warning.test
@@ -16,102 +16,247 @@
############################################################################
#
# The focus of this file is to test pre-commit warnings.
#
-test_setup ""
+test_setup
+
+# binary
+write_file binary "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+
+# text with CRLF lines
+write_file crlf.txt [subst -nocommands -novariables \
+{ordinary text\r
+cariage returns and line feeds\r
+on several lines\r\n}]
+
+# text with mixed line endings
+write_file cr-only.txt "AAA\rBBB\rCCC\r"
+write_file cr-lf-crlf.txt "AAA\rBBB\nCCC\r\n"
+
+# unix plain text includes the empty file by generalization
+write_file empty ""
+write_file plain.txt {
+Lorem ipsum
+dolor sic amet
+}
+
+# try long lines
+set a3 "abcdefgh"
+set a4 $a3$a3
+set a5 $a4$a4
+set a6 $a5$a5
+write_file line-0064 "$a6\n"
+set a7 $a6$a6
+set a8 $a7$a7
+set a9 $a8$a8
+set a10 $a9$a9
+write_file line-1024 "$a10\n"
+set a11 $a10$a10
+set a12 $a11$a11
+write_file line-4096 "$a12\n"
+set a13 $a12$a12
+write_file line-8192 "$a13\n"
+set a14 $a13$a13
+set a15 $a14$a14
+set a16 $a15$a15
+write_file line-64K "$a16\n"
+
+# UTF-8 extends 7-bit ASCII using bytes 80 and above to encode
+# larger character codes. Unicode uses U+0 through U+10FFFF only,
+# with U+D800 through U+DFFF reserved for surrogate pairs.
+# UTF-8 is valid if it is the shortest possible coding, encodes a
+# valid Unicode code point. But it's complicated.
+write_file utf-mod-c0-80 "11 bit NUL:\xC0\x80 is sometimes ok\n"
+write_file utf-bad-e0-80-80 "16 bit NUL:\xE0\x80\x80 is bad\n"
+write_file utf-bad-f0-80-80-80 "21 bit NUL:\xF0\x80\x80\x80 is bad\n"
+write_file utf-bad-f8-80-80-80-80 "26 bit NUL:\xF8\x80\x80\x80\x80 is bad\n"
+write_file utf-bad-fc-80-80-80-80-80 "31 bit NUL:\xFC\x80\x80\x80\x80\x80 is bad\n"
+write_file utf-bad-fe-80-80-80-80-80-80 "36 bit NUL:\xFC\x80\x80\x80\x80\x80 is bad\n"
+write_file utf-bad-c0-81 "overlong SOH:\xC0\x81 is bad\n"
+write_file utf-bad-c0-bf "overlong '?':\xC0\xBF is bad\n"
+write_file utf-bad-c1-bf "overlong DEL:\xC1\xBF is bad\n"
+write_file utf-bad-f4-90-80-80 "U+110000 not allowed:\xF4\x90\x80 not unicode\n"
+write_file utf-bad-f9-80-80-80-80 "U+2000000 not allowed:\xF9\x80\x80\x80\x80 not unicode\n"
+write_file utf-bad-ff "no byte FF:\xFF\n"
+write_file utf-ill16-lead "lead surrogate U+D800:\xED\xA0\x80 is ill formed\n"
+write_file utf-ill16-trail "trail surrogate U+DC00:\xED\xB0\x80 is ill formed\n"
+write_file utf-ill16-pair "surrogate pair U+10000:\xED\xA0\x80\xED\xB0\x80 is ill formed\n"
+set emoji "micro-smile \xC2\xB5\xE2\x98\xBA\npale facepalm \xF0\x9F\xA4\xA6\xF0\x9F\x8F\xBB\n"
+protOut $emoji
+write_file utf-8-emoji $emoji
+write_file utf-8-bom-emoji "\xef\xbb\xbf$emoji"
+
+# UTF-16 uses 16-bit values to cover all valid unicode code points
+# from U+0 to U+10FFFF, using surrogate pairs to escape the BMP.
+# Interchange require knowing (and preserving) byte order.
+set hello16LE "h\x00e\x00l\x00l\x00o\x00\n\x00"
+set hello16BE "\x00h\x00e\x00l\x00l\x00o\x00\n"
+write_file utf-16le-hello $hello16LE
+write_file utf-16be-hello $hello16BE
+set bomLE "\xff\xfe"
+set bomBE "\xfe\xff"
+write_file utf-16le-bomle-hello "$bomLE$hello16LE"
+write_file utf-16be-bombe-hello "$bomBE$hello16BE"
+write_file utf-16le-bombe-hello "$bomBE$hello16LE"
+write_file utf-16be-bomle-hello "$bomLE$hello16BE"
+set le16 [read_file [file join $testdir utf16le.txt]]
+set be16 [read_file [file join $testdir utf16be.txt]]
+write_file utf-16le.txt $le16
+write_file utf-16be.txt $be16
+write_file utf-nobom-16le.txt [string range $le16 2 end]
+write_file utf-nobom-16be.txt [string range $be16 2 end]
+#write_file [file join $::env(TEMP) utf-nobom-16le.txt] [string range $le16 2 end]
+#write_file [file join $::env(TEMP) utf-nobom-16be.txt] [string range $be16 2 end]
+
+# make all the test files known to fossil, then test
+fossil addremove
+fossil test-commit-warning --no-settings -v
+test pre-commit-warnings-1 {[normalize_result] eq \
+ [subst -nocommands -novariables [string trim {
+1\tbinary\tbinary data
+1\tcr-lf-crlf.txt\tmixed line endings
+1\tcr-only.txt\tCR line endings
+1\tcrlf.txt\tCR/LF line endings
+0\tempty\t
+0\tline-0064\t
+0\tline-1024\t
+0\tline-4096\t
+1\tline-64K\tlong lines
+1\tline-8192\tlong lines
+0\tplain.txt\t
+1\tutf-16be-bombe-hello\tUnicode
+1\tutf-16be-bomle-hello\tUnicode
+1\tutf-16be-hello\tbinary data
+1\tutf-16be.txt\tUnicode
+1\tutf-16le-bombe-hello\tUnicode
+1\tutf-16le-bomle-hello\tUnicode
+1\tutf-16le-hello\tbinary data
+1\tutf-16le.txt\tUnicode
+0\tutf-8-bom-emoji\t
+0\tutf-8-emoji\t
+1\tutf-bad-c0-81\tinvalid UTF-8
+1\tutf-bad-c0-bf\tinvalid UTF-8
+1\tutf-bad-c1-bf\tinvalid UTF-8
+1\tutf-bad-e0-80-80\tinvalid UTF-8
+1\tutf-bad-f0-80-80-80\tinvalid UTF-8
+1\tutf-bad-f4-90-80-80\tinvalid UTF-8
+1\tutf-bad-f8-80-80-80-80\tinvalid UTF-8
+1\tutf-bad-f9-80-80-80-80\tinvalid UTF-8
+1\tutf-bad-fc-80-80-80-80-80\tinvalid UTF-8
+1\tutf-bad-fe-80-80-80-80-80-80\tinvalid UTF-8
+1\tutf-bad-ff\tinvalid UTF-8
+0\tutf-ill16-lead\t
+0\tutf-ill16-pair\t
+0\tutf-ill16-trail\t
+0\tutf-mod-c0-80\t
+1\tutf-nobom-16be.txt\tbinary data
+1\tutf-nobom-16le.txt\tbinary data
+1}]]}
+
###############################################################################
+# TODO: Change to a collection of test-case crafted files
+# rather than depend on this list of files that will
+# be fragile as development progresses.
+#
+# Unless the real goal of this test is to document a collection
+# of source files that MUST NEVER BE TEXT.
+#
run_in_checkout {
- fossil test-commit-warning
+ fossil test-commit-warning --no-settings
}
-test pre-commit-warnings-1 {[normalize_result] eq \
+test pre-commit-warnings-fossil-1 {[normalize_result] eq \
[subst -nocommands -novariables [string trim {
1\tart/branching.odp\tbinary data
1\tart/concept1.dia\tbinary data
1\tart/concept2.dia\tbinary data
-1\tcompat/zlib/ChangeLog\tinvalid UTF-8
-1\tcompat/zlib/contrib/README.contrib\tinvalid UTF-8
1\tcompat/zlib/contrib/blast/test.pk\tbinary data
-1\tcompat/zlib/contrib/dotzlib/DotZLib.build\tCR/NL line endings
+1\tcompat/zlib/contrib/dotzlib/DotZLib.build\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/DotZLib.chm\tbinary data
-1\tcompat/zlib/contrib/dotzlib/DotZLib.sln\tCR/NL line endings
-1\tcompat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs\tCR/NL line endings
-1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj\tCR/NL line endings
-1\tcompat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs\tCR/NL line endings
-1\tcompat/zlib/contrib/dotzlib/LICENSE_1_0.txt\tCR/NL line endings
-1\tcompat/zlib/contrib/dotzlib/readme.txt\tCR/NL line endings
-1\tcompat/zlib/contrib/gcc_gvmat64/gvmat64.S\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx64/bld_ml64.bat\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx64/gvmat64.asm\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx64/inffas8664.c\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx64/inffasx64.asm\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx64/readme.txt\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx86/bld_ml32.bat\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx86/inffas32.asm\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx86/match686.asm\tCR/NL line endings
-1\tcompat/zlib/contrib/masmx86/readme.txt\tCR/NL line endings
+1\tcompat/zlib/contrib/dotzlib/DotZLib.sln\tCR/LF line endings
+1\tcompat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs\tCR/LF line endings
+1\tcompat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/Deflater.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj\tCR/LF line endings
+1\tcompat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/Inflater.cs\tinvalid UTF-8
+1\tcompat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs\tCR/LF line endings
+1\tcompat/zlib/contrib/dotzlib/LICENSE_1_0.txt\tCR/LF line endings
+1\tcompat/zlib/contrib/dotzlib/readme.txt\tCR/LF line endings
+1\tcompat/zlib/contrib/gcc_gvmat64/gvmat64.S\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx64/bld_ml64.bat\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx64/gvmat64.asm\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx64/inffas8664.c\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx64/inffasx64.asm\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx64/readme.txt\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx86/bld_ml32.bat\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx86/inffas32.asm\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx86/match686.asm\tCR/LF line endings
+1\tcompat/zlib/contrib/masmx86/readme.txt\tCR/LF line endings
1\tcompat/zlib/contrib/puff/zeros.raw\tbinary data
-1\tcompat/zlib/contrib/testzlib/testzlib.c\tCR/NL line endings
-1\tcompat/zlib/contrib/testzlib/testzlib.txt\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/readme.txt\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.user\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj.user\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.user\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.user\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlib.rc\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.user\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.def\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.sln\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.user\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/miniunz.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/minizip.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/testzlib.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/testzlibdll.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/zlib.rc\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/zlibstat.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.def\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.sln\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.vcxproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/miniunz.vcproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/minizip.vcproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/testzlib.vcproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/testzlibdll.vcproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/zlib.rc\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/zlibstat.vcproj\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.def\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.sln\tCR/NL line endings
-1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.vcproj\tCR/NL line endings
+1\tcompat/zlib/contrib/testzlib/testzlib.c\tCR/LF line endings
+1\tcompat/zlib/contrib/testzlib/testzlib.txt\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/readme.txt\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlib.rc\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.def\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.sln\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/miniunz.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/minizip.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/testzlib.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/testzlibdll.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/zlib.rc\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/zlibstat.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.def\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.sln\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.vcxproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc12/zlibvc.def\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc14/zlibvc.def\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/miniunz.vcproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/minizip.vcproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/testzlib.vcproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/testzlibdll.vcproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/zlib.rc\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/zlibstat.vcproj\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.def\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.sln\tCR/LF line endings
+1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.vcproj\tCR/LF line endings
+1\tcompat/zlib/win32/zlib.def\tCR/LF line endings
1\tcompat/zlib/zlib.3.pdf\tbinary data
-1\tsetup/fossil.iss\tCR/NL line endings
+1\tcompat/zlib/zlib.map\tCR/LF line endings
+1\tsetup/fossil.iss\tCR/LF line endings
1\tskins/blitz/arrow_project.png\tbinary data
1\tskins/blitz/dir.png\tbinary data
1\tskins/blitz/file.png\tbinary data
1\tskins/blitz/fossil_100.png\tbinary data
1\tskins/blitz/fossil_80_reversed_darkcyan.png\tbinary data
1\tskins/blitz/fossil_80_reversed_darkcyan_text.png\tbinary data
1\tskins/blitz/rss_20.png\tbinary data
-1\ttest/th1-docs-input.txt\tCR/NL line endings
-1\ttest/th1-hooks-input.txt\tCR/NL line endings
+1\ttest/th1-docs-input.txt\tCR/LF line endings
+1\ttest/th1-hooks-input.txt\tCR/LF line endings
1\ttest/utf16be.txt\tUnicode
1\ttest/utf16le.txt\tUnicode
-1\twin/buildmsvc.bat\tCR/NL line endings
+1\twin/buildmsvc.bat\tCR/LF line endings
1\twin/fossil.ico\tbinary data
+1\twin/fossil.rc\tinvalid UTF-8
1\twww/CollRev1.gif\tbinary data
1\twww/CollRev2.gif\tbinary data
1\twww/CollRev3.gif\tbinary data
1\twww/CollRev4.gif\tbinary data
1\twww/apple-touch-icon.png\tbinary data
Index: test/json.test
==================================================================
--- test/json.test
+++ test/json.test
@@ -133,10 +133,14 @@
}
# Inspect a dict for keys it must have and keys it must not have
proc test_dict_keys {testname D okfields badfields} {
+ if {$D eq ""} {
+ test $testname-validJSON 0
+ return
+ }
set i 1
foreach f $okfields {
test "$testname-$i" {[dict exists $D $f]}
incr i
}
@@ -201,10 +205,12 @@
#### ARTIFACT
# sha1 of 0 bytes and a file to match in a commit
set UUID_empty da39a3ee5e6b4b0d3255bfef95601890afd80709
+# sha3 of 0 bytes and a file to match in a commit
+set UUID_empty_64 a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a
write_file empty ""
fossil add empty
fossil ci -m "empty file"
# json artifact (checkin)
@@ -213,11 +219,11 @@
test json-artifact-checkin {[dict get $JR payload type] eq "checkin"}
test_json_payload json-artifact \
[concat type uuid isLeaf timestamp user comment parents tags files] {}
# json artifact (file)
-fossil_json [concat artifact $UUID_empty]
+fossil_json [concat artifact $UUID_empty_64]
test_json_envelope_ok json-artifact-file-env
test json-artifact-file {[dict get $JR payload type] eq "file"}
test_json_payload json-artifact [concat type uuid size checkins] {}
# json artifact (wiki)
@@ -740,24 +746,34 @@
{
"command":"no/such/endpoint"
}
}
fossil_json --json-input e1102.json -expectError
-test json-env-RC-1102-CLI-exit {$CODE != 0}
-test_json_envelope json-env-RC-1102-env {fossil timestamp command procTimeUs \
+test json-env-RC-1102a-CLI-exit {$CODE != 0}
+test_json_envelope json-env-RC-1102a-env {fossil timestamp command procTimeUs \
procTimeMs resultCode resultText} {payload}
-test json-env-RC-1102-code {[dict get $JR resultCode] eq "FOSSIL-1102"}
+test json-env-RC-1102a-code {[dict get $JR resultCode] eq "FOSSIL-1102"}
# FOSSIL-1103 FSL_JSON_E_UNKNOWN
# Unknown error
-#write_file bad.sql {
-#CREATE TABLE spam(a integer, b text);
-#}
-#exec $::fossilexe sqlite3 --no-repository bad.fossil An Example HTML Readme
+
+
+The test/subdir/ directory and its children exist purely for testing
+in the self-hosting Fossil repository. This particular file is used
+to verify that a file name "README.html" is displayed correctly.
+beneath the directory listing.
+
+
+
+
+
ADDED test/subdir/one/readme.wiki
Index: test/subdir/one/readme.wiki
==================================================================
--- /dev/null
+++ test/subdir/one/readme.wiki
@@ -0,0 +1,9 @@
+Fossil Wiki Readme
+
+This is another test README file. The point of this file is to show that
+lower-case "readme" is recognized, and the Fossil-Wiki formatting is
+displayed correctly.
+
+ * First bullet
+
+ * Second bullet
Index: test/tester.tcl
==================================================================
--- test/tester.tcl
+++ test/tester.tcl
@@ -112,10 +112,21 @@
fconfigure $out -translation platform
puts $out $msg
close $out
}
}
+
+# write a dict with just enough formatting
+# to make it human readable
+#
+proc protOutDict {dict {pattern *}} {
+ set longest [tcl::mathfunc::max 0 {*}[lmap key [dict keys $dict $pattern] {string length $key}]]
+ dict for {key value} $dict {
+ protOut [format "%-${longest}s = %s" $key $value]
+ }
+}
+
# Run the Fossil program with the specified arguments.
#
# Consults the VERBOSE global variable to determine if
# diagnostics should be emitted when no error is seen.
@@ -326,10 +337,33 @@
regsub -all { +\n} $x \n x
set y [read_file $b]
regsub -all { +\n} $y \n y
return [expr {$x==$y}]
}
+
+# Return true if two strings refer to the
+# same uuid. That is, the shorter is a prefix
+# of the longer.
+#
+proc same_uuid {a b} {
+ set na [string length $a]
+ set nb [string length $b]
+ if {$na == $nb} {
+ return [expr {$a eq $b}]
+ }
+ if {$na < $nb} then {
+ return [string match "$a*" $b]
+ }
+ return [string match "$b*" $a]
+}
+
+# Return a prefix of a uuid, defaulting to 10 chars.
+#
+proc short_uuid {uuid {len 10}} {
+ string range $uuid 0 $len-1
+}
+
proc require_no_open_checkout {} {
if {[info exists ::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT)] && \
$::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT) eq "YES_DO_IT"} {
return
@@ -936,16 +970,23 @@
file mkdir $tempHomePath
} error] != 0} {
error "Could not make directory \"$tempHomePath\",\
please set TEMP variable in environment, error: $error"
}
+
protInit $fossilexe
set ::tempKeepHome 1
foreach testfile $argv {
protOut "***** $testfile ******"
- source $testdir/$testfile.test
+ if { [catch {source $testdir/$testfile.test} testerror testopts] } {
+ test test-framework-$testfile 0
+ protOut "!!!!! $testfile: $testerror"
+ protOutDict $testopts"
+ } else {
+ test test-framework-$testfile 1
+ }
protOut "***** End of $testfile: [llength $bad_test] errors so far ******"
}
unset ::tempKeepHome; delete_temporary_home
set nErr [llength $bad_test]
if {$nErr>0 || !$::QUIET} {
Index: test/th1-docs.test
==================================================================
--- test/th1-docs.test
+++ test/th1-docs.test
@@ -61,11 +61,11 @@
set RESULT [test_fossil_http \
$repository $dataFileName /doc/trunk/test/fileStat.th1]
}
test th1-docs-1a {[regexp {Fossil: test/fileStat.th1} $RESULT]}
-test th1-docs-1b {[regexp {>\[[0-9a-f]{40}\]<} $RESULT]}
+test th1-docs-1b {[regexp {>\[[0-9a-f]{40,64}\]<} $RESULT]}
test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]}
###############################################################################
test_cleanup
Index: test/th1.test
==================================================================
--- test/th1.test
+++ test/th1.test
@@ -852,11 +852,11 @@
run_in_checkout {
fossil test-th-eval --open-config "artifact tip"
}
-test th1-artifact-3 {[regexp -- {F test/th1\.test [0-9a-f]{40}} $RESULT]}
+test th1-artifact-3 {[regexp -- {F test/th1\.test [0-9a-f]{40,64}} $RESULT]}
###############################################################################
fossil test-th-eval "artifact 0000000000"
test th1-artifact-4 {$RESULT eq {TH_ERROR: repository unavailable}}
@@ -1504,10 +1504,23 @@
}}}
###############################################################################
+# Verify that quoted delimiters like * and _ don't terminate their
+# span. This was fixed by checkin [dd41f85acf].
+fossil test-th-eval {markdown "*This is\\*a test.*\n_second\\_test_"}
+test th1-markdown-6 {[normalize_result] eq {{} {
+
+
This is*a test.
+second_test
+
+
+}}}
+
+###############################################################################
+
fossil test-th-eval {encode64 test}
test th1-encode64-1 {$RESULT eq "dGVzdA=="}
###############################################################################
@@ -1565,42 +1578,26 @@
test th1-source-1 {$RESULT eq {TH_RETURN: 0 1 2 3 4 5 6 7 8 9}}
file delete $th1FileName
###############################################################################
-#
-# TODO: Modify the result of this test if the list of unversioned files
-# changes.
-#
-run_in_checkout {
- fossil test-th-eval --open-config "unversioned list"
-}
-
-test th1-unversioned-1 {[normalize_result] eq \
-{build-icons/linux.gif build-icons/linux64.gif build-icons/mac.gif\
-build-icons/openbsd.gif build-icons/src.gif build-icons/win32.gif\
-download.html download/fossil-linux-x86-1.32.zip\
-download/fossil-linux-x86-1.33.zip download/fossil-linux-x86-1.34.zip\
-download/fossil-linux-x86-1.35.zip download/fossil-macosx-x86-1.32.zip\
-download/fossil-macosx-x86-1.33.zip download/fossil-macosx-x86-1.34.zip\
-download/fossil-macosx-x86-1.35.zip download/fossil-openbsd-x86-1.32.zip\
-download/fossil-openbsd-x86-1.33.zip download/fossil-openbsd-x86-1.34.tar.gz\
-download/fossil-openbsd-x86-1.35.tar.gz download/fossil-src-1.32.tar.gz\
-download/fossil-src-1.33.tar.gz download/fossil-src-1.34.tar.gz\
-download/fossil-src-1.35.tar.gz download/fossil-w32-1.32.zip\
-download/fossil-w32-1.33.zip download/fossil-w32-1.34.zip\
-download/fossil-w32-1.35.zip download/releasenotes-1.32.html\
-download/releasenotes-1.33.html download/releasenotes-1.34.html\
-download/releasenotes-1.35.html index.wiki}}
-
-###############################################################################
-
-run_in_checkout {
- fossil test-th-eval --open-config \
- {string length [unversioned content build-icons/src.gif]}
-}
-
-test th1-unversioned-2 {$RESULT eq {4592}}
+# Tests for the TH1 unversioned command require at least one
+# unversioned file in the repository. All tests run in a freshly
+# created checkout of a freshly created repo, so we can just
+# create a file or two for the purpose.
+write_file ten.txt "0123456789"
+fossil unversioned add ten.txt
+fossil unversioned list
+
+# unversioned list
+fossil test-th-eval --open-config "unversioned list"
+test th1-unversioned-1 {[normalize_result] eq {ten.txt}}
+
+# unversioned content
+fossil test-th-eval --open-config \
+ {string length [unversioned content ten.txt]}
+test th1-unversioned-2 {$RESULT eq {10}}
+
###############################################################################
test_cleanup
Index: test/unversioned.test
==================================================================
--- test/unversioned.test
+++ test/unversioned.test
@@ -240,19 +240,19 @@
{962f96ebd613e4fdd9aa2d20bd9fe21a64e925f2}}
###############################################################################
fossil unversioned hash
-test unversioned-36 {[regexp {^[0-9a-f]{40}$} [normalize_result]]}
+test unversioned-36 {[regexp {^[0-9a-f]{40,64}$} [normalize_result]]}
###############################################################################
fossil unversioned hash --debug
test unversioned-37 {[regexp \
-{^unversioned2\.txt 2016-10-01 00:00:00 [0-9a-f]{40}
-unversioned4\.txt 2016-10-01 00:00:00 [0-9a-f]{40}
-[0-9a-f]{40}$} [normalize_result]]}
+{^unversioned2\.txt 2016-10-01 00:00:00 [0-9a-f]{40,64}
+unversioned4\.txt 2016-10-01 00:00:00 [0-9a-f]{40,64}
+[0-9a-f]{40,64}$} [normalize_result]]}
###############################################################################
fossil unversioned remove unversioned4.txt --mtime "2016-10-02 13:47:29"
test unversioned-38 {[normalize_result] eq {}}
Index: win/Makefile.PellesCGMake
==================================================================
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -83,11 +83,11 @@
# define the SQLite files, which need special flags on compile
SQLITESRC=sqlite3.c
ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf))
SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj))
-SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_WIN32_NO_ANSI
+SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_WIN32_NO_ANSI
# define the SQLite shell files, which need special flags on compile
SQLITESHELLSRC=shell.c
ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf))
SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj))
Index: win/Makefile.dmc
==================================================================
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,11 +24,11 @@
CFLAGS = -o
BCC = $(DMDIR)\bin\dmc $(CFLAGS)
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
-SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
+SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
Index: win/Makefile.mingw
==================================================================
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -225,11 +225,11 @@
# run on the target platform. This is usually the almost the same
# as BCC, unless you are cross-compiling. This C compiler builds
# the finished binary for fossil. The BCC compiler above is used
# for building intermediate code-generator tools.
#
-TCC = $(PREFIX)$(TCCEXE) -Wall
+TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement
#### Add the necessary command line options to build with debugging
# symbols, if enabled.
#
ifdef FOSSIL_ENABLE_SYMBOLS
@@ -980,11 +980,11 @@
SQLITE3_SHELL_SRC.0 = shell.c
SQLITE3_SHELL_SRC.1 = shell-see.c
SQLITE3_SHELL_SRC. = shell.c
SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE))
SEE_FLAGS.0 =
-SEE_FLAGS.1 = -DSQLITE_HAS_CODEC
+SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key
SEE_FLAGS. =
SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE))
EXTRAOBJ = \
@@ -2208,10 +2208,11 @@
-DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS \
-DSQLITE_OMIT_DECLTYPE \
-DSQLITE_OMIT_DEPRECATED \
+ -DSQLITE_OMIT_GET_TABLE \
-DSQLITE_OMIT_PROGRESS_CALLBACK \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_MAX_EXPR_DEPTH=0 \
-DSQLITE_USE_ALLOCA \
@@ -2250,11 +2251,11 @@
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
$(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw
- $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SQLITE3_SHELL_SRC) -o $@
+ $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) -o $@
$(OBJDIR)/th.o: $(SRCDIR)/th.c
$(XTCC) -c $(SRCDIR)/th.c -o $@
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
Index: win/Makefile.mingw.mistachkin
==================================================================
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -225,11 +225,11 @@
# run on the target platform. This is usually the almost the same
# as BCC, unless you are cross-compiling. This C compiler builds
# the finished binary for fossil. The BCC compiler above is used
# for building intermediate code-generator tools.
#
-TCC = $(PREFIX)$(TCCEXE) -Wall
+TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement
#### Add the necessary command line options to build with debugging
# symbols, if enabled.
#
ifdef FOSSIL_ENABLE_SYMBOLS
@@ -980,11 +980,11 @@
SQLITE3_SHELL_SRC.0 = shell.c
SQLITE3_SHELL_SRC.1 = shell-see.c
SQLITE3_SHELL_SRC. = shell.c
SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE))
SEE_FLAGS.0 =
-SEE_FLAGS.1 = -DSQLITE_HAS_CODEC
+SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key
SEE_FLAGS. =
SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE))
EXTRAOBJ = \
@@ -2208,10 +2208,11 @@
-DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS \
-DSQLITE_OMIT_DECLTYPE \
-DSQLITE_OMIT_DEPRECATED \
+ -DSQLITE_OMIT_GET_TABLE \
-DSQLITE_OMIT_PROGRESS_CALLBACK \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_MAX_EXPR_DEPTH=0 \
-DSQLITE_USE_ALLOCA \
@@ -2250,11 +2251,11 @@
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
$(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw.mistachkin
- $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SQLITE3_SHELL_SRC) -o $@
+ $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) -o $@
$(OBJDIR)/th.o: $(SRCDIR)/th.c
$(XTCC) -c $(SRCDIR)/th.c -o $@
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
Index: win/Makefile.msc
==================================================================
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -318,10 +318,11 @@
/DSQLITE_DEFAULT_MEMSTATUS=0 \
/DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
/DSQLITE_LIKE_DOESNT_MATCH_BLOBS \
/DSQLITE_OMIT_DECLTYPE \
/DSQLITE_OMIT_DEPRECATED \
+ /DSQLITE_OMIT_GET_TABLE \
/DSQLITE_OMIT_PROGRESS_CALLBACK \
/DSQLITE_OMIT_SHARED_CACHE \
/DSQLITE_OMIT_LOAD_EXTENSION \
/DSQLITE_MAX_EXPR_DEPTH=0 \
/DSQLITE_USE_ALLOCA \
@@ -867,23 +868,21 @@
codecheck1$E: $(SRCDIR)\codecheck1.c
$(BCC) $**
!if $(USE_SEE)!=0
+SEE_FLAGS = /DSQLITE_HAS_CODEC=1 /DSQLITE_SHELL_DBKEY_PROC=fossil_key
SQLITE3_SHELL_SRC = $(SRCDIR)\shell-see.c
+SQLITE3_SRC = $(SRCDIR)\sqlite3-see.c
!else
+SEE_FLAGS =
SQLITE3_SHELL_SRC = $(SRCDIR)\shell.c
+SQLITE3_SRC = $(SRCDIR)\sqlite3.c
!endif
$(OX)\shell$O : $(SQLITE3_SHELL_SRC) $B\win\Makefile.msc
- $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SQLITE3_SHELL_SRC)
-
-!if $(USE_SEE)!=0
-SQLITE3_SRC = $(SRCDIR)\sqlite3-see.c
-!else
-SQLITE3_SRC = $(SRCDIR)\sqlite3.c
-!endif
+ $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC)
$(OX)\sqlite3$O : $(SQLITE3_SRC) $B\win\Makefile.msc
$(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) $(SQLITE3_SRC)
$(OX)\th$O : $(SRCDIR)\th.c
Index: win/include/unistd.h
==================================================================
--- win/include/unistd.h
+++ win/include/unistd.h
@@ -22,18 +22,18 @@
#ifndef X_OK
#define X_OK 1
#endif /* not X_OK */
+#ifndef W_OK
+#define W_OK 2
+#endif /* not W_OK */
+
#ifndef R_OK
-#define R_OK 2
+#define R_OK 4
#endif /* not R_OK */
-#ifndef W_OK
-#define W_OK 4
-#endif /* not W_OK */
-
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
ADDED www/aboutdownload.wiki
Index: www/aboutdownload.wiki
==================================================================
--- /dev/null
+++ www/aboutdownload.wiki
@@ -0,0 +1,92 @@
+How The Fossil Download Page Works
+How The Download Page Works
+
+1.0 Overview
+
+The [/uv/download.html|Download] page for the Fossil self-hosting
+repository is implemented using [./unvers.wiki|unversioned files].
+The "download.html" screen itself, and the various build products
+are all stored as unversioned content. The download.html page
+uses AJAX to retrieve the [/help?cmd=/juvlist|/juvlist] webpage
+for a list of all unversioned files. Javascript within the
+download.html page then figures out which unversioned files are
+build products and paints appropriate icons on the displayed
+download page.
+
+When a new version is generated, the developers use the
+[/help?cmd=uv|fossil uv edit] command to make minor changes
+to the "[/uv/download.html?mimetype=text/plain|download.html]"
+file so that it knows about the
+new version number. Then the developers run
+the [/help?cmd=uv|fossil uv add] command for each
+build product. Finally, the
+[/help?cmd=uv|fossil uv sync] command is run to push all
+the content up to servers. All
+[./selfhost.wiki|three self-hosting repositories] for Fossil
+are updated automatically.
+
+2.0 Details
+
+The current text of the "download.html" file can be seen
+[/uv/download.html?mimetype=text/plain|here]. (Mouse-over that
+hyperlink to see how the "mimetype=text/plain" query parameter
+is added in order to display the file as plain text instead of
+the usual HTML.) The default mimetype for "download.html" is
+text/html. But because the entire page is enclosed within
+
+
+ <div class='fossil-doc' data-title='Download Page'>...</div>
+
+Fossil knows to add its standard header and footer information to the
+document, making it look just like any other page. See
+"[./embeddeddoc.wiki|embedded documentation]" for further details on
+how this works.
+
+With each new release, the "releases" variable in the javascript on
+the [/uv/download.html?mimetype=text/plain|download.html] page is
+edited (using "[/help?cmd=uv|fossil uv edit download.html]") to add
+details of the release.
+
+When the javascript on the "download.html" page runs, it requests
+a listing of all unversioned content using the /juvlist URL.
+([/juvlist|sample /juvlist output]). The content of the download page is
+constructed by matching unversioned files against regular expressions
+in the "releases" variable.
+
+Build products need to be constructed on different machines. The precompiled
+binary for Linux is compiled on Linux, the precompiled binary for Windows
+is compiled on Windows10, and so forth. After a new release is tagged,
+the release manager goes around to each of the target platforms, checks
+out the release and compiles it, then runs
+[/help?cmd=uv|fossil uv add] for the build product followed by
+[/help?cmd=uv|fossil uv sync] to push the new build product to the
+[./selfhost.wiki|various servers]. This process is repeated for
+each build product.
+
+When older builds are retired from the download page, the
+[/uv/download.html?mimetype=text/plain|download.html] page is again
+edited to remove the corresponding entry from the "release" variable
+and the edit is synced using
+[/help?cmd=uv|fossil uv sync]. This causes the build products to
+disappear from the download page immediately. But those build products
+are still taking up space in the unversioned content table of the
+server repository. To purge the obsolete build products, one or
+more [/help?cmd=uv|fossil uv rm] commands are run, followed by
+another [/help?cmd=uv|fossil uv sync]. It is important to purge
+obsolete build products since they take up a lot of space.
+At [/repo-tabsize] you can see that the unversioned table takes up
+a substantial fraction of the repository.
+
+3.0 Security
+
+Only users with the [/setup_ulist_notes|"y" permission] are allowed
+to push unversioned content up to the servers. Having the ability
+to push check-ins (the [/setup_ulist_notes|"i" permission]) is not
+sufficient.
+
+On the Fossil project there are 67 people (as of 2017-03-24) who have
+check-in privileges. But only 3 core developers
+can push unversioned content and thus
+change the build products on the download page. Minimizing the number
+of people who can change the build products helps to ensure that
+rogue binaries do not slip onto the download page unnoticed.
Index: www/antibot.wiki
==================================================================
--- www/antibot.wiki
+++ www/antibot.wiki
@@ -89,11 +89,11 @@
the anchor tags with the hyperlink targets, thus enabling the hyperlinks.
This extra step of using javascript to enable the hyperlink targets
is a security measure against spiders that forge a human-looking
UserAgent string. Most spiders do not bother to run javascript and
so to the spider the empty anchor tag will be useless. But all modern
-web browsers implement javascript, so hyperlinks will appears
+web browsers implement javascript, so hyperlinks will show up
normally for human users.
Further defenses
Recently (as of this writing, in the spring of 2013) the Fossil server
@@ -129,10 +129,14 @@
to be run, thus will never enable the hyperlinks.
These two subsettings can be used separately or together. If used together,
then the delay timer does not start until after the first mouse movement
is detected.
+
+See also [./server.wiki#loadmgmt|Managing Server Load] for a description
+of how expensive pages can be disabled when the server is under heavy
+load.
The ongoing struggle
Fossil currently does a very good job of providing easy access to humans
while keeping out troublesome robots and spiders. However, spiders and
Index: www/changes.wiki
==================================================================
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,36 @@
Change Log
+
+Changes for Version 2.3 (2017-??-??)
+
+ * Update the built-in SQLite to version 3.19.2.
+ * Update internal Unicode character tables, used in regular expression
+ handling, from version 9.0 to 10.0.
+ * Show the last-sync-URL on the [/help?cmd=/urllist|/urllist] page.
+ * Fix "database locked" warnings caused by "PRAGMA optimize".
+ * Fix a potential XSS vulnerability on the
+ [/help?cmd=/help|/help] webpage.
+ * Documentation updates
+
+
+Changes for Version 2.2 (2017-04-11)
+
+ * GIT comment tags are now handled by Fossil during import/export.
+ * Show the content of README files on directory listings.
+ ([/file/skins|example])
+ * Support for Basic Authentication if enabled (default off).
+ * Show the hash algorithms used on the
+ [/help?cmd=/rcvfromlist|/rcvfromlist] page.
+ * The [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] pages
+ now use the the r= query parameter
+ to select which check-in to deliver. The uuid= query parameter
+ is still accepted for backwards compatibility.
+ * Update the built-in SQLite to version 3.18.0.
+ * Run "[https://www.sqlite.org/pragma.html#pragma_optimize|PRAGMA optimize]"
+ on the database connection as it is closing.
+
Changes for Version 2.1 (2017-03-10)
* Add support for [./hashpolicy.wiki|hash policies] that control which
of the Hardened-SHA1 or SHA3-256 algorithms is used to name new
@@ -26,11 +55,11 @@
Changes for Version 1.37 (2017-01-16)
* Add checkbox widgets to various web pages. See [/technote/8d18bf27e9|
this technote] for more information. To get the checkboxes to look as
- intended, you must update the CSS in your repository and all clones.
+ intended, you must update the CSS in your repository and all clones.
* Add the [/help/all|fossil all ui] command
* Add the [/help?cmd=/file|/file] webpage
* Enhance the [/help?cmd=/brlist|/brlist] webpage to make use of branch colors.
* Add support for the ms=EXACT|LIKE|GLOB|REGEXP query parameter on the
[/help?cmd=/timeline|/timeline] webpage, with associated form widgets.
Index: www/env-opts.md
==================================================================
--- www/env-opts.md
+++ www/env-opts.md
@@ -141,10 +141,16 @@
`FOSSIL_HOME`: Location of the `~/.fossil` file. The first environment
variable found in the environment from the list `FOSSIL_HOME`,
`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and
`HOMEPATH` (Windows, used together), and `HOME` is used as the
location of the `~/.fossil` file.
+
+
+`FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for
+SEE as text to be hashed into the actaul encryption key. This has no
+effect if Fossil was not compiled with SEE support enabled.
+
`FOSSIL_USER`: Name of the default user account if the checkout, local
or global `default-user` setting is not present. The first environment
variable found in the environment from the list `FOSSIL_USER`, `USER`,
`LOGNAME`, and `USERNAME` is the user name. If none of those are set,
ADDED www/globs.md
Index: www/globs.md
==================================================================
--- /dev/null
+++ www/globs.md
@@ -0,0 +1,540 @@
+# File Name Glob Patterns
+
+
+A [glob pattern][glob] is a text expression that matches one or more
+file names using wild cards familiar to most users of a command line.
+For example, `*` is a glob that matches any name at all and
+`Readme.txt` is a glob that matches exactly one file.
+
+Note that although both are notations for describing patterns in text,
+glob patterns are not the same thing as a [regular expression or
+regexp][regexp].
+
+[glob]: https://en.wikipedia.org/wiki/Glob_(programming) (Wikipedia)
+[regexp]: https://en.wikipedia.org/wiki/Regular_expression
+
+
+A number of fossil setting values hold one or more file glob patterns
+that will identify files needing special treatment. Glob patterns are
+also accepted in options to certain commands as well as query
+parameters to certain pages.
+
+In many cases more than one glob may be specified in a setting,
+option, or query parameter by listing multiple globs separated by a
+comma or white space.
+
+Of course, many fossil commands also accept lists of files to act on,
+and those also may be specified with globs. Although those glob
+patterns are similar to what is described here, they are not defined
+by fossil, but rather by the conventions of the operating system in
+use.
+
+
+## Syntax
+
+A list of glob patterns is simply one or more glob patterns separated
+by white space or commas. If a glob must contain white spaces or
+commas, it can be quoted with either single or double quotation marks.
+A list is said to match if any one (or more) globs in the list
+matches.
+
+A glob pattern is a collection of characters compared to a target
+text, usually a file name. The whole glob is said to match if it
+successfully consumes and matches the entire target text. Glob
+patterns are made up of ordinary characters and special characters.
+
+Ordinary characters consume a single character of the target and must
+match it exactly.
+
+Special characters (and special character sequences) consume zero or
+more characters from the target and describe what matches. The special
+characters (and sequences) are:
+
+ * `*` Matches any sequence of zero or more characters;
+ * `?` Matches exactly one character;
+ * `[...]` Matches one character from the enclosed list of characters; and
+ * `[^...]` Matches one character not in the enclosed list.
+
+Special character sequences have some additional features:
+
+ * A range of characters may be specified with `-`, so `[a-d]` matches
+ exactly the same characters as `[abcd]`. Ranges reflect Unicode
+ code points without any locale-specific collation sequence.
+ * Include `-` in a list by placing it last, just before the `]`.
+ * Include `]` in a list by making the first character after the `[` or
+ `[^`. At any other place, `]` ends the list.
+ * Include `^` in a list by placing anywhere except first after the
+ `[`.
+ * Beware that ranges in lists may include more than you expect:
+ `[A-z]` Matches `A` and `Z`, but also matches `a` and some less
+ obvious characters such as `[`, `\`, and `]` with code point
+ values between `Z` and `a`.
+ * Beware that a range must be specified from low value to high
+ value: `[z-a]` does not match any character at all, preventing the
+ entire glob from matching.
+ * Note that unlike typical Unix shell globs, wildcards (`*`, `?`,
+ and character lists) are allowed to match `/` directory
+ separators as well as the initial `.` in the name of a hidden
+ file or directory.
+
+Some examples of character lists:
+
+ * `[a-d]` Matches any one of `a`, `b`, `c`, or `d` but not `ä`;
+ * `[^a-d]` Matches exactly one character other than `a`, `b`, `c`,
+ or `d`;
+ * `[0-9a-fA-F]` Matches exactly one hexadecimal digit;
+ * `[a-]` Matches either `a` or `-`;
+ * `[][]` Matches either `]` or `[`;
+ * `[^]]` Matches exactly one character other than `]`;
+ * `[]^]` Matches either `]` or `^`; and
+ * `[^-]` Matches exactly one character other than `-`.
+
+White space means the specific ASCII characters TAB, LF, VT, FF, CR,
+and SPACE. Note that this does not include any of the many additional
+spacing characters available in Unicode, and specifically does not
+include U+00A0 NO-BREAK SPACE.
+
+Because both LF and CR are white space and leading and trailing spaces
+are stripped from each glob in a list, a list of globs may be broken
+into lines between globs when the list is stored in a file (as for a
+versioned setting).
+
+Similarly 'single quotes' and "double quotes" are the ASCII straight
+quote characters, not any of the other quotation marks provided in
+Unicode and specifically not the "curly" quotes preferred by
+typesetters and word processors.
+
+
+## File Names to Match
+
+Before it is compared to a glob pattern, each file name is transformed
+to a canonical form. The glob must match the entire canonical file
+name to be considered a match.
+
+The canonical name of a file has all directory separators changed to
+`/`, redundant slashes are removed, all `.` path components are
+removed, and all `..` path components are resolved. (There are
+additional details we are ignoring here, but they cover rare edge
+cases and also follow the principle of least surprise.)
+
+The goal is to have a name that is the simplest possible for each
+particular file, and that will be the same on Windows, Unix, and any
+other platform where fossil is run.
+
+Beware, however, that all glob matching is case sensitive. This will
+not be a surprise on Unix where all file names are also case
+sensitive. However, most Windows file systems are case preserving and
+case insensitive. That is, on Windows, the names `ReadMe` and `README`
+are names of the same file; on Unix they are different files.
+
+Some example cases:
+
+ * The glob `README` matches only a file named `README` in the root of
+ the tree. It does not match a file named `src/README` because it
+ does not include any characters that consume (and match) the
+ `src/` part.
+ * The glob `*/README` does match `src/README`. Unlike Unix file
+ globs, it also matches `src/library/README`. However it does not
+ match the file `README` in the root of the tree.
+ * The glob `*README` does match `src/README` as well as the file
+ `README` in the root of the tree as well as `foo/bar/README` or
+ any other file named `README` in the tree. However, it also
+ matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other
+ file whose name ends with `README`.
+ * The glob `src/README` does match the file named `src\README` on
+ Windows because all directory separators are rewritten as `/` in
+ the canonical name before the glob is matched. This makes it much
+ easier to write globs that work on both Unix and Windows.
+ * The glob `*.[ch]` matches every C source or header file in the
+ tree at the root or at any depth. Again, this is (deliberately)
+ different from Unix file globs and Windows wild cards.
+
+
+## Where Globs are Used
+
+### Settings that are Globs
+
+These settings are all lists of glob patterns:
+
+ * `binary-glob`
+ * `clean-glob`
+ * `crlf-glob`
+ * `crnl-glob`
+ * `encoding-glob`
+ * `ignore-glob`
+ * `keep-glob`
+
+All may be [versioned, local, or global](settings.wiki). Use `fossil
+settings` to manage local and global settings, or a file in the
+repository's `.fossil-settings/` folder at the root of the tree named
+for each for versioned setting.
+
+Using versioned settings for these not only has the advantage that
+they are tracked in the repository just like the rest of your project,
+but you can more easily keep longer lists of more complicated glob
+patterns than would be practical in either local or global settings.
+
+The `ignore-glob` is an example of one setting that frequently grows
+to be an elaborate list of files that should be ignored by most
+commands. This is especially true when one (or more) IDEs are used in
+a project because each IDE has its own ideas of how and where to cache
+information that speeds up its browsing and building tasks but which
+need not be preserved in your project's history.
+
+
+### Commands that Refer to Globs
+
+Many of the commands that respect the settings containing globs have
+options to override some or all of the settings. These options are
+usually named to correspond to the setting they override, such as
+`--ignore` to override the `ignore-glob` setting. These commands are:
+
+ * [`add`][]
+ * [`addremove`][]
+ * [`changes`][]
+ * [`clean`][]
+ * [`extras`][]
+ * [`merge`][]
+ * [`settings`][]
+ * [`status`][]
+ * [`unset`][]
+
+The commands [`tarball`][] and [`zip`][] produce compressed archives of a
+specific checkin. They may be further restricted by options that
+specify glob patterns that name files to include or exclude rather
+than archiving the entire checkin.
+
+The commands [`http`][], [`cgi`][], [`server`][], and [`ui`][] that
+implement or support with web servers provide a mechanism to name some
+files to serve with static content where a list of glob patterns
+specifies what content may be served.
+
+[`add`]: /help?cmd=add
+[`addremove`]: /help?cmd=addremove
+[`changes`]: /help?cmd=changes
+[`clean`]: /help?cmd=clean
+[`extras`]: /help?cmd=extras
+[`merge`]: /help?cmd=merge
+[`settings`]: /help?cmd=settings
+[`status`]: /help?cmd=status
+[`unset`]: /help?cmd=unset
+
+[`tarball`]: /help?cmd=tarball
+[`zip`]: /help?cmd=zip
+
+[`http`]: /help?cmd=http
+[`cgi`]: /help?cmd=cgi
+[`server`]: /help?cmd=server
+[`ui`]: /help?cmd=ui
+
+
+### Web Pages that Refer to Globs
+
+The [`/timeline`][] page supports the query parameter `chng=GLOBLIST` that
+names a list of glob patterns defining which files to focus the
+timeline on. It also has the query parameters `t=TAG` and `r=TAG` that
+names a tag to focus on, which can be configured with `ms=STYLE` to
+use a glob pattern to match tag names instead of the default exact
+match or a couple of other comparison styles.
+
+The pages [`/tarball`][] and [`/zip`][] generate compressed archives
+of a specific checkin. They may be further restricted by query
+parameters that specify glob patterns that name files to include or
+exclude rather than taking the entire checkin.
+
+[`/timeline`]: /help?cmd=/timeline
+[`/tarball`]: /help?cmd=/tarball
+[`/zip`]: /help?cmd=/zip
+
+
+## Platform Quirks
+
+Fossil glob patterns are based on the glob pattern feature of POSIX
+shells. Fossil glob patterns also have a quoting mechanism, discussed
+above. Because other parts of your operating system may interpret glob
+patterns and quotes separately from Fossil, it is often difficult to
+give glob patterns correctly to Fossil on the command line. Quotes and
+special characters in glob patterns are likely to be interpreted when
+given as part of a `fossil` command, causing unexpected behavior.
+
+These problems do not affect [versioned settings files](settings.wiki)
+or Admin → Settings in Fossil UI. Consequently, it is better to
+set long-term `*-glob` settings via these methods than to use `fossil
+settings` commands.
+
+That advice does not help you when you are giving one-off glob patterns
+in `fossil` commands. The remainder of this section gives remedies and
+workarounds for these problems.
+
+
+## POSIX Systems
+
+If you are using Fossil on a system with a POSIX-compatible shell
+— Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. — the shell
+may expand the glob patterns before passing the result to the `fossil`
+executable.
+
+Sometimes this is exactly what you want. Consider this command for
+example:
+
+ $ fossil add RE*
+
+If you give that command in a directory containing `README.txt` and
+`RELEASE-NOTES.txt`, the shell will expand the command to:
+
+ $ fossil add README.txt RELEASE-NOTES.txt
+
+…which is compatible with the `fossil add` command's argument list,
+which allows multiple files.
+
+Now consider what happens instead if you say:
+
+ $ fossil add --ignore RE* src/*.c
+
+This *does not* do what you want because the shell will expand both `RE*`
+and `src/*.c`, causing one of the two files matching the `RE*` glob
+pattern to be ignored and the other to be added to the repository. You
+need to say this in that case:
+
+ $ fossil add --ignore 'RE*' src/*.c
+
+The single quotes force a POSIX shell to pass the `RE*` glob pattern
+through to Fossil untouched, which will do its own glob pattern
+matching. There are other methods of quoting a glob pattern or escaping
+its special characters; see your shell's manual.
+
+Beware that Fossil's `--ignore` option does not override explicit file
+mentions:
+
+ $ fossil add --ignore 'REALLY SECRET STUFF.txt' RE*
+
+You might think that would add everything beginning with `RE` *except*
+for `REALLY SECRET STUFF.txt`, but when a file is both given
+explicitly to Fossil and also matches an ignore rule, Fossil asks what
+you want to do with it in the default case; and it does not even ask
+if you gave the `-f` or `--force` option along with `--ignore`.
+
+The spaces in the ignored file name above bring us to another point:
+such file names must be quoted in Fossil glob patterns, lest Fossil
+interpret it as multiple glob patterns, but the shell interprets
+quotation marks itself.
+
+One way to fix both this and the previous problem is:
+
+ $ fossil add --ignore "'REALLY SECRET STUFF.txt'" READ*
+
+The nested quotation marks cause the inner set to be passed through to
+Fossil, and the more specific glob pattern at the end — that is,
+`READ*` vs `RE*` — avoids a conflict between explicitly-listed
+files and `--ignore` rules in the `fossil add` command.
+
+Another solution would be to use shell escaping instead of nested
+quoting:
+
+ $ fossil add --ignore "\"REALLY SECRET STUFF.txt\"" READ*
+
+It bears repeating that the two glob patterns here are not interpreted
+the same way when running this command from a *subdirectory* of the top
+checkout directory as when running it at the top of the checkout tree.
+If these files were in a subdirectory of the checkout tree called `doc`
+and that was your current working directory, the command would have to
+be:
+
+ $ fossil add --ignore "'doc/REALLY SECRET STUFF.txt'" READ*
+
+instead. The Fossil glob pattern still needs the `doc/` prefix because
+Fossil always interprets glob patterns from the base of the checkout
+directory, not from the current working directory as POSIX shells do.
+
+When in doubt, use `fossil status` after running commands like the
+above to make sure the right set of files were scheduled for insertion
+into the repository before checking the changes in. You never want to
+accidentally check something like a password, an API key, or the
+private half of a public cryptographic key into Fossil repository that
+can be read by people who should not have such secrets.
+
+
+## Windows
+
+Neither standard Windows command shell — `cmd.exe` or PowerShell
+— expands glob patterns the way POSIX shells do. Windows command
+shells rely on the command itself to do the glob pattern expansion. The
+way this works depends on several factors:
+
+ * the version of Windows you are using
+ * which OS upgrades have been applied to it
+ * the compiler that built your Fossil executable
+ * whether you are running the command interactively
+ * whether the command is built against a runtime system that does this
+ at all
+ * whether the Fossil command is being run from a file named `*.BAT` vs
+ being named `*.CMD`
+
+These factors also affect how a program like `fossil.exe` interprets
+quotation marks on its command line.
+
+The fifth item above does not apply to `fossil.exe` when built with
+typical tool chains, but we will see an example below where the exception
+applies in a way that affects how Fossil interprets the glob pattern.
+
+The most common problem is figuring out how to get a glob pattern passed
+on the command line into `fossil.exe` without it being expanded by the C
+runtime library that your particular Fossil executable is linked to,
+which tries to act like the POSIX systems described above. Windows is
+not strongly governed by POSIX, so it has not historically hewed closely
+to its strictures.
+
+(This section does not cover the [Microsoft POSIX
+subsystem](https://en.wikipedia.org/wiki/Microsoft_POSIX_subsystem),
+Windows' obsolete [Services for Unix
+3.*x*](https://en.wikipedia.org/wiki/Windows_Services_for_UNIX) feature,
+or the [Windows Subsystem for
+Linux](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux). (The
+latter is sometimes incorrectly called "Bash on Windows" or "Ubuntu on
+Windows.") See the POSIX Systems section above for those cases.)
+
+For example, consider how you would set `crlf-glob` to `*` in order to
+disable Fossil's "looks like a binary file" checks. The naïve
+approach will not work:
+
+ C:\...> fossil setting crlf-glob *
+
+The C runtime library will expand that to the list of all files in the
+current directory, which will probably cause a Fossil error because
+Fossil expects either nothing or option flags after the setting's new
+value.
+
+Let's try again:
+
+ C:\...> fossil setting crlf-glob '*'
+
+That may or may not work. Either `'*'` or `*` needs to be passed through
+to Fossil untouched for this to do what you expect, which may or may not
+happen, depending on the factors listed above.
+
+An approach that *will* work reliably is:
+
+ C:\...> echo * | fossil setting crlf-glob --args -
+
+This works because the built-in command `echo` does not expand its
+arguments, and the `--args -` option makes it read further command
+arguments from Fossil's standard input, which is connected to the output
+of `echo` by the pipe. (`-` is a common Unix convention meaning
+"standard input.")
+
+Another (usually) correct approach is:
+
+ C:\...> fossil setting crlf-glob *,
+
+This works because the trailing comma prevents the command shell from
+matching any files, unless you happen to have files named with a
+trailing comma in the current directory. If the pattern matches no
+files, it is passed into Fossil's `main()` function as-is by the C
+runtime system. Since Fossil uses commas to separate multiple glob
+patterns, this means "all files at the root of the Fossil checkout
+directory and nothing else."
+
+
+## Converting `.gitignore` to `ignore-glob`
+
+Many other version control systems handle the specific case of
+ignoring certain files differently from fossil: they have you create
+individual "ignore" files in each folder, which specify things ignored
+in that folder and below. Usually some form of glob patterns are used
+in those files, but the details differ from fossil.
+
+In many simple cases, you can just store a top level "ignore" file in
+`.fossil-settings/ignore-glob`. But as usual, there will be lots of
+edge cases.
+
+[Git has a rich collection of ignore files][gitignore] which
+accumulate rules that affect the current command. There are global
+files, per-user files, per workspace unmanaged files, and fully
+version controlled files. Some of the files used have no set name, but
+are called out in configuration files.
+
+[gitignore]: https://git-scm.com/docs/gitignore
+
+In contrast, fossil has a global setting and a local setting, but the local setting
+overrides the global rather than extending it. Similarly, a fossil
+command's `--ignore` option replaces the `ignore-glob` setting rather
+than extending it.
+
+With that in mind, translating a `.gitignore` file into
+`.fossil-settings/ignore-glob` may be possible in many cases. Here are
+some of features of `.gitignore` and comments on how they relate to
+fossil:
+
+ * "A blank line matches no files..." is the same in fossil.
+ * "A line starting with # serves as a comment...." not in fossil.
+ * "Trailing spaces are ignored unless they are quoted..." is similar
+ in fossil. All whitespace before and after a glob is trimmed in
+ fossil unless quoted with single or double quotes. Git uses
+ backslash quoting instead, which fossil does not.
+ * "An optional prefix "!" which negates the pattern..." not in
+ fossil.
+ * Git's globs are relative to the location of the `.gitignore` file;
+ fossil's globs are relative to the root of the workspace.
+ * Git's globs and fossil's globs treat directory separators
+ differently. Git includes a notation for zero or more directories
+ that is not needed in fossil.
+
+### Example
+
+In a project with source and documentation:
+
+ work
+ +-- doc
+ +-- src
+
+The file `doc/.gitignore` might contain:
+
+ # Finished documents by pandoc via LaTeX
+ *.pdf
+ # Intermediate files
+ *.tex
+ *.toc
+ *.log
+ *.out
+ *.tmp
+
+Entries in `.fossil-settings/ignore-glob` with similar effect, also
+limited to the `doc` folder:
+
+ doc/*.pdf
+ doc/*.tex, doc/*.toc, doc/*.log, doc/*.out, doc/*.tmp
+
+
+
+
+
+## Implementation and References
+
+Most of the implementation of glob pattern handling in fossil is found
+`glob.c`, `file.c`, and each individual command and web page that uses
+a glob pattern. Find commands and pages in the fossil sources by
+looking for comments like `COMMAND: add` or `WEBPAGE: timeline` in
+front of the function that implements the command or page in files
+`src/*.c`. (Fossil's build system creates the tables used to dispatch
+commands at build time by searching the sources for those comments.) A
+few starting points:
+
+ * [`src/glob.c`][glob.c] implements glob pattern list loading,
+ parsing, and matching.
+ * [`src/file.c`][file.c] implements various kinds of canonical
+ names of a file.
+
+
+[glob.c]: https://www.fossil-scm.org/index.html/file/src/glob.c
+[file.c]: https://www.fossil-scm.org/index.html/file/src/file.c
+
+The actual pattern matching is implemented in SQL, so the
+documentation for `GLOB` and the other string matching operators in
+[SQLite] (https://sqlite.org/lang_expr.html#like) is useful. Of
+course, the SQLite source code and test harnesses also make
+entertaining reading:
+
+ * `src/func.c` [lines 570-768]
+ (https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768)
+ * `test/expr.test` [lines 586-673]
+ (https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673)
Index: www/index.wiki
==================================================================
--- www/index.wiki
+++ www/index.wiki
@@ -58,11 +58,12 @@
Fossil uses ordinary HTTP (or HTTPS or SSH)
for network communications, so it works fine from behind
restrictive firewalls, including [./quickstart.wiki#proxy|proxies].
The protocol is
[./stats.wiki | bandwidth efficient] to the point that Fossil can be
- used comfortably over dial-up.
+ used comfortably over dial-up or over the exceedingly slow Wifi on
+ airliners.
5. CGI/SCGI Enabled - No server is required, but if you want to
set one up, Fossil supports four easy
[./server.wiki | server configurations].
Index: www/mkindex.tcl
==================================================================
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -6,10 +6,11 @@
# tclsh mkindex.tcl
#
set doclist {
aboutcgi.wiki {How CGI Works In Fossil}
+ aboutdownload.wiki {How The Download Page Works}
adding_code.wiki {Adding New Features To Fossil}
adding_code.wiki {Hacking Fossil}
antibot.wiki {Defense against Spiders and Bots}
blame.wiki {The Annotate/Blame Algorithm Of Fossil}
branching.wiki {Branching, Forking, Merging, and Tagging}
@@ -31,14 +32,15 @@
encryptedrepos.wiki {How To Use Encrypted Repositories}
env-opts.md {Environment Variables and Global Options}
event.wiki {Events}
faq.wiki {Frequently Asked Questions}
fileformat.wiki {Fossil File Format}
- fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
+ fiveminutes.wiki {Up and Running in 5 Minutes as a Single User}
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
fossil-v-git.wiki {Fossil Versus Git}
+ globs.md {File Name Glob Patterns}
hacker-howto.wiki {Hacker How-To}
hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256}
/help {Lists of Commands and Webpages}
hints.wiki {Fossil Tips And Usage Hints}
index.wiki {Home Page}
Index: www/permutedindex.html
==================================================================
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -17,11 +17,11 @@
Command-line help
Permuted Index:
-- 5 Minutes as a Single User — Update and Running in
+- 5 Minutes as a Single User — Up and Running in
- 2010 IDE — Integrating Fossil in the Microsoft Express
- A Technical Overview Of The Design And Implementation Of Fossil
- Adding New Features To Fossil
- Agreement — Contributor License
- Algorithm — Fossil Delta Encoding
@@ -72,10 +72,11 @@
- Delta Format — Fossil
- Design And Implementation Of Fossil — A Technical Overview Of The
- Design Of The Fossil DVCS — Thoughts On The
- Documentation — Embedded Project
- Documentation To The Fossil Project — Contributing Code or
+- Download Page Works — How The
- DVCS — Thoughts On The Design Of The Fossil
- DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and
- Embedded Project Documentation
- Encoding Algorithm — Fossil Delta
- Encrypted Repositories — How To Use
@@ -84,10 +85,11 @@
- Examples — Webpage
- Export To And From Git — Import And
- Express 2010 IDE — Integrating Fossil in the Microsoft
- Features To Fossil — Adding New
- File Format — Fossil
+- File Name Glob Patterns
- Files — Unversioned
- Forking, Merging, and Tagging — Branching,
- Format — Fossil Delta
- Format — Fossil File
- Formatting Rules — Markdown
@@ -107,10 +109,11 @@
- Frequently Asked Questions
- General — Quotes: What People Are Saying About Fossil, Git, and DVCSes in
- Git — Fossil Versus
- Git — Import And Export To And From
- Git, and DVCSes in General — Quotes: What People Are Saying About Fossil,
+- Glob Patterns — File Name
- Global Options — Environment Variables and
- Graph — Theming: Customizing the Timeline
- Guide — Fossil Quick Start
- Guidelines — Source Code Style
- Hacker How-To
@@ -118,10 +121,11 @@
- Hash Policy: Choosing Between SHA1 and SHA3-256
- Hints — Fossil Tips And Usage
- Home Page
- Hosting Repositories — Fossil Self
- How CGI Works In Fossil
+- How The Download Page Works
- How To Configure A Fossil Server
- How To Create A New Fossil Repository
- How To Use Encrypted Repositories
- How-To — Hacker
- IDE — Integrating Fossil in the Microsoft Express 2010
@@ -137,21 +141,24 @@
- Management And Authentication — Password
- Map — Site
- Markdown Formatting Rules
- Merging, and Tagging — Branching, Forking,
- Microsoft Express 2010 IDE — Integrating Fossil in the
-- Minutes as a Single User — Update and Running in 5
+- Minutes as a Single User — Up and Running in 5
+- Name Glob Patterns — File
- Names — Check-in And Version
- New Features To Fossil — Adding
- New Fossil Repository — How To Create A
- Open-Source Projects — Checklist For Successful
- Operation — Principles Of
- Options — Environment Variables and Global
- Overview Of The Design And Implementation Of Fossil — A Technical
- Page — Home
+- Page Works — How The Download
- Pages — Theming: Customizing The Appearance of Web
- Password Management And Authentication
+- Patterns — File Name Glob
- People Are Saying About Fossil, Git, and DVCSes in General — Quotes: What
- Performance Statistics
- Policy: Choosing Between SHA1 and SHA3-256 — Hash
- Pre-Release Testing Checklist
- Principles Of Operation
@@ -171,21 +178,21 @@
- Repository — How To Create A New Fossil
- Repository Integrity Self Checks — Fossil
- Reviews
- Rules — Markdown Formatting
- Rules — Wiki Formatting
-- Running in 5 Minutes as a Single User — Update and
+- Running in 5 Minutes as a Single User — Up and
- Saying About Fossil, Git, and DVCSes in General — Quotes: What People Are
- Scripting Language — The TH1
- Self Checks — Fossil Repository Integrity
- Self Hosting Repositories — Fossil
- Server — How To Configure A Fossil
- Settings — Fossil
- SHA1 and SHA3-256 — Hash Policy: Choosing Between
- SHA3-256 — Hash Policy: Choosing Between SHA1 and
- Shunning: Deleting Content From Fossil
-- Single User — Update and Running in 5 Minutes as a
+- Single User — Up and Running in 5 Minutes as a
- Site Map
- Source Code Style Guidelines
- Spiders and Bots — Defense against
- SQLite Databases Used By Fossil
- SSL with Fossil — Using
@@ -214,13 +221,13 @@
- Ticket System — The Fossil
- Timeline Graph — Theming: Customizing the
- Tips And Usage Hints — Fossil
- Tracking In Fossil — Bug
- Unversioned Files
-- Update and Running in 5 Minutes as a Single User
+- Up and Running in 5 Minutes as a Single User
- Usage Hints — Fossil Tips And
-- User — Update and Running in 5 Minutes as a Single
+- User — Up and Running in 5 Minutes as a Single
- Using SSL with Fossil
- Variables and Global Options — Environment
- Version Control — Benefits Of
- Version Names — Check-in And
- Versus Git — Fossil
@@ -230,8 +237,9 @@
- Webpages — Lists of Commands and
- What People Are Saying About Fossil, Git, and DVCSes in General — Quotes:
- Why You Should Use Fossil
- Wiki Formatting Rules
- Wiki In Fossil
+- Works — How The Download Page
- Works In Fossil — How CGI
- You Should Use Fossil — Why
Index: www/server.wiki
==================================================================
--- www/server.wiki
+++ www/server.wiki
@@ -349,12 +349,12 @@
this interface, but Windows does not, so the feature will not work on Windows.
Note also that Linux implements "getloadavg()" by accessing the "/proc/loadavg"
file in the "proc" virtual filesystem. If you are running a Fossil instance
inside a chroot() jail on Linux, you will need to make the "/proc" file
system available inside that jail in order for this feature to work. On
-the self-hosting Fossil repository, this was accomplished by adding a line
-to the "/etc/fstab" file that looks like:
+the [./selfhost.wiki|self-hosting Fossil repositories], this was accomplished
+by adding a line to the "/etc/fstab" file that looks like:
chroot_jail_proc /home/www/proc proc ro 0 0
The /home/www/proc pathname should be adjusted so that the "/proc" component is
in the root of the chroot jail, of course.
Index: www/sync.wiki
==================================================================
--- www/sync.wiki
+++ www/sync.wiki
@@ -24,14 +24,15 @@
Each repository also has local state. The local state determines
the web-page formatting preferences, authorized users, ticket formats,
and similar information that varies from one repository to another.
The local state is not using transferred during a sync. Except,
some local state is transferred during a [/help?cmd=clone|clone]
-in order to initialize the local state of the new repository. And
+in order to initialize the local state of the new repository. Also,
+an administrator can sync local state using
the [/help?cmd=configuration|config push] and
[/help?cmd=configuration|config pull]
-commands can be an administrator to sync local state.
+commands.
2.0 Transport
All communication between client and server is via HTTP requests.