Index: src/add.c ================================================================== --- src/add.c +++ src/add.c @@ -196,15 +196,20 @@ ** The --ignore option is a comma-separate list of glob patterns for files ** to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore option ** does not appear on the command line then the "ignore-glob" setting is ** used. ** +** The --case-sensitive option determines whether or not filenames should +** be treated case sensitive or not. If the option is not given, the default +** depends on the global setting, or the operating system default, if not set. +** ** Options: ** -** --dotfiles include files beginning with a dot (".") -** --ignore ignore files matching patterns from the -** comma separated list of glob patterns. +** --case-sensitive override case-sensitive setting +** --dotfiles include files beginning with a dot (".") +** --ignore ignore files matching patterns from the +** comma separated list of glob patterns. ** ** See also: addremove, rm */ void add_cmd(void){ int i; /* Loop counter */ @@ -408,22 +413,24 @@ ** as a separate step. ** ** Files and directories whose names begin with "." are ignored unless ** the --dotfiles option is used. ** -** The --ignore option overrides the "ignore-glob" setting. See +** The --ignore option overrides the "ignore-glob" setting, as does the +** --case-sensitive option with the "case-sensitive" setting. See the ** documentation on the "settings" command for further information. ** ** The --test option shows what would happen without actually doing anything. ** ** This command can be used to track third party software. ** ** Options: -** --dotfiles include files beginning with a dot (".") -** --ignore ignore files matching patterns from the -** comma separated list of glob patterns. -** --test If given, show what would be done without doing so. +** --case-sensitive override case-sensitive setting +** --dotfiles include files beginning with a dot (".") +** --ignore ignore files matching patterns from the +** comma separated list of glob patterns. +** --test If given, display instead of run actions ** ** See also: add, rm */ void addremove_cmd(void){ Blob path; Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -238,22 +238,32 @@ char *zUUID; const char *zComment; char *zDate; int rid; int i, n; + int addCompress = 0; + Manifest *pManifest; db_begin_transaction(); blob_init(&content, aContent, szContent); + pManifest = manifest_parse(&content, 0); + manifest_destroy(pManifest); + blob_init(&content, aContent, szContent); + if( pManifest ){ + blob_compress(&content, &content); + addCompress = 1; + } rid = content_put(&content); zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_zero(&manifest); for(i=n=0; zName[i]; i++){ if( zName[i]=='/' || zName[i]=='\\' ) n = i; } zName += n; if( zName[0]==0 ) zName = "unknown"; - blob_appendf(&manifest, "A %F %F %s\n", zName, zTarget, zUUID); + blob_appendf(&manifest, "A %F%s %F %s\n", + zName, addCompress ? ".gz" : "", zTarget, zUUID); zComment = PD("comment", ""); while( fossil_isspace(zComment[0]) ) zComment++; n = strlen(zComment); while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; } if( n>0 ){ Index: src/login.c ================================================================== --- src/login.c +++ src/login.c @@ -385,11 +385,11 @@ ** is a manually operated browser or a bot. When in doubt, assume a bot. ** Return true if we believe the agent is a real person. */ static int isHuman(const char *zAgent){ int i; - if( zAgent==0 ) return 0; /* If not UserAgent, the probably a bot */ + if( zAgent==0 ) return 0; /* If not UserAgent, then probably a bot */ for(i=0; zAgent[i]; i++){ if( prefix_match("bot", zAgent+i) ) return 0; if( prefix_match("spider", zAgent+i) ) return 0; if( prefix_match("crawl", zAgent+i) ) return 0; /* If a URI appears in the User-Agent, it is probably a bot */ Index: src/manifest.c ================================================================== --- src/manifest.c +++ src/manifest.c @@ -334,11 +334,11 @@ ** Each card is divided into tokens by a single space character. ** The first token is a single upper-case letter which is the card type. ** The card type determines the other parameters to the card. ** Cards must occur in lexicographical order. */ -static Manifest *manifest_parse(Blob *pContent, int rid){ +Manifest *manifest_parse(Blob *pContent, int rid){ Manifest *p; int seenZ = 0; int i, lineNo=0; ManifestText x; char cPrevType = 0; @@ -348,11 +348,13 @@ char *zUuid; int sz = 0; int isRepeat; static Bag seen; - if( bag_find(&seen, rid) ){ + if( rid==0 ){ + isRepeat = 1; + }else if( bag_find(&seen, rid) ){ isRepeat = 1; }else{ isRepeat = 0; bag_insert(&seen, rid); } Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -419,10 +419,11 @@ sqlite3 *db; /* The database */ int echoOn; /* True to echo input commands */ int statsOn; /* True to display memory stats before each finalize */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ + FILE *traceOut; /* Output for sqlite3_trace() */ int nErr; /* Number of errors seen */ int mode; /* An output mode setting */ int writableSchema; /* True if PRAGMA writable_schema=ON */ int showHeader; /* True to show column names in List or Column mode */ char *zDestTable; /* Name of destination table when MODE_Insert */ @@ -1307,10 +1308,11 @@ /* Always quote the table name, even if it appears to be pure ascii, ** in case it is a keyword. Ex: INSERT INTO "table" ... */ zTmp = appendText(zTmp, zTable, '"'); if( zTmp ){ zSelect = appendText(zSelect, zTmp, '\''); + free(zTmp); } zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); rc = sqlite3_step(pTableInfo); while( rc==SQLITE_ROW ){ const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1); @@ -1335,11 +1337,11 @@ rc = run_table_dump_query(p, zSelect, zPrepStmt); if( rc==SQLITE_CORRUPT ){ zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); run_table_dump_query(p, zSelect, 0); } - if( zSelect ) free(zSelect); + free(zSelect); } return 0; } /* @@ -1365,11 +1367,11 @@ sqlite3_free(zErr); zErr = 0; } zQ2 = malloc( len+100 ); if( zQ2==0 ) return rc; - sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); + sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery); rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); if( rc ){ fprintf(p->out, "/****** ERROR: %s ******/\n", zErr); }else{ rc = SQLITE_CORRUPT; @@ -1431,10 +1433,11 @@ ".stats ON|OFF Turn stats on or off\n" ".tables ?TABLE? List names of tables\n" " If TABLE specified, only list tables matching\n" " LIKE pattern TABLE.\n" ".timeout MS Try opening locked tables for MS milliseconds\n" + ".trace FILE|off Output each SQL statement as it is run\n" ".vfsname ?AUX? Print the name of the VFS stack\n" ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" ; static char zTimerHelp[] = @@ -1519,10 +1522,56 @@ }else if( strcmp(zArg,"yes")==0 ){ val = 1; } return val; } + +/* +** Close an output file, assuming it is not stderr or stdout +*/ +static void output_file_close(FILE *f){ + if( f && f!=stdout && f!=stderr ) fclose(f); +} + +/* +** Try to open an output file. The names "stdout" and "stderr" are +** recognized and do the right thing. NULL is returned if the output +** filename is "off". +*/ +static FILE *output_file_open(const char *zFile){ + FILE *f; + if( strcmp(zFile,"stdout")==0 ){ + f = stdout; + }else if( strcmp(zFile, "stderr")==0 ){ + f = stderr; + }else if( strcmp(zFile, "off")==0 ){ + f = 0; + }else{ + f = fopen(zFile, "wb"); + if( f==0 ){ + fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); + } + } + return f; +} + +/* +** A routine for handling output from sqlite3_trace(). +*/ +static void sql_trace_callback(void *pArg, const char *z){ + FILE *f = (FILE*)pArg; + if( f ) fprintf(f, "%s\n", z); +} + +/* +** A no-op routine that runs with the ".breakpoint" doc-command. This is +** a useful spot to set a debugger breakpoint. +*/ +static void test_breakpoint(void){ + static int nCall = 0; + nCall++; +} /* ** If an input line begins with "." then invoke this routine to ** process that line. ** @@ -1598,10 +1647,17 @@ }else if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){ bail_on_error = booleanValue(azArg[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 ){ + test_breakpoint(); + }else if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); @@ -1930,26 +1986,12 @@ }else #endif if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){ const char *zFile = azArg[1]; - if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){ - fclose(p->pLog); - p->pLog = 0; - } - if( strcmp(zFile,"stdout")==0 ){ - p->pLog = stdout; - }else if( strcmp(zFile, "stderr")==0 ){ - p->pLog = stderr; - }else if( strcmp(zFile, "off")==0 ){ - p->pLog = 0; - }else{ - p->pLog = fopen(zFile, "w"); - if( p->pLog==0 ){ - fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); - } - } + output_file_close(p->pLog); + p->pLog = output_file_open(zFile); }else if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){ int n2 = strlen30(azArg[1]); if( (n2==4 && strncmp(azArg[1],"line",n2)==0) @@ -1998,37 +2040,35 @@ sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); }else if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ - if( p->out!=stdout ){ - if( p->outfile[0]=='|' ){ - pclose(p->out); - }else{ - fclose(p->out); - } + if( p->outfile[0]=='|' ){ + pclose(p->out); + }else{ + output_file_close(p->out); } - if( strcmp(azArg[1],"stdout")==0 ){ - p->out = stdout; - sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout"); - }else if( azArg[1][0]=='|' ){ + p->outfile[0] = 0; + if( azArg[1][0]=='|' ){ p->out = popen(&azArg[1][1], "w"); if( p->out==0 ){ fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]); p->out = stdout; rc = 1; }else{ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); } }else{ - p->out = fopen(azArg[1], "wb"); + p->out = output_file_open(azArg[1]); if( p->out==0 ){ - fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); + if( strcmp(azArg[1],"off")!=0 ){ + fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); + } p->out = stdout; rc = 1; } else { - sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); } } }else if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ @@ -2394,10 +2434,22 @@ && nArg==2 ){ enableTimer = booleanValue(azArg[1]); }else + if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ + output_file_close(p->traceOut); + p->traceOut = output_file_open(azArg[1]); +#ifndef SQLITE_OMIT_TRACE + if( p->traceOut==0 ){ + sqlite3_trace(p->db, 0, 0); + }else{ + sqlite3_trace(p->db, sql_trace_callback, p->traceOut); + } +#endif + }else + if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ printf("SQLite %s %s\n" /*extra-version-info*/, sqlite3_libversion(), sqlite3_sourceid()); }else @@ -2605,16 +2657,15 @@ return errCnt; } /* ** Return a pathname which is the user's home directory. A -** 0 return indicates an error of some kind. Space to hold the -** resulting string is obtained from malloc(). The calling -** function should free the result. +** 0 return indicates an error of some kind. */ static char *find_home_dir(void){ - char *home_dir = NULL; + static char *home_dir = NULL; + if( home_dir ) return home_dir; #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) struct passwd *pwent; uid_t uid = getuid(); if( (pwent=getpwuid(uid)) != NULL) { @@ -2623,11 +2674,11 @@ #endif #if defined(_WIN32_WCE) /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() */ - home_dir = strdup("/"); + home_dir = "/"; #else #if defined(_WIN32) || defined(WIN32) || defined(__OS2__) if (!home_dir) { home_dir = getenv("USERPROFILE"); @@ -2679,11 +2730,10 @@ ){ char *home_dir = NULL; const char *sqliterc = sqliterc_override; char *zBuf = 0; FILE *in = NULL; - int nBuf; int rc = 0; if (sqliterc == NULL) { home_dir = find_home_dir(); if( home_dir==0 ){ @@ -2690,29 +2740,22 @@ #if !defined(__RTP__) && !defined(_WRS_KERNEL) fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); #endif return 1; } - nBuf = strlen30(home_dir) + 16; - zBuf = malloc( nBuf ); - if( zBuf==0 ){ - fprintf(stderr,"%s: Error: out of memory\n",Argv0); - return 1; - } - sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir); - free(home_dir); - sqliterc = (const char*)zBuf; + zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); + sqliterc = zBuf; } in = fopen(sqliterc,"rb"); if( in ){ if( stdin_is_interactive ){ fprintf(stderr,"-- Loading resources from %s\n",sqliterc); } rc = process_input(p,in); fclose(in); } - free(zBuf); + sqlite3_free(zBuf); return rc; } /* ** Show available command line options @@ -3055,11 +3098,10 @@ if( zHistory ){ stifle_history(100); write_history(zHistory); free(zHistory); } - free(zHome); }else{ rc = process_input(&data, stdin); } } set_table_name(&data, 0); Index: src/sqlite3.c ================================================================== --- src/sqlite3.c +++ src/sqlite3.c @@ -657,11 +657,11 @@ ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.12" #define SQLITE_VERSION_NUMBER 3007012 -#define SQLITE_SOURCE_ID "2012-03-31 19:12:23 af602d87736b52802a4e760ffeeaa28112b99d9a" +#define SQLITE_SOURCE_ID "2012-04-17 09:09:33 8e2363ad76446e863d03ead91fd621e59d5cb495" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -2095,11 +2095,11 @@ ** database connection is opened. By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined. ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] -**
SQLITE_CONFIG_PCACHE and SQLITE_CONFNIG_GETPCACHE +**
SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE **
These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -7533,11 +7533,15 @@ ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes), +#ifdef SQLITE_RTREE_INT_ONLY + int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), +#else + int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), +#endif void *pContext ); /* @@ -10933,11 +10937,10 @@ int nRef; /* Number of names resolved by this context */ int nErr; /* Number of errors encountered while resolving names */ u8 allowAgg; /* Aggregate functions allowed here */ u8 hasAgg; /* True if aggregates are seen */ u8 isCheck; /* True if resolving names in a CHECK constraint */ - int nDepth; /* Depth of subquery recursion. 1 for no recursion */ AggInfo *pAggInfo; /* Information about aggregates at this level */ NameContext *pNext; /* Next outer name context. NULL for outermost */ }; /* @@ -11399,10 +11402,11 @@ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ Parse *pParse; /* Parser context. */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ int i; /* Integer value */ + SrcList *pSrcList; /* FROM clause */ } u; }; /* Forward declarations */ SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); @@ -11767,11 +11771,11 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); -SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int); +SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void); SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); @@ -24995,12 +24999,12 @@ #ifndef SQLITE_DEFAULT_FILE_PERMISSIONS # define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 #endif /* - ** Default permissions when creating auto proxy dir - */ +** Default permissions when creating auto proxy dir +*/ #ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS # define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 #endif /* @@ -25550,11 +25554,11 @@ return 0; } /* ** Invoke open(). Do so multiple times, until it either succeeds or -** files for some reason other than EINTR. +** fails for some reason other than EINTR. ** ** If the file creation mode "m" is 0 then set it to the default for ** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally ** 0644) as modified by the system umask. If m is not 0, then ** make the file creation mode be exactly m ignoring the umask. @@ -25566,24 +25570,33 @@ ** transaction crashes and leaves behind hot journals, then any ** process that is able to write to the database will also be able to ** recover the hot journals. */ static int robust_open(const char *z, int f, mode_t m){ - int rc; + int fd; mode_t m2; mode_t origM = 0; if( m==0 ){ m2 = SQLITE_DEFAULT_FILE_PERMISSIONS; }else{ m2 = m; origM = osUmask(0); } - do{ rc = osOpen(z,f,m2); }while( rc<0 && errno==EINTR ); + do{ +#if defined(O_CLOEXEC) + fd = osOpen(z,f|O_CLOEXEC,m2); +#else + fd = osOpen(z,f,m2); +#endif + }while( fd<0 && errno==EINTR ); if( m ){ osUmask(origM); } - return rc; +#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) + if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); +#endif + return fd; } /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the unixInodeInfo and @@ -28374,13 +28387,10 @@ for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); if( ii>0 ){ zDirname[ii] = '\0'; fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); if( fd>=0 ){ -#ifdef FD_CLOEXEC - osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); -#endif OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); } } *pFd = fd; return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); @@ -28459,11 +28469,11 @@ /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ - if( pFile->szChunk ){ + if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } rc = robust_ftruncate(pFile->h, (off_t)nByte); if( rc ){ @@ -30221,14 +30231,10 @@ else{ p->openFlags = openFlags; } #endif -#ifdef FD_CLOEXEC - osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); -#endif - noLock = eType!=SQLITE_OPEN_MAIN_DB; #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE if( fstatfs(fd, &fsInfo) == -1 ){ @@ -38001,10 +38007,15 @@ #define ROWSET_ENTRY_PER_CHUNK \ ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry)) /* ** Each entry in a RowSet is an instance of the following object. +** +** This same object is reused to store a linked list of trees of RowSetEntry +** objects. In that alternative use, pRight points to the next entry +** in the list, pLeft points to the tree, and v is unused. The +** RowSet.pForest value points to the head of this forest list. */ struct RowSetEntry { i64 v; /* ROWID value for this entry */ struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */ struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */ @@ -38030,16 +38041,22 @@ struct RowSetChunk *pChunk; /* List of all chunk allocations */ sqlite3 *db; /* The database connection */ struct RowSetEntry *pEntry; /* List of entries using pRight */ struct RowSetEntry *pLast; /* Last entry on the pEntry list */ struct RowSetEntry *pFresh; /* Source of new entry objects */ - struct RowSetEntry *pTree; /* Binary tree of entries */ + struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ - u8 isSorted; /* True if pEntry is sorted */ + u8 rsFlags; /* Various flags */ u8 iBatch; /* Current insert batch */ }; +/* +** Allowed values for RowSet.rsFlags +*/ +#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */ +#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ + /* ** Turn bulk memory into a RowSet object. N bytes of memory ** are available at pSpace. The db pointer is used as a memory context ** for any subsequent allocations that need to occur. ** Return a pointer to the new RowSet object. @@ -38056,14 +38073,14 @@ p = pSpace; p->pChunk = 0; p->db = db; p->pEntry = 0; p->pLast = 0; - p->pTree = 0; + p->pForest = 0; p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); - p->isSorted = 1; + p->rsFlags = ROWSET_SORTED; p->iBatch = 0; return p; } /* @@ -38079,12 +38096,37 @@ } p->pChunk = 0; p->nFresh = 0; p->pEntry = 0; p->pLast = 0; - p->pTree = 0; - p->isSorted = 1; + p->pForest = 0; + p->rsFlags = ROWSET_SORTED; +} + +/* +** Allocate a new RowSetEntry object that is associated with the +** given RowSet. Return a pointer to the new and completely uninitialized +** objected. +** +** In an OOM situation, the RowSet.db->mallocFailed flag is set and this +** routine returns NULL. +*/ +static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){ + assert( p!=0 ); + if( p->nFresh==0 ){ + struct RowSetChunk *pNew; + pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew)); + if( pNew==0 ){ + return 0; + } + pNew->pNextChunk = p->pChunk; + p->pChunk = pNew; + p->pFresh = pNew->aEntry; + p->nFresh = ROWSET_ENTRY_PER_CHUNK; + } + p->nFresh--; + return p->pFresh++; } /* ** Insert a new value into a RowSet. ** @@ -38092,34 +38134,25 @@ ** memory allocation fails. */ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){ struct RowSetEntry *pEntry; /* The new entry */ struct RowSetEntry *pLast; /* The last prior entry */ - assert( p!=0 ); - if( p->nFresh==0 ){ - struct RowSetChunk *pNew; - pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew)); - if( pNew==0 ){ - return; - } - pNew->pNextChunk = p->pChunk; - p->pChunk = pNew; - p->pFresh = pNew->aEntry; - p->nFresh = ROWSET_ENTRY_PER_CHUNK; - } - pEntry = p->pFresh++; - p->nFresh--; + + /* This routine is never called after sqlite3RowSetNext() */ + assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); + + pEntry = rowSetEntryAlloc(p); + if( pEntry==0 ) return; pEntry->v = rowid; pEntry->pRight = 0; pLast = p->pLast; if( pLast ){ - if( p->isSorted && rowid<=pLast->v ){ - p->isSorted = 0; + if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){ + p->rsFlags &= ~ROWSET_SORTED; } pLast->pRight = pEntry; }else{ - assert( p->pEntry==0 ); /* Fires if INSERT after SMALLEST */ p->pEntry = pEntry; } p->pLast = pEntry; } @@ -38127,11 +38160,11 @@ ** Merge two lists of RowSetEntry objects. Remove duplicates. ** ** The input lists are connected via pRight pointers and are ** assumed to each already be in sorted order. */ -static struct RowSetEntry *rowSetMerge( +static struct RowSetEntry *rowSetEntryMerge( struct RowSetEntry *pA, /* First sorted list to be merged */ struct RowSetEntry *pB /* Second sorted list to be merged */ ){ struct RowSetEntry head; struct RowSetEntry *pTail; @@ -38161,36 +38194,33 @@ } return head.pRight; } /* -** Sort all elements on the pEntry list of the RowSet into ascending order. +** Sort all elements on the list of RowSetEntry objects into order of +** increasing v. */ -static void rowSetSort(RowSet *p){ +static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){ unsigned int i; - struct RowSetEntry *pEntry; - struct RowSetEntry *aBucket[40]; + struct RowSetEntry *pNext, *aBucket[40]; - assert( p->isSorted==0 ); memset(aBucket, 0, sizeof(aBucket)); - while( p->pEntry ){ - pEntry = p->pEntry; - p->pEntry = pEntry->pRight; - pEntry->pRight = 0; + while( pIn ){ + pNext = pIn->pRight; + pIn->pRight = 0; for(i=0; aBucket[i]; i++){ - pEntry = rowSetMerge(aBucket[i], pEntry); + pIn = rowSetEntryMerge(aBucket[i], pIn); aBucket[i] = 0; } - aBucket[i] = pEntry; + aBucket[i] = pIn; + pIn = pNext; } - pEntry = 0; + pIn = 0; for(i=0; ipEntry = pEntry; - p->pLast = 0; - p->isSorted = 1; + return pIn; } /* ** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects. @@ -38280,24 +38310,41 @@ } return p; } /* -** Convert the list in p->pEntry into a sorted list if it is not -** sorted already. If there is a binary tree on p->pTree, then -** convert it into a list too and merge it into the p->pEntry list. +** Take all the entries on p->pEntry and on the trees in p->pForest and +** sort them all together into one big ordered list on p->pEntry. +** +** This routine should only be called once in the life of a RowSet. */ static void rowSetToList(RowSet *p){ - if( !p->isSorted ){ - rowSetSort(p); + + /* This routine is called only once */ + assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); + + if( (p->rsFlags & ROWSET_SORTED)==0 ){ + p->pEntry = rowSetEntrySort(p->pEntry); } - if( p->pTree ){ - struct RowSetEntry *pHead, *pTail; - rowSetTreeToList(p->pTree, &pHead, &pTail); - p->pTree = 0; - p->pEntry = rowSetMerge(p->pEntry, pHead); + + /* While this module could theoretically support it, sqlite3RowSetNext() + ** is never called after sqlite3RowSetText() for the same RowSet. So + ** there is never a forest to deal with. Should this change, simply + ** remove the assert() and the #if 0. */ + assert( p->pForest==0 ); +#if 0 + while( p->pForest ){ + struct RowSetEntry *pTree = p->pForest->pLeft; + if( pTree ){ + struct RowSetEntry *pHead, *pTail; + rowSetTreeToList(pTree, &pHead, &pTail); + p->pEntry = rowSetEntryMerge(p->pEntry, pHead); + } + p->pForest = p->pForest->pRight; } +#endif + p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */ } /* ** Extract the smallest element from the RowSet. ** Write the element into *pRowid. Return 1 on success. Return @@ -38305,11 +38352,16 @@ ** ** After this routine has been called, the sqlite3RowSetInsert() ** routine may not be called again. */ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ - rowSetToList(p); + assert( p!=0 ); + + /* Merge the forest into a single sorted list on first call */ + if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p); + + /* Return the next entry on the list */ if( p->pEntry ){ *pRowid = p->pEntry->v; p->pEntry = p->pEntry->pRight; if( p->pEntry==0 ){ sqlite3RowSetClear(p); @@ -38321,30 +38373,70 @@ } /* ** Check to see if element iRowid was inserted into the the rowset as ** part of any insert batch prior to iBatch. Return 1 or 0. +** +** If this is the first test of a new batch and if there exist entires +** on pRowSet->pEntry, then sort those entires into the forest at +** pRowSet->pForest so that they can be tested. */ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ - struct RowSetEntry *p; + struct RowSetEntry *p, *pTree; + + /* This routine is never called after sqlite3RowSetNext() */ + assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); + + /* Sort entries into the forest on the first test of a new batch + */ if( iBatch!=pRowSet->iBatch ){ - if( pRowSet->pEntry ){ - rowSetToList(pRowSet); - pRowSet->pTree = rowSetListToTree(pRowSet->pEntry); + p = pRowSet->pEntry; + if( p ){ + struct RowSetEntry **ppPrevTree = &pRowSet->pForest; + if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ + p = rowSetEntrySort(p); + } + for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ + ppPrevTree = &pTree->pRight; + if( pTree->pLeft==0 ){ + pTree->pLeft = rowSetListToTree(p); + break; + }else{ + struct RowSetEntry *pAux, *pTail; + rowSetTreeToList(pTree->pLeft, &pAux, &pTail); + pTree->pLeft = 0; + p = rowSetEntryMerge(pAux, p); + } + } + if( pTree==0 ){ + *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet); + if( pTree ){ + pTree->v = 0; + pTree->pRight = 0; + pTree->pLeft = rowSetListToTree(p); + } + } pRowSet->pEntry = 0; pRowSet->pLast = 0; + pRowSet->rsFlags |= ROWSET_SORTED; } pRowSet->iBatch = iBatch; } - p = pRowSet->pTree; - while( p ){ - if( p->vpRight; - }else if( p->v>iRowid ){ - p = p->pLeft; - }else{ - return 1; + + /* Test to see if the iRowid value appears anywhere in the forest. + ** Return 1 if it does and 0 if not. + */ + for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ + p = pTree->pLeft; + while( p ){ + if( p->vpRight; + }else if( p->v>iRowid ){ + p = p->pLeft; + }else{ + return 1; + } } } return 0; } @@ -49148,16 +49240,22 @@ /* ** This structure is passed around through all the sanity checking routines ** in order to keep track of some global state information. +** +** The aRef[] array is allocated so that there is 1 bit for each page in +** the database. As the integrity-check proceeds, for each page used in +** the database the corresponding bit is set. This allows integrity-check to +** detect pages that are used twice and orphaned pages (both of which +** indicate corruption). */ typedef struct IntegrityCk IntegrityCk; struct IntegrityCk { BtShared *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ - int *anRef; /* Number of times each page is referenced */ + u8 *aPgRef; /* 1 bit per page in the db (see above) */ Pgno nPage; /* Number of pages in the database */ int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ int mallocFailed; /* A memory allocation error has occurred */ StrAccum errMsg; /* Accumulate the error message text here */ @@ -56998,10 +57096,29 @@ } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_INTEGRITY_CHECK + +/* +** Return non-zero if the bit in the IntegrityCk.aPgRef[] array that +** corresponds to page iPg is already set. +*/ +static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07))); +} + +/* +** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg. +*/ +static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07)); +} + + /* ** Add 1 to the reference count for page iPage. If this is the second ** reference to the page, add an error message to pCheck->zErrMsg. ** Return 1 if there are 2 ore more references to the page and 0 if ** if this is the first reference to the page. @@ -57012,15 +57129,16 @@ if( iPage==0 ) return 1; if( iPage>pCheck->nPage ){ checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage); return 1; } - if( pCheck->anRef[iPage]==1 ){ + if( getPageReferenced(pCheck, iPage) ){ checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage); return 1; } - return (pCheck->anRef[iPage]++)>1; + setPageReferenced(pCheck, iPage); + return 0; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Check that the entry in the pointer-map for page iChild maps to @@ -57392,21 +57510,19 @@ *pnErr = 0; if( sCheck.nPage==0 ){ sqlite3BtreeLeave(p); return 0; } - sCheck.anRef = sqlite3Malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); - if( !sCheck.anRef ){ + + sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); + if( !sCheck.aPgRef ){ *pnErr = 1; sqlite3BtreeLeave(p); return 0; } - for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; } i = PENDING_BYTE_PAGE(pBt); - if( i<=sCheck.nPage ){ - sCheck.anRef[i] = 1; - } + if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000); sCheck.errMsg.useMalloc = 2; /* Check the integrity of the freelist */ @@ -57427,22 +57543,22 @@ /* Make sure every page in the file is referenced */ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM - if( sCheck.anRef[i]==0 ){ + if( getPageReferenced(&sCheck, i)==0 ){ checkAppendMsg(&sCheck, 0, "Page %d is never used", i); } #else /* If the database supports auto-vacuum, make sure no tables contain ** references to pointer-map pages. */ - if( sCheck.anRef[i]==0 && + if( getPageReferenced(&sCheck, i)==0 && (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ checkAppendMsg(&sCheck, 0, "Page %d is never used", i); } - if( sCheck.anRef[i]!=0 && + if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i); } #endif } @@ -57459,11 +57575,11 @@ } /* Clean up and report errors. */ sqlite3BtreeLeave(p); - sqlite3_free(sCheck.anRef); + sqlite3_free(sCheck.aPgRef); if( sCheck.mallocFailed ){ sqlite3StrAccumReset(&sCheck.errMsg); *pnErr = sCheck.nErr+1; return 0; } @@ -73807,11 +73923,11 @@ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); if( pDef==0 ){ - pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); + pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0); if( pDef==0 ){ no_such_func = 1; }else{ wrong_num_args = 1; } @@ -78277,11 +78393,11 @@ if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2; if( ExprHasProperty(pA, EP_IntValue) ){ if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){ return 2; } - }else if( pA->op!=TK_COLUMN && pA->u.zToken ){ + }else if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2; if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } @@ -78313,10 +78429,45 @@ if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; if( sqlite3ExprCompare(pExprA, pExprB) ) return 1; } return 0; } + +/* +** This is the expression callback for sqlite3FunctionUsesOtherSrc(). +** +** Determine if an expression references any table other than one of the +** tables in pWalker->u.pSrcList and abort if it does. +*/ +static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){ + int i; + SrcList *pSrc = pWalker->u.pSrcList; + for(i=0; inSrc; i++){ + if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue; + } + return WRC_Abort; + }else{ + return WRC_Continue; + } +} + +/* +** Determine if any of the arguments to the pExpr Function references +** any SrcList other than pSrcList. Return true if they do. Return +** false if pExpr has no argument or has only constant arguments or +** only references tables named in pSrcList. +*/ +static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){ + Walker w; + assert( pExpr->op==TK_AGG_FUNCTION ); + memset(&w, 0, sizeof(w)); + w.xExprCallback = exprUsesOtherSrc; + w.u.pSrcList = pSrcList; + if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1; + return 0; +} /* ** Add a new element to the pAggInfo->aCol[] array. Return the index of ** the new element. Return a negative number if malloc fails. */ @@ -78429,13 +78580,11 @@ } /* end loop over pSrcList */ } return WRC_Prune; } case TK_AGG_FUNCTION: { - /* The pNC->nDepth==0 test causes aggregate functions in subqueries - ** to be ignored */ - if( pNC->nDepth==0 ){ + if( !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList) ){ /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; inFunc; i++, pItem++){ @@ -78475,19 +78624,11 @@ } } return WRC_Continue; } static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ - NameContext *pNC = pWalker->u.pNC; - if( pNC->nDepth==0 ){ - pNC->nDepth++; - sqlite3WalkSelect(pWalker, pSelect); - pNC->nDepth--; - return WRC_Prune; - }else{ - return WRC_Continue; - } + return WRC_Continue; } /* ** Analyze the given expression looking for aggregate functions and ** for variables that need to be added to the pParse->aAgg[] array. @@ -78496,10 +78637,11 @@ ** 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.u.pNC = pNC; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); @@ -85399,43 +85541,62 @@ /* During the search for the best function definition, this procedure ** is called to test how well the function passed as the first argument ** matches the request for a function with nArg arguments in a system ** that uses encoding enc. The value returned indicates how well the ** request is matched. A higher value indicates a better match. +** +** If nArg is -1 that means to only return a match (non-zero) if p->nArg +** is also -1. In other words, we are searching for a function that +** takes a variable number of arguments. +** +** If nArg is -2 that means that we are searching for any function +** regardless of the number of arguments it uses, so return a positive +** match score for any ** ** The returned value is always between 0 and 6, as follows: ** -** 0: Not a match, or if nArg<0 and the function is has no implementation. -** 1: A variable arguments function that prefers UTF-8 when a UTF-16 -** encoding is requested, or vice versa. -** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is -** requested, or vice versa. -** 3: A variable arguments function using the same text encoding. -** 4: A function with the exact number of arguments requested that -** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa. -** 5: A function with the exact number of arguments requested that -** prefers UTF-16LE when UTF-16BE is requested, or vice versa. -** 6: An exact match. -** -*/ -static int matchQuality(FuncDef *p, int nArg, u8 enc){ - int match = 0; - if( p->nArg==-1 || p->nArg==nArg - || (nArg==-1 && (p->xFunc!=0 || p->xStep!=0)) - ){ +** 0: Not a match. +** 1: UTF8/16 conversion required and function takes any number of arguments. +** 2: UTF16 byte order change required and function takes any number of args. +** 3: encoding matches and function takes any number of arguments +** 4: UTF8/16 conversion required - argument count matches exactly +** 5: UTF16 byte order conversion required - argument count matches exactly +** 6: Perfect match: encoding and argument count match exactly. +** +** If nArg==(-2) then any function with a non-null xStep or xFunc is +** a perfect match and any function with both xStep and xFunc NULL is +** a non-match. +*/ +#define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ +static int matchQuality( + FuncDef *p, /* The function we are evaluating for match quality */ + int nArg, /* Desired number of arguments. (-1)==any */ + u8 enc /* Desired text encoding */ +){ + int match; + + /* nArg of -2 is a special case */ + if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH; + + /* Wrong number of arguments means "no match" */ + if( p->nArg!=nArg && p->nArg>=0 ) return 0; + + /* Give a better score to a function with a specific number of arguments + ** than to function that accepts any number of arguments. */ + if( p->nArg==nArg ){ + match = 4; + }else{ match = 1; - if( p->nArg==nArg || nArg==-1 ){ - match = 4; - } - if( enc==p->iPrefEnc ){ - match += 2; - } - else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) || - (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){ - match += 1; - } } + + /* Bonus points if the text encoding matches */ + if( enc==p->iPrefEnc ){ + match += 2; /* Exact encoding match */ + }else if( (enc & p->iPrefEnc & 2)!=0 ){ + match += 1; /* Both are UTF16, but with different byte orders */ + } + return match; } /* ** Search a FuncDefHash for a function with the given name. Return @@ -85487,17 +85648,16 @@ ** pointer to the FuncDef structure that defines that function, or return ** NULL if the function does not exist. ** ** If the createFlag argument is true, then a new (blank) FuncDef ** structure is created and liked into the "db" structure if a -** no matching function previously existed. When createFlag is true -** and the nArg parameter is -1, then only a function that accepts -** any number of arguments will be returned. +** no matching function previously existed. ** -** If createFlag is false and nArg is -1, then the first valid -** function found is returned. A function is valid if either xFunc -** or xStep is non-zero. +** If nArg is -2, then the first valid function found is returned. A +** function is valid if either xFunc or xStep is non-zero. The nArg==(-2) +** case is used to see if zName is a valid function name for some number +** of arguments. If nArg is -2, then createFlag must be 0. ** ** If createFlag is false, then a function with the required name and ** number of arguments may be returned even if the eTextRep flag does not ** match that requested. */ @@ -85505,18 +85665,19 @@ sqlite3 *db, /* An open database */ const char *zName, /* Name of the function. Not null-terminated */ int nName, /* Number of characters in the name */ int nArg, /* Number of arguments. -1 means any number */ u8 enc, /* Preferred text encoding */ - int createFlag /* Create new entry if true and does not otherwise exist */ + u8 createFlag /* Create new entry if true and does not otherwise exist */ ){ FuncDef *p; /* Iterator variable */ FuncDef *pBest = 0; /* Best match found so far */ int bestScore = 0; /* Score of best match */ int h; /* Hash value */ - + assert( nArg>=(-2) ); + assert( nArg>=(-1) || createFlag==0 ); assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a); /* First search for a match amongst the application-defined functions. */ @@ -85558,11 +85719,11 @@ /* If the createFlag parameter is true and the search did not reveal an ** exact match for the name, number of arguments and encoding, then add a ** new entry to the hash table and return it. */ - if( createFlag && (bestScore<6 || pBest->nArg!=nArg) && + if( createFlag && bestScorezName = (char *)&pBest[1]; pBest->nArg = (u16)nArg; pBest->iPrefEnc = enc; memcpy(pBest->zName, zName, nName); @@ -97526,11 +97687,12 @@ /***** If we reach this point, flattening is permitted. *****/ /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; - sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); + TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); + testcase( i==SQLITE_DENY ); pParse->zAuthContext = zSavedAuthContext; /* If the sub-query is a compound SELECT statement, then (by restrictions ** 17 and 18 above) it must be a UNION ALL and the parent query must ** be of the form: @@ -129049,11 +129211,10 @@ /* Advance to the next output block */ pLeaf->iBlock++; pLeaf->key.n = 0; pLeaf->block.n = 0; - nPrefix = 0; nSuffix = nTerm; nSpace = 1; nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; } @@ -132384,10 +132545,23 @@ /* Possible values for eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 +/* +** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will +** only deal with integer coordinates. No floating point operations +** will be done. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ + typedef int RtreeValue; /* Low accuracy coordinate */ +#else + typedef double RtreeDValue; /* High accuracy coordinate */ + typedef float RtreeValue; /* Low accuracy coordinate */ +#endif + /* ** The minimum number of cells allowed for a node is a third of the ** maximum. In Gutman's notation: ** ** m = M/3 @@ -132419,33 +132593,38 @@ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ }; union RtreeCoord { - float f; + RtreeValue f; int i; }; /* ** The argument is an RtreeCoord. Return the value stored within the RtreeCoord -** formatted as a double. This macro assumes that local variable pRtree points -** to the Rtree structure associated with the RtreeCoord. +** formatted as a RtreeDValue (double or int64). This macro assumes that local +** variable pRtree points to the Rtree structure associated with the +** RtreeCoord. */ -#define DCOORD(coord) ( \ - (pRtree->eCoordType==RTREE_COORD_REAL32) ? \ - ((double)coord.f) : \ - ((double)coord.i) \ -) +#ifdef SQLITE_RTREE_INT_ONLY +# define DCOORD(coord) ((RtreeDValue)coord.i) +#else +# define DCOORD(coord) ( \ + (pRtree->eCoordType==RTREE_COORD_REAL32) ? \ + ((double)coord.f) : \ + ((double)coord.i) \ + ) +#endif /* ** A search constraint. */ struct RtreeConstraint { int iCoord; /* Index of constrained coordinate */ int op; /* Constraining operation */ - double rValue; /* Constraint value. */ - int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); + RtreeDValue rValue; /* Constraint value. */ + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */ }; /* Possible values for RtreeConstraint.op */ #define RTREE_EQ 0x41 @@ -132489,14 +132668,14 @@ ** the right-hand-side of an SQL MATCH operator used to constrain an ** r-tree query. */ struct RtreeMatchArg { u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ - int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); + int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *); void *pContext; int nParam; - double aParam[1]; + RtreeDValue aParam[1]; }; /* ** When a geometry callback is created (see sqlite3_rtree_geometry_callback), ** a single instance of the following structure is allocated. It is used @@ -132504,11 +132683,11 @@ ** is eventually deleted by the destructor mechanism provided by ** sqlite3_create_function_v2() (which is called by s_r_g_c() to create ** the geometry callback function). */ struct RtreeGeomCallback { - int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); void *pContext; }; #ifndef MAX # define MAX(x,y) ((x) < (y) ? (y) : (x)) @@ -133070,11 +133249,11 @@ RtreeConstraint *pConstraint, /* MATCH constraint to test */ RtreeCell *pCell, /* Cell to test */ int *pbRes /* OUT: Test result */ ){ int i; - double aCoord[RTREE_MAX_DIMENSIONS*2]; + RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2]; int nCoord = pRtree->nDim*2; assert( pConstraint->op==RTREE_MATCH ); assert( pConstraint->pGeom ); @@ -133100,12 +133279,12 @@ int rc = SQLITE_OK; nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); for(ii=0; bRes==0 && iinConstraint; ii++){ RtreeConstraint *p = &pCursor->aConstraint[ii]; - double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); - double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); + RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); + RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH ); @@ -133153,11 +133332,11 @@ *pbEof = 0; nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); for(ii=0; iinConstraint; ii++){ RtreeConstraint *p = &pCursor->aConstraint[ii]; - double coord = DCOORD(cell.aCoord[p->iCoord]); + RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]); int res; assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH ); switch( p->op ){ @@ -133351,13 +133530,16 @@ i64 iRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); sqlite3_result_int64(ctx, iRowid); }else{ RtreeCoord c; nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c); +#ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); - }else{ + }else +#endif + { assert( pRtree->eCoordType==RTREE_COORD_INT32 ); sqlite3_result_int(ctx, c.i); } } @@ -133400,11 +133582,11 @@ if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; /* Check that the blob is roughly the right size. */ nBlob = sqlite3_value_bytes(pValue); if( nBlob<(int)sizeof(RtreeMatchArg) - || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0 + || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0 ){ return SQLITE_ERROR; } pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc( @@ -133414,11 +133596,11 @@ memset(pGeom, 0, sizeof(sqlite3_rtree_geometry)); p = (RtreeMatchArg *)&pGeom[1]; memcpy(p, sqlite3_value_blob(pValue), nBlob); if( p->magic!=RTREE_GEOMETRY_MAGIC - || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double)) + || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue)) ){ sqlite3_free(pGeom); return SQLITE_ERROR; } @@ -133486,11 +133668,15 @@ rc = deserializeGeometry(argv[ii], p); if( rc!=SQLITE_OK ){ break; } }else{ +#ifdef SQLITE_RTREE_INT_ONLY + p->rValue = sqlite3_value_int64(argv[ii]); +#else p->rValue = sqlite3_value_double(argv[ii]); +#endif } } } } @@ -133620,28 +133806,28 @@ } /* ** Return the N-dimensional volumn of the cell stored in *p. */ -static float cellArea(Rtree *pRtree, RtreeCell *p){ - float area = 1.0; +static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ + RtreeDValue area = (RtreeDValue)1; int ii; for(ii=0; ii<(pRtree->nDim*2); ii+=2){ - area = (float)(area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]))); + area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]))); } return area; } /* ** Return the margin length of cell p. The margin length is the sum ** of the objects size in each dimension. */ -static float cellMargin(Rtree *pRtree, RtreeCell *p){ - float margin = 0.0; +static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ + RtreeDValue margin = (RtreeDValue)0; int ii; for(ii=0; ii<(pRtree->nDim*2); ii+=2){ - margin += (float)(DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); + margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); } return margin; } /* @@ -133682,51 +133868,50 @@ } /* ** Return the amount cell p would grow by if it were unioned with pCell. */ -static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ - float area; +static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ + RtreeDValue area; RtreeCell cell; memcpy(&cell, p, sizeof(RtreeCell)); area = cellArea(pRtree, &cell); cellUnion(pRtree, &cell, pCell); return (cellArea(pRtree, &cell)-area); } #if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT -static float cellOverlap( +static RtreeDValue cellOverlap( Rtree *pRtree, RtreeCell *p, RtreeCell *aCell, int nCell, int iExclude ){ int ii; - float overlap = 0.0; + RtreeDValue overlap = 0.0; for(ii=0; iinDim*2); jj+=2){ - double x1; - double x2; + RtreeDValue x1, x2; x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); if( x2iDepth-iHeight); ii++){ int iCell; sqlite3_int64 iBest = 0; - float fMinGrowth = 0.0; - float fMinArea = 0.0; + RtreeDValue fMinGrowth = 0.0; + RtreeDValue fMinArea = 0.0; #if VARIANT_RSTARTREE_CHOOSESUBTREE - float fMinOverlap = 0.0; - float overlap; + RtreeDValue fMinOverlap = 0.0; + RtreeDValue overlap; #endif int nCell = NCELL(pNode); RtreeCell cell; RtreeNode *pChild; @@ -133805,12 +133989,12 @@ ** is inserted into it. Resolve ties by choosing the entry with ** the smallest area. */ for(iCell=0; iCellnDim; i++){ - float x1 = DCOORD(aCell[0].aCoord[i*2]); - float x2 = DCOORD(aCell[0].aCoord[i*2+1]); - float x3 = x1; - float x4 = x2; + RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]); + RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]); + RtreeDValue x3 = x1; + RtreeDValue x4 = x2; int jj; int iCellLeft = 0; int iCellRight = 0; for(jj=1; jjx4 ) x4 = right; if( left>x3 ){ x3 = left; @@ -133967,11 +134151,11 @@ iCellLeft = jj; } } if( x4!=x1 ){ - float normalwidth = (x3 - x2) / (x4 - x1); + RtreeDValue normalwidth = (x3 - x2) / (x4 - x1); if( normalwidth>maxNormalInnerWidth ){ iLeftSeed = iCellLeft; iRightSeed = iCellRight; } } @@ -133996,17 +134180,17 @@ int *aiUsed ){ #define FABS(a) ((a)<0.0?-1.0*(a):(a)) int iSelect = -1; - float fDiff; + RtreeDValue fDiff; int ii; for(ii=0; iifDiff ){ fDiff = diff; iSelect = ii; } } @@ -134029,17 +134213,17 @@ int ii; int jj; int iLeftSeed = 0; int iRightSeed = 1; - float fWaste = 0.0; + RtreeDValue fWaste = 0.0; for(ii=0; iifWaste ){ iLeftSeed = ii; iRightSeed = jj; fWaste = waste; @@ -134070,11 +134254,11 @@ ** sorting algorithm. */ static void SortByDistance( int *aIdx, int nIdx, - float *aDistance, + RtreeDValue *aDistance, int *aSpare ){ if( nIdx>1 ){ int iLeft = 0; int iRight = 0; @@ -134096,12 +134280,12 @@ iRight++; }else if( iRight==nRight ){ aIdx[iLeft+iRight] = aLeft[iLeft]; iLeft++; }else{ - float fLeft = aDistance[aLeft[iLeft]]; - float fRight = aDistance[aRight[iRight]]; + RtreeDValue fLeft = aDistance[aLeft[iLeft]]; + RtreeDValue fRight = aDistance[aRight[iRight]]; if( fLeftnDim+1)*(sizeof(int*)+nCell*sizeof(int)); aaSorted = (int **)sqlite3_malloc(nByte); if( !aaSorted ){ @@ -134229,13 +134413,13 @@ } SortByDimension(pRtree, aaSorted[ii], nCell, ii, aCell, aSpare); } for(ii=0; iinDim; ii++){ - float margin = 0.0; - float fBestOverlap = 0.0; - float fBestArea = 0.0; + RtreeDValue margin = 0.0; + RtreeDValue fBestOverlap = 0.0; + RtreeDValue fBestArea = 0.0; int iBestLeft = 0; int nLeft; for( nLeft=RTREE_MINCELLS(pRtree); @@ -134243,12 +134427,12 @@ nLeft++ ){ RtreeCell left; RtreeCell right; int kk; - float overlap; - float area; + RtreeDValue overlap; + RtreeDValue area; memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); for(kk=1; kk<(nCell-1); kk++){ if( kk0; i--){ RtreeCell *pNext; pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); - float diff = + RtreeDValue diff = cellGrowth(pRtree, pBboxLeft, pNext) - cellGrowth(pRtree, pBboxRight, pNext) ; if( (RTREE_MINCELLS(pRtree)-NCELL(pRight)==i) || (diff>0.0 && (RTREE_MINCELLS(pRtree)-NCELL(pLeft)!=i)) @@ -134660,58 +134844,60 @@ int iHeight ){ int *aOrder; int *aSpare; RtreeCell *aCell; - float *aDistance; + RtreeDValue *aDistance; int nCell; - float aCenterCoord[RTREE_MAX_DIMENSIONS]; + RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS]; int iDim; int ii; int rc = SQLITE_OK; + int n; - memset(aCenterCoord, 0, sizeof(float)*RTREE_MAX_DIMENSIONS); + memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS); nCell = NCELL(pNode)+1; + n = (nCell+1)&(~1); /* Allocate the buffers used by this operation. The allocation is ** relinquished before this function returns. */ - aCell = (RtreeCell *)sqlite3_malloc(nCell * ( - sizeof(RtreeCell) + /* aCell array */ - sizeof(int) + /* aOrder array */ - sizeof(int) + /* aSpare array */ - sizeof(float) /* aDistance array */ + aCell = (RtreeCell *)sqlite3_malloc(n * ( + sizeof(RtreeCell) + /* aCell array */ + sizeof(int) + /* aOrder array */ + sizeof(int) + /* aSpare array */ + sizeof(RtreeDValue) /* aDistance array */ )); if( !aCell ){ return SQLITE_NOMEM; } - aOrder = (int *)&aCell[nCell]; - aSpare = (int *)&aOrder[nCell]; - aDistance = (float *)&aSpare[nCell]; + aOrder = (int *)&aCell[n]; + aSpare = (int *)&aOrder[n]; + aDistance = (RtreeDValue *)&aSpare[n]; for(ii=0; iinDim; iDim++){ - aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]); - aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]); + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]); + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]); } } for(iDim=0; iDimnDim; iDim++){ - aCenterCoord[iDim] = (float)(aCenterCoord[iDim]/((float)nCell*2.0)); + aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); } for(ii=0; iinDim; iDim++){ - float coord = (float)(DCOORD(aCell[ii].aCoord[iDim*2+1]) - - DCOORD(aCell[ii].aCoord[iDim*2])); + RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - + DCOORD(aCell[ii].aCoord[iDim*2])); aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); } } SortByDistance(aOrder, nCell, aDistance, aSpare); @@ -134949,20 +135135,23 @@ if( nData>1 ){ int ii; /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ assert( nData==(pRtree->nDim*2 + 3) ); +#ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){ - cell.aCoord[ii].f = (float)sqlite3_value_double(azData[ii+3]); - cell.aCoord[ii+1].f = (float)sqlite3_value_double(azData[ii+4]); + cell.aCoord[ii].f = (RtreeValue)sqlite3_value_double(azData[ii+3]); + cell.aCoord[ii+1].f = (RtreeValue)sqlite3_value_double(azData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ rc = SQLITE_CONSTRAINT; goto constraint; } } - }else{ + }else +#endif + { for(ii=0; ii<(pRtree->nDim*2); ii+=2){ cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]); cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]); if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){ rc = SQLITE_CONSTRAINT; @@ -135356,11 +135545,17 @@ nodeGetCell(&tree, &node, ii, &cell); sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); nCell = (int)strlen(zCell); for(jj=0; jjmagic = RTREE_GEOMETRY_MAGIC; pBlob->xGeom = pGeomCtx->xGeom; pBlob->pContext = pGeomCtx->pContext; pBlob->nParam = nArg; for(i=0; iaParam[i] = sqlite3_value_int64(aArg[i]); +#else pBlob->aParam[i] = sqlite3_value_double(aArg[i]); +#endif } sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free); } } @@ -135455,11 +135658,11 @@ ** Register a new geometry function for use with the r-tree MATCH operator. */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *), + int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *), void *pContext ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ /* Allocate and populate the context object. */ Index: src/sqlite3.h ================================================================== --- src/sqlite3.h +++ src/sqlite3.h @@ -107,11 +107,11 @@ ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.12" #define SQLITE_VERSION_NUMBER 3007012 -#define SQLITE_SOURCE_ID "2012-03-31 19:12:23 af602d87736b52802a4e760ffeeaa28112b99d9a" +#define SQLITE_SOURCE_ID "2012-04-17 09:09:33 8e2363ad76446e863d03ead91fd621e59d5cb495" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -1545,11 +1545,11 @@ ** database connection is opened. By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined. ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] -**
SQLITE_CONFIG_PCACHE and SQLITE_CONFNIG_GETPCACHE +**
SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE **
These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -6983,11 +6983,15 @@ ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes), +#ifdef SQLITE_RTREE_INT_ONLY + int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), +#else + int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), +#endif void *pContext ); /*