Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch feech-versionedsettingsupport Excluding Merge-Ins
This is equivalent to a diff from 4e32063e22 to 201339bcc3
2014-10-24
| ||
02:24 | integrate feech-versionedsettingsupport. Not strictly fully tested, but I feel pretty good about it, so I'm going to close it out. I'll do any bugfixes here that might show up in the next days of testing. check-in: 03c3149b0e user: dave tags: dave | |
01:22 | added support for 'non-multi-var settings' (most settings, actually), which inhibits list processing (i.e. doing comma/newline normalization). Also made alteration to VC6 project file to suppress warnings about sqlite3.c. Closed-Leaf check-in: 201339bcc3 user: dave tags: feech-versionedsettingsupport | |
2014-10-23
| ||
22:21 | bug storing match_or_fail context structure; modded some accept regexes to include the 'empty is OK' metametacharacter check-in: 699fec5042 user: dave tags: feech-versionedsettingsupport | |
2014-10-20
| ||
13:06 | I committed into wrong branch, so pulling to the intended one. The changes thus far are benign, so I'm going to leave them there for the moment, and also since ultimately I'll be merging them back. (I'm such a buffoon.) check-in: d9afd076f1 user: dave tags: feech-versionedsettingsupport | |
13:02 | interim; add source for settings vtable and regexp extension functions; not wired it yet. update VC/DS projects. minor mod to auto.def to avoid redefining a define that oftentimes comes from the command line to cl, and would otherwise generate a warning in some projects. check-in: 4e32063e22 user: dave tags: dave | |
2014-10-19
| ||
15:07 | (keeping up to date; merge trunk) check-in: 92fd52048b user: dave tags: dave | |
Changes to include/fossil-scm/fossil-confdb.h.
︙ | ︙ | |||
41 42 43 44 45 46 47 | /** Signfies the repository-level configuration area. */ FSL_CONFDB_REPO = 2, /** Signfies the checkout-level (a.k.a. "local") configuration area. */ | | > > > > > > > > > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /** Signfies the repository-level configuration area. */ FSL_CONFDB_REPO = 2, /** Signfies the checkout-level (a.k.a. "local") configuration area. */ FSL_CONFDB_CKOUT = 3, /** Signifies the versioned-level (via ".fossil-settings") configuration area. */ FSL_CONFDB_VERSIONED = 4, /** Signifies the default-level (and other settings metadata) configuration area. This are is read-only, and only contains the publicly documented settings. */ FSL_CONFDB_METADATA = 5 }; typedef enum fsl_confdb_t fsl_confdb_t; /** Returns the name of the db table associated with the given mode. Results are undefined if mode is an invalid value. The returned bytes are static and constant. |
︙ | ︙ |
Changes to include/fossil-scm/fossil-core.h.
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 | FSL_EXPORT fsl_db * fsl_needs_repo(fsl_cx * f); /** The checkout-db counterpart of fsl_needs_repo(). */ FSL_EXPORT fsl_db * fsl_needs_checkout(fsl_cx * f); /** Opens the given database file as f's configuration database. If f already has a config database opened, it is closed before opening the new one. The database is created and populated with an initial schema if needed. | > > > > > > > > > > > | 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 | FSL_EXPORT fsl_db * fsl_needs_repo(fsl_cx * f); /** The checkout-db counterpart of fsl_needs_repo(). */ FSL_EXPORT fsl_db * fsl_needs_checkout(fsl_cx * f); /** The versioned settings counterpart of fsl_needs_repo(). */ FSL_EXPORT fsl_db * fsl_cx_db_versioned( fsl_cx * f ); /** The settings metadata are read-only aspects of settings. */ FSL_EXPORT fsl_db * fsl_cx_db_metadata( fsl_cx * f ); /** Opens the given database file as f's configuration database. If f already has a config database opened, it is closed before opening the new one. The database is created and populated with an initial schema if needed. |
︙ | ︙ |
Changes to include/fossil-scm/fossil-ext_regexp.h.
︙ | ︙ | |||
61 62 63 64 65 66 67 | #if !defined NET_FOSSIL_SCM_REGEXP_H_INCLUDED #define NET_FOSSIL_SCM_REGEXP_H_INCLUDED #ifdef __cplusplus extern "C" { #endif | | | | | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #if !defined NET_FOSSIL_SCM_REGEXP_H_INCLUDED #define NET_FOSSIL_SCM_REGEXP_H_INCLUDED #ifdef __cplusplus extern "C" { #endif struct sqlite3_api_routines; /*(this file is derived from sqlite3 regexp.c; I wanted to expose the engine to also be used directly*/ typedef struct sqlite3_ReCompiled sqlite3_ReCompiled; /* ** Compile a textual regular expression in zIn[] into a compiled regular ** expression suitable for us by re_match() and return a pointer to the ** compiled regular expression in *ppRe. Return NULL on success or an ** error message if something goes wrong. */ const char* sqlite3re_compile ( sqlite3_ReCompiled** ppRe, const char* zIn, int noCase ); /* Free and reclaim all the memory used by a previously compiled ** regular expression. Applications should invoke this routine once ** for every call to re_compile() to avoid memory leaks. */ void sqlite3re_free ( sqlite3_ReCompiled* pRe ); /* Run a compiled regular expression on the zero-terminated input ** string zIn[]. Return true on a match and false if there is no match. */ int sqlite3re_match ( sqlite3_ReCompiled* pRe, const unsigned char* zIn, int nIn ); /*registers the REGEXP extension function into a sqlite3 database instance */ int sqlite3_regexp_init ( sqlite3* db, char** pzErrMsg, const struct sqlite3_api_routines* pApi ); |
︙ | ︙ |
Changes to include/fossil-scm/fossil-vtbl_fossil_settings.h.
︙ | ︙ | |||
17 18 19 20 21 22 23 | #define NET_FOSSIL_SCM_VTBLFOSSILSETTINGS_H_INCLUDED #ifdef __cplusplus extern "C" { #endif | | > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #define NET_FOSSIL_SCM_VTBLFOSSILSETTINGS_H_INCLUDED #ifdef __cplusplus extern "C" { #endif struct sqlite3_api_routines; /*registers some sqlite3 extensions for handling versioned settings */ int sqlite3_vtbl_fossilsettings_init ( sqlite3* db, char** pzErrMsg, const struct sqlite3_api_routines* pApi ); |
︙ | ︙ |
Changes to libfossil_VC6.dsp.
︙ | ︙ | |||
278 279 280 281 282 283 284 | # Begin Source File SOURCE=.\src\fsl_zip.c # End Source File # Begin Source File SOURCE=.\src\sqlite3.c | | | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | # Begin Source File SOURCE=.\src\fsl_zip.c # End Source File # Begin Source File SOURCE=.\src\sqlite3.c # ADD CPP /w /W0 # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File |
︙ | ︙ |
Changes to src/Makefile.in.
1 2 3 | all: include ../subdir-inc.make #$(error $(TOP_SRCDIR)) | | | 1 2 3 4 5 6 7 8 9 10 11 | all: include ../subdir-inc.make #$(error $(TOP_SRCDIR)) CPPFLAGS += -DBUILD_libfossil -DSQLITE_CORE #CPPFLAGS += -I$(TOP_INCDIR) #CPPFLAGS += -I$(TOP_SRCDIR)/include #CPPFLAGS += -I$(TOP_SRCDIR)/src# workaround for in-tree sqlite3.h EXTRA_LIBS := -lz EXTRA_LIBS += $(LDFLAGS_MODULE_LOADER) #INCLUDES_PATH ?= $(HOME)/include /usr/local/include /usr/include |
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | fsl_config.c \ fsl_cx.c \ fsl_db.c \ fsl_delta.c \ fsl_diff.c \ fsl_encode.c \ fsl_event.c \ fsl_fs.c \ fsl_glob.c \ fsl_io.c \ fsl_leaf.c \ fsl_list.c \ fsl_md5.c \ fsl_mf.c \ fsl_path.c \ fsl_popen.c \ fsl_pq.c \ fsl_repo.c \ fsl_schema.c \ fsl_sha1.c \ fsl_strftime.c \ fsl_tag.c \ fsl_ticket.c \ fsl_utf8.c \ fsl_vfile.c \ fsl_wiki.c \ fsl_zip.c FSL.SRC := $(FSL.SRC.BASE) \ fsl_jni.c \ fsl_tcl.c | > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | fsl_config.c \ fsl_cx.c \ fsl_db.c \ fsl_delta.c \ fsl_diff.c \ fsl_encode.c \ fsl_event.c \ fsl_ext_regexp.c \ fsl_fs.c \ fsl_glob.c \ fsl_io.c \ fsl_leaf.c \ fsl_list.c \ fsl_md5.c \ fsl_mf.c \ fsl_path.c \ fsl_popen.c \ fsl_pq.c \ fsl_repo.c \ fsl_schema.c \ fsl_sha1.c \ fsl_strftime.c \ fsl_tag.c \ fsl_ticket.c \ fsl_utf8.c \ fsl_vfile.c \ fsl_vtbl_fossil_settings.c \ fsl_wiki.c \ fsl_zip.c FSL.SRC := $(FSL.SRC.BASE) \ fsl_jni.c \ fsl_tcl.c |
︙ | ︙ | |||
173 174 175 176 177 178 179 180 181 182 183 184 185 186 | $(INCD)/fossil-hash.h \ $(INCD)/fossil-content.h \ $(INCD)/fossil-confdb.h \ $(INCD)/fossil-path.h \ $(INCD)/fossil-internal.h \ $(INCD)/fossil-auth.h \ $(INCD)/fossil-pages.h \ $(INCD)/fossil-cli.h $(AMAL_H.SRC): $(AMAL_C.SRC): $(AMAL_H): $(MAKEFILE_LIST) $(AMAL_H.SRC) $(AMAL_CONF.H) $(AMAL_C): $(MAKEFILE_LIST) $(AMAL_H) $(AMAL_C.SRC) $(AMAL_CONF.H): $(MAIN_MAKEFILES) @echo "Generating $@ ..." | > > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | $(INCD)/fossil-hash.h \ $(INCD)/fossil-content.h \ $(INCD)/fossil-confdb.h \ $(INCD)/fossil-path.h \ $(INCD)/fossil-internal.h \ $(INCD)/fossil-auth.h \ $(INCD)/fossil-pages.h \ $(INCD)/fossil-ext_regexp.h \ $(INCD)/fossil-vtbl_fossil_settings.h \ $(INCD)/fossil-cli.h $(AMAL_H.SRC): $(AMAL_C.SRC): $(AMAL_H): $(MAKEFILE_LIST) $(AMAL_H.SRC) $(AMAL_CONF.H) $(AMAL_C): $(MAKEFILE_LIST) $(AMAL_H) $(AMAL_C.SRC) $(AMAL_CONF.H): $(MAIN_MAKEFILES) @echo "Generating $@ ..." |
︙ | ︙ |
Changes to src/fsl_config.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #define SELECT_FROM_CONFIG "SELECT value FROM %s WHERE name=?" char const * fsl_config_table_for_role(fsl_confdb_t mode){ switch(mode){ case FSL_CONFDB_REPO: return "config"; case FSL_CONFDB_CKOUT: return "vvar"; case FSL_CONFDB_GLOBAL: return "global_config"; default: assert(!"Invalid fsl_confdb_t value"); return NULL; } } fsl_db * fsl_config_for_role(fsl_cx * f, fsl_confdb_t mode){ switch(mode){ case FSL_CONFDB_REPO: return fsl_cx_db_repo(f); case FSL_CONFDB_CKOUT: return fsl_cx_db_checkout(f); case FSL_CONFDB_GLOBAL: return fsl_cx_db_config(f); default: assert(!"Invalid fsl_confdb_t value"); return NULL; } } | > > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #define SELECT_FROM_CONFIG "SELECT value FROM %s WHERE name=?" char const * fsl_config_table_for_role(fsl_confdb_t mode){ switch(mode){ case FSL_CONFDB_REPO: return "config"; case FSL_CONFDB_CKOUT: return "vvar"; case FSL_CONFDB_GLOBAL: return "global_config"; case FSL_CONFDB_VERSIONED: return "versionedsettings"; case FSL_CONFDB_METADATA: return "settingsmetadata"; default: assert(!"Invalid fsl_confdb_t value"); return NULL; } } fsl_db * fsl_config_for_role(fsl_cx * f, fsl_confdb_t mode){ switch(mode){ case FSL_CONFDB_REPO: return fsl_cx_db_repo(f); case FSL_CONFDB_CKOUT: return fsl_cx_db_checkout(f); case FSL_CONFDB_GLOBAL: return fsl_cx_db_config(f); case FSL_CONFDB_VERSIONED: return fsl_cx_db_versioned(f); case FSL_CONFDB_METADATA: return fsl_cx_db_metadata(f); default: assert(!"Invalid fsl_confdb_t value"); return NULL; } } |
︙ | ︙ |
Changes to src/fsl_cx.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | http://www.hwaci.com/drh/ ***************************************************************************** This file houses most of the context-related APIs. */ #include "fossil-scm/fossil-internal.h" #include <assert.h> #if defined(_WIN32) # include <windows.h> # define F_OK 0 # define W_OK 2 #else # include <unistd.h> /* F_OK */ | > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | http://www.hwaci.com/drh/ ***************************************************************************** This file houses most of the context-related APIs. */ #include "fossil-scm/fossil-internal.h" #include <assert.h> #include "fossil-scm/fossil-ext_regexp.h" #include "fossil-scm/fossil-vtbl_fossil_settings.h" #if defined(_WIN32) # include <windows.h> # define F_OK 0 # define W_OK 2 #else # include <unistd.h> /* F_OK */ |
︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 | f = fsl_cx_malloc(); if(!f) return FSL_RC_OOM; *tgt = f; } f->output = param->output; f->cxConfig = param->config; return rc; } void fsl_cx_reset(fsl_cx * f, char closeDatabases){ if(!f) return; fsl_checkin_discard(f); #define SFREE(X) fsl_free(X); X = NULL | > > > > > > > > > > > > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | f = fsl_cx_malloc(); if(!f) return FSL_RC_OOM; *tgt = f; } f->output = param->output; f->cxConfig = param->config; /*HHH idempotent */ { static int bRegistered = 0; if ( ! bRegistered ) { /*register our statically linked extensions to be auto-init'ed at the appropriate time*/ sqlite3_auto_extension((void(*)(void))(sqlite3_vtbl_fossilsettings_init)); /*our settings vtables*/ sqlite3_auto_extension((void(*)(void))(sqlite3_regexp_init)); /*sqlite regexp extension*/ bRegistered = 1; } } return rc; } void fsl_cx_reset(fsl_cx * f, char closeDatabases){ if(!f) return; fsl_checkin_discard(f); #define SFREE(X) fsl_free(X); X = NULL |
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 | fsl_db * fsl_cx_db_checkout( fsl_cx * f ){ if(!f) return NULL; else if(f->ckout.db.dbh) return &f->ckout.db; else if(f->dbMain && (FSL_DB_ROLE_CHECKOUT & f->dbMain->role)) return f->dbMain; else return NULL; } fsl_db * fsl_cx_db( fsl_cx * f ){ return f ? f->dbMain : NULL; } | > > > > > > > > > > | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | fsl_db * fsl_cx_db_checkout( fsl_cx * f ){ if(!f) return NULL; else if(f->ckout.db.dbh) return &f->ckout.db; else if(f->dbMain && (FSL_DB_ROLE_CHECKOUT & f->dbMain->role)) return f->dbMain; else return NULL; } fsl_db * fsl_cx_db_versioned( fsl_cx * f ){ /*the 'versioned settings' is a virtual table strapped onto the checkout db*/ return fsl_cx_db_checkout ( f ); } fsl_db * fsl_cx_db_metadata( fsl_cx * f ){ /*the 'settings metadata' is a virtual table strapped onto the main db*/ return fsl_cx_db ( f ); } fsl_db * fsl_cx_db( fsl_cx * f ){ return f ? f->dbMain : NULL; } |
︙ | ︙ | |||
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 | *(end+1) = 0; /* rather than strdup'ing, we'll just lop off the filename part. Keep the '/' for historical conventions purposes. */ f->ckout.dir = (char *)buf->mem; *buf = fsl_buffer_empty /* we took ownership of buf->mem */; assert(!f->ckout.dir[f->ckout.dirLen]); assert('/' == f->ckout.dir[f->ckout.dirLen-1]); /* why? rc = fsl_config_open(f, NULL); Seems to me we don't need that at the library level. In my experience global config options for a lib which is used by multiple apps are generally a bad idea, as no single setting of any given property will be best for all apps. Fossil's global config db assumes that there is only one fossil-based app, which is no longer the case. */ f->flags |= FSL_CX_F_IS_OPENING_CKOUT; rc = fsl_repo_open_for_checkout(f); f->flags &= ~FSL_CX_F_IS_OPENING_CKOUT; rc = fsl_cx_after_open(f); if(rc){ /* Is this sane? Is not doing it sane? */ fsl_checkout_close(f); } return rc; } | > > > > > > > > > > > > > > > > > > > > > > | 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 | *(end+1) = 0; /* rather than strdup'ing, we'll just lop off the filename part. Keep the '/' for historical conventions purposes. */ f->ckout.dir = (char *)buf->mem; *buf = fsl_buffer_empty /* we took ownership of buf->mem */; assert(!f->ckout.dir[f->ckout.dirLen]); assert('/' == f->ckout.dir[f->ckout.dirLen-1]); /*defensively drop any existing table definition; there shouldn't be one, but maybe could be if the application crashed before closing gracefully*/ rc = sqlite3_exec ( f->dbMain->dbh, "DROP TABLE versionedsettings;", NULL, NULL, NULL ); /*now we create our versioned settings table*/ { /*alas, we must coin the name ourselves, because parameters to CREATE VIRTUAL TABLE are not processed by sqlite, so we can't use FSL_CKOUT_DIR(). Since we go that far, we might as well just add the surrounding sql as well.*/ fsl_buffer strCreateSql; strCreateSql = fsl_buffer_empty; fsl_buffer_append ( &strCreateSql, "CREATE VIRTUAL TABLE " "versionedsettings USING VERSIONED_SETTINGS( '", -1 ); fsl_buffer_append ( &strCreateSql, f->ckout.dir, -1 ); fsl_buffer_append ( &strCreateSql, ".fossil-settings", -1 ); fsl_buffer_append ( &strCreateSql, "', MKDIR );", -1 ); rc = sqlite3_exec ( f->dbMain->dbh, fsl_buffer_cstr ( &strCreateSql ), NULL, NULL, NULL ); fsl_buffer_clear ( &strCreateSql ); } /* why? rc = fsl_config_open(f, NULL); Seems to me we don't need that at the library level. In my experience global config options for a lib which is used by multiple apps are generally a bad idea, as no single setting of any given property will be best for all apps. Fossil's global config db assumes that there is only one fossil-based app, which is no longer the case. */ f->flags |= FSL_CX_F_IS_OPENING_CKOUT; rc = fsl_repo_open_for_checkout(f); f->flags &= ~FSL_CX_F_IS_OPENING_CKOUT; /*HHH this updates some copies of settings!!!*/ rc = fsl_cx_after_open(f); if(rc){ /* Is this sane? Is not doing it sane? */ fsl_checkout_close(f); } return rc; } |
︙ | ︙ |
Changes to src/fsl_db.c.
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 | fsl_db_transaction_end(db, 1); } if(0!=db->openStatementCount){ MARKER(("WARNING: %d open statement(s) left on db [%s].\n", (int)db->openStatementCount, db->filename)); } if(db->dbh){ sqlite3_close(db->dbh) /* ignoring result in the style of "destructors may not throw". */; } fsl_db_clear_strings(db, 1); fsl_db_cleanup_beforeCommit(db); | > > > > | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | fsl_db_transaction_end(db, 1); } if(0!=db->openStatementCount){ MARKER(("WARNING: %d open statement(s) left on db [%s].\n", (int)db->openStatementCount, db->filename)); } if(db->dbh){ /*drop our virtual tables, if they exist*/ int rc; rc = sqlite3_exec ( db->dbh, "DROP TABLE settingsmetadata;", NULL, NULL, NULL ); rc = sqlite3_exec ( db->dbh, "DROP TABLE versionedsettings;", NULL, NULL, NULL ); sqlite3_close(db->dbh) /* ignoring result in the style of "destructors may not throw". */; } fsl_db_clear_strings(db, 1); fsl_db_cleanup_beforeCommit(db); |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 | /* functions registered in v1 by db.c:db_open(). */ /* porting cgi() requires access to the HTTP/CGI layer. i.e. this belongs downstream. */ sqlite3_create_function(dbh, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0); sqlite3_create_function(dbh, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0); re_add_sql_func(db) /* Requires the regex bits. */; #endif }/*if(db->f)*/ } end: if(rc){ #if 1 /* This is arguable... */ if(db->f && db->error.code && !db->f->error.code){ | > > > > > | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | /* functions registered in v1 by db.c:db_open(). */ /* porting cgi() requires access to the HTTP/CGI layer. i.e. this belongs downstream. */ sqlite3_create_function(dbh, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0); sqlite3_create_function(dbh, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0); re_add_sql_func(db) /* Requires the regex bits. */; #endif /*HHH check out the re_add_sql_func; did we already have regex somewhere?*/ /*create the settingsmetadata virtual table in the db*/ rc = sqlite3_exec ( dbh, "CREATE VIRTUAL TABLE IF NOT EXISTS " "settingsmetadata USING SETTINGS_METADATA();", NULL, NULL, NULL ); assert(SQLITE_OK==rc); /*shoud only fails if you haven't registered the extension*/ }/*if(db->f)*/ } end: if(rc){ #if 1 /* This is arguable... */ if(db->f && db->error.code && !db->f->error.code){ |
︙ | ︙ |
Changes to src/fsl_ext_regexp.c.
︙ | ︙ | |||
59 60 61 62 63 64 65 | ** this expansion. */ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #ifndef SQLITE_CORE #include "sqlite3ext.h" | | < < < < < < < < | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ** this expansion. */ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #ifndef SQLITE_CORE #include "sqlite3ext.h" /*declares extern the vtable of all the sqlite3 functions (for loadable modules only)*/ SQLITE_EXTENSION_INIT3 #else #include "sqlite3.h" #endif #include "fossil-scm/fossil-ext_regexp.h" #include <string.h> #include <stdlib.h> /* The end-of-input character */ #define RE_EOF 0 /* End of input */ /* The NFA is implemented as sequence of opcodes taken from the following ** set. Each opcode has a single integer argument. */ |
︙ | ︙ | |||
102 103 104 105 106 107 108 | #define RE_OP_DIGIT 13 /* digit: [0-9] */ #define RE_OP_NOTDIGIT 14 /* Not a digit */ #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ #define RE_OP_NOTSPACE 16 /* Not a digit */ #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ /* Each opcode is a "state" in the NFA */ | | | | | | | > | | | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | #define RE_OP_DIGIT 13 /* digit: [0-9] */ #define RE_OP_NOTDIGIT 14 /* Not a digit */ #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ #define RE_OP_NOTSPACE 16 /* Not a digit */ #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ /* Each opcode is a "state" in the NFA */ typedef unsigned short sqlite3_ReStateNumber; /* Because this is an NFA and not a DFA, multiple states can be active at ** once. An instance of the following object records all active states in ** the NFA. The implementation is optimized for the common case where the ** number of actives states is small. */ typedef struct sqlite3_ReStateSet { unsigned nState; /* Number of current states */ sqlite3_ReStateNumber *aState; /* Current states */ } sqlite3_ReStateSet; /* An input string read one character at a time. */ typedef struct sqlite3_ReInput sqlite3_ReInput; struct sqlite3_ReInput { const unsigned char *z; /* All text */ int i; /* Next byte to read */ int mx; /* EOF when i>=mx */ }; /* A compiled NFA (or an NFA that is in the process of being compiled) is ** an instance of the following object. */ /*typedef struct sqlite3_ReCompiled sqlite3_ReCompiled;*/ struct sqlite3_ReCompiled { sqlite3_ReInput sIn; /* Regular expression text */ const char *zErr; /* Error message to return */ char *aOp; /* Operators for the virtual machine */ int *aArg; /* Arguments to each operator */ unsigned (*xNextChar)(sqlite3_ReInput*); /* Next character function */ unsigned char zInit[12]; /* Initial text to match */ int nInit; /* Number of characters in zInit */ unsigned nState; /* Number of entries in aOp[] and aArg[] */ unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ }; /* Add a state to the given state set if it is not already there */ static void sqlite3re_add_state(sqlite3_ReStateSet *pSet, int newState){ unsigned i; for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return; pSet->aState[pSet->nState++] = newState; } /* Extract the next unicode character from *pzIn and return it. Advance ** *pzIn to the first byte past the end of the character returned. To ** be clear: this routine converts utf8 to unicode. This routine is ** optimized for the common case where the next character is a single byte. */ static unsigned sqlite3re_next_char(sqlite3_ReInput *p){ unsigned c; if( p->i>=p->mx ) return 0; c = p->z[p->i++]; if( c>=0x80 ){ if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); if( c<0x80 ) c = 0xfffd; |
︙ | ︙ | |||
175 176 177 178 179 180 181 | if( c<=0xffff || c>0x10ffff ) c = 0xfffd; }else{ c = 0xfffd; } } return c; } | | | | | | | | | | | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | if( c<=0xffff || c>0x10ffff ) c = 0xfffd; }else{ c = 0xfffd; } } return c; } static unsigned sqlite3re_next_char_nocase(sqlite3_ReInput *p){ unsigned c = sqlite3re_next_char(p); if( c>='A' && c<='Z' ) c += 'a' - 'A'; return c; } /* Return true if c is a perl "word" character: [A-Za-z0-9_] */ static int sqlite3re_word_char(int c){ return (c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='_'; } /* Return true if c is a "digit" character: [0-9] */ static int sqlite3re_digit_char(int c){ return (c>='0' && c<='9'); } /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */ static int sqlite3re_space_char(int c){ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* Run a compiled regular expression on the zero-terminated input ** string zIn[]. Return true on a match and false if there is no match. */ int sqlite3re_match(sqlite3_ReCompiled *pRe, const unsigned char *zIn, int nIn){ sqlite3_ReStateSet aStateSet[2], *pThis, *pNext; sqlite3_ReStateNumber aSpace[100]; sqlite3_ReStateNumber *pToFree; unsigned int i = 0; unsigned int iSwap = 0; int c = RE_EOF+1; int cPrev = 0; int rc = 0; sqlite3_ReInput in; in.z = zIn; in.i = 0; in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); /* Look for the initial prefix match, if there is one. */ if( pRe->nInit ){ |
︙ | ︙ | |||
231 232 233 234 235 236 237 | if( in.i+pRe->nInit>in.mx ) return 0; } if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ pToFree = 0; aStateSet[0].aState = aSpace; }else{ | | | | | | | | | | | | | | | | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | if( in.i+pRe->nInit>in.mx ) return 0; } if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ pToFree = 0; aStateSet[0].aState = aSpace; }else{ pToFree = sqlite3_malloc( sizeof(sqlite3_ReStateNumber)*2*pRe->nState ); if( pToFree==0 ) return -1; aStateSet[0].aState = pToFree; } aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; pNext = &aStateSet[1]; pNext->nState = 0; sqlite3re_add_state(pNext, 0); while( c!=RE_EOF && pNext->nState>0 ){ cPrev = c; c = pRe->xNextChar(&in); pThis = pNext; pNext = &aStateSet[iSwap]; iSwap = 1 - iSwap; pNext->nState = 0; for(i=0; i<pThis->nState; i++){ int x = pThis->aState[i]; switch( pRe->aOp[x] ){ case RE_OP_MATCH: { if( pRe->aArg[x]==c ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_ANY: { sqlite3re_add_state(pNext, x+1); break; } case RE_OP_WORD: { if( sqlite3re_word_char(c) ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_NOTWORD: { if( !sqlite3re_word_char(c) ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_DIGIT: { if( sqlite3re_digit_char(c) ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_NOTDIGIT: { if( !sqlite3re_digit_char(c) ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_SPACE: { if( sqlite3re_space_char(c) ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_NOTSPACE: { if( !sqlite3re_space_char(c) ) sqlite3re_add_state(pNext, x+1); break; } case RE_OP_BOUNDARY: { if( sqlite3re_word_char(c)!=sqlite3re_word_char(cPrev) ) sqlite3re_add_state(pThis, x+1); break; } case RE_OP_ANYSTAR: { sqlite3re_add_state(pNext, x); sqlite3re_add_state(pThis, x+1); break; } case RE_OP_FORK: { sqlite3re_add_state(pThis, x+pRe->aArg[x]); sqlite3re_add_state(pThis, x+1); break; } case RE_OP_GOTO: { sqlite3re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } case RE_OP_CC_INC: |
︙ | ︙ | |||
324 325 326 327 328 329 330 | j = -1; }else{ j++; } } } if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | j = -1; }else{ j++; } } } if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; if( hit ) sqlite3re_add_state(pNext, x+n); break; } } } } for(i=0; i<pNext->nState; i++){ if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } } re_match_end: sqlite3_free(pToFree); return rc; } /* Resize the opcode and argument arrays for an RE under construction. */ static int sqlite3re_resize(sqlite3_ReCompiled *p, int N){ char *aOp; int *aArg; aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0])); if( aOp==0 ) return 1; p->aOp = aOp; aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0])); if( aArg==0 ) return 1; p->aArg = aArg; p->nAlloc = N; return 0; } /* Insert a new opcode and argument into an RE under construction. The ** insertion point is just prior to existing opcode iBefore. */ static int sqlite3re_insert(sqlite3_ReCompiled *p, int iBefore, int op, int arg){ int i; if( p->nAlloc<=p->nState && sqlite3re_resize(p, p->nAlloc*2) ) return 0; for(i=p->nState; i>iBefore; i--){ p->aOp[i] = p->aOp[i-1]; p->aArg[i] = p->aArg[i-1]; } p->nState++; p->aOp[iBefore] = op; p->aArg[iBefore] = arg; return iBefore; } /* Append a new opcode and argument to the end of the RE under construction. */ static int sqlite3re_append(sqlite3_ReCompiled *p, int op, int arg){ return sqlite3re_insert(p, p->nState, op, arg); } /* Make a copy of N opcodes starting at iStart onto the end of the RE ** under construction. */ static void sqlite3re_copy(sqlite3_ReCompiled *p, int iStart, int N){ if( p->nState+N>=p->nAlloc && sqlite3re_resize(p, p->nAlloc*2+N) ) return; memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0])); memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0])); p->nState += N; } /* Return true if c is a hexadecimal digit character: [0-9a-fA-F] ** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If ** c is not a hex digit *pV is unchanged. */ static int sqlite3re_hex(int c, int *pV){ if( c>='0' && c<='9' ){ c -= '0'; }else if( c>='a' && c<='f' ){ c -= 'a' - 10; }else if( c>='A' && c<='F' ){ c -= 'A' - 10; }else{ return 0; } *pV = (*pV)*16 + (c & 0xff); return 1; } /* A backslash character has been seen, read the next character and ** return its interpretation. */ static unsigned sqlite3re_esc_char(sqlite3_ReCompiled *p){ static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; static const char zTrans[] = "\a\f\n\r\t\v"; int i, v = 0; char c; if( p->sIn.i>=p->sIn.mx ) return 0; c = p->sIn.z[p->sIn.i]; if( c=='u' && p->sIn.i+4<p->sIn.mx ){ const unsigned char *zIn = p->sIn.z + p->sIn.i; if( sqlite3re_hex(zIn[1],&v) && sqlite3re_hex(zIn[2],&v) && sqlite3re_hex(zIn[3],&v) && sqlite3re_hex(zIn[4],&v) ){ p->sIn.i += 5; return v; } } if( c=='x' && p->sIn.i+2<p->sIn.mx ){ const unsigned char *zIn = p->sIn.z + p->sIn.i; if( sqlite3re_hex(zIn[1],&v) && sqlite3re_hex(zIn[2],&v) ){ p->sIn.i += 3; return v; } } for(i=0; zEsc[i] && zEsc[i]!=c; i++){} if( zEsc[i] ){ if( i<6 ) c = zTrans[i]; p->sIn.i++; }else{ p->zErr = "unknown \\ escape"; } return c; } /* Forward declaration */ static const char* sqlite3re_subcompile_string(sqlite3_ReCompiled*); /* Peek at the next byte of input */ static unsigned char sqlite3rePeek(sqlite3_ReCompiled *p){ return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0; } /* Compile RE text into a sequence of opcodes. Continue up to the ** first unmatched ")" character, then return. If an error is found, ** return a pointer to the error message string. */ static const char* sqlite3re_subcompile_re(sqlite3_ReCompiled *p){ const char *zErr; int iStart, iEnd, iGoto; iStart = p->nState; zErr = sqlite3re_subcompile_string(p); if( zErr ) return zErr; while( sqlite3rePeek(p)=='|' ){ iEnd = p->nState; sqlite3re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart); iGoto = sqlite3re_append(p, RE_OP_GOTO, 0); p->sIn.i++; zErr = sqlite3re_subcompile_string(p); if( zErr ) return zErr; p->aArg[iGoto] = p->nState - iGoto; } return 0; } /* Compile an element of regular expression text (anything that can be ** an operand to the "|" operator). Return NULL on success or a pointer ** to the error message if there is a problem. */ static const char* sqlite3re_subcompile_string(sqlite3_ReCompiled *p){ int iPrev = -1; int iStart; unsigned c; const char *zErr; while( (c = p->xNextChar(&p->sIn))!=0 ){ iStart = p->nState; switch( c ){ case '|': case '$': case ')': { p->sIn.i--; return 0; } case '(': { zErr = sqlite3re_subcompile_re(p); if( zErr ) return zErr; if( sqlite3rePeek(p)!=')' ) return "unmatched '('"; p->sIn.i++; break; } case '.': { if( sqlite3rePeek(p)=='*' ){ sqlite3re_append(p, RE_OP_ANYSTAR, 0); p->sIn.i++; }else{ sqlite3re_append(p, RE_OP_ANY, 0); } break; } case '*': { if( iPrev<0 ) return "'*' without operand"; sqlite3re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); sqlite3re_append(p, RE_OP_FORK, iPrev - p->nState + 1); break; } case '+': { if( iPrev<0 ) return "'+' without operand"; sqlite3re_append(p, RE_OP_FORK, iPrev - p->nState); break; } case '?': { if( iPrev<0 ) return "'?' without operand"; sqlite3re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); break; } case '{': { int m = 0, n = 0; int sz, j; if( iPrev<0 ) return "'{m,n}' without operand"; while( (c=sqlite3rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } n = m; if( c==',' ){ p->sIn.i++; n = 0; while( (c=sqlite3rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } } if( c!='}' ) return "unmatched '{'"; if( n>0 && n<m ) return "n less than m in '{m,n}'"; p->sIn.i++; sz = p->nState - iPrev; if( m==0 ){ if( n==0 ) return "both m and n are zero in '{m,n}'"; sqlite3re_insert(p, iPrev, RE_OP_FORK, sz+1); n--; }else{ for(j=1; j<m; j++) sqlite3re_copy(p, iPrev, sz); } for(j=m; j<n; j++){ sqlite3re_append(p, RE_OP_FORK, sz+1); sqlite3re_copy(p, iPrev, sz); } if( n==0 && m>0 ){ sqlite3re_append(p, RE_OP_FORK, -sz); } break; } case '[': { int iFirst = p->nState; if( sqlite3rePeek(p)=='^' ){ sqlite3re_append(p, RE_OP_CC_EXC, 0); p->sIn.i++; }else{ sqlite3re_append(p, RE_OP_CC_INC, 0); } while( (c = p->xNextChar(&p->sIn))!=0 ){ if( c=='[' && sqlite3rePeek(p)==':' ){ return "POSIX character classes not supported"; } if( c=='\\' ) c = sqlite3re_esc_char(p); if( sqlite3rePeek(p)=='-' ){ sqlite3re_append(p, RE_OP_CC_RANGE, c); p->sIn.i++; c = p->xNextChar(&p->sIn); if( c=='\\' ) c = sqlite3re_esc_char(p); sqlite3re_append(p, RE_OP_CC_RANGE, c); }else{ sqlite3re_append(p, RE_OP_CC_VALUE, c); } if( sqlite3rePeek(p)==']' ){ p->sIn.i++; break; } } if( c==0 ) return "unclosed '['"; p->aArg[iFirst] = p->nState - iFirst; break; } case '\\': { int specialOp = 0; switch( sqlite3rePeek(p) ){ case 'b': specialOp = RE_OP_BOUNDARY; break; case 'd': specialOp = RE_OP_DIGIT; break; case 'D': specialOp = RE_OP_NOTDIGIT; break; case 's': specialOp = RE_OP_SPACE; break; case 'S': specialOp = RE_OP_NOTSPACE; break; case 'w': specialOp = RE_OP_WORD; break; case 'W': specialOp = RE_OP_NOTWORD; break; } if( specialOp ){ p->sIn.i++; sqlite3re_append(p, specialOp, 0); }else{ c = sqlite3re_esc_char(p); sqlite3re_append(p, RE_OP_MATCH, c); } break; } default: { sqlite3re_append(p, RE_OP_MATCH, c); break; } } iPrev = iStart; } return 0; } /* Free and reclaim all the memory used by a previously compiled ** regular expression. Applications should invoke this routine once ** for every call to re_compile() to avoid memory leaks. */ void sqlite3re_free(sqlite3_ReCompiled *pRe){ if( pRe ){ sqlite3_free(pRe->aOp); sqlite3_free(pRe->aArg); sqlite3_free(pRe); } } /* ** Compile a textual regular expression in zIn[] into a compiled regular ** expression suitable for us by re_match() and return a pointer to the ** compiled regular expression in *ppRe. Return NULL on success or an ** error message if something goes wrong. */ const char* sqlite3re_compile(sqlite3_ReCompiled **ppRe, const char *zIn, int noCase){ sqlite3_ReCompiled *pRe; const char *zErr; int i, j; *ppRe = 0; pRe = sqlite3_malloc( sizeof(*pRe) ); if( pRe==0 ){ return "out of memory"; } memset(pRe, 0, sizeof(*pRe)); pRe->xNextChar = noCase ? sqlite3re_next_char_nocase : sqlite3re_next_char; if( sqlite3re_resize(pRe, 30) ){ sqlite3re_free(pRe); return "out of memory"; } if( zIn[0]=='^' ){ zIn++; }else{ sqlite3re_append(pRe, RE_OP_ANYSTAR, 0); } pRe->sIn.z = (unsigned char*)zIn; pRe->sIn.i = 0; pRe->sIn.mx = (int)strlen(zIn); zErr = sqlite3re_subcompile_re(pRe); if( zErr ){ sqlite3re_free(pRe); return zErr; } if( sqlite3rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ sqlite3re_append(pRe, RE_OP_MATCH, RE_EOF); sqlite3re_append(pRe, RE_OP_ACCEPT, 0); *ppRe = pRe; }else if( pRe->sIn.i>=pRe->sIn.mx ){ sqlite3re_append(pRe, RE_OP_ACCEPT, 0); *ppRe = pRe; }else{ sqlite3re_free(pRe); return "unrecognized character"; } /* The following is a performance optimization. If the regex begins with ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ if( pRe->aOp[0]==RE_OP_ANYSTAR ){ for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ unsigned x = pRe->aArg[i]; if( x<=127 ){ pRe->zInit[j++] = x; }else if( x<=0xfff ){ pRe->zInit[j++] = 0xc0 | (x>>6); pRe->zInit[j++] = 0x80 | (x&0x3f); }else if( x<=0xffff ){ |
︙ | ︙ | |||
715 716 717 718 719 720 721 | ** is implemented as regexp(B,A). */ static void re_sql_func( sqlite3_context *context, int argc, sqlite3_value **argv ){ | | | | | | | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 | ** is implemented as regexp(B,A). */ static void re_sql_func( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_ReCompiled *pRe; /* Compiled regular expression */ const char *zPattern; /* The regular expression */ const unsigned char *zStr;/* String being searched */ const char *zErr; /* Compile error message */ int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ pRe = sqlite3_get_auxdata(context, 0); if( pRe==0 ){ zPattern = (const char*)sqlite3_value_text(argv[0]); if( zPattern==0 ) return; zErr = sqlite3re_compile(&pRe, zPattern, 0); if( zErr ){ sqlite3re_free(pRe); sqlite3_result_error(context, zErr, -1); return; } if( pRe==0 ){ sqlite3_result_error_nomem(context); return; } setAux = 1; } zStr = (const unsigned char*)sqlite3_value_text(argv[1]); if( zStr!=0 ){ sqlite3_result_int(context, sqlite3re_match(pRe, zStr, -1)); } if( setAux ){ sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))sqlite3re_free); } } /* ** Invoke this routine to register the regexp() function with the ** SQLite database connection. */ int sqlite3_regexp_init( sqlite3 *db, char **pzErrMsg, const struct sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT2(pApi) /*sets up the 'vtable' to the host exe sqlite3 impl*/ #else #endif rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, re_sql_func, 0, 0); return rc; } |
Changes to src/fsl_vtbl_fossil_settings.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include <direct.h> #else #include <unistd.h> #include <strings.h> #endif #include "fossil-scm/fossil-ext_regexp.h" /*sqlite3's regex engine*/ #include "fossil-scm/fossil-util.h" /*for some internal class defs*/ #ifndef COUNTOF #define COUNTOF(arr) (sizeof(arr)/sizeof(*arr)) #endif | > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <direct.h> #else #include <unistd.h> #include <strings.h> #endif #include "fossil-scm/fossil-ext_regexp.h" /*sqlite3's regex engine*/ #include "fossil-scm/fossil-core.h" /*for some public defs*/ #include "fossil-scm/fossil-util.h" /*for some internal class defs*/ #ifndef COUNTOF #define COUNTOF(arr) (sizeof(arr)/sizeof(*arr)) #endif |
︙ | ︙ | |||
85 86 87 88 89 90 91 92 93 94 95 96 97 98 | /*descriptor of a well-known (publicly facing) setting in fossil*/ struct tagSettingDesc { const char* _pszName; /*setting name*/ bool _bIsVersionable; /*can it be in .fossil-settings?*/ const char* _pszDefault; /*the default value, if any*/ const char* _pszHelp; /*Help text, tooltip*/ int _nHelpTextID; /*id of Help text (for eventual i18n)*/ const char* _pszRegexAccept; /*regex to validate input value*/ }; typedef struct tagSettingDesc SettingDesc; /*common validation regexes*/ | > > > > > > > > > > > > > > > | > > | | > > > > > > > | > > | > > | > > | > > | > > > > > > > > | | > | > > > > > > > > | > | > > | > | > > > | > > > > > | > | > > > > | > | > | > > | > | > | > > > > > > > | | | | | | | > | | | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 | /*descriptor of a well-known (publicly facing) setting in fossil*/ struct tagSettingDesc { const char* _pszName; /*setting name*/ bool _bIsVersionable; /*can it be in .fossil-settings?*/ const char* _pszDefault; /*the default value, if any*/ const char* _pszHelp; /*Help text, tooltip*/ int _nHelpTextID; /*id of Help text (for eventual i18n)*/ bool _bIsMultivalue; /*should there be list processing?*/ const char* _pszRegexAccept; /*regex to validate input value*/ }; typedef struct tagSettingDesc SettingDesc; /*common validation regexes*/ /*Note: we have created some 'extended' metacharacters beyond those supported by the regex engine proper: \$i regex is case-insensitive \$m regex is for a multi-valued setting (e.g. 'ignore-glob') \$e regex should match the empty setting as well these metacharacters must be at the beginning of the regex, because we handle their processing programattically, and use the rest of the string to compile as per usual. These metacharacters are needed principally because MATCH_OR_FAIL doesn't have context of the setting it is validating, to get to the metadata for that setting. I could have made MATCH_OR_FAIL also take the setting name, so that it can find the metatdata, but this way it is also generally useful for other non-setting-related data validation purposes. */ static const char sg_pszreNonvalidated[] = ".*"; static const char sg_pszreBasicMultivalue[] = "\\$e\\$m^\\s*[^,\n\r]*\\s*$"; static const char sg_pszreBoolean[] = "\\$e\\$i^\\s*(true|false|1|0|on|off|yes|no)\\s*$"; static const char sg_pszreNumber[] = "\\$e^\\s*\\d+\\s*$"; static const char sg_pszreDecNumber[] = "\\$e^\\s*(\\d+\\.?\\d*)\\s*|\\s*(\\d*\\.?\\d+)\\s*$"; static const char sg_pszrePermissions[] = "^[abcdefghijklmnopqrstuvwxz]*$"; /*Note, these MUST be in alpha order by name, because we do binary searches*/ /*over the collection*/ static const SettingDesc g_asdSettingsDescriptors[] = { { "access-log", false, "off", "If enabled, record successful and failed login attempts " "in the \"accesslog\" table.", 0, false, sg_pszreBoolean }, { "allow-symlinks", true, "off", "If enabled, don't follow symlinks, and instead treat " "them as symlinks on Unix. Has no effect on Windows " "(existing links in repository created on Unix become " "plain-text files with link destination path inside).", 0, false, sg_pszreBoolean }, { "auto-captcha", false, "on", "If enabled, the Login page provides a button to " "fill in the captcha password.", 0, false, sg_pszreBoolean }, { "auto-hyperlink", false, "on", "Use javascript to enable hyperlinks on web pages " "for all users (regardless of the \"h\" privilege) if the " "User-Agent string in the HTTP header look like it came " "from real person, not a spider or bot.", 0, false, sg_pszreBoolean }, { "auto-shun", false, "on", "If enabled, automatically pull the shunning list " "from a server to which the client autosyncs.", 0, false, sg_pszreBoolean }, { "autosync", false, "on", "If enabled, automatically pull prior to commit " "or update and automatically push after commit or " "tag or branch creation. If the value is \"pullonly\" " "then only pull operations occur automatically.", 0, false, sg_pszreBoolean }, { "binary-glob", true, "", "The VALUE is a comma or newline-separated list of " "GLOB patterns that should be treated as binary files " "for committing and merging purposes. Example: *.jpg ", 0, true, sg_pszreBasicMultivalue }, { "case-sensitive", false, "false", "If TRUE, the files whose names differ only in case " "are considered distinct. If FALSE files whose names " "differ only in case are the same file.\r\n" "Defaults to TRUE for unix and FALSE for Cygwin, Mac and Windows.", 0, false, sg_pszreBoolean }, { "clean-glob", true, "", "The VALUE is a comma or newline-separated list of GLOB " "patterns specifying files that the \"clean\" command will " "delete without prompting even when the -force flag has " "not been used. Example: *.a *.lib *.o", 0, true, sg_pszreBasicMultivalue }, { "clearsign", false, "off", "When enabled, fossil will attempt to sign all commits " "with gpg. When disabled (the default), commits will " "be unsigned.", 0, false, sg_pszreBoolean }, { "crnl-glob", true, "", "A comma or newline-separated list of GLOB patterns for " "text files in which it is ok to have CR, CR+NL or mixed " "line endings. Set to \"*\" to disable CR+NL checking.", 0, true, sg_pszreBasicMultivalue }, { "default-perms", false, "u", "Permissions given automatically to new users. For more " "information on permissions see Users page in Server " "Administration of the HTTP UI.", 0, false, sg_pszrePermissions }, { "diff-binary", false, "true", "If TRUE (the default), permit files that may be binary " "or that match the \"binary-glob\" setting to be used with " "external diff programs. If FALSE, skip these files.", 0, false, sg_pszreBoolean }, { "diff-command", false, "", "External command to run when performing a diff.\r\n" "If undefined, the internal text diff will be used.", 0, false, sg_pszreNonvalidated }, { "dont-push", false, "false", "Prevent this repository from pushing from client to " "server. Useful when setting up a private branch.", 0, false, sg_pszreBoolean }, { "editor", false, #ifdef WIN32 "notepad.exe", #elif defined ( __APPLE__ ) || defined ( __OSX__ ) "", /*YYY verify*/ #else "", /*YYY verify*/ #endif "Text editor command used for check-in comments.", 0, false, sg_pszreNonvalidated }, { "empty-dirs", true, "", "A comma or newline-separated list of pathnames. On " "update and checkout commands, if no file or directory " "exists with that name, an empty directory will be " "created.", 0, true, sg_pszreBasicMultivalue }, { "encoding-glob", true, "", "The VALUE is a comma or newline-separated list of GLOB " "patterns specifying files that the \"commit\" command will " "ignore when issuing warnings about text files that may " "use another encoding than ASCII or UTF-8. Set to \"*\" " "to disable encoding checking.", 0, true, sg_pszreBasicMultivalue }, { "gdiff-command", false, #ifdef WIN32 "WinDiff.exe", #elif defined ( __APPLE__ ) || defined ( __OSX__ ) "", /*YYY verify*/ #else "", /*YYY verify*/ #endif "External command to run when performing a graphical " "diff. If undefined, text diff will be used.", 0, false, sg_pszreNonvalidated }, { "gmerge-command", false, "", "A graphical merge conflict resolver command operating " "on four files.\r\n" "Ex: kdiff3 \"%baseline\" \"%original\" \"%merge\" -o \"%output\"\r\n" "Ex: xxdiff \"%original\" \"%baseline\" \"%merge\" -M \"%output\"\r\n" "Ex: meld \"%baseline\" \"%original\" \"%merge\" \"%output\"", 0, false, sg_pszreNonvalidated }, { "http-port", false, "8080", "The TCP/IP port number to use by the \"server\"" "and \"ui\" commands.", 0, false, sg_pszreNumber }, { "https-login", false, "", "Send login credentials using HTTPS instead of HTTP " "even if the login page request came via HTTP.", 0, false, sg_pszreBoolean }, { "ignore-glob", true, "", "The VALUE is a comma or newline-separated list of GLOB " "patterns specifying files that the \"add\", \"addremove\", " "\"clean\", and \"extra\" commands will ignore.\r\n" "Example: *.log customCode.c notes.txt", 0, true, sg_pszreBasicMultivalue }, { "keep-glob", true, "", "The VALUE is a comma or newline-separated list of GLOB " "patterns specifying files that the \"clean\" command will " "keep.", 0, true, sg_pszreBasicMultivalue }, { "localauth", false, "false", "If enabled, require that HTTP connections from " "127.0.0.1 be authenticated by password. If " "false, all HTTP requests from localhost have " "unrestricted access to the repository.", 0, false, sg_pszreBoolean }, { "main-branch", false, "trunk", "The primary branch for the project.", 0, false, sg_pszreNonvalidated /*YYY need regex*/ }, { "manifest", true, "off", "If enabled, automatically create files \"manifest\" and " "\"manifest.uuid\" in every checkout. The SQLite and " "Fossil repositories both require this.", 0, false, sg_pszreBoolean }, { "max-loadavg", false, "0.0", "Some CPU-intensive web pages (ex: /zip, /tarball, /blame) " "are disallowed if the system load average goes above this " "value. \"0.0\" means no limit. This only works on unix.\r\n" "Only local settings of this value make a difference since " "when running as a web-server, Fossil does not open the " "global configuration database.", 0, false, sg_pszreDecNumber }, { "max-upload", false, "250000", "A limit on the size of uplink HTTP requests. The " "default is 250000 bytes.", 0, false, sg_pszreNumber }, { "mtime-changes", false, "on", "Use file modification times (mtimes) to detect when " "files have been modified.", 0, false, sg_pszreBoolean }, { "pgp-command", false, "gpg --clearsign -o ", "Command used to clear-sign manifests at check-in.", 0, false, sg_pszreNonvalidated }, { "proxy", false, "", "URL of the HTTP proxy. If undefined or \"off\" then " "the \"http_proxy\" environment variable is consulted.\r\n" "If the http_proxy environment variable is undefined " "then a direct HTTP connection is used.", 0, false, sg_pszreNonvalidated /*YYY could/should be better?*/ }, { "relative-paths", false, "on", "When showing changes and extras, report paths relative " "to the current working directory.", 0, false, sg_pszreBoolean }, { "repo-cksum", false, "on", "Compute checksums over all files in each checkout " "as a double-check of correctness. Defaults to \"on\". " "Disable on large repositories for a performance " "improvement.", 0, false, sg_pszreBoolean }, { "self-register", false, "off", "Allow users to register themselves through the HTTP UI.\r\n" "This is useful if you want to see other names than " "\"Anonymous\" in e.g. ticketing system. On the other hand " "users can not be deleted.", 0, false, sg_pszreBoolean }, { "ssh-command", false, "", "Command used to talk to a remote machine with " "the \"ssh://\" protocol.", 0, false, sg_pszreNonvalidated }, { "ssl-ca-location", false, "", "The full pathname to a file containing PEM encoded " "CA root certificates, or a directory of certificates " "with filenames formed from the certificate hashes as " "required by OpenSSL.\r\n" "If set, this will override the OS default list of " "OpenSSL CAs. If unset, the default list will be used.\r\n" "Some platforms may add additional certificates.\r\n" "Check your platform behaviour is as required if the " "exact contents of the CA root is critical for your " "application.", 0, false, sg_pszreNonvalidated }, { "ssl-identity", false, "", "The full pathname to a file containing a certificate " "and private key in PEM format. Create by concatenating " "the certificate and private key files.\r\n" "This identity will be presented to SSL servers to " "authenticate this client, in addition to the normal " "password authentication.", 0, false, sg_pszreNonvalidated }, { "tcl", false, "off", "If enabled (and Fossil was compiled with Tcl support), " "Tcl integration commands will be added to the TH1 " "interpreter, allowing arbitrary Tcl expressions and " "scripts to be evaluated from TH1. Additionally, the Tcl " "interpreter will be able to evaluate arbitrary TH1 " "expressions and scripts.", 0, false, sg_pszreBoolean }, { "tcl-setup", true, "", "This is the setup script to be evaluated after creating " "and initializing the Tcl interpreter. By default, this " "is empty and no extra setup is performed.", 0, false, sg_pszreNonvalidated }, { "th1-setup", true, "", "This is the setup script to be evaluated after creating " "and initializing the TH1 interpreter. By default, this " "is empty and no extra setup is performed.", 0, false, sg_pszreNonvalidated }, { "th1-uri-regexp", true, "", "Specify which URI's are allowed in HTTP requests from " "TH1 scripts. If empty, no HTTP requests are allowed " "whatsoever. The default is an empty string.", 0, false, sg_pszreNonvalidated }, { "web-browser", false, #ifdef WIN32 "start", #elif defined ( __APPLE__ ) || defined ( __OSX__ ) "open", #else "firefox", #endif "A shell command used to launch your preferred " "web browser when given a URL as an argument.\r\n" "Defaults to \"start\" on windows, \"open\" on Mac, " "and \"firefox\" on Unix.", 0, false, sg_pszreNonvalidated }, }; static const size_t g_asdSettingsDescriptorsCount = COUNTOF(g_asdSettingsDescriptors); /*=========================================== / *our objects for settings metadata v-table */ struct tagvtblSetMetDat_table { sqlite3_vtab _base; /*const sqlite3_module *pModule; / *The module for this virtual table*/ /*int nRef; / *NO LONGER USED*/ /*char *zErrMsg; / *Error message from sqlite3_mprintf()*/ /*Virtual table implementations will typically add additional fields*/ }; typedef struct tagvtblSetMetDat_table vtblSetMetDat_table; static vtblSetMetDat_table* vtblSetMetDat_table_new ( void ) { vtblSetMetDat_table* pThis = (vtblSetMetDat_table*) malloc ( sizeof(vtblSetMetDat_table) ); /*any ctor actions...*/ /*YYY (BBB docs say lib will set these up, but it doesn't. it does setup pModule, however)*/ pThis->_base.nRef = 0; /*unused, but we clear it anyway*/ pThis->_base.zErrMsg = NULL; /*ensure null lest there be crashes when lib tries to free*/ return pThis; } static void vtblSetMetDat_table_delete ( vtblSetMetDat_table* pThis ) { if ( NULL != pThis ) { /*any dtor actions...*/ free ( pThis ); } } struct tagvtblSetMetDat_cursor { sqlite3_vtab_cursor _base; /*sqlite3_vtab *pVtab; / *Virtual table of this cursor*/ /*Virtual table implementations will typically add additional fields*/ size_t _nIdxEntry; }; typedef struct tagvtblSetMetDat_cursor vtblSetMetDat_cursor; static vtblSetMetDat_cursor* vtblSetMetDat_cursor_new() { vtblSetMetDat_cursor* pThis = (vtblSetMetDat_cursor*) malloc ( sizeof(vtblSetMetDat_cursor) ); /*(any ctor actions...)*/ pThis->_nIdxEntry = 0; return pThis; } static void vtblSetMetDat_cursor_delete ( vtblSetMetDat_cursor* pThis ) { if ( NULL != pThis ) { /*(any dtor actions...)*/ free ( pThis ); } } /*===========================================*/ /*sqlite vtable interface code*/ /*'table' stuff*/ /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/ static int vtblSetMetDat_Create ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) { /*argv[0] / *name of module*/ /*argv[1] / *name of database; "main", "temp", ...*/ /*argv[2] / *name of the virtual table*/ /*argv[3...] / *arguments of the sql create virtual table statement; if present*/ /*first, declare our effective schema*/ int ret = sqlite3_declare_vtab ( db, "CREATE TABLE [ignored] ( " "NAME TEXT," /*setting name*/ "ISVERSIONABLE INTEGER," /*can it be in .fossil-settings*/ "DEFAULT_VALUE TEXT," /*the default value, if any*/ "VALUE TEXT HIDDEN," /*the default value, aliased to 'value'*/ "HELP TEXT," /*Help text, tooltip*/ "HELP_ID INTEGER," /*id of Help text (for eventual i18n)*/ "REGEX_ACCEPT TEXT" /*regex to validate input value*/ ")" ); if ( SQLITE_OK != ret ) return ret; /*anything else we need?*/ *ppVTab = &vtblSetMetDat_table_new()->_base; return SQLITE_OK; } /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/ /*last connection to this table is going away*/ static int vtblSetMetDat_Destroy ( sqlite3_vtab* pVTab ) { vtblSetMetDat_table* pThis = DOWNCAST(vtblSetMetDat_table,_base,pVTab); vtblSetMetDat_table_delete ( pThis ); return SQLITE_OK; } /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate */ /*new connection to existing table; we just treat it the same as 'create'*/ static int vtblSetMetDat_Connect ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) { return vtblSetMetDat_Create ( db, pAux, argc, argv, ppVTab, pzErr ); } /*xDisconnect -- drop virtual table, but not the last one*/ /*table is going away, but not last one*/ /*(BBB actually I have seen the last one go away via this method in the*/ /*case of database closure when there was not an explicit drop table)*/ static int vtblSetMetDat_Disconnect ( sqlite3_vtab* pVTab ) { return vtblSetMetDat_Destroy ( pVTab ); } /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/ /*think about what query is being done, and indicate what possible internal*/ /*quasi-index we might have*/ static int vtblSetMetDat_BestIndex ( sqlite3_vtab* pVTab, sqlite3_index_info* pIdxInfo ) { /* vtblSetMetDat_table* pThis = DOWNCAST(vtblSetMetDat_table,_base,pVTab); int nIdx; / *Inputs* / pIdxInfo->nConstraint; / *Number of entries in aConstraint* / pIdxInfo->aConstraint[0].iColumn; / *Column on left-hand side of constraint* / pIdxInfo->aConstraint[0].op; / *Constraint operator* / |
︙ | ︙ | |||
715 716 717 718 719 720 721 | /*===========================================*/ /*'cursor' stuff*/ /*xOpen -- open a cursor*/ | | | | | | | | > > | | | | | | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 | /*===========================================*/ /*'cursor' stuff*/ /*xOpen -- open a cursor*/ static int vtblSetMetDat_cursor_Open ( sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor ) { *ppCursor = &vtblSetMetDat_cursor_new()->_base; return SQLITE_OK; } /*xClose -- close a cursor*/ static int vtblSetMetDat_cursor_Close ( sqlite3_vtab_cursor* pCur ) { vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur); vtblSetMetDat_cursor_delete ( pThis ); return SQLITE_OK; } static int vtblSetMetDat_cursor_Filter ( sqlite3_vtab_cursor* pCur, int idxNum, const char* idxStr, int argc, sqlite3_value** argv ) { vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur); /*position cursor to location based on value arguments and parameters that ultimately came from xBestIndex*/ /*this will 'rewind' the cursor to the beginning*/ pThis->_nIdxEntry = 0; return SQLITE_OK; } /*xNext -- advance a cursor*/ static int vtblSetMetDat_cursor_Next ( sqlite3_vtab_cursor* pCur ) { vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur); /*advance a cursor*/ /*we iterate through the list*/ if ( pThis->_nIdxEntry != g_asdSettingsDescriptorsCount ) { /*still some left*/ ++pThis->_nIdxEntry; /*next*/ return SQLITE_OK; } return SQLITE_OK; } /*xEof -- check for end of scan*/ static int vtblSetMetDat_cursor_Eof ( sqlite3_vtab_cursor* pCur ) { vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur); /*check for end of iteration*/ return ( g_asdSettingsDescriptorsCount == pThis->_nIdxEntry ) ? 1 : 0; } /*xColumn -- read data*/ static int vtblSetMetDat_cursor_Column ( sqlite3_vtab_cursor* pCur, sqlite3_context* pCtx, int nCol ) { vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur); const SettingDesc* psd; /*read data*/ if ( g_asdSettingsDescriptorsCount == pThis->_nIdxEntry ) { /*shouldn't happen; I don't think*/ sqlite3_result_error ( pCtx, "reading past end vtblSetMetDat_cursor", -1 ); return SQLITE_ERROR; } psd = &g_asdSettingsDescriptors[pThis->_nIdxEntry]; switch ( nCol ) { /*"NAME TEXT," / *setting name*/ case 0: sqlite3_result_text ( pCtx, psd->_pszName, -1, SQLITE_STATIC ); break; /*"ISVERSIONABLE INTEGER," / *can it be in .fossil-settings*/ case 1: sqlite3_result_int ( pCtx, psd->_bIsVersionable ? 1 : 0 ); break; /*"DEFAULT_VALUE TEXT," / *the default value, if any*/ /*"VALUE TEXT," / *the default value, aliased to 'value'*/ case 2: case 3: if ( NULL == psd->_pszDefault || '\0' == psd->_pszDefault[0] ) sqlite3_result_null ( pCtx ); else sqlite3_result_text ( pCtx, psd->_pszDefault, -1, SQLITE_STATIC ); break; /*HELP TEXT," / *Help text, tooltip*/ case 4: if ( NULL == psd->_pszHelp || '\0' == psd->_pszHelp[0] ) sqlite3_result_null ( pCtx ); else sqlite3_result_text ( pCtx, psd->_pszHelp, -1, SQLITE_STATIC ); break; /*"HELP_ID INTEGER," / *id of Help text (for eventual i18n)*/ case 5: sqlite3_result_int ( pCtx, psd->_nHelpTextID ); break; /*"REGEX_ACCEPT TEXT" / *regex to validate input value*/ case 6: if ( NULL == psd->_pszRegexAccept || '\0' == psd->_pszRegexAccept[0] ) sqlite3_result_null ( pCtx ); else sqlite3_result_text ( pCtx, psd->_pszRegexAccept, -1, SQLITE_STATIC ); break; default: /*que?*/ sqlite3_result_null ( pCtx ); break; } return SQLITE_OK; } /*xRowid -- read data*/ static int vtblSetMetDat_cursor_Rowid ( sqlite3_vtab_cursor* pCur, sqlite3_int64* pRowid ) { vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur); /*read data*/ *pRowid = pThis->_nIdxEntry; return SQLITE_OK; } static const sqlite3_module sg_pvtblSettingsMetadata = { 2, /*iVersion -- version of this structure, so sqlite doesn't access past end*/ vtblSetMetDat_Create, /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/ vtblSetMetDat_Connect, /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/ vtblSetMetDat_BestIndex, /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/ vtblSetMetDat_Disconnect, /*xDisconnect -- drop virtual table, but not the last one*/ vtblSetMetDat_Destroy, /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/ vtblSetMetDat_cursor_Open, /*xOpen -- open a cursor*/ |
︙ | ︙ | |||
876 877 878 879 880 881 882 | /*since there are only a handful of 'versioned' settings that are supported,*/ /*and since the ones that are, are small textual values, we will just make*/ /*our life easier here, and read them all into memory at once.*/ | | > > > > | | | | | | | | | | > > | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | /*since there are only a handful of 'versioned' settings that are supported,*/ /*and since the ones that are, are small textual values, we will just make*/ /*our life easier here, and read them all into memory at once.*/ /*for multi-valued types (e.g. 'ignore-glob'), we attempt to detect and preserve the style of the original file to minimize diffs*/ typedef enum StyleValueSeparation { SEPSTYLE_UNKNOWN = 0, /*couldn't figure it out; probably because there were no multi-values*/ SEPSTYLE_NEWLINE = 1, SEPSTYLE_COMMA = 2, SEPSTYLE_NONE = 3 /*this type is known to not be multivalue; inhibit list processing*/ } StyleValueSeparation; /*we attempt to detect and preserve the newline style of the original file to minimize diffs*/ typedef enum tagStyleLineEnding { NLSTYLE_UNKNOWN = 0, /*couldn't figure it out; probably because there were no newlines*/ NLSTYLE_CRLF = 1, /*DOS/Windows*/ NLSTYLE_CR = 2, /*Mac*/ NLSTYLE_LF = 3 /*Unices*/ } StyleLineEnding; #if defined(WIN32) || defined(WINDOWS) || defined(DOS) static const char sg_chPathSep = '\\'; #else static const char sg_chPathSep = '/'; #endif struct tagSettingInfo { fsl_buffer _strName; /*name*/ fsl_buffer _strValue; /*value, normalized to CSV*/ /*We try to figure out the separators from the file itself, so we can*/ /*preserve those choices when persisting back out. This is done as a*/ /*courtesy, to avoid creating unnecessary diffs.*/ StyleValueSeparation _esvsSep; /*what was the original value separation style*/ StyleLineEnding _esleNewline; /*what was the original 'newline' style*/ fsl_buffer _strOriginalPath; /*what file contained this setting*/ /*synthesized properties*/ sqlite_int64 _nRowId; /*sqlite needs this, and it can only be int64*/ }; typedef struct tagSettingInfo SettingInfo; static void SettingInfo_ctor ( SettingInfo* pThis ) { pThis->_strName = fsl_buffer_empty; /*name*/ pThis->_strValue = fsl_buffer_empty; /*value, normalized to CSV*/ /*We try to figure out the separators from the file itself, so we can*/ /*preserve those choices when persisting back out. This is done as a*/ /*courtesy, to avoid creating unnecessary diffs.*/ pThis->_esvsSep = SEPSTYLE_UNKNOWN; /*what was the original value separation style*/ pThis->_esleNewline = NLSTYLE_UNKNOWN; /*what was the original 'newline' style*/ pThis->_strOriginalPath = fsl_buffer_empty; /*what file contained this setting*/ /*synthesized properties*/ pThis->_nRowId = 0; /*sqlite needs this, and it can only be int64*/ } static void SettingInfo_dtor ( SettingInfo* pThis ) { fsl_buffer_clear( &pThis->_strName ); fsl_buffer_clear( &pThis->_strValue ); fsl_buffer_clear( &pThis->_strOriginalPath ); } static SettingInfo* SettingInfo_new ( void ) { SettingInfo* pThis = (SettingInfo*) malloc ( sizeof(SettingInfo) ); SettingInfo_ctor ( pThis ); return pThis; } static void SettingInfo_delete ( SettingInfo* pThis ) { if ( NULL != pThis ) { SettingInfo_dtor ( pThis ); free ( pThis ); } } static int fsl_list_visitor_free ( void* obj, void* visitorState ) { fsl_free ( obj ); return 0; } static SettingInfo* SettingInfo_createFromFile ( const char* pszDir, const SettingDesc* pdesc ) { /*Note to self; this impl was originally in C++, where it (maybe) made a*/ /*little more sense, however a tidier impl comes to mind:*/ /** read the whole file into buffer*/ /** characterise the styles from that buffer*/ /** strpbrk out the comma, cr, lf -> nul*/ /* list_append the ptr into the buffer of the start of the value text*/ /** finally, transform the value into csv*/ /*this would avoid a lot of buffer copies and dtor code*/ /*YYY Note: fsl_buffer_fill_from_filename can help*/ /*YYY Note: fsl_glob_list_parse/fsl_glob_list_clear can help*/ StyleValueSeparation esvsSep; StyleLineEnding esleNewline; fsl_buffer strPath; struct _stat buf; fsl_buffer strValue; SettingInfo* psi; strPath = fsl_buffer_empty; fsl_buffer_appendf ( &strPath, "%s%c%s", pszDir, sg_chPathSep, pdesc->_pszName ); /*if the file does not exist, we can't try to depersist*/ if ( 0 != _stat ( fsl_buffer_cstr ( &strPath ), &buf ) ) { fsl_buffer_clear ( &strPath ); return NULL; } |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 | } /*unknown; impossible*/ } } } fclose ( f ); } | > > > | > | > > > > > > > > > > > | | | | | | | | | < | | | | | | | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 | } /*unknown; impossible*/ } } } fclose ( f ); } /*well, OK, if metadata says we're not multivalue, override any inferred sep style*/ if ( ! pdesc->_bIsMultivalue ) { esvsSep = SEPSTYLE_NONE; } /*now, open file, read lines, parse seps, build string list, then*/ /*anneal string list into csv*/ strValue = fsl_buffer_empty; if ( SEPSTYLE_NONE == esvsSep ) { if ( FSL_RC_OK != fsl_buffer_fill_from_filename ( &strValue, fsl_buffer_cstr ( &strPath ) ) ) { /*absurd; we just opened it a moment ago*/ fsl_buffer_clear ( &strValue ); fsl_buffer_clear ( &strPath ); return NULL; } } else { /*YYY reimplement this using the fsl_glob_list_parse()*/ fsl_list lstrValues; fsl_buffer strToken; char ch; size_t nRead; bool bEOF; FILE* f; fsl_size_t nIdx; lstrValues = fsl_list_empty; strToken = fsl_buffer_empty; f = fopen ( fsl_buffer_cstr ( &strPath ), "rb" ); if ( NULL == f ) { /*absurd; we just opened it a moment ago*/ fsl_buffer_clear ( &strToken ); fsl_list_reserve ( &lstrValues, 0 ); fsl_buffer_clear ( &strValue ); fsl_buffer_clear ( &strPath ); return NULL; } while ( nRead = fread ( &ch, sizeof(ch), 1, f ), bEOF = ( sizeof(ch) != nRead ), ! bEOF ) { if ( ',' == ch || '\r' == ch || '\n' == ch ) { if ( 0 != fsl_buffer_size ( &strToken ) ) { /*push token*/ fsl_list_append ( &lstrValues, fsl_strdup ( fsl_buffer_cstr ( &strToken ) ) ); fsl_buffer_reset ( &strToken ); } } else /*build token*/ fsl_buffer_append ( &strToken, &ch, sizeof(ch) ); } if ( 0 != fsl_buffer_size ( &strToken ) ) { /*a last one? (like if file ended without final sep)*/ fsl_list_append ( &lstrValues, fsl_strdup ( fsl_buffer_cstr ( &strToken ) ) ); fsl_buffer_reset ( &strToken ); } fclose ( f ); /*normalize into CSV*/ for ( nIdx = 0; nIdx < lstrValues.used; ++nIdx ) { char chComma = ','; if ( 0 != fsl_buffer_size ( &strValue ) ) fsl_buffer_append ( &strValue, &chComma, sizeof(chComma) ); fsl_buffer_append ( &strValue, lstrValues.list[nIdx], fsl_strlen ( lstrValues.list[nIdx] ) ); } /*dtor*/ fsl_buffer_clear ( &strToken ); fsl_list_clear ( &lstrValues, fsl_list_visitor_free, NULL ); } /*OK, now we can get down to business...*/ psi = SettingInfo_new(); fsl_buffer_append ( &psi->_strName, pdesc->_pszName, fsl_strlen ( pdesc->_pszName ) ); fsl_buffer_append ( &psi->_strOriginalPath, fsl_buffer_cstr ( &strPath ), fsl_buffer_size ( &strPath ) ); psi->_esvsSep = esvsSep; psi->_esleNewline = esleNewline; fsl_buffer_append ( &psi->_strValue, fsl_buffer_cstr ( &strValue ), fsl_buffer_size ( &strValue ) ); psi->_nRowId = 0; /*(parent will set this up)*/ fsl_buffer_clear ( &strValue ); fsl_buffer_clear ( &strPath ); return psi; } static SettingInfo* SettingInfo_createFromParams ( const char* pszDir, const char* pszName, const char* pszValue, StyleValueSeparation esvsSep, StyleLineEnding esleNewline ) { fsl_buffer strPath; SettingInfo* psi; strPath = fsl_buffer_empty; fsl_buffer_appendf ( &strPath, "%s%c%s", pszDir, sg_chPathSep, pszName ); |
︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 | fsl_buffer_clear ( &strPath ); return psi; } | | > > > > > > > > > | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | fsl_buffer_clear ( &strPath ); return psi; } static bool SettingInfo_saveToFile ( const SettingInfo* pThis ) { if ( SEPSTYLE_NONE == pThis->_esvsSep ) { /*this is not a multivar; just emit the data verbatim*/ if ( FSL_RC_OK != fsl_buffer_to_filename( &pThis->_strValue, fsl_buffer_cstr ( &pThis->_strOriginalPath ) ) ) { return false; } } else { FILE* f; size_t nIdx; f = fopen ( fsl_buffer_cstr ( &pThis->_strOriginalPath ), "wb" ); if ( NULL == f ) { return false; } /*emit characters in the string until we hit a ',' which we will*/ /*translate into separators/newline according to style.*/ for ( nIdx = 0; nIdx < fsl_buffer_size ( &pThis->_strValue ); ++nIdx ) { if ( ',' == pThis->_strValue.mem[nIdx] ) { if ( SEPSTYLE_COMMA == pThis->_esvsSep ) { char ch = ','; fwrite ( &ch, sizeof(ch), 1, f ); } else { if ( NLSTYLE_CRLF == pThis->_esleNewline ) { char ach[2] = { '\r', '\n' }; fwrite ( ach, sizeof(ach), 1, f ); } else if ( NLSTYLE_CR == pThis->_esleNewline ) { char ch = '\r'; fwrite ( &ch, sizeof(ch), 1, f ); } else { /*NLSTYLE_LF*/ char ch = '\n'; fwrite ( &ch, sizeof(ch), 1, f ); } } } else { fwrite ( &pThis->_strValue.mem[nIdx], sizeof(pThis->_strValue.mem[nIdx]), 1, f ); } } fclose ( f ); } return true; } static bool SettingInfo_removeFile ( const SettingInfo* pThis ) { return 0 == _unlink ( fsl_buffer_cstr ( &pThis->_strOriginalPath ) ); } /*our setting collection is a map of 'rowid's to settings info*/ /*since we only have a few known 'versioned settings', I am just going to use*/ /*an array, and do a linear search for my finds.*/ struct tagSettingCollTuple { sqlite_int64 _nRowId; SettingInfo* _psi; }; typedef struct tagSettingCollTuple SettingCollTuple; static int fsl_list_visitor_settingtuple_free ( void* obj, void* visitorState ) { SettingCollTuple* ptpl = (SettingCollTuple*)obj; /*dtor on the tuple members*/ /*ptpl->_nRowId*/ SettingInfo_delete ( ptpl->_psi ); /*delete the tuple*/ free ( ptpl ); return 0; |
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | fsl_list _settings; /*the settings, depersisted from files*/ int _nCursorsOpen; /*count of open cursors; some updating cannot happen with > 1*/ }; typedef struct tagvtblVerSet_table vtblVerSet_table; | | | | | | | | | | | | | | | 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 | fsl_list _settings; /*the settings, depersisted from files*/ int _nCursorsOpen; /*count of open cursors; some updating cannot happen with > 1*/ }; typedef struct tagvtblVerSet_table vtblVerSet_table; static void vtblVerSet_table_ctor ( vtblVerSet_table* pThis, sqlite3* db, const char* pszVerSettingsPath ) { /*YYY (BBB docs say lib will set these up, but it doesn't. it does setup pModule, however)*/ pThis->_base.nRef = 0; /*unused, but we clear it anyway*/ pThis->_base.zErrMsg = NULL; /*ensure null lest there be crashes when lib tries to free*/ pThis->_db = db; /*we need this from time-to-time*/ /*platform-specific defaults for multi-value and newline styles. These*/ /*are used in cases where we couldn't figure them out, like, if there*/ /*was only one element*/ pThis->_esvsSepPlat = SEPSTYLE_NEWLINE; #if defined(WIN32) || defined(WINDOWS) || defined(DOS) pThis->_esleNewlinePlat = NLSTYLE_CRLF; /*use windowsian CRLF*/ #else pThis->_esleNewlinePlat = NLSTYLE_LF; /*fall back to unixian LF*/ #endif pThis->_strVerSettingsPath = fsl_buffer_empty; fsl_buffer_append ( &pThis->_strVerSettingsPath, pszVerSettingsPath, fsl_strlen ( pszVerSettingsPath ) ); pThis->_nLastRowId = 0; pThis->_settings = fsl_list_empty; pThis->_nCursorsOpen = 0; } static void vtblVerSet_table_dtor ( vtblVerSet_table* pThis ) { fsl_list_clear ( &pThis->_settings, fsl_list_visitor_settingtuple_free, NULL ); fsl_buffer_clear( &pThis->_strVerSettingsPath ); } static vtblVerSet_table* vtblVerSet_table_new ( sqlite3* db, const char* pszVerSettingsPath ) { vtblVerSet_table* pThis = (vtblVerSet_table*) malloc ( sizeof(vtblVerSet_table) ); vtblVerSet_table_ctor ( pThis, db, pszVerSettingsPath ); return pThis; } static void vtblVerSet_table_delete ( vtblVerSet_table* pThis ) { if ( NULL != pThis ) { vtblVerSet_table_dtor ( pThis ); free ( pThis ); } } static bool vtblVerSet_table_addExistingSetting ( vtblVerSet_table* pThis, const SettingDesc* pdesc ) { /*factory idiom*/ SettingInfo* psi = SettingInfo_createFromFile ( fsl_buffer_cstr ( &pThis->_strVerSettingsPath ), pdesc ); if ( NULL != psi ) { SettingCollTuple* psct; if ( psi->_esvsSep == SEPSTYLE_UNKNOWN ) psi->_esvsSep = pThis->_esvsSepPlat; if ( psi->_esleNewline == NLSTYLE_UNKNOWN ) psi->_esleNewline = pThis->_esleNewlinePlat; psi->_nRowId = ++(pThis->_nLastRowId); /**/ psct = (SettingCollTuple*) malloc ( sizeof(SettingCollTuple) ); psct->_nRowId = psi->_nRowId; psct->_psi = psi; fsl_list_append ( &pThis->_settings, psct ); } return NULL != psi; } static bool vtblVerSet_table_populate ( vtblVerSet_table* pThis ) { size_t nIdx; for ( nIdx = 0; nIdx < g_asdSettingsDescriptorsCount; ++nIdx ) { if ( g_asdSettingsDescriptors[nIdx]._bIsVersionable ) vtblVerSet_table_addExistingSetting ( pThis, &g_asdSettingsDescriptors[nIdx] ); } return true; } /*since there are only a few well-known versionable settings, I am simply going*/ /*to do a linear search for 'find' operations. The 'find' operation will*/ /*return the index into the _settings array (er, 'list'). You may use this*/ /*index to get at the setting object, or use it to erase the setting (and*/ /*manage the list correctly). Non-found items will return an index of -1.*/ static int vtblVerSet_table_find_setting_idx_by_rowid ( vtblVerSet_table* pThis, sqlite3_int64 nRowId ) { int nIdx; for ( nIdx = 0; nIdx < (int) pThis->_settings.used; ++nIdx ) { if ( ((SettingCollTuple*)(pThis->_settings.list[nIdx]))->_nRowId == nRowId ) return nIdx; } return -1; } static int vtblVerSet_table_find_setting_idx_by_name ( vtblVerSet_table* pThis, const char* pszName ) { int nIdx; for ( nIdx = 0; nIdx < (int) pThis->_settings.used; ++nIdx ) { if ( 0 == _stricmp ( fsl_buffer_cstr ( &((SettingCollTuple*)(pThis->_settings.list[nIdx]))->_psi->_strName ), pszName ) ) return nIdx; } return -1; } static void vtblVerSet_table_erase_setting_by_idx ( vtblVerSet_table* pThis, int nIdx ) { SettingCollTuple* ptpl; if ( nIdx < 0 || nIdx >= (int) pThis->_settings.used ) return; /*bogus; assert-worthy*/ /*delete the tuple*/ ptpl = (SettingCollTuple*)(pThis->_settings.list[nIdx]); fsl_list_visitor_settingtuple_free ( ptpl, NULL ); /*scootch memory and update counts*/ memmove ( &pThis->_settings.list[nIdx], &pThis->_settings.list[nIdx+1], |
︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 | vtblVerSet_table* _pvst; /*(strictly, this is redundant with base member pVtab)*/ /*anything else we need?*/ }; typedef struct tagvtblVerSet_cursor vtblVerSet_cursor; | | | | | | | 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 | vtblVerSet_table* _pvst; /*(strictly, this is redundant with base member pVtab)*/ /*anything else we need?*/ }; typedef struct tagvtblVerSet_cursor vtblVerSet_cursor; static void vtblVerSet_cursor_ctor ( vtblVerSet_cursor* pThis, vtblVerSet_table* pvst ) { pThis->_nIter = 0; pThis->_pvst = pvst; ++(pThis->_pvst->_nCursorsOpen); } static void vtblVerSet_cursor_dtor ( vtblVerSet_cursor* pThis ) { --(pThis->_pvst->_nCursorsOpen); } static vtblVerSet_cursor* vtblVerSet_cursor_new ( vtblVerSet_table* pvst ) { vtblVerSet_cursor* pThis = (vtblVerSet_cursor*) malloc ( sizeof(vtblVerSet_cursor) ); vtblVerSet_cursor_ctor ( pThis, pvst ); return pThis; } static void vtblVerSet_cursor_delete ( vtblVerSet_cursor* pThis ) { if ( NULL != pThis ) { vtblVerSet_cursor_dtor ( pThis ); free ( pThis ); } } /*===========================================*/ /*sqlite vtable interface code*/ /*'table' stuff*/ /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/ static int vtblVerSet_Create ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) { int nLen; char* pszValue; fsl_buffer strVerSettingsPath; char ch; bool bMkdirOK; int nIdx; struct _stat buf; |
︙ | ︙ | |||
1461 1462 1463 1464 1465 1466 1467 | return SQLITE_ERROR; /*if you return error, you must set pzErr to something or NULL*/ } /*first arg is the fully-qualified path to the .fossil-settings directory*/ strVerSettingsPath = fsl_buffer_empty; /*knock off the SQL quotes*/ pszValue = (char*) argv[3]; | | | 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | return SQLITE_ERROR; /*if you return error, you must set pzErr to something or NULL*/ } /*first arg is the fully-qualified path to the .fossil-settings directory*/ strVerSettingsPath = fsl_buffer_empty; /*knock off the SQL quotes*/ pszValue = (char*) argv[3]; nLen = fsl_strlen ( pszValue ); if ( 0 != nLen && '\'' == pszValue[0] ) { ++pszValue; --nLen; } if ( 0 != nLen && '\'' == pszValue[nLen-1] ) { --nLen; } |
︙ | ︙ | |||
1563 1564 1565 1566 1567 1568 1569 | return SQLITE_OK; } /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/ /*last connection to this table is going away*/ | | | | | | 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 | return SQLITE_OK; } /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/ /*last connection to this table is going away*/ static int vtblVerSet_Destroy ( sqlite3_vtab* pVTab ) { vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab); vtblVerSet_table_delete ( pThis ); return SQLITE_OK; } /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/ /*new connection to existing table; we just treat it the same as 'create'*/ static int vtblVerSet_Connect ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) { return vtblVerSet_Create ( db, pAux, argc, argv, ppVTab, pzErr ); } /*xDisconnect -- drop virtual table, but not the last one*/ /*table is going away, but not last one*/ /*(BBB actually I have seen the last one go away via this method in the*/ /*case of database closure when there was not an explicit drop table)*/ static int vtblVerSet_Disconnect ( sqlite3_vtab* pVTab ) { return vtblVerSet_Destroy ( pVTab ); } /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/ /*think about what query is being done, and indicate what possible internal*/ /*quasi-index we might have*/ static int vtblVerSet_BestIndex ( sqlite3_vtab* pVTab, sqlite3_index_info* pIdxInfo ) { /*vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab); int nIdx; / *Inputs* / pIdxInfo->nConstraint; / *Number of entries in aConstraint* / pIdxInfo->aConstraint[0].iColumn; / *Column on left-hand side of constraint* / pIdxInfo->aConstraint[0].op; / *Constraint operator* / pIdxInfo->aConstraint[0].usable; / *True if this constraint is usable* / |
︙ | ︙ | |||
1636 1637 1638 1639 1640 1641 1642 | /*===========================================*/ /*'cursor' stuff*/ /*xOpen -- open a cursor*/ | | | | | | | | 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 | /*===========================================*/ /*'cursor' stuff*/ /*xOpen -- open a cursor*/ static int vtblVerSet_cursor_Open ( sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor ) { vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab); *ppCursor = &vtblVerSet_cursor_new ( pThis )->_base; return SQLITE_OK; } /*xClose -- close a cursor*/ static int vtblVerSet_cursor_Close ( sqlite3_vtab_cursor* pCur ) { vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur); vtblVerSet_cursor_delete ( pThis ); return SQLITE_OK; } static int vtblVerSet_cursor_Filter ( sqlite3_vtab_cursor* pCur, int idxNum, const char* idxStr, int argc, sqlite3_value** argv ) { vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur); /*position cursor to location based on value arguments and parameters that ultimately came from xBestIndex*/ /*this will 'rewind' the cursor to the beginning*/ pThis->_nIter = 0; return SQLITE_OK; } /*xNext -- advance a cursor*/ static int vtblVerSet_cursor_Next ( sqlite3_vtab_cursor* pCur ) { vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur); /*advance a cursor*/ /*we iterate through the list*/ if ( pThis->_nIter < pThis->_pvst->_settings.used ) { /*still some left*/ ++pThis->_nIter; /*next*/ return SQLITE_OK; } return SQLITE_OK; } /*xEof -- check for end of scan*/ static int vtblVerSet_cursor_Eof ( sqlite3_vtab_cursor* pCur ) { vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur); /*check for end of iteration*/ return ( pThis->_nIter >= pThis->_pvst->_settings.used ) ? 1 : 0; } /*xColumn -- read data*/ static int vtblVerSet_cursor_Column ( sqlite3_vtab_cursor* pCur, sqlite3_context* pCtx, int nCol ) { const SettingInfo* psi; vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur); /*read data*/ psi = ((SettingCollTuple*)pThis->_pvst->_settings.list[pThis->_nIter])->_psi; switch ( nCol ) { /*"NAME TEXT," / *setting name*/ |
︙ | ︙ | |||
1729 1730 1731 1732 1733 1734 1735 | } return SQLITE_OK; } /*xRowid -- read data*/ | | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 | } return SQLITE_OK; } /*xRowid -- read data*/ static int vtblVerSet_cursor_Rowid ( sqlite3_vtab_cursor* pCur, sqlite3_int64* pRowid ) { vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur); /*read data*/ *pRowid = ((SettingCollTuple*)pThis->_pvst->_settings.list[pThis->_nIter])->_nRowId; return SQLITE_OK; } |
︙ | ︙ | |||
1755 1756 1757 1758 1759 1760 1761 | return true; } return false; } | | | 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 | return true; } return false; } static int vtblVerSet_Update ( sqlite3_vtab* pVTab, int argc, sqlite3_value** argv, sqlite3_int64* pRowid ) { vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab); /*All changes to a virtual table are made using the xUpdate method.*/ /*This one method can be used to insert, delete, or update.*/ /*The argv[1] parameter is the rowid of a new row to be inserted into*/ /*the virtual table. If argv[1] is an SQL NULL, then the implementation*/ |
︙ | ︙ | |||
1843 1844 1845 1846 1847 1848 1849 | /*explicitly, supplying null for those which the user did not provide.*/ /*"NAME TEXT," / *setting name*/ pszName = (const char*) sqlite3_value_text ( argv[2] ); /*"VALUE TEXT," / *setting value, if any*/ pszValue = (const char*) sqlite3_value_text ( argv[3] ); /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/ nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? | | | | 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 | /*explicitly, supplying null for those which the user did not provide.*/ /*"NAME TEXT," / *setting name*/ pszName = (const char*) sqlite3_value_text ( argv[2] ); /*"VALUE TEXT," / *setting value, if any*/ pszValue = (const char*) sqlite3_value_text ( argv[3] ); /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/ nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? (int) pThis->_esvsSepPlat : sqlite3_value_int ( argv[4] ); /*"LINE_ENDINGS INTEGER HIDDEN," / *style of line endings*/ nsle = SQLITE_NULL == sqlite3_value_type ( argv[5] ) ? (int) pThis->_esleNewlinePlat : sqlite3_value_int ( argv[5] ); /*"ORIGINAL_PATH TEXT HIDDEN" / *path where this setting came from*/ /*you're never going to be able to set this, but we'll just ignore it if you try*/ /*argv[6]*/ /*first, some sanity checks on the data*/ if ( SQLITE_NULL != sqlite3_value_type ( argv[1] ) ) { pThis->_base.zErrMsg = sqlite3_mprintf ( "you cannot specify the rowid on insert" ); |
︙ | ︙ | |||
1976 1977 1978 1979 1980 1981 1982 | /*name cannot change*/ if ( 0 != _stricmp ( pszName, fsl_buffer_cstr ( &ptpl->_psi->_strName ) ) ) { pThis->_base.zErrMsg = sqlite3_mprintf ( "NAME cannot change" ); return SQLITE_ERROR; } /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/ nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? | | | | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 | /*name cannot change*/ if ( 0 != _stricmp ( pszName, fsl_buffer_cstr ( &ptpl->_psi->_strName ) ) ) { pThis->_base.zErrMsg = sqlite3_mprintf ( "NAME cannot change" ); return SQLITE_ERROR; } /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/ nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? (int) pThis->_esvsSepPlat : sqlite3_value_int ( argv[4] ); /*range check: nsvs must be a value enum value*/ if ( nsvs < SEPSTYLE_NEWLINE || nsvs > SEPSTYLE_COMMA ) { pThis->_base.zErrMsg = sqlite3_mprintf ( "VALUE_SEPARATOR must be a valid value" ); return SQLITE_CONSTRAINT; } /*"LINE_ENDINGS INTEGER HIDDEN," / *style of line endings*/ nsle = SQLITE_NULL == sqlite3_value_type ( argv[5] ) ? (int) pThis->_esvsSepPlat : sqlite3_value_int ( argv[5] ); /*range check: nsle must be a value enum value*/ if ( nsle < NLSTYLE_CRLF || nsvs > NLSTYLE_LF ) { pThis->_base.zErrMsg = sqlite3_mprintf ( "LINE_ENDINGS must be a valid value" ); return SQLITE_CONSTRAINT; } /*"ORIGINAL_PATH TEXT HIDDEN" / *path where this setting came from*/ /*you're never going to be able to change this, but we'll just ignore it if you try*/ |
︙ | ︙ | |||
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 | /*notification of impending commit/rollback; for realizing two-phase commit*/ /*int vtblVerSet_Sync ( sqlite3_vtab* pVTab );*/ /*end a transaction on a virtual table*/ /*int vtblVerSet_Commit ( sqlite3_vtab* pVTab );*/ /*int vtblVerSet_Rollback ( sqlite3_vtab* pVTab );*/ /*This is a sqlite3 extension function that either matches a text to a regex pattern, or fails (with a SQLITE_CONSTRAINT error. This is intended to be used for value validation for INSERTs or UPDATE, and was created for the fossil settings vtable, but it may be of general use, since it doesn't have any special bindings to that system. Some things of note: NULL pattern yields NULL result. Empty pattern (non- null, zero length) matches everything. This implementation uses the sqlite3 sample regexp engine, but it is simple enough that you could easily use another, more powerful, engine, like PCRE. argv[0] = text to match argv[1] = regex */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < < > | | > > > > > > > > | | | | > > | > > > > > > | | | | | | | 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 | /*notification of impending commit/rollback; for realizing two-phase commit*/ /*int vtblVerSet_Sync ( sqlite3_vtab* pVTab );*/ /*end a transaction on a virtual table*/ /*int vtblVerSet_Commit ( sqlite3_vtab* pVTab );*/ /*int vtblVerSet_Rollback ( sqlite3_vtab* pVTab );*/ /*here, we preprocess a regex for our 'extended' escapes (which must be at the start of the regex; we just have a couple, and set bools to indicate whether they were detected. we return a pointer to the 'rest' of the regex, which can be processed as per usual.*/ static const char* _implPreprocessRegex ( const char* pszRegex, bool* pbInsensitive, bool* pbMultivar, bool* pbEmptyOK ) { const char* pszRest = pszRegex; *pbInsensitive = false; /*init defaults for params we are parsing*/ *pbMultivar = false; while ( '\0' != *pszRest ) { /*must start with our special escape sequence*/ if ( '\\' != pszRest[0] || '$' != pszRest[1] ) { break; } /*must be one of our known instructions*/ if ( 'i' == pszRest[2] ) { *pbInsensitive = true; } else if ( 'm' == pszRest[2] ) { *pbMultivar = true; } else if ( 'e' == pszRest[2] ) { *pbEmptyOK = true; } else break; /*consume*/ pszRest += 3; } return pszRest; } /*context data stored in 'aux data'*/ typedef struct tagMatchOrFailFxnCtx MatchOrFailFxnCtx; struct tagMatchOrFailFxnCtx { sqlite3_ReCompiled* pRe; /* Compiled regular expression */ bool bInsensitive; /*and rude*/ bool bMultivar; /*must we crack it into several items?*/ bool bEmptyOK; /*is empty input text considered a match?*/ }; void MatchOrFailFxnCtx_delete ( MatchOrFailFxnCtx* pThis ) { sqlite3re_free ( pThis->pRe ); free ( pThis ); } bool MatchOrFailFxnCtx_match ( MatchOrFailFxnCtx* pThis, const char* pszStr ) { if ( '\0' == pszStr[0] && pThis->bEmptyOK ) { return true; } else if ( ! pThis->bMultivar ) { return sqlite3re_match ( pThis->pRe, (const unsigned char*)pszStr, -1 ); } else { /*this is a 'multivar' value, so crack it, and test them all individually*/ fsl_list lstrValues = fsl_list_empty; fsl_size_t nIdx; bool bResult; /*while it is called a 'glob_list', in fact, it is just a list of strings*/ if ( 0 != fsl_glob_list_parse ( &lstrValues, pszStr ) ) { /*horror*/ return false; } /*for each; match. return logical 'and' over all tests*/ bResult = true; for ( nIdx = 0; bResult && nIdx < lstrValues.used; ++nIdx ) { if ( ! sqlite3re_match ( pThis->pRe, (const unsigned char*)lstrValues.list[nIdx], -1 ) ) { bResult = false; } } fsl_glob_list_clear ( &lstrValues ); return bResult; } } /*This is a sqlite3 extension function that either matches a text to a regex pattern, or fails (with a SQLITE_CONSTRAINT error. This is intended to be used for value validation for INSERTs or UPDATE, and was created for the fossil settings vtable, but it may be of general use, since it doesn't have any special bindings to that system. Some things of note: NULL pattern yields NULL result. Empty pattern (non- null, zero length) matches everything. This implementation uses the sqlite3 sample regexp engine, but it is simple enough that you could easily use another, more powerful, engine, like PCRE. argv[0] = text to match argv[1] = regex */ static void implMatchOrFail ( sqlite3_context* pctx, int argc, sqlite3_value** argv ) { MatchOrFailFxnCtx* pCtx; const char* zStr; /* String being searched */ /*we registered this method explicitly as taking two parameters, so we don't need to check that assuption*/ /*we definitely need the text to test, and do some pre-checks*/ zStr = (const char*) sqlite3_value_text ( argv[0] ); if ( NULL == zStr ) { sqlite3_result_null ( pctx ); return; } /*see if we precomputed this, and compute if needed*/ pCtx = (MatchOrFailFxnCtx*)sqlite3_get_auxdata ( pctx, 0 ); /*precomputed?*/ if ( NULL == pCtx ) { /*no, must compile it now*/ const char* zErr; /* Compile error message */ sqlite3_ReCompiled* pRe; /* Compiled regular expression */ const char* zPattern; /*The regular expression*/ const char* pszProcessedPattern; /*the pattern after custom escapes*/ bool bInsensitive; /*and rude*/ bool bMultivar; /*must we crack it into several items?*/ bool bEmptyOK; /*is the empty string OK?*/ zPattern = (const char*) sqlite3_value_text ( argv[1] ); /*null pattern == null return*/ if ( NULL == zPattern ) { sqlite3_result_null ( pctx ); return; } /*empty pattern == never match*/ if ( '\0' == zPattern[0] ) { sqlite3_result_error_code ( pctx, SQLITE_CONSTRAINT ); return; } /*parse off our special metachars, if any*/ pszProcessedPattern = _implPreprocessRegex ( zPattern, &bInsensitive, &bMultivar, &bEmptyOK ); /*compile regex machine*/ zErr = sqlite3re_compile ( &pRe, pszProcessedPattern, bInsensitive ); if ( NULL != zErr ) { sqlite3re_free ( pRe ); sqlite3_result_error ( pctx, zErr, -1 ); return; } if ( NULL == pRe ) { sqlite3_result_error_nomem ( pctx ); return; } /*remember...*/ pCtx = (MatchOrFailFxnCtx*) malloc ( sizeof(MatchOrFailFxnCtx) ); pCtx->pRe = pRe; pCtx->bInsensitive = bInsensitive; pCtx->bMultivar = bMultivar; pCtx->bEmptyOK = bEmptyOK; sqlite3_set_auxdata ( pctx, 0, pCtx, (void(*)(void*))MatchOrFailFxnCtx_delete ); } /*OK, now, finally we can test*/ if ( MatchOrFailFxnCtx_match ( pCtx, zStr ) ) { sqlite3_result_text ( pctx, zStr, -1, SQLITE_TRANSIENT ); } else { sqlite3_result_error_code ( pctx, SQLITE_CONSTRAINT ); } } /*'overloading' functions*/ static int vtblVerSet_FindFunction ( sqlite3_vtab* pVtab, int nArg, const char* zName, void (**pxFunc) ( sqlite3_context*, int, sqlite3_value** ), void** ppArg ) { return 0; /*do not override*/ } static int vtblVerSet_Rename ( sqlite3_vtab* pVtab, const char* zNew ) { return SQLITE_OK; /*we don't care about being renamed*/ } static const sqlite3_module sg_pvtblVersionedSettings = { 2, /*iVersion -- version of this structure, so sqlite doesn't access past end*/ vtblVerSet_Create, /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/ vtblVerSet_Connect, /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/ vtblVerSet_BestIndex, /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/ vtblVerSet_Disconnect, /*xDisconnect -- drop virtual table, but not the last one*/ vtblVerSet_Destroy, /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/ vtblVerSet_cursor_Open, /*xOpen -- open a cursor*/ |
︙ | ︙ | |||
2185 2186 2187 2188 2189 2190 2191 | int sqlite3_vtbl_fossilsettings_init ( sqlite3* db, char** pzErrMsg, const struct sqlite3_api_routines* pApi ) { | | | | | | 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 | int sqlite3_vtbl_fossilsettings_init ( sqlite3* db, char** pzErrMsg, const struct sqlite3_api_routines* pApi ) { /* int nRet; */ #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT2(pApi) /*sets up the 'vtable' to the host exe sqlite3 impl*/ #else #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* nRet = */sqlite3_create_module_v2 ( db, "SETTINGS_METADATA", &sg_pvtblSettingsMetadata, NULL, NULL ); /* nRet = */sqlite3_create_module_v2 ( db, "VERSIONED_SETTINGS", &sg_pvtblVersionedSettings, NULL, NULL ); #endif /* nRet = */sqlite3_create_function ( db, "MATCH_OR_FAIL", 2, SQLITE_UTF8, 0, implMatchOrFail, 0, 0 ); return SQLITE_OK; } |
Changes to src/sqlite3.c.
︙ | ︙ | |||
229 230 231 232 233 234 235 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.7" #define SQLITE_VERSION_NUMBER 3008007 | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.7" #define SQLITE_VERSION_NUMBER 3008007 #define SQLITE_SOURCE_ID "2014-10-17 11:24:17 e4ab094f8afce0817f4074e823fabe59fc29ebb4" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
︙ | ︙ | |||
2789 2790 2791 2792 2793 2794 2795 | ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** | | | | | 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 | ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** ** ^The default encoding will be UTF-8 for databases created using ** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases ** created using sqlite3_open16() will be UTF-16 in the native byte order. ** ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control |
︙ | ︙ | |||
2879 2880 2881 2882 2883 2884 2885 | ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file ** which contains the database. ^If the path begins with a '/' character, ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. | | | > | | 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 | ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file ** which contains the database. ^If the path begins with a '/' character, ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. ** ^(On windows, the first component of an absolute path ** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] ** The query component of a URI may contain parameters that are interpreted ** either by SQLite itself, or by a [VFS | custom VFS implementation]. ** SQLite and its built-in [VFSes] interpret the ** following query parameters: ** ** <ul> ** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of ** a VFS object that provides the operating system interface that should ** be used to access the database file on disk. ^If this option is set to ** an empty string the default VFS object is used. ^Specifying an unknown ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is |
︙ | ︙ | |||
2920 2921 2922 2923 2924 2925 2926 | ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** | | < | < | 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 | ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** ** <li> <b>psow</b>: ^The psow parameter indicates whether or not the ** [powersafe overwrite] property does or does not apply to the ** storage media on which the database file resides. ** ** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter ** which if set disables file locking in rollback journal modes. This ** is useful for accessing a database on a filesystem that does not ** support locking. Caution: Database corruption might result if two ** or more processes write to the same database and any one of those ** processes uses nolock=1. |
︙ | ︙ | |||
3519 3520 3521 3522 3523 3524 3525 | ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** | | | | < | | 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 | ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** ** ^The fifth argument to the BLOB and string binding interfaces ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called ** to dispose of the BLOB or string even if the call to bind API fails. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. ** ^If the fifth argument has the value [SQLITE_TRANSIENT], then ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] ** to specify the encoding of the text in the third parameter. If ** the sixth argument to sqlite3_bind_text64() is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. ** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. |
︙ | ︙ | |||
4570 4571 4572 4573 4574 4575 4576 | ** of the application-defined function to be the 64-bit signed integer ** value given in the 2nd argument. ** ** ^The sqlite3_result_null() interface sets the return value ** of the application-defined function to be NULL. ** ** ^The sqlite3_result_text(), sqlite3_result_text16(), | | | 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 | ** of the application-defined function to be the 64-bit signed integer ** value given in the 2nd argument. ** ** ^The sqlite3_result_null() interface sets the return value ** of the application-defined function to be NULL. ** ** ^The sqlite3_result_text(), sqlite3_result_text16(), ** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. |
︙ | ︙ | |||
7944 7945 7946 7947 7948 7949 7950 | /* ** A macro to hint to the compiler that a function should not be ** inlined. */ #if defined(__GNUC__) # define SQLITE_NOINLINE __attribute__((noinline)) | | | 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 | /* ** A macro to hint to the compiler that a function should not be ** inlined. */ #if defined(__GNUC__) # define SQLITE_NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) && _MSC_VER>=1310 # define SQLITE_NOINLINE __declspec(noinline) #else # define SQLITE_NOINLINE #endif /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. |
︙ | ︙ | |||
11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 | unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ #endif }; /* ** Allowed values for Index.idxType */ #define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ | > | 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 | unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this table */ #endif }; /* ** Allowed values for Index.idxType */ #define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ |
︙ | ︙ | |||
12186 12187 12188 12189 12190 12191 12192 | */ #define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ | < | 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198 | */ #define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ /* |
︙ | ︙ | |||
13320 13321 13322 13323 13324 13325 13326 | SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1 # define sqlite3MemdebugNoType(X,Y) 1 #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ | | < | 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 | SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1 # define sqlite3MemdebugNoType(X,Y) 1 #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ #define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ #define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ /* ** Threading interface */ #if SQLITE_MAX_WORKER_THREADS>0 SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); |
︙ | ︙ | |||
13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478 13479 13480 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; #endif #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #endif | > > > > > > > | 13464 13465 13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478 13479 13480 13481 13482 13483 13484 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; #endif /* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards ** compatibility for legacy applications, the URI filename capability is ** disabled by default. ** ** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled ** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #endif |
︙ | ︙ | |||
14088 14089 14090 14091 14092 14093 14094 | i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ #ifdef SQLITE_DEBUG u8 seekOp; /* Most recent seek operation on this cursor */ #endif i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ | < < > | 14092 14093 14094 14095 14096 14097 14098 14099 14100 14101 14102 14103 14104 14105 14106 14107 14108 14109 14110 14111 14112 14113 14114 14115 14116 14117 14118 14119 14120 14121 14122 14123 14124 14125 14126 14127 14128 14129 14130 14131 | i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ #ifdef SQLITE_DEBUG u8 seekOp; /* Most recent seek operation on this cursor */ #endif i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ Pgno pgnoRoot; /* Root page of the open btree cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. ** ** aRow might point to (ephemeral) data for the current row, or it might ** be NULL. */ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ u32 payloadSize; /* Total number of bytes in the record */ u32 szRow; /* Byte available in aRow */ u32 iHdrOffset; /* Offset to next unparsed byte of the header */ const u8 *aRow; /* Data for the current row, if all on one page */ u32 *aOffset; /* Pointer to aType[nField] */ u32 aType[1]; /* Type values for all entries in the record */ /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for ** aType[] and nField+1 array slots for aOffset[] */ }; typedef struct VdbeCursor VdbeCursor; |
︙ | ︙ | |||
14191 14192 14193 14194 14195 14196 14197 | u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ int n; /* Number of characters in string value, excluding '\0' */ char *z; /* String or BLOB value */ /* ShallowCopy only needs to copy the information above */ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ int szMalloc; /* Size of the zMalloc allocation */ | | | 14194 14195 14196 14197 14198 14199 14200 14201 14202 14203 14204 14205 14206 14207 14208 | u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ int n; /* Number of characters in string value, excluding '\0' */ char *z; /* String or BLOB value */ /* ShallowCopy only needs to copy the information above */ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ int szMalloc; /* Size of the zMalloc allocation */ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ sqlite3 *db; /* The associated database connection */ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ #endif }; |
︙ | ︙ | |||
14399 14400 14401 14402 14403 14404 14405 14406 14407 14408 14409 14410 14411 14412 | /* ** Function prototypes */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*); #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); #endif SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int); SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); | > | 14402 14403 14404 14405 14406 14407 14408 14409 14410 14411 14412 14413 14414 14415 14416 | /* ** Function prototypes */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*); SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); #endif SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int); SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); |
︙ | ︙ | |||
14698 14699 14700 14701 14702 14703 14704 | db->pnBytesFreed = &nByte; for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ sqlite3VdbeClearObject(db, pVdbe); sqlite3DbFree(db, pVdbe); } db->pnBytesFreed = 0; | | | 14702 14703 14704 14705 14706 14707 14708 14709 14710 14711 14712 14713 14714 14715 14716 | db->pnBytesFreed = &nByte; for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ sqlite3VdbeClearObject(db, pVdbe); sqlite3DbFree(db, pVdbe); } db->pnBytesFreed = 0; *pHighwater = 0; /* IMP: R-64479-57858 */ *pCurrent = nByte; break; } /* ** Set *pCurrent to the total cache hits or misses encountered by all |
︙ | ︙ | |||
14723 14724 14725 14726 14727 14728 14729 | for(i=0; i<db->nDb; i++){ if( db->aDb[i].pBt ){ Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); } } | | > > | | 14727 14728 14729 14730 14731 14732 14733 14734 14735 14736 14737 14738 14739 14740 14741 14742 14743 14744 14745 14746 14747 14748 14749 14750 14751 14752 14753 | for(i=0; i<db->nDb; i++){ if( db->aDb[i].pBt ){ Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); } } *pHighwater = 0; /* IMP: R-42420-56072 */ /* IMP: R-54100-20147 */ /* IMP: R-29431-39229 */ *pCurrent = nRet; break; } /* Set *pCurrent to non-zero if there are unresolved deferred foreign ** key constraints. Set *pCurrent to zero if all foreign key constraints ** have been satisfied. The *pHighwater is always set to zero. */ case SQLITE_DBSTATUS_DEFERRED_FKS: { *pHighwater = 0; /* IMP: R-11967-56545 */ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; break; } default: { rc = SQLITE_ERROR; } |
︙ | ︙ | |||
17121 17122 17123 17124 17125 17126 17127 | /* ** Return TRUE if the mask of type in eType matches the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** | | | 17127 17128 17129 17130 17131 17132 17133 17134 17135 17136 17137 17138 17139 17140 17141 | /* ** Return TRUE if the mask of type in eType matches the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ |
︙ | ︙ | |||
17143 17144 17145 17146 17147 17148 17149 | /* ** Return TRUE if the mask of type in eType matches no bits of the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** | | | 17149 17150 17151 17152 17153 17154 17155 17156 17157 17158 17159 17160 17161 17162 17163 | /* ** Return TRUE if the mask of type in eType matches no bits of the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ |
︙ | ︙ | |||
20218 20219 20220 20221 20222 20223 20224 | }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); mallocWithAlarm((int)n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ p = sqlite3GlobalConfig.m.xMalloc((int)n); } | | | 20224 20225 20226 20227 20228 20229 20230 20231 20232 20233 20234 20235 20236 20237 20238 | }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); mallocWithAlarm((int)n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ p = sqlite3GlobalConfig.m.xMalloc((int)n); } assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */ return p; } /* ** This version of the memory allocation is for use by the application. ** First make sure the memory subsystem is initialized, then do the ** allocation. |
︙ | ︙ | |||
20355 20356 20357 20358 20359 20360 20361 | /* ** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ SQLITE_PRIVATE int sqlite3MallocSize(void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); | < > > | | < > > < > | 20361 20362 20363 20364 20365 20366 20367 20368 20369 20370 20371 20372 20373 20374 20375 20376 20377 20378 20379 20380 20381 20382 20383 20384 20385 20386 20387 20388 20389 20390 20391 20392 20393 20394 20395 20396 20397 20398 20399 20400 20401 20402 20403 20404 20405 | /* ** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ SQLITE_PRIVATE int sqlite3MallocSize(void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3GlobalConfig.m.xSize(p); } SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ if( db==0 ){ assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3MallocSize(p); }else{ assert( sqlite3_mutex_held(db->mutex) ); if( isLookaside(db, p) ){ return db->lookaside.sz; }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); return sqlite3GlobalConfig.m.xSize(p); } } } SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p); } /* ** Free memory previously obtained from sqlite3Malloc(). */ SQLITE_API void sqlite3_free(void *p){ if( p==0 ) return; /* IMP: R-49053-54554 */ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p)); sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1); sqlite3GlobalConfig.m.xFree(p); sqlite3_mutex_leave(mem0.mutex); }else{ |
︙ | ︙ | |||
20427 20428 20429 20430 20431 20432 20433 | #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; db->lookaside.nOut--; return; } } | | | > > | | | 20435 20436 20437 20438 20439 20440 20441 20442 20443 20444 20445 20446 20447 20448 20449 20450 20451 20452 20453 20454 20455 20456 20457 20458 20459 20460 20461 20462 20463 20464 20465 20466 20467 20468 | #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; db->lookaside.nOut--; return; } } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } /* ** Change the size of an existing memory allocation */ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ int nOld, nNew, nDiff; void *pNew; assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); if( pOld==0 ){ return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ } if( nBytes==0 ){ sqlite3_free(pOld); /* IMP: R-26507-47431 */ return 0; } if( nBytes>=0x7fffff00 ){ /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ return 0; } nOld = sqlite3MallocSize(pOld); |
︙ | ︙ | |||
20466 20467 20468 20469 20470 20471 20472 | sqlite3_mutex_enter(mem0.mutex); sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); } | < < | | | 20476 20477 20478 20479 20480 20481 20482 20483 20484 20485 20486 20487 20488 20489 20490 20491 20492 20493 20494 20495 20496 20497 20498 20499 20500 20501 20502 20503 20504 20505 20506 20507 20508 20509 20510 20511 20512 20513 20514 20515 | sqlite3_mutex_enter(mem0.mutex); sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmCallback ){ sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } if( pNew ){ nNew = sqlite3MallocSize(pNew); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */ return pNew; } /* ** The public interface to sqlite3Realloc. Make sure that the memory ** subsystem is initialized prior to invoking sqliteRealloc. */ SQLITE_API void *sqlite3_realloc(void *pOld, int n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif if( n<0 ) n = 0; /* IMP: R-26507-47431 */ return sqlite3Realloc(pOld, n); } SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return sqlite3Realloc(pOld, n); |
︙ | ︙ | |||
20580 20581 20582 20583 20584 20585 20586 | return 0; } #endif p = sqlite3Malloc(n); if( !p && db ){ db->mallocFailed = 1; } | | | | 20588 20589 20590 20591 20592 20593 20594 20595 20596 20597 20598 20599 20600 20601 20602 20603 | return 0; } #endif p = sqlite3Malloc(n); if( !p && db ){ db->mallocFailed = 1; } sqlite3MemdebugSetType(p, (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); return p; } /* ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ |
︙ | ︙ | |||
20607 20608 20609 20610 20611 20612 20613 | } pNew = sqlite3DbMallocRaw(db, n); if( pNew ){ memcpy(pNew, p, db->lookaside.sz); sqlite3DbFree(db, p); } }else{ | | | < | | 20615 20616 20617 20618 20619 20620 20621 20622 20623 20624 20625 20626 20627 20628 20629 20630 20631 20632 20633 20634 20635 20636 | } pNew = sqlite3DbMallocRaw(db, n); if( pNew ){ memcpy(pNew, p, db->lookaside.sz); sqlite3DbFree(db, p); } }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3_realloc64(p, n); if( !pNew ){ db->mallocFailed = 1; } sqlite3MemdebugSetType(pNew, (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } return pNew; } /* |
︙ | ︙ | |||
22082 22083 22084 22085 22086 22087 22088 | } #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ /******************************** End Unix Pthreads *************************/ /********************************* Win32 Threads ****************************/ | | | | 22089 22090 22091 22092 22093 22094 22095 22096 22097 22098 22099 22100 22101 22102 22103 22104 22105 22106 22107 22108 22109 22110 | } #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ /******************************** End Unix Pthreads *************************/ /********************************* Win32 Threads ****************************/ #if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ #include <process.h> /* A running thread */ struct SQLiteThread { void *tid; /* The thread handle */ unsigned id; /* The thread identifier */ void *(*xTask)(void*); /* The routine to run as a thread */ void *pIn; /* Argument to xTask */ void *pResult; /* Result of xTask */ }; /* Thread procedure Win32 compatibility shim */ |
︙ | ︙ | |||
22137 22138 22139 22140 22141 22142 22143 | p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; if( sqlite3GlobalConfig.bCoreMutex==0 ){ memset(p, 0, sizeof(*p)); }else{ p->xTask = xTask; p->pIn = pIn; | | | 22144 22145 22146 22147 22148 22149 22150 22151 22152 22153 22154 22155 22156 22157 22158 | p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; if( sqlite3GlobalConfig.bCoreMutex==0 ){ memset(p, 0, sizeof(*p)); }else{ p->xTask = xTask; p->pIn = pIn; p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); if( p->tid==0 ){ memset(p, 0, sizeof(*p)); } } if( p->xTask==0 ){ p->id = GetCurrentThreadId(); p->pResult = xTask(pIn); |
︙ | ︙ | |||
22175 22176 22177 22178 22179 22180 22181 | assert( bRc ); } if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; sqlite3_free(p); return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; } | | | 22182 22183 22184 22185 22186 22187 22188 22189 22190 22191 22192 22193 22194 22195 22196 | assert( bRc ); } if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; sqlite3_free(p); return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; } #endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */ /******************************** End Win32 Threads *************************/ /********************************* Single-Threaded **************************/ #ifndef SQLITE_THREADS_IMPLEMENTED /* ** This implementation does not actually create a new thread. It does the |
︙ | ︙ | |||
33478 33479 33480 33481 33482 33483 33484 33485 33486 33487 33488 33489 33490 33491 33492 | #else { "WaitForSingleObject", (SYSCALL)0, 0 }, #endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ BOOL))aSyscall[64].pCurrent) #if SQLITE_OS_WINRT { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, #else | > > > > | 33485 33486 33487 33488 33489 33490 33491 33492 33493 33494 33495 33496 33497 33498 33499 33500 33501 33502 33503 | #else { "WaitForSingleObject", (SYSCALL)0, 0 }, #endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) #if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, #else { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, #endif #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ BOOL))aSyscall[64].pCurrent) #if SQLITE_OS_WINRT { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, #else |
︙ | ︙ | |||
33821 33822 33823 33824 33825 33826 33827 | assert( sleepObj!=NULL ); osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); #else osSleep(milliseconds); #endif } | | > | 33832 33833 33834 33835 33836 33837 33838 33839 33840 33841 33842 33843 33844 33845 33846 33847 | assert( sleepObj!=NULL ); osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); #else osSleep(milliseconds); #endif } #if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ SQLITE_THREADSAFE>0 SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ DWORD rc; while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, TRUE))==WAIT_IO_COMPLETION ){} return rc; } #endif |
︙ | ︙ | |||
37837 37838 37839 37840 37841 37842 37843 | static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ int n = 0; UNUSED_PARAMETER(pVfs); #if defined(SQLITE_TEST) n = nBuf; memset(zBuf, 0, nBuf); #else | | | | | | | 37849 37850 37851 37852 37853 37854 37855 37856 37857 37858 37859 37860 37861 37862 37863 37864 37865 37866 37867 37868 37869 37870 37871 37872 37873 37874 37875 37876 37877 37878 37879 37880 37881 37882 37883 37884 37885 37886 37887 | static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ int n = 0; UNUSED_PARAMETER(pVfs); #if defined(SQLITE_TEST) n = nBuf; memset(zBuf, 0, nBuf); #else if( sizeof(SYSTEMTIME)<=nBuf-n ){ SYSTEMTIME x; osGetSystemTime(&x); memcpy(&zBuf[n], &x, sizeof(x)); n += sizeof(x); } if( sizeof(DWORD)<=nBuf-n ){ DWORD pid = osGetCurrentProcessId(); memcpy(&zBuf[n], &pid, sizeof(pid)); n += sizeof(pid); } #if SQLITE_OS_WINRT if( sizeof(ULONGLONG)<=nBuf-n ){ ULONGLONG cnt = osGetTickCount64(); memcpy(&zBuf[n], &cnt, sizeof(cnt)); n += sizeof(cnt); } #else if( sizeof(DWORD)<=nBuf-n ){ DWORD cnt = osGetTickCount(); memcpy(&zBuf[n], &cnt, sizeof(cnt)); n += sizeof(cnt); } #endif if( sizeof(LARGE_INTEGER)<=nBuf-n ){ LARGE_INTEGER i; osQueryPerformanceCounter(&i); memcpy(&zBuf[n], &i, sizeof(i)); n += sizeof(i); } #endif return n; |
︙ | ︙ | |||
39846 39847 39848 39849 39850 39851 39852 | assert( pCache->nPage >= pCache->nRecyclable ); nPinned = pCache->nPage - pCache->nRecyclable; assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); assert( pCache->n90pct == pCache->nMax*9/10 ); if( createFlag==1 && ( nPinned>=pGroup->mxPinned || nPinned>=pCache->n90pct | | | 39858 39859 39860 39861 39862 39863 39864 39865 39866 39867 39868 39869 39870 39871 39872 | assert( pCache->nPage >= pCache->nRecyclable ); nPinned = pCache->nPage - pCache->nRecyclable; assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); assert( pCache->n90pct == pCache->nMax*9/10 ); if( createFlag==1 && ( nPinned>=pGroup->mxPinned || nPinned>=pCache->n90pct || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclable<nPinned) )){ return 0; } if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache); assert( pCache->nHash>0 && pCache->apHash ); |
︙ | ︙ | |||
44467 44468 44469 44470 44471 44472 44473 | if( rc==SQLITE_OK ){ pNew = (char *)sqlite3PageMalloc(pageSize); if( !pNew ) rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ pager_reset(pPager); | < < > > > > | 44479 44480 44481 44482 44483 44484 44485 44486 44487 44488 44489 44490 44491 44492 44493 44494 44495 44496 44497 44498 44499 44500 44501 | if( rc==SQLITE_OK ){ pNew = (char *)sqlite3PageMalloc(pageSize); if( !pNew ) rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ pager_reset(pPager); rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); } if( rc==SQLITE_OK ){ sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->pageSize = pageSize; }else{ sqlite3PageFree(pNew); } } *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); |
︙ | ︙ | |||
51640 51641 51642 51643 51644 51645 51646 | Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif | | | 51654 51655 51656 51657 51658 51659 51660 51661 51662 51663 51664 51665 51666 51667 51668 | Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ }; /* ** Allowed values for BtShared.btsFlags */ #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ |
︙ | ︙ | |||
52938 52939 52940 52941 52942 52943 52944 | ** ** Calling this routine with a NULL cursor pointer returns false. ** ** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ | | | 52952 52953 52954 52955 52956 52957 52958 52959 52960 52961 52962 52963 52964 52965 52966 | ** ** Calling this routine with a NULL cursor pointer returns false. ** ** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ return pCur->eState!=CURSOR_VALID; } /* ** This routine restores a cursor back to its original position after it ** has been moved by some outside activity (such as a btree rebalance or ** a row having been deleted out from under the cursor). ** |
︙ | ︙ | |||
54270 54271 54272 54273 54274 54275 54276 | #else return 1; #endif } /* ** Make sure pBt->pTmpSpace points to an allocation of | | > | > > > > > | > > > | > > | > | 54284 54285 54286 54287 54288 54289 54290 54291 54292 54293 54294 54295 54296 54297 54298 54299 54300 54301 54302 54303 54304 54305 54306 54307 54308 54309 54310 54311 54312 54313 54314 54315 54316 54317 54318 54319 54320 54321 54322 54323 54324 54325 54326 54327 54328 54329 54330 54331 54332 54333 54334 54335 | #else return 1; #endif } /* ** Make sure pBt->pTmpSpace points to an allocation of ** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child ** pointer. */ static void allocateTempSpace(BtShared *pBt){ if( !pBt->pTmpSpace ){ pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); /* One of the uses of pBt->pTmpSpace is to format cells before ** inserting them into a leaf page (function fillInCell()). If ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes ** by the various routines that manipulate binary cells. Which ** can mean that fillInCell() only initializes the first 2 or 3 ** bytes of pTmpSpace, but that the first 4 bytes are copied from ** it into a database page. This is not actually a problem, but it ** does cause a valgrind error when the 1 or 2 bytes of unitialized ** data is passed to system call write(). So to avoid this error, ** zero the first 4 bytes of temp space here. ** ** Also: Provide four bytes of initialized space before the ** beginning of pTmpSpace as an area available to prepend the ** left-child pointer to the beginning of a cell. */ if( pBt->pTmpSpace ){ memset(pBt->pTmpSpace, 0, 8); pBt->pTmpSpace += 4; } } } /* ** Free the pBt->pTmpSpace allocation */ static void freeTempSpace(BtShared *pBt){ if( pBt->pTmpSpace ){ pBt->pTmpSpace -= 4; sqlite3PageFree(pBt->pTmpSpace); pBt->pTmpSpace = 0; } } /* ** Close an open database and invalidate all cursors. */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; |
︙ | ︙ | |||
58007 58008 58009 58010 58011 58012 58013 | ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. | < < < < < < | | 58033 58034 58035 58036 58037 58038 58039 58040 58041 58042 58043 58044 58045 58046 58047 58048 58049 58050 58051 58052 58053 58054 58055 58056 58057 58058 58059 58060 58061 58062 58063 58064 58065 58066 58067 58068 58069 58070 58071 58072 58073 58074 58075 58076 58077 58078 58079 58080 | ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ int sz, /* Bytes of content in pCell */ u8 *pTemp, /* Temp storage space for pCell, if needed */ Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ int *pRC /* Read and write return code from here */ ){ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ int end; /* First byte past the last cell pointer in data[] */ int ins; /* Index in data[] where new cell pointer is inserted */ int cellOffset; /* Address of first cell pointer in data[] */ u8 *data; /* The content of the whole page */ if( *pRC ) return; assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* The cell should normally be sized correctly. However, when moving a ** malformed cell from a leaf page to an interior page, if the cell size ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size ** might be less than 8 (leaf-size + pointer) on the interior node. Hence ** the term after the || in the following assert(). */ assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); pCell = pTemp; } if( iChild ){ put4byte(pCell, iChild); } j = pPage->nOverflow++; assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) ); |
︙ | ︙ | |||
58075 58076 58077 58078 58079 58080 58081 | if( rc ){ *pRC = rc; return; } /* The allocateSpace() routine guarantees the following two properties ** if it returns success */ assert( idx >= end+2 ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); | | | 58095 58096 58097 58098 58099 58100 58101 58102 58103 58104 58105 58106 58107 58108 58109 | if( rc ){ *pRC = rc; return; } /* The allocateSpace() routine guarantees the following two properties ** if it returns success */ assert( idx >= end+2 ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); memcpy(&data[idx], pCell, sz); if( iChild ){ put4byte(&data[idx], iChild); } memmove(&data[ins+2], &data[ins], end-ins); put2byte(&data[ins], idx); put2byte(&data[pPage->hdrOffset+3], pPage->nCell); #ifndef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
61621 61622 61623 61624 61625 61626 61627 | */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. ** Mem.xDel is might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); | | > > > | 61641 61642 61643 61644 61645 61646 61647 61648 61649 61650 61651 61652 61653 61654 61655 61656 61657 61658 | */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. ** Mem.xDel is might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we ** ensure that if Mem.szMalloc>0 then it is safe to do ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. ** That saves a few cycles in inner loops. */ 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) ); /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 |
︙ | ︙ | |||
61730 61731 61732 61733 61734 61735 61736 | pMem->szMalloc = 0; return SQLITE_NOMEM; }else{ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } } | | | 61753 61754 61755 61756 61757 61758 61759 61760 61761 61762 61763 61764 61765 61766 61767 | pMem->szMalloc = 0; return SQLITE_NOMEM; }else{ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } } if( bPreserve && pMem->z && 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)); } |
︙ | ︙ | |||
61757 61758 61759 61760 61761 61762 61763 | ** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null ** values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. */ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ | | > | 61780 61781 61782 61783 61784 61785 61786 61787 61788 61789 61790 61791 61792 61793 61794 61795 | ** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null ** values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. */ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ assert( szNew>0 ); assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); if( pMem->szMalloc<szNew ){ return sqlite3VdbeMemGrow(pMem, szNew, 0); } assert( (pMem->flags & MEM_Dyn)==0 ); pMem->z = pMem->zMalloc; pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); return SQLITE_OK; |
︙ | ︙ | |||
62481 62482 62483 62484 62485 62486 62487 | int nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } if( nByte>iLimit ){ return SQLITE_TOOBIG; } | > > > | | 62505 62506 62507 62508 62509 62510 62511 62512 62513 62514 62515 62516 62517 62518 62519 62520 62521 62522 | int nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } if( nByte>iLimit ){ return SQLITE_TOOBIG; } testcase( nAlloc==0 ); testcase( nAlloc==31 ); testcase( nAlloc==32 ); if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ return SQLITE_NOMEM; } memcpy(pMem->z, z, nAlloc); }else if( xDel==SQLITE_DYNAMIC ){ sqlite3VdbeMemRelease(pMem); pMem->zMalloc = pMem->z = (char *)z; pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); |
︙ | ︙ | |||
62584 62585 62586 62587 62588 62589 62590 | } /* ** The pVal argument is known to be a value other than NULL. ** Convert it into a string with encoding enc and return a pointer ** to a zero-terminated version of that string. */ | | | 62611 62612 62613 62614 62615 62616 62617 62618 62619 62620 62621 62622 62623 62624 62625 | } /* ** The pVal argument is known to be a value other than NULL. ** Convert it into a string with encoding enc and return a pointer ** to a zero-terminated version of that string. */ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( (pVal->flags & MEM_RowSet)==0 ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ pVal->flags |= MEM_Str; |
︙ | ︙ | |||
64904 64905 64906 64907 64908 64909 64910 | sqlite3BtreeClose(pCx->pBt); /* The pCx->pCursor will be close automatically, if it exists, by ** the call above. */ }else if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } #ifndef SQLITE_OMIT_VIRTUALTABLE | | | 64931 64932 64933 64934 64935 64936 64937 64938 64939 64940 64941 64942 64943 64944 64945 | sqlite3BtreeClose(pCx->pBt); /* The pCx->pCursor will be close automatically, if it exists, by ** the call above. */ }else if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( pCx->pVtabCursor ){ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; p->inVtabMethod = 1; pModule->xClose(pVtabCursor); p->inVtabMethod = 0; } #endif |
︙ | ︙ | |||
64947 64948 64949 64950 64951 64952 64953 | ** open cursors. */ static void closeAllCursors(Vdbe *p){ if( p->pFrame ){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); | < | | > > | 64974 64975 64976 64977 64978 64979 64980 64981 64982 64983 64984 64985 64986 64987 64988 64989 64990 64991 | ** open cursors. */ static void closeAllCursors(Vdbe *p){ if( p->pFrame ){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); p->pFrame = 0; p->nFrame = 0; } assert( p->nFrame==0 ); if( p->apCsr ){ int i; for(i=0; i<p->nCursor; i++){ VdbeCursor *pC = p->apCsr[i]; if( pC ){ sqlite3VdbeFreeCursor(p, pC); |
︙ | ︙ | |||
64971 64972 64973 64974 64975 64976 64977 | while( p->pDelFrame ){ VdbeFrame *pDel = p->pDelFrame; p->pDelFrame = pDel->pParent; sqlite3VdbeFrameDelete(pDel); } /* Delete any auxdata allocations made by the VM */ | | | 64999 65000 65001 65002 65003 65004 65005 65006 65007 65008 65009 65010 65011 65012 65013 | while( p->pDelFrame ){ VdbeFrame *pDel = p->pDelFrame; p->pDelFrame = pDel->pParent; sqlite3VdbeFrameDelete(pDel); } /* Delete any auxdata allocations made by the VM */ if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0); assert( p->pAuxData==0 ); } /* ** Clean up the VM after a single run. */ static void Cleanup(Vdbe *p){ |
︙ | ︙ | |||
65877 65878 65879 65880 65881 65882 65883 | #ifdef SQLITE_TEST extern int sqlite3_search_count; #endif assert( p->deferredMoveto ); assert( p->isTable ); rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); if( rc ) return rc; | < < | 65905 65906 65907 65908 65909 65910 65911 65912 65913 65914 65915 65916 65917 65918 65919 | #ifdef SQLITE_TEST extern int sqlite3_search_count; #endif assert( p->deferredMoveto ); assert( p->isTable ); rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); if( rc ) return rc; if( res!=0 ) return SQLITE_CORRUPT_BKPT; #ifdef SQLITE_TEST sqlite3_search_count++; #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; return SQLITE_OK; } |
︙ | ︙ | |||
65904 65905 65906 65907 65908 65909 65910 65911 65912 65913 65914 65915 65916 65917 65918 65919 65920 65921 65922 65923 65924 65925 65926 65927 65928 | assert( p->pCursor!=0 ); assert( sqlite3BtreeCursorHasMoved(p->pCursor) ); rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow); p->cacheStatus = CACHE_STALE; if( isDifferentRow ) p->nullRow = 1; return rc; } /* ** Make sure the cursor p is ready to read or write the row to which it ** was last positioned. Return an error code if an OOM fault or I/O error ** prevents us from positioning the cursor to its correct position. ** ** If a MoveTo operation is pending on the given cursor, then do that ** MoveTo now. If no move is pending, check to see if the row has been ** deleted out from under the cursor and if it has, mark the row as ** a NULL row. ** ** If the cursor is already pointing to the correct row and that row has ** not been deleted out from under the cursor, then this routine is a no-op. */ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){ if( p->deferredMoveto ){ return handleDeferredMoveto(p); } | > > > > > > > > > > > | | 65930 65931 65932 65933 65934 65935 65936 65937 65938 65939 65940 65941 65942 65943 65944 65945 65946 65947 65948 65949 65950 65951 65952 65953 65954 65955 65956 65957 65958 65959 65960 65961 65962 65963 65964 65965 65966 65967 65968 65969 65970 65971 65972 65973 | assert( p->pCursor!=0 ); assert( sqlite3BtreeCursorHasMoved(p->pCursor) ); rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow); p->cacheStatus = CACHE_STALE; if( isDifferentRow ) p->nullRow = 1; return rc; } /* ** Check to ensure that the cursor is valid. Restore the cursor ** if need be. Return any I/O error from the restore operation. */ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ if( sqlite3BtreeCursorHasMoved(p->pCursor) ){ return handleMovedCursor(p); } return SQLITE_OK; } /* ** Make sure the cursor p is ready to read or write the row to which it ** was last positioned. Return an error code if an OOM fault or I/O error ** prevents us from positioning the cursor to its correct position. ** ** If a MoveTo operation is pending on the given cursor, then do that ** MoveTo now. If no move is pending, check to see if the row has been ** deleted out from under the cursor and if it has, mark the row as ** a NULL row. ** ** If the cursor is already pointing to the correct row and that row has ** not been deleted out from under the cursor, then this routine is a no-op. */ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){ if( p->deferredMoveto ){ return handleDeferredMoveto(p); } if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){ return handleMovedCursor(p); } return SQLITE_OK; } /* ** The following functions: |
︙ | ︙ | |||
67547 67548 67549 67550 67551 67552 67553 67554 67555 67556 67557 67558 67559 67560 | const char *z, sqlite3_uint64 n, void (*xDel)(void *), unsigned char enc ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, enc, xDel); } } #ifndef SQLITE_OMIT_UTF16 | > | 67584 67585 67586 67587 67588 67589 67590 67591 67592 67593 67594 67595 67596 67597 67598 | const char *z, sqlite3_uint64 n, void (*xDel)(void *), unsigned char enc ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, enc, xDel); } } #ifndef SQLITE_OMIT_UTF16 |
︙ | ︙ | |||
69085 69086 69087 69088 69089 69090 69091 69092 69093 69094 69095 69096 69097 69098 | p->apCsr[iCur] = 0; } if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; memset(pCx, 0, sizeof(VdbeCursor)); pCx->iDb = iDb; pCx->nField = nField; if( isBtreeCursor ){ pCx->pCursor = (BtCursor*) &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; sqlite3BtreeCursorZero(pCx->pCursor); } } return pCx; | > | 69123 69124 69125 69126 69127 69128 69129 69130 69131 69132 69133 69134 69135 69136 69137 | p->apCsr[iCur] = 0; } if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; memset(pCx, 0, sizeof(VdbeCursor)); pCx->iDb = iDb; pCx->nField = nField; pCx->aOffset = &pCx->aType[nField]; if( isBtreeCursor ){ pCx->pCursor = (BtCursor*) &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; sqlite3BtreeCursorZero(pCx->pCursor); } } return pCx; |
︙ | ︙ | |||
70518 70519 70520 70521 70522 70523 70524 | assert( pOp->p4type==P4_FUNCDEF ); ctx.pFunc = pOp->p4.pFunc; ctx.iOp = pc; ctx.pVdbe = p; MemSetTypeFlag(ctx.pOut, MEM_Null); ctx.fErrorOrAux = 0; | | | 70557 70558 70559 70560 70561 70562 70563 70564 70565 70566 70567 70568 70569 70570 70571 | assert( pOp->p4type==P4_FUNCDEF ); ctx.pFunc = pOp->p4.pFunc; ctx.iOp = pc; ctx.pVdbe = p; MemSetTypeFlag(ctx.pOut, MEM_Null); ctx.fErrorOrAux = 0; db->lastRowid = lastRowid; (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */ lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ /* If the function returned an error, throw an exception */ if( ctx.fErrorOrAux ){ if( ctx.isError ){ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut)); |
︙ | ︙ | |||
71236 71237 71238 71239 71240 71241 71242 | assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2<pC->nField ); | | | | 71275 71276 71277 71278 71279 71280 71281 71282 71283 71284 71285 71286 71287 71288 71289 71290 71291 71292 71293 71294 71295 71296 71297 71298 71299 71300 | assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2<pC->nField ); aOffset = pC->aOffset; #ifndef SQLITE_OMIT_VIRTUALTABLE assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */ #endif pCrsr = pC->pCursor; assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */ assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */ /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; if( pC->cacheStatus!=p->cacheCtr ){ if( pC->nullRow ){ if( pCrsr==0 ){ assert( pC->pseudoTableReg>0 ); pReg = &aMem[pC->pseudoTableReg]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); pC->payloadSize = pC->szRow = avail = pReg->n; |
︙ | ︙ | |||
71292 71293 71294 71295 71296 71297 71298 | goto too_big; } } pC->cacheStatus = p->cacheCtr; pC->iHdrOffset = getVarint32(pC->aRow, offset); pC->nHdrParsed = 0; aOffset[0] = offset; | < < < < < < < < > > > > > > > > > > > > > > > > > | 71331 71332 71333 71334 71335 71336 71337 71338 71339 71340 71341 71342 71343 71344 71345 71346 71347 71348 71349 71350 71351 71352 71353 71354 71355 71356 71357 71358 71359 71360 71361 71362 71363 71364 71365 71366 71367 71368 71369 71370 71371 71372 71373 71374 71375 71376 71377 71378 71379 71380 71381 71382 71383 71384 | goto too_big; } } pC->cacheStatus = p->cacheCtr; pC->iHdrOffset = getVarint32(pC->aRow, offset); pC->nHdrParsed = 0; aOffset[0] = offset; /* Make sure a corrupt database has not given us an oversize header. ** Do this now to avoid an oversize memory allocation. ** ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte ** types use so much data space that there can only be 4096 and 32 of ** them, respectively. So the maximum header length results from a ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ if( offset > 98307 || offset > pC->payloadSize ){ rc = SQLITE_CORRUPT_BKPT; goto op_column_error; } if( avail<offset ){ /* pC->aRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be ** dynamically allocated. */ pC->aRow = 0; pC->szRow = 0; } /* The following goto is an optimization. It can be omitted and ** everything will still work. But OP_Column is measurably faster ** by skipping the subsequent conditional, which is always true. */ assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ goto op_column_read_header; } /* Make sure at least the first p2+1 entries of the header have been ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ op_column_read_header: if( pC->iHdrOffset<aOffset[0] ){ /* Make sure zData points to enough of the record to cover the header. */ if( pC->aRow==0 ){ memset(&sMem, 0, sizeof(sMem)); rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
71367 71368 71369 71370 71371 71372 71373 | pC->nHdrParsed = i; pC->iHdrOffset = (u32)(zHdr - zData); if( pC->aRow==0 ){ sqlite3VdbeMemRelease(&sMem); sMem.flags = MEM_Null; } | | | > > > | < < > | < | 71415 71416 71417 71418 71419 71420 71421 71422 71423 71424 71425 71426 71427 71428 71429 71430 71431 71432 71433 71434 71435 71436 71437 71438 | pC->nHdrParsed = i; pC->iHdrOffset = (u32)(zHdr - zData); if( pC->aRow==0 ){ sqlite3VdbeMemRelease(&sMem); sMem.flags = MEM_Null; } /* The record is corrupt if any of the following are true: ** (1) the bytes of the header extend past the declared header size ** (zHdr>zEndHdr) ** (2) the entire header was used but not all data was used ** (zHdr==zEndHdr && offset!=pC->payloadSize) ** (3) the end of the data extends beyond the end of the record. ** (offset > pC->payloadSize) */ if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize)) || (offset > pC->payloadSize) ){ rc = SQLITE_CORRUPT_BKPT; goto op_column_error; } } /* If after trying to extra new entries from the header, nHdrParsed is |
︙ | ︙ | |||
71566 71567 71568 71569 71570 71571 71572 | /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ pRec = pLast; do{ assert( memIsValid(pRec) ); | | | 71615 71616 71617 71618 71619 71620 71621 71622 71623 71624 71625 71626 71627 71628 71629 | /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ pRec = pLast; do{ assert( memIsValid(pRec) ); pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format); len = sqlite3VdbeSerialTypeLen(serial_type); if( pRec->flags & MEM_Zero ){ if( nData ){ sqlite3VdbeMemExpandBlob(pRec); }else{ nZero += pRec->u.nZero; len -= pRec->u.nZero; |
︙ | ︙ | |||
71615 71616 71617 71618 71619 71620 71621 | /* Write the record */ i = putVarint32(zNewRecord, nHdr); j = nHdr; assert( pData0<=pLast ); pRec = pData0; do{ | | | 71664 71665 71666 71667 71668 71669 71670 71671 71672 71673 71674 71675 71676 71677 71678 | /* Write the record */ i = putVarint32(zNewRecord, nHdr); j = nHdr; assert( pData0<=pLast ); pRec = pData0; do{ serial_type = pRec->uTemp; i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); assert( i==nHdr ); assert( j==nByte ); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
︙ | ︙ | |||
72514 72515 72516 72517 72518 72519 72520 | ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); | < | 72563 72564 72565 72566 72567 72568 72569 72570 72571 72572 72573 72574 72575 72576 | ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ if( (pIn3->flags & MEM_Int)==0 ){ if( (pIn3->flags & MEM_Real)==0 ){ /* If the P3 value cannot be converted into any kind of a number, ** then the seek is not possible, so jump to P2 */ |
︙ | ︙ | |||
72550 72551 72552 72553 72554 72555 72556 72557 72558 72559 | assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } | > < < < < | 72598 72599 72600 72601 72602 72603 72604 72605 72606 72607 72608 72609 72610 72611 72612 72613 72614 72615 | assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } }else{ nField = pOp->p4.i; assert( pOp->p4type==P4_INT32 ); assert( nField>0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)nField; |
︙ | ︙ | |||
72586 72587 72588 72589 72590 72591 72592 | { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } #endif ExpandBlob(r.aMem); rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } | < < < | 72631 72632 72633 72634 72635 72636 72637 72638 72639 72640 72641 72642 72643 72644 72645 72646 72647 72648 72649 72650 72651 72652 72653 72654 72655 72656 72657 72658 72659 72660 72661 72662 72663 72664 | { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } #endif ExpandBlob(r.aMem); rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_TEST 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->pCursor, &res); if( rc!=SQLITE_OK ) 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->pCursor, &res); if( rc!=SQLITE_OK ) 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->pCursor); } } |
︙ | ︙ | |||
72645 72646 72647 72648 72649 72650 72651 | pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); assert( pC->isTable ); pC->nullRow = 0; pIn2 = &aMem[pOp->p2]; pC->movetoTarget = sqlite3VdbeIntValue(pIn2); | < | 72687 72688 72689 72690 72691 72692 72693 72694 72695 72696 72697 72698 72699 72700 | pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); assert( pC->isTable ); pC->nullRow = 0; pIn2 = &aMem[pOp->p2]; pC->movetoTarget = sqlite3VdbeIntValue(pIn2); pC->deferredMoveto = 1; break; } /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] |
︙ | ︙ | |||
72831 72832 72833 72834 72835 72836 72837 | assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; assert( pCrsr!=0 ); res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); | | < < | 72872 72873 72874 72875 72876 72877 72878 72879 72880 72881 72882 72883 72884 72885 72886 72887 72888 72889 72890 72891 72892 | assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; assert( pCrsr!=0 ); res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; } pC->seekResult = res; break; } /* Opcode: Sequence P1 P2 * * * ** Synopsis: r[P2]=cursor[P1].ctr++ |
︙ | ︙ | |||
72987 72988 72989 72990 72991 72992 72993 | && (++cnt<100)); if( rc==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } assert( v>0 ); /* EV: R-40812-03570 */ } | < | 73026 73027 73028 73029 73030 73031 73032 73033 73034 73035 73036 73037 73038 73039 | && (++cnt<100)); if( rc==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } assert( v>0 ); /* EV: R-40812-03570 */ } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } pOut->u.i = v; break; } |
︙ | ︙ | |||
73092 73093 73094 73095 73096 73097 73098 | }else{ nZero = 0; } rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pData->z, pData->n, nZero, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); | < | 73130 73131 73132 73133 73134 73135 73136 73137 73138 73139 73140 73141 73142 73143 | }else{ nZero = 0; } rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pData->z, pData->n, nZero, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ zDb = db->aDb[pC->iDb].zName; zTbl = pOp->p4.z; |
︙ | ︙ | |||
73129 73130 73131 73132 73133 73134 73135 | ** ** If P4 is not NULL, then it is the name of the table that P1 is ** pointing to. The update hook will be invoked, if it exists. ** If P4 is not NULL then the P1 cursor must have been positioned ** using OP_NotFound prior to invoking this opcode. */ case OP_Delete: { | < | | | | | | | < > | < > | | | | 73166 73167 73168 73169 73170 73171 73172 73173 73174 73175 73176 73177 73178 73179 73180 73181 73182 73183 73184 73185 73186 73187 73188 73189 73190 73191 73192 73193 73194 73195 73196 73197 73198 73199 73200 73201 73202 73203 73204 73205 | ** ** If P4 is not NULL, then it is the name of the table that P1 is ** pointing to. The update hook will be invoked, if it exists. ** If P4 is not NULL then the P1 cursor must have been positioned ** using OP_NotFound prior to invoking this opcode. */ case OP_Delete: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ assert( pC->deferredMoveto==0 ); #ifdef SQLITE_DEBUG /* The seek operation that positioned the cursor prior to OP_Delete will ** have also set the pC->movetoTarget field to the rowid of the row that ** is being deleted */ if( pOp->p4.z && pC->isTable ){ i64 iKey = 0; sqlite3BtreeKeySize(pC->pCursor, &iKey); assert( pC->movetoTarget==iKey ); } #endif rc = sqlite3BtreeDelete(pC->pCursor); pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget); assert( pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } /* Opcode: ResetCount * * * * * ** |
︙ | ︙ | |||
73208 73209 73210 73211 73212 73213 73214 | VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; } break; }; | | > > > > > > > > > | 73244 73245 73246 73247 73248 73249 73250 73251 73252 73253 73254 73255 73256 73257 73258 73259 73260 73261 73262 73263 73264 73265 73266 73267 73268 73269 73270 73271 73272 73273 73274 73275 73276 73277 73278 73279 | VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; } break; }; /* Opcode: SorterData P1 P2 P3 * * ** Synopsis: r[P2]=data ** ** Write into register P2 the current sorter data for sorter cursor P1. ** Then clear the column header cache on cursor P3. ** ** This opcode is normally use to move a record out of the sorter and into ** a register that is the source for a pseudo-table cursor created using ** OpenPseudo. That pseudo-table cursor is the one that is identified by ** parameter P3. Clearing the P3 column cache as part of this opcode saves ** us from having to issue a separate NullRow instruction to clear that cache. */ case OP_SorterData: { VdbeCursor *pC; pOut = &aMem[pOp->p2]; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } /* Opcode: RowData P1 P2 * * * ** Synopsis: r[P2]=data ** ** Write into register P2 the complete row data for cursor P1. |
︙ | ︙ | |||
73267 73268 73269 73270 73271 73272 73273 | assert( pC->isTable || pOp->opcode!=OP_RowData ); assert( pC->isTable==0 || pOp->opcode==OP_RowData ); assert( pC!=0 ); assert( pC->nullRow==0 ); assert( pC->pseudoTableReg==0 ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; | < > > > | < > > | > > | | 73312 73313 73314 73315 73316 73317 73318 73319 73320 73321 73322 73323 73324 73325 73326 73327 73328 73329 73330 73331 73332 73333 73334 73335 73336 73337 73338 73339 73340 73341 73342 73343 73344 73345 73346 73347 73348 73349 73350 73351 73352 73353 73354 73355 73356 73357 | assert( pC->isTable || pOp->opcode!=OP_RowData ); assert( pC->isTable==0 || pOp->opcode==OP_RowData ); assert( pC!=0 ); assert( pC->nullRow==0 ); assert( pC->pseudoTableReg==0 ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_Rewind/Op_Next with no intervening instructions that might invalidate ** the cursor. If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); #if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif if( pC->isTable==0 ){ assert( !pC->isTable ); VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } n = (u32)n64; }else{ VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } } testcase( n==0 ); if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ goto no_mem; } pOut->n = n; MemSetTypeFlag(pOut, MEM_Blob); if( pC->isTable==0 ){ rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z); }else{ |
︙ | ︙ | |||
73344 73345 73346 73347 73348 73349 73350 | pModule = pVtab->pModule; assert( pModule->xRowid ); rc = pModule->xRowid(pC->pVtabCursor, &v); sqlite3VtabImportErrmsg(p, pVtab); #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->pCursor!=0 ); | | < < < | | < < | 73394 73395 73396 73397 73398 73399 73400 73401 73402 73403 73404 73405 73406 73407 73408 73409 73410 73411 73412 73413 73414 73415 73416 73417 73418 73419 73420 73421 73422 73423 73424 73425 73426 73427 73428 73429 | pModule = pVtab->pModule; assert( pModule->xRowid ); rc = pModule->xRowid(pC->pVtabCursor, &v); sqlite3VtabImportErrmsg(p, pVtab); #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; rc = sqlite3BtreeKeySize(pC->pCursor, &v); assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ } pOut->u.i = v; break; } /* Opcode: NullRow P1 * * * * ** ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. */ case OP_NullRow: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pC->nullRow = 1; pC->cacheStatus = CACHE_STALE; if( pC->pCursor ){ sqlite3BtreeClearCursor(pC->pCursor); } break; } |
︙ | ︙ | |||
73404 73405 73406 73407 73408 73409 73410 | assert( pC!=0 ); pCrsr = pC->pCursor; res = 0; assert( pCrsr!=0 ); rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; | < | 73449 73450 73451 73452 73453 73454 73455 73456 73457 73458 73459 73460 73461 73462 | assert( pC!=0 ); pCrsr = pC->pCursor; res = 0; assert( pCrsr!=0 ); rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_DEBUG pC->seekOp = OP_Last; #endif if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); if( res ) pc = pOp->p2 - 1; |
︙ | ︙ | |||
73471 73472 73473 73474 73475 73476 73477 | rc = sqlite3VdbeSorterRewind(pC, &res); }else{ pCrsr = pC->pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; | < | 73515 73516 73517 73518 73519 73520 73521 73522 73523 73524 73525 73526 73527 73528 | rc = sqlite3VdbeSorterRewind(pC, &res); }else{ pCrsr = pC->pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2<p->nOp ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; } |
︙ | ︙ | |||
73597 73598 73599 73600 73601 73602 73603 | p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif }else{ pC->nullRow = 1; } | < | 73640 73641 73642 73643 73644 73645 73646 73647 73648 73649 73650 73651 73652 73653 | p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif }else{ pC->nullRow = 1; } goto check_for_interrupt; } /* Opcode: IdxInsert P1 P2 P3 * P5 ** Synopsis: key=r[P2] ** ** Register P2 holds an SQL index key made using the |
︙ | ︙ | |||
73713 73714 73715 73716 73717 73718 73719 | assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->pCursor; assert( pCrsr!=0 ); pOut->flags = MEM_Null; | > > > > > > > | | | < | 73755 73756 73757 73758 73759 73760 73761 73762 73763 73764 73765 73766 73767 73768 73769 73770 73771 73772 73773 73774 73775 73776 73777 73778 | assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->pCursor; assert( pCrsr!=0 ); pOut->flags = MEM_Null; assert( pC->isTable==0 ); assert( pC->deferredMoveto==0 ); /* sqlite3VbeCursorRestore() can only fail if the record has been deleted ** out from under the cursor. That will never happend for an IdxRowid ** opcode, hence the NEVER() arround the check of the return value. */ rc = sqlite3VdbeCursorRestore(pC); if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; if( !pC->nullRow ){ rowid = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pOut->u.i = rowid; |
︙ | ︙ | |||
78177 78178 78179 78180 78181 78182 78183 | rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); if( rc==SQLITE_OK ){ #if SQLITE_MAX_WORKER_THREADS assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); if( pSorter->bUseThreads ){ int iTask; | | | 78225 78226 78227 78228 78229 78230 78231 78232 78233 78234 78235 78236 78237 78238 78239 | rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); if( rc==SQLITE_OK ){ #if SQLITE_MAX_WORKER_THREADS assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); if( pSorter->bUseThreads ){ int iTask; PmaReader *pReadr = 0; SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; rc = vdbeSortAllocUnpacked(pLast); if( rc==SQLITE_OK ){ pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); pSorter->pReader = pReadr; if( pReadr==0 ) rc = SQLITE_NOMEM; } |
︙ | ︙ | |||
87158 87159 87160 87161 87162 87163 87164 | int c; int i; tRowcnt v; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( z==0 ) z = ""; #else | | | | < | < | < > | 87206 87207 87208 87209 87210 87211 87212 87213 87214 87215 87216 87217 87218 87219 87220 87221 87222 87223 87224 87225 87226 87227 87228 87229 87230 87231 87232 87233 87234 87235 87236 | int c; int i; tRowcnt v; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( z==0 ) z = ""; #else assert( z!=0 ); #endif for(i=0; *z && i<nOut; i++){ v = 0; while( (c=z[0])>='0' && c<='9' ){ v = v*10 + c - '0'; z++; } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( aOut ) aOut[i] = v; if( aLog ) aLog[i] = sqlite3LogEst(v); #else assert( aOut==0 ); UNUSED_PARAMETER(aOut); assert( aLog!=0 ); aLog[i] = sqlite3LogEst(v); #endif if( *z==' ' ) z++; } #ifndef SQLITE_ENABLE_STAT3_OR_STAT4 assert( pIndex!=0 ); #else if( pIndex ) #endif |
︙ | ︙ | |||
87237 87238 87239 87240 87241 87242 87243 87244 | pIndex = sqlite3PrimaryKeyIndex(pTable); }else{ pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ pIndex->bUnordered = 0; | > > > > > > > > > | | 87283 87284 87285 87286 87287 87288 87289 87290 87291 87292 87293 87294 87295 87296 87297 87298 87299 87300 87301 87302 87303 87304 87305 87306 87307 | pIndex = sqlite3PrimaryKeyIndex(pTable); }else{ pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ int nCol = pIndex->nKeyCol+1; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 tRowcnt * const aiRowEst = pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero( sizeof(tRowcnt) * nCol ); if( aiRowEst==0 ) pInfo->db->mallocFailed = 1; #else tRowcnt * const aiRowEst = 0; #endif pIndex->bUnordered = 0; decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; #ifdef SQLITE_ENABLE_COSTMULT fakeIdx.pTable = pTable; #endif |
︙ | ︙ | |||
87297 87298 87299 87300 87301 87302 87303 87304 87305 | ** sample columns except the last. The last is always set to 1, as ** once the trailing PK fields are considered all index keys are ** unique. */ nCol = pIdx->nSampleCol-1; pIdx->aAvgEq[nCol] = 1; } for(iCol=0; iCol<nCol; iCol++){ int i; /* Used to iterate through samples */ tRowcnt sumEq = 0; /* Sum of the nEq values */ | > < > > > > > > | > > > > | > | | | < > | | > | | > | | 87352 87353 87354 87355 87356 87357 87358 87359 87360 87361 87362 87363 87364 87365 87366 87367 87368 87369 87370 87371 87372 87373 87374 87375 87376 87377 87378 87379 87380 87381 87382 87383 87384 87385 87386 87387 87388 87389 87390 87391 87392 87393 87394 87395 87396 87397 | ** sample columns except the last. The last is always set to 1, as ** once the trailing PK fields are considered all index keys are ** unique. */ nCol = pIdx->nSampleCol-1; pIdx->aAvgEq[nCol] = 1; } for(iCol=0; iCol<nCol; iCol++){ int nSample = pIdx->nSample; int i; /* Used to iterate through samples */ tRowcnt sumEq = 0; /* Sum of the nEq values */ tRowcnt avgEq = 0; tRowcnt nRow; /* Number of rows in index */ i64 nSum100 = 0; /* Number of terms contributing to sumEq */ i64 nDist100; /* Number of distinct values in index */ if( pIdx->aiRowEst==0 || pIdx->aiRowEst[iCol+1]==0 ){ nRow = pFinal->anLt[iCol]; nDist100 = (i64)100 * pFinal->anDLt[iCol]; nSample--; }else{ nRow = pIdx->aiRowEst[0]; nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1]; } /* Set nSum to the number of distinct (iCol+1) field prefixes that ** occur in the stat4 table for this index. Set sumEq to the sum of ** the nEq values for column iCol for the same set (adding the value ** only once where there exist duplicate prefixes). */ for(i=0; i<nSample; i++){ if( i==(pIdx->nSample-1) || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){ sumEq += aSample[i].anEq[iCol]; nSum100 += 100; } } if( nDist100>nSum100 ){ avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100); } if( avgEq==0 ) avgEq = 1; pIdx->aAvgEq[iCol] = avgEq; } } } |
︙ | ︙ | |||
87566 87567 87568 87569 87570 87571 87572 87573 87574 87575 87576 87577 87578 87579 | /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( rc==SQLITE_OK ){ int lookasideEnabled = db->lookaside.bEnabled; db->lookaside.bEnabled = 0; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bEnabled = lookasideEnabled; } #endif if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; } return rc; | > > > > > | 87634 87635 87636 87637 87638 87639 87640 87641 87642 87643 87644 87645 87646 87647 87648 87649 87650 87651 87652 | /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( rc==SQLITE_OK ){ int lookasideEnabled = db->lookaside.bEnabled; db->lookaside.bEnabled = 0; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bEnabled = lookasideEnabled; } for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3_free(pIdx->aiRowEst); pIdx->aiRowEst = 0; } #endif if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; } return rc; |
︙ | ︙ | |||
88860 88861 88862 88863 88864 88865 88866 88867 88868 88869 88870 88871 88872 88873 | #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo); sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); sqlite3DbFree(db, p); } /* ** For the index called zIdxName which is found in the database iDb, ** unlike that index from its Table then remove the index from ** the index hash table and free all memory structures associated | > > > | 88933 88934 88935 88936 88937 88938 88939 88940 88941 88942 88943 88944 88945 88946 88947 88948 88949 | #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo); sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 sqlite3_free(p->aiRowEst); #endif sqlite3DbFree(db, p); } /* ** For the index called zIdxName which is found in the database iDb, ** unlike that index from its Table then remove the index from ** the index hash table and free all memory structures associated |
︙ | ︙ | |||
91169 91170 91171 91172 91173 91174 91175 | addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } | | | 91245 91246 91247 91248 91249 91250 91251 91252 91253 91254 91255 91256 91257 91258 91259 | addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); |
︙ | ︙ | |||
105112 105113 105114 105115 105116 105117 105118 | int eDest = pDest->eDest; int iParm = pDest->iSDParm; int regRow; int regRowid; int nKey; int iSortTab; /* Sorter cursor to read from */ int nSortData; /* Trailing values to read from sorter */ | < | 105188 105189 105190 105191 105192 105193 105194 105195 105196 105197 105198 105199 105200 105201 | int eDest = pDest->eDest; int iParm = pDest->iSDParm; int regRow; int regRowid; int nKey; int iSortTab; /* Sorter cursor to read from */ int nSortData; /* Trailing values to read from sorter */ int i; int bSeq; /* True if sorter record includes seq. no. */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS struct ExprList_item *aOutEx = p->pEList->a; #endif if( pSort->labelBkOut ){ |
︙ | ︙ | |||
105146 105147 105148 105149 105150 105151 105152 | addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); | | < < < | 105221 105222 105223 105224 105225 105226 105227 105228 105229 105230 105231 105232 105233 105234 105235 105236 105237 105238 105239 105240 105241 105242 105243 105244 | addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; bSeq = 1; } for(i=0; i<nSortData; i++){ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i); VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); |
︙ | ︙ | |||
109087 109088 109089 109090 109091 109092 109093 | ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3ExprCacheClear(pParse); if( groupBySort ){ | | < | 109159 109160 109161 109162 109163 109164 109165 109166 109167 109168 109169 109170 109171 109172 109173 109174 109175 109176 109177 | ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3ExprCacheClear(pParse); if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab); } for(j=0; j<pGroupBy->nExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); }else{ sAggInfo.directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); } } sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); |
︙ | ︙ | |||
112440 112441 112442 112443 112444 112445 112446 112447 112448 112449 112450 112451 112452 112453 | *pzErr = sqlite3MPrintf(db, "%s", zErr); sqlite3_free(zErr); } sqlite3DbFree(db, pVTable); }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; if( sCtx.pTab ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; | > | 112511 112512 112513 112514 112515 112516 112517 112518 112519 112520 112521 112522 112523 112524 112525 | *pzErr = sqlite3MPrintf(db, "%s", zErr); sqlite3_free(zErr); } sqlite3DbFree(db, pVTable); }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; if( sCtx.pTab ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; |
︙ | ︙ | |||
115690 115691 115692 115693 115694 115695 115696 115697 115698 115699 115700 115701 | }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ whereKeyStats(pParse, p, pRec, 0, a); iLower = a[0]; iUpper = a[0] + a[1]; } /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; | > > > > > > > > < | < | | 115762 115763 115764 115765 115766 115767 115768 115769 115770 115771 115772 115773 115774 115775 115776 115777 115778 115779 115780 115781 115782 115783 115784 115785 115786 115787 115788 115789 115790 115791 115792 115793 115794 115795 115796 115797 115798 115799 115800 115801 115802 115803 115804 115805 115806 115807 115808 | }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ whereKeyStats(pParse, p, pRec, 0, a); iLower = a[0]; iUpper = a[0] + a[1]; } assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 ); assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); assert( p->aSortOrder!=0 ); if( p->aSortOrder[nEq] ){ /* The roles of pLower and pUpper are swapped for a DESC index */ SWAP(WhereTerm*, pLower, pUpper); } /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; whereKeyStats(pParse, p, pRec, 0, a); iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; pLower = 0; } } /* If possible, improve on the iUpper estimate using ($P:$U). */ if( pUpper ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; whereKeyStats(pParse, p, pRec, 1, a); iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNew<iUpper ) iUpper = iNew; nOut--; pUpper = 0; } } pBuilder->pRec = pRec; |
︙ | ︙ | |||
116215 116216 116217 116218 116219 116220 116221 | sqlite3StrAccumAppendAll(pStr, zColumn); sqlite3StrAccumAppend(pStr, zOp, 1); sqlite3StrAccumAppend(pStr, "?", 1); } /* ** Argument pLevel describes a strategy for scanning table pTab. This | | | < < < < < | < | < < < < | | | < | < | | | < | 116293 116294 116295 116296 116297 116298 116299 116300 116301 116302 116303 116304 116305 116306 116307 116308 116309 116310 116311 116312 116313 116314 116315 116316 116317 116318 116319 116320 116321 116322 116323 116324 116325 116326 116327 116328 116329 116330 116331 116332 116333 116334 116335 116336 116337 116338 116339 116340 116341 116342 116343 116344 116345 116346 116347 116348 | sqlite3StrAccumAppendAll(pStr, zColumn); sqlite3StrAccumAppend(pStr, zOp, 1); sqlite3StrAccumAppend(pStr, "?", 1); } /* ** Argument pLevel describes a strategy for scanning table pTab. This ** function appends text to pStr that describes the subset of table ** rows scanned by the strategy in the form of an SQL expression. ** ** For example, if the query: ** ** SELECT * FROM t1 WHERE a=1 AND b>2; ** ** is run and there is an index on (a, b), then this function returns a ** string similar to: ** ** "a=? AND b>?" */ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ Index *pIndex = pLoop->u.btree.pIndex; u16 nEq = pLoop->u.btree.nEq; u16 nSkip = pLoop->u.btree.nSkip; int i, j; Column *aCol = pTab->aCol; i16 *aiColumn = pIndex->aiColumn; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; sqlite3StrAccumAppend(pStr, " (", 2); for(i=0; i<nEq; i++){ char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName; if( i>=nSkip ){ explainAppendTerm(pStr, i, z, "="); }else{ if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5); sqlite3XPrintf(pStr, 0, "ANY(%s)", z); } } j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(pStr, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(pStr, i, z, "<"); } sqlite3StrAccumAppend(pStr, ")", 1); } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN ** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single ** record is added to the output to describe the table scan strategy in ** pLevel. |
︙ | ︙ | |||
116293 116294 116295 116296 116297 116298 116299 | #ifndef SQLITE_DEBUG if( pParse->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ | < > > > > > | | | | | < < | | | > > > | > | | | | | > > > < | | | | > | | > > | > > > > > > > | | 116358 116359 116360 116361 116362 116363 116364 116365 116366 116367 116368 116369 116370 116371 116372 116373 116374 116375 116376 116377 116378 116379 116380 116381 116382 116383 116384 116385 116386 116387 116388 116389 116390 116391 116392 116393 116394 116395 116396 116397 116398 116399 116400 116401 116402 116403 116404 116405 116406 116407 116408 116409 116410 116411 116412 116413 116414 116415 116416 116417 116418 116419 116420 116421 116422 116423 116424 116425 116426 116427 116428 116429 116430 116431 116432 116433 116434 116435 116436 116437 116438 116439 116440 116441 116442 116443 116444 116445 116446 116447 116448 116449 116450 116451 | #ifndef SQLITE_DEBUG if( pParse->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.db = db; sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); }else{ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; Index *pIdx; assert( pLoop->u.btree.pIndex!=0 ); pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ if( isSearch ){ zFmt = "PRIMARY KEY"; } }else if( flags & WHERE_AUTO_INDEX ){ zFmt = "AUTOMATIC COVERING INDEX"; }else if( flags & WHERE_IDX_ONLY ){ zFmt = "COVERING INDEX %s"; }else{ zFmt = "INDEX %s"; } if( zFmt ){ sqlite3StrAccumAppend(&str, " USING ", 7); sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); explainIndexRange(&str, pLoop, pItem->pTab); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ const char *zRange; if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ zRange = "(rowid=?)"; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ zRange = "(rowid>? AND rowid<?)"; }else if( flags&WHERE_BTM_LIMIT ){ zRange = "(rowid>?)"; }else{ assert( flags&WHERE_TOP_LIMIT); zRange = "(rowid<?)"; } sqlite3StrAccumAppendAll(&str, " USING INTEGER PRIMARY KEY "); sqlite3StrAccumAppendAll(&str, zRange); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3StrAccumAppend(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } #else # define explainOneScan(u,v,w,x,y,z) #endif /* SQLITE_OMIT_EXPLAIN */ |
︙ | ︙ | |||
117623 117624 117625 117626 117627 117628 117629 | ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); if( ppPrev==0 ){ /* There already exists a WhereLoop on the list that is better ** than pTemplate, so just ignore pTemplate */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ | | | | | 117706 117707 117708 117709 117710 117711 117712 117713 117714 117715 117716 117717 117718 117719 117720 117721 117722 117723 117724 117725 117726 117727 117728 117729 117730 117731 117732 117733 117734 117735 117736 117737 117738 117739 | ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); if( ppPrev==0 ){ /* There already exists a WhereLoop on the list that is better ** than pTemplate, so just ignore pTemplate */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" skip: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif return SQLITE_OK; }else{ p = *ppPrev; } /* If we reach this point it means that either p[] should be overwritten ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new ** WhereLoop and insert it. */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ sqlite3DebugPrintf("replace: "); whereLoopPrint(p, pBuilder->pWC); } sqlite3DebugPrintf(" add: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif if( p==0 ){ /* Allocate a new WhereLoop to add to the end of the list */ *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; |
︙ | ︙ | |||
117666 117667 117668 117669 117670 117671 117672 | ppTail = whereLoopFindLesser(ppTail, pTemplate); if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ | | | 117749 117750 117751 117752 117753 117754 117755 117756 117757 117758 117759 117760 117761 117762 117763 | ppTail = whereLoopFindLesser(ppTail, pTemplate); if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); whereLoopPrint(pToDel, pBuilder->pWC); } #endif whereLoopDelete(db, pToDel); } } whereLoopXfer(db, p, pTemplate); |
︙ | ︙ | |||
118833 118834 118835 118836 118837 118838 118839 | pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } isMatch = 1; break; } | | | 118916 118917 118918 118919 118920 118921 118922 118923 118924 118925 118926 118927 118928 118929 118930 | pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } isMatch = 1; break; } if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ /* Make sure the sort order is compatible in an ORDER BY clause. ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; }else{ rev = revIdx ^ pOrderBy->a[i].sortOrder; if( rev ) *pRevMask |= MASKBIT(iLoop); |
︙ | ︙ | |||
119298 119299 119300 119301 119302 119303 119304 | pWInfo->nOBSat = pFrom->isOrdered; if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; pWInfo->revMask = pFrom->revLoop; } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr ){ | | | > | > > | 119381 119382 119383 119384 119385 119386 119387 119388 119389 119390 119391 119392 119393 119394 119395 119396 119397 119398 119399 119400 119401 119402 119403 | pWInfo->nOBSat = pFrom->isOrdered; if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; pWInfo->revMask = pFrom->revLoop; } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr ){ Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask ); assert( pWInfo->sorted==0 ); if( nOrder==pWInfo->pOrderBy->nExpr ){ pWInfo->sorted = 1; pWInfo->revMask = revMask; } } } pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ |
︙ | ︙ | |||
120192 120193 120194 120195 120196 120197 120198 | pOut->zEnd = &pPostOp->z[pPostOp->n]; } /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; | | | 120278 120279 120280 120281 120282 120283 120284 120285 120286 120287 120288 120289 120290 120291 120292 | pOut->zEnd = &pPostOp->z[pPostOp->n]; } /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; if( pY && pA && pY->op==TK_NULL ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; } } /* Construct an expression node for a unary prefix operator |
︙ | ︙ | |||
125293 125294 125295 125296 125297 125298 125299 125300 125301 125302 125303 125304 125305 125306 | */ typedef void(*LOGFUNC_t)(void*,int,const char*); sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); break; } case SQLITE_CONFIG_URI: { sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; } case SQLITE_CONFIG_COVERING_INDEX_SCAN: { sqlite3GlobalConfig.bUseCis = va_arg(ap, int); | > > > > > | 125379 125380 125381 125382 125383 125384 125385 125386 125387 125388 125389 125390 125391 125392 125393 125394 125395 125396 125397 | */ typedef void(*LOGFUNC_t)(void*,int,const char*); sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); break; } /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames ** can be changed at start-time using the ** sqlite3_config(SQLITE_CONFIG_URI,1) or ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. */ case SQLITE_CONFIG_URI: { sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; } case SQLITE_CONFIG_COVERING_INDEX_SCAN: { sqlite3GlobalConfig.bUseCis = va_arg(ap, int); |
︙ | ︙ | |||
127030 127031 127032 127033 127034 127035 127036 | char *zFile; char c; int nUri = sqlite3Strlen30(zUri); assert( *pzErrMsg==0 ); if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) | | | 127121 127122 127123 127124 127125 127126 127127 127128 127129 127130 127131 127132 127133 127134 127135 | char *zFile; char c; int nUri = sqlite3Strlen30(zUri); assert( *pzErrMsg==0 ); if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ int iIn; /* Input character index */ int iOut = 0; /* Output character index */ int nByte = nUri+2; /* Bytes of space to allocate */ |
︙ | ︙ | |||
127260 127261 127262 127263 127264 127265 127266 | */ assert( SQLITE_OPEN_READONLY == 0x01 ); assert( SQLITE_OPEN_READWRITE == 0x02 ); assert( SQLITE_OPEN_CREATE == 0x04 ); testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ | | > > | 127351 127352 127353 127354 127355 127356 127357 127358 127359 127360 127361 127362 127363 127364 127365 127366 127367 | */ assert( SQLITE_OPEN_READONLY == 0x01 ); assert( SQLITE_OPEN_READWRITE == 0x02 ); assert( SQLITE_OPEN_CREATE == 0x04 ); testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ if( ((1<<(flags&7)) & 0x46)==0 ){ return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ } if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_NOMUTEX ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_FULLMUTEX ){ isThreadsafe = 1; |
︙ | ︙ | |||
132603 132604 132605 132606 132607 132608 132609 132610 132611 132612 132613 132614 132615 132616 | if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++]; if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++]; assert( iIdx==nVal ); /* In case the cursor has been used before, clear it now. */ sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr->aDoclist); sqlite3Fts3ExprFree(pCsr->pExpr); memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); /* Set the lower and upper bounds on docids to return */ pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64); | > | 132696 132697 132698 132699 132700 132701 132702 132703 132704 132705 132706 132707 132708 132709 132710 | if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++]; if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++]; assert( iIdx==nVal ); /* In case the cursor has been used before, clear it now. */ sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr->aDoclist); sqlite3_free(pCsr->aMatchinfo); sqlite3Fts3ExprFree(pCsr->pExpr); memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); /* Set the lower and upper bounds on docids to return */ pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64); |
︙ | ︙ | |||
133913 133914 133915 133916 133917 133918 133919 | for(i=0; rc==SQLITE_OK && i<p->nToken && bEof==0; i++){ rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){ iMax = a[i].iDocid; bMaxSet = 1; } } | | | 134007 134008 134009 134010 134011 134012 134013 134014 134015 134016 134017 134018 134019 134020 134021 | for(i=0; rc==SQLITE_OK && i<p->nToken && bEof==0; i++){ rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){ iMax = a[i].iDocid; bMaxSet = 1; } } assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); assert( rc!=SQLITE_OK || bMaxSet ); /* Keep advancing iterators until they all point to the same document */ for(i=0; i<p->nToken; i++){ while( rc==SQLITE_OK && bEof==0 && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 ){ |
︙ | ︙ | |||
136030 136031 136032 136033 136034 136035 136036 | sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; int i = 0; /* Set variable i to the maximum number of bytes of input to tokenize. */ for(i=0; i<n; i++){ if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break; | | | 136124 136125 136126 136127 136128 136129 136130 136131 136132 136133 136134 136135 136136 136137 136138 | sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; int i = 0; /* Set variable i to the maximum number of bytes of input to tokenize. */ for(i=0; i<n; i++){ if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break; if( z[i]=='"' ) break; } *pnConsumed = i; rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; |
︙ | ︙ |
Changes to src/sqlite3.h.
︙ | ︙ | |||
105 106 107 108 109 110 111 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.7" #define SQLITE_VERSION_NUMBER 3008007 | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.7" #define SQLITE_VERSION_NUMBER 3008007 #define SQLITE_SOURCE_ID "2014-10-17 11:24:17 e4ab094f8afce0817f4074e823fabe59fc29ebb4" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
︙ | ︙ | |||
2665 2666 2667 2668 2669 2670 2671 | ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** | | | | | 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 | ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** ** ^The default encoding will be UTF-8 for databases created using ** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases ** created using sqlite3_open16() will be UTF-16 in the native byte order. ** ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control |
︙ | ︙ | |||
2755 2756 2757 2758 2759 2760 2761 | ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file ** which contains the database. ^If the path begins with a '/' character, ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. | | | > | | 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 | ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file ** which contains the database. ^If the path begins with a '/' character, ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. ** ^(On windows, the first component of an absolute path ** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] ** The query component of a URI may contain parameters that are interpreted ** either by SQLite itself, or by a [VFS | custom VFS implementation]. ** SQLite and its built-in [VFSes] interpret the ** following query parameters: ** ** <ul> ** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of ** a VFS object that provides the operating system interface that should ** be used to access the database file on disk. ^If this option is set to ** an empty string the default VFS object is used. ^Specifying an unknown ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is |
︙ | ︙ | |||
2796 2797 2798 2799 2800 2801 2802 | ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** | | < | < | 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 | ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** ** <li> <b>psow</b>: ^The psow parameter indicates whether or not the ** [powersafe overwrite] property does or does not apply to the ** storage media on which the database file resides. ** ** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter ** which if set disables file locking in rollback journal modes. This ** is useful for accessing a database on a filesystem that does not ** support locking. Caution: Database corruption might result if two ** or more processes write to the same database and any one of those ** processes uses nolock=1. |
︙ | ︙ | |||
3395 3396 3397 3398 3399 3400 3401 | ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** | | | | < | | 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 | ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** ** ^The fifth argument to the BLOB and string binding interfaces ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called ** to dispose of the BLOB or string even if the call to bind API fails. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. ** ^If the fifth argument has the value [SQLITE_TRANSIENT], then ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] ** to specify the encoding of the text in the third parameter. If ** the sixth argument to sqlite3_bind_text64() is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. ** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. |
︙ | ︙ | |||
4446 4447 4448 4449 4450 4451 4452 | ** of the application-defined function to be the 64-bit signed integer ** value given in the 2nd argument. ** ** ^The sqlite3_result_null() interface sets the return value ** of the application-defined function to be NULL. ** ** ^The sqlite3_result_text(), sqlite3_result_text16(), | | | 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 | ** of the application-defined function to be the 64-bit signed integer ** value given in the 2nd argument. ** ** ^The sqlite3_result_null() interface sets the return value ** of the application-defined function to be NULL. ** ** ^The sqlite3_result_text(), sqlite3_result_text16(), ** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. |
︙ | ︙ |
Added src/sqlite3ext.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | /* ** 2006 June 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ #ifndef _SQLITE3EXT_H_ #define _SQLITE3EXT_H_ #include "sqlite3.h" typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** The following structure holds pointers to all of the SQLite API ** routines. ** ** WARNING: In order to maintain backwards compatibility, add new ** interfaces to the end of this structure only. If you insert new ** interfaces in the middle of this structure, then older different ** versions of SQLite will not be able to load each other's shared ** libraries! */ struct sqlite3_api_routines { void * (*aggregate_context)(sqlite3_context*,int nBytes); int (*aggregate_count)(sqlite3_context*); int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); int (*bind_double)(sqlite3_stmt*,int,double); int (*bind_int)(sqlite3_stmt*,int,int); int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); int (*bind_null)(sqlite3_stmt*,int); int (*bind_parameter_count)(sqlite3_stmt*); int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); const char * (*bind_parameter_name)(sqlite3_stmt*,int); int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); int (*busy_timeout)(sqlite3*,int ms); int (*changes)(sqlite3*); int (*close)(sqlite3*); int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, int eTextRep,const char*)); int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, int eTextRep,const void*)); const void * (*column_blob)(sqlite3_stmt*,int iCol); int (*column_bytes)(sqlite3_stmt*,int iCol); int (*column_bytes16)(sqlite3_stmt*,int iCol); int (*column_count)(sqlite3_stmt*pStmt); const char * (*column_database_name)(sqlite3_stmt*,int); const void * (*column_database_name16)(sqlite3_stmt*,int); const char * (*column_decltype)(sqlite3_stmt*,int i); const void * (*column_decltype16)(sqlite3_stmt*,int); double (*column_double)(sqlite3_stmt*,int iCol); int (*column_int)(sqlite3_stmt*,int iCol); sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); const char * (*column_name)(sqlite3_stmt*,int); const void * (*column_name16)(sqlite3_stmt*,int); const char * (*column_origin_name)(sqlite3_stmt*,int); const void * (*column_origin_name16)(sqlite3_stmt*,int); const char * (*column_table_name)(sqlite3_stmt*,int); const void * (*column_table_name16)(sqlite3_stmt*,int); const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); const void * (*column_text16)(sqlite3_stmt*,int iCol); int (*column_type)(sqlite3_stmt*,int iCol); sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); void * (*commit_hook)(sqlite3*,int(*)(void*),void*); int (*complete)(const char*sql); int (*complete16)(const void*sql); int (*create_collation)(sqlite3*,const char*,int,void*, int(*)(void*,int,const void*,int,const void*)); int (*create_collation16)(sqlite3*,const void*,int,void*, int(*)(void*,int,const void*,int,const void*)); int (*create_function)(sqlite3*,const char*,int,int,void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*)); int (*create_function16)(sqlite3*,const void*,int,int,void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*)); int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); int (*data_count)(sqlite3_stmt*pStmt); sqlite3 * (*db_handle)(sqlite3_stmt*); int (*declare_vtab)(sqlite3*,const char*); int (*enable_shared_cache)(int); int (*errcode)(sqlite3*db); const char * (*errmsg)(sqlite3*); const void * (*errmsg16)(sqlite3*); int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); int (*expired)(sqlite3_stmt*); int (*finalize)(sqlite3_stmt*pStmt); void (*free)(void*); void (*free_table)(char**result); int (*get_autocommit)(sqlite3*); void * (*get_auxdata)(sqlite3_context*,int); int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); int (*global_recover)(void); void (*interruptx)(sqlite3*); sqlite_int64 (*last_insert_rowid)(sqlite3*); const char * (*libversion)(void); int (*libversion_number)(void); void *(*malloc)(int); char * (*mprintf)(const char*,...); int (*open)(const char*,sqlite3**); int (*open16)(const void*,sqlite3**); int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); void *(*realloc)(void*,int); int (*reset)(sqlite3_stmt*pStmt); void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_double)(sqlite3_context*,double); void (*result_error)(sqlite3_context*,const char*,int); void (*result_error16)(sqlite3_context*,const void*,int); void (*result_int)(sqlite3_context*,int); void (*result_int64)(sqlite3_context*,sqlite_int64); void (*result_null)(sqlite3_context*); void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); char * (*snprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); void (*thread_cleanup)(void); int (*total_changes)(sqlite3*); void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, sqlite_int64),void*); void * (*user_data)(sqlite3_context*); const void * (*value_blob)(sqlite3_value*); int (*value_bytes)(sqlite3_value*); int (*value_bytes16)(sqlite3_value*); double (*value_double)(sqlite3_value*); int (*value_int)(sqlite3_value*); sqlite_int64 (*value_int64)(sqlite3_value*); int (*value_numeric_type)(sqlite3_value*); const unsigned char * (*value_text)(sqlite3_value*); const void * (*value_text16)(sqlite3_value*); const void * (*value_text16be)(sqlite3_value*); const void * (*value_text16le)(sqlite3_value*); int (*value_type)(sqlite3_value*); char *(*vmprintf)(const char*,va_list); /* Added ??? */ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); /* Added by 3.3.13 */ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); int (*clear_bindings)(sqlite3_stmt*); /* Added by 3.4.1 */ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, void (*xDestroy)(void *)); /* Added by 3.5.0 */ int (*bind_zeroblob)(sqlite3_stmt*,int,int); int (*blob_bytes)(sqlite3_blob*); int (*blob_close)(sqlite3_blob*); int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, int,sqlite3_blob**); int (*blob_read)(sqlite3_blob*,void*,int,int); int (*blob_write)(sqlite3_blob*,const void*,int,int); int (*create_collation_v2)(sqlite3*,const char*,int,void*, int(*)(void*,int,const void*,int,const void*), void(*)(void*)); int (*file_control)(sqlite3*,const char*,int,void*); sqlite3_int64 (*memory_highwater)(int); sqlite3_int64 (*memory_used)(void); sqlite3_mutex *(*mutex_alloc)(int); void (*mutex_enter)(sqlite3_mutex*); void (*mutex_free)(sqlite3_mutex*); void (*mutex_leave)(sqlite3_mutex*); int (*mutex_try)(sqlite3_mutex*); int (*open_v2)(const char*,sqlite3**,int,const char*); int (*release_memory)(int); void (*result_error_nomem)(sqlite3_context*); void (*result_error_toobig)(sqlite3_context*); int (*sleep)(int); void (*soft_heap_limit)(int); sqlite3_vfs *(*vfs_find)(const char*); int (*vfs_register)(sqlite3_vfs*,int); int (*vfs_unregister)(sqlite3_vfs*); int (*xthreadsafe)(void); void (*result_zeroblob)(sqlite3_context*,int); void (*result_error_code)(sqlite3_context*,int); int (*test_control)(int, ...); void (*randomness)(int,void*); sqlite3 *(*context_db_handle)(sqlite3_context*); int (*extended_result_codes)(sqlite3*,int); int (*limit)(sqlite3*,int,int); sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); const char *(*sql)(sqlite3_stmt*); int (*status)(int,int*,int*,int); int (*backup_finish)(sqlite3_backup*); sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); int (*backup_pagecount)(sqlite3_backup*); int (*backup_remaining)(sqlite3_backup*); int (*backup_step)(sqlite3_backup*,int); const char *(*compileoption_get)(int); int (*compileoption_used)(const char*); int (*create_function_v2)(sqlite3*,const char*,int,int,void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*)); int (*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); int (*extended_errcode)(sqlite3*); void (*log)(int,const char*,...); sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); const char *(*sourceid)(void); int (*stmt_status)(sqlite3_stmt*,int,int); int (*strnicmp)(const char*,const char*,int); int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); int (*wal_autocheckpoint)(sqlite3*,int); int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); int (*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); const char *(*db_filename)(sqlite3*,const char*); int (*db_readonly)(sqlite3*,const char*); int (*db_release_memory)(sqlite3*); const char *(*errstr)(int); int (*stmt_busy)(sqlite3_stmt*); int (*stmt_readonly)(sqlite3_stmt*); int (*stricmp)(const char*,const char*); int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); char *(*vsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); /* Version 3.8.7 and later */ int (*auto_extension)(void(*)(void)); int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, void(*)(void*)); int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, void(*)(void*),unsigned char); int (*cancel_auto_extension)(void(*)(void)); int (*load_extension)(sqlite3*,const char*,const char*,char**); void *(*malloc64)(sqlite3_uint64); sqlite3_uint64 (*msize)(void*); void *(*realloc64)(void*,sqlite3_uint64); void (*reset_auto_extension)(void); void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, void(*)(void*)); void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, void(*)(void*), unsigned char); int (*strglob)(const char*,const char*); }; /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file ** (part of the main SQLite library - not an extension) so that ** it can get access to the sqlite3_api_routines structure ** definition. But the main library does not want to redefine ** the API. So the redefinition macros are only valid if the ** SQLITE_CORE macros is undefined. */ #ifndef SQLITE_CORE #define sqlite3_aggregate_context sqlite3_api->aggregate_context #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_aggregate_count sqlite3_api->aggregate_count #endif #define sqlite3_bind_blob sqlite3_api->bind_blob #define sqlite3_bind_double sqlite3_api->bind_double #define sqlite3_bind_int sqlite3_api->bind_int #define sqlite3_bind_int64 sqlite3_api->bind_int64 #define sqlite3_bind_null sqlite3_api->bind_null #define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count #define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index #define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name #define sqlite3_bind_text sqlite3_api->bind_text #define sqlite3_bind_text16 sqlite3_api->bind_text16 #define sqlite3_bind_value sqlite3_api->bind_value #define sqlite3_busy_handler sqlite3_api->busy_handler #define sqlite3_busy_timeout sqlite3_api->busy_timeout #define sqlite3_changes sqlite3_api->changes #define sqlite3_close sqlite3_api->close #define sqlite3_collation_needed sqlite3_api->collation_needed #define sqlite3_collation_needed16 sqlite3_api->collation_needed16 #define sqlite3_column_blob sqlite3_api->column_blob #define sqlite3_column_bytes sqlite3_api->column_bytes #define sqlite3_column_bytes16 sqlite3_api->column_bytes16 #define sqlite3_column_count sqlite3_api->column_count #define sqlite3_column_database_name sqlite3_api->column_database_name #define sqlite3_column_database_name16 sqlite3_api->column_database_name16 #define sqlite3_column_decltype sqlite3_api->column_decltype #define sqlite3_column_decltype16 sqlite3_api->column_decltype16 #define sqlite3_column_double sqlite3_api->column_double #define sqlite3_column_int sqlite3_api->column_int #define sqlite3_column_int64 sqlite3_api->column_int64 #define sqlite3_column_name sqlite3_api->column_name #define sqlite3_column_name16 sqlite3_api->column_name16 #define sqlite3_column_origin_name sqlite3_api->column_origin_name #define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 #define sqlite3_column_table_name sqlite3_api->column_table_name #define sqlite3_column_table_name16 sqlite3_api->column_table_name16 #define sqlite3_column_text sqlite3_api->column_text #define sqlite3_column_text16 sqlite3_api->column_text16 #define sqlite3_column_type sqlite3_api->column_type #define sqlite3_column_value sqlite3_api->column_value #define sqlite3_commit_hook sqlite3_api->commit_hook #define sqlite3_complete sqlite3_api->complete #define sqlite3_complete16 sqlite3_api->complete16 #define sqlite3_create_collation sqlite3_api->create_collation #define sqlite3_create_collation16 sqlite3_api->create_collation16 #define sqlite3_create_function sqlite3_api->create_function #define sqlite3_create_function16 sqlite3_api->create_function16 #define sqlite3_create_module sqlite3_api->create_module #define sqlite3_create_module_v2 sqlite3_api->create_module_v2 #define sqlite3_data_count sqlite3_api->data_count #define sqlite3_db_handle sqlite3_api->db_handle #define sqlite3_declare_vtab sqlite3_api->declare_vtab #define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache #define sqlite3_errcode sqlite3_api->errcode #define sqlite3_errmsg sqlite3_api->errmsg #define sqlite3_errmsg16 sqlite3_api->errmsg16 #define sqlite3_exec sqlite3_api->exec #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_expired sqlite3_api->expired #endif #define sqlite3_finalize sqlite3_api->finalize #define sqlite3_free sqlite3_api->free #define sqlite3_free_table sqlite3_api->free_table #define sqlite3_get_autocommit sqlite3_api->get_autocommit #define sqlite3_get_auxdata sqlite3_api->get_auxdata #define sqlite3_get_table sqlite3_api->get_table #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_global_recover sqlite3_api->global_recover #endif #define sqlite3_interrupt sqlite3_api->interruptx #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid #define sqlite3_libversion sqlite3_api->libversion #define sqlite3_libversion_number sqlite3_api->libversion_number #define sqlite3_malloc sqlite3_api->malloc #define sqlite3_mprintf sqlite3_api->mprintf #define sqlite3_open sqlite3_api->open #define sqlite3_open16 sqlite3_api->open16 #define sqlite3_prepare sqlite3_api->prepare #define sqlite3_prepare16 sqlite3_api->prepare16 #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_profile sqlite3_api->profile #define sqlite3_progress_handler sqlite3_api->progress_handler #define sqlite3_realloc sqlite3_api->realloc #define sqlite3_reset sqlite3_api->reset #define sqlite3_result_blob sqlite3_api->result_blob #define sqlite3_result_double sqlite3_api->result_double #define sqlite3_result_error sqlite3_api->result_error #define sqlite3_result_error16 sqlite3_api->result_error16 #define sqlite3_result_int sqlite3_api->result_int #define sqlite3_result_int64 sqlite3_api->result_int64 #define sqlite3_result_null sqlite3_api->result_null #define sqlite3_result_text sqlite3_api->result_text #define sqlite3_result_text16 sqlite3_api->result_text16 #define sqlite3_result_text16be sqlite3_api->result_text16be #define sqlite3_result_text16le sqlite3_api->result_text16le #define sqlite3_result_value sqlite3_api->result_value #define sqlite3_rollback_hook sqlite3_api->rollback_hook #define sqlite3_set_authorizer sqlite3_api->set_authorizer #define sqlite3_set_auxdata sqlite3_api->set_auxdata #define sqlite3_snprintf sqlite3_api->snprintf #define sqlite3_step sqlite3_api->step #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup #define sqlite3_total_changes sqlite3_api->total_changes #define sqlite3_trace sqlite3_api->trace #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings #endif #define sqlite3_update_hook sqlite3_api->update_hook #define sqlite3_user_data sqlite3_api->user_data #define sqlite3_value_blob sqlite3_api->value_blob #define sqlite3_value_bytes sqlite3_api->value_bytes #define sqlite3_value_bytes16 sqlite3_api->value_bytes16 #define sqlite3_value_double sqlite3_api->value_double #define sqlite3_value_int sqlite3_api->value_int #define sqlite3_value_int64 sqlite3_api->value_int64 #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type #define sqlite3_value_text sqlite3_api->value_text #define sqlite3_value_text16 sqlite3_api->value_text16 #define sqlite3_value_text16be sqlite3_api->value_text16be #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_clear_bindings sqlite3_api->clear_bindings #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob #define sqlite3_blob_bytes sqlite3_api->blob_bytes #define sqlite3_blob_close sqlite3_api->blob_close #define sqlite3_blob_open sqlite3_api->blob_open #define sqlite3_blob_read sqlite3_api->blob_read #define sqlite3_blob_write sqlite3_api->blob_write #define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 #define sqlite3_file_control sqlite3_api->file_control #define sqlite3_memory_highwater sqlite3_api->memory_highwater #define sqlite3_memory_used sqlite3_api->memory_used #define sqlite3_mutex_alloc sqlite3_api->mutex_alloc #define sqlite3_mutex_enter sqlite3_api->mutex_enter #define sqlite3_mutex_free sqlite3_api->mutex_free #define sqlite3_mutex_leave sqlite3_api->mutex_leave #define sqlite3_mutex_try sqlite3_api->mutex_try #define sqlite3_open_v2 sqlite3_api->open_v2 #define sqlite3_release_memory sqlite3_api->release_memory #define sqlite3_result_error_nomem sqlite3_api->result_error_nomem #define sqlite3_result_error_toobig sqlite3_api->result_error_toobig #define sqlite3_sleep sqlite3_api->sleep #define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit #define sqlite3_vfs_find sqlite3_api->vfs_find #define sqlite3_vfs_register sqlite3_api->vfs_register #define sqlite3_vfs_unregister sqlite3_api->vfs_unregister #define sqlite3_threadsafe sqlite3_api->xthreadsafe #define sqlite3_result_zeroblob sqlite3_api->result_zeroblob #define sqlite3_result_error_code sqlite3_api->result_error_code #define sqlite3_test_control sqlite3_api->test_control #define sqlite3_randomness sqlite3_api->randomness #define sqlite3_context_db_handle sqlite3_api->context_db_handle #define sqlite3_extended_result_codes sqlite3_api->extended_result_codes #define sqlite3_limit sqlite3_api->limit #define sqlite3_next_stmt sqlite3_api->next_stmt #define sqlite3_sql sqlite3_api->sql #define sqlite3_status sqlite3_api->status #define sqlite3_backup_finish sqlite3_api->backup_finish #define sqlite3_backup_init sqlite3_api->backup_init #define sqlite3_backup_pagecount sqlite3_api->backup_pagecount #define sqlite3_backup_remaining sqlite3_api->backup_remaining #define sqlite3_backup_step sqlite3_api->backup_step #define sqlite3_compileoption_get sqlite3_api->compileoption_get #define sqlite3_compileoption_used sqlite3_api->compileoption_used #define sqlite3_create_function_v2 sqlite3_api->create_function_v2 #define sqlite3_db_config sqlite3_api->db_config #define sqlite3_db_mutex sqlite3_api->db_mutex #define sqlite3_db_status sqlite3_api->db_status #define sqlite3_extended_errcode sqlite3_api->extended_errcode #define sqlite3_log sqlite3_api->log #define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 #define sqlite3_sourceid sqlite3_api->sourceid #define sqlite3_stmt_status sqlite3_api->stmt_status #define sqlite3_strnicmp sqlite3_api->strnicmp #define sqlite3_unlock_notify sqlite3_api->unlock_notify #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_blob_reopen sqlite3_api->blob_reopen #define sqlite3_vtab_config sqlite3_api->vtab_config #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict /* Version 3.7.16 and later */ #define sqlite3_close_v2 sqlite3_api->close_v2 #define sqlite3_db_filename sqlite3_api->db_filename #define sqlite3_db_readonly sqlite3_api->db_readonly #define sqlite3_db_release_memory sqlite3_api->db_release_memory #define sqlite3_errstr sqlite3_api->errstr #define sqlite3_stmt_busy sqlite3_api->stmt_busy #define sqlite3_stmt_readonly sqlite3_api->stmt_readonly #define sqlite3_stricmp sqlite3_api->stricmp #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 /* Version 3.8.7 and later */ #define sqlite3_auto_extension sqlite3_api->auto_extension #define sqlite3_bind_blob64 sqlite3_api->bind_blob64 #define sqlite3_bind_text64 sqlite3_api->bind_text64 #define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension #define sqlite3_load_extension sqlite3_api->load_extension #define sqlite3_malloc64 sqlite3_api->malloc64 #define sqlite3_msize sqlite3_api->msize #define sqlite3_realloc64 sqlite3_api->realloc64 #define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension #define sqlite3_result_blob64 sqlite3_api->result_blob64 #define sqlite3_result_text64 sqlite3_api->result_text64 #define sqlite3_strglob sqlite3_api->strglob #endif /* SQLITE_CORE */ #ifndef SQLITE_CORE /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; # define SQLITE_EXTENSION_INIT3 \ extern const sqlite3_api_routines *sqlite3_api; #else /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif #endif /* _SQLITE3EXT_H_ */ |