From: numist Date: Fri, 13 Dec 2019 22:59:38 +0000 (+0000) Subject: Initial exploration of blocky APIs, starting with a variant of sqlite3_exec. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fblocky-exec;p=thirdparty%2Fsqlite.git Initial exploration of blocky APIs, starting with a variant of sqlite3_exec. FossilOrigin-Name: fd849d5b6a891c57facbfbba1de855b4349577dbc7afaa7f503e23bc4ca74e8f --- diff --git a/manifest b/manifest index 786d389eeb..aa8a0c6e9d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Patch\sto\sthe\spage\scache\sto\savoid\sharmless\spointer\sarithmetic\sthat\sdue\sto\sbugs\nin\sthe\sSTD-C\sspec\sis\stechnically\sUB.\s\sThis\sis\sto\sfix\sa\sharmless\sUBSAN\ncomplaint\sthat\sOSSFuzz\sis\shitting. -D 2019-12-13T21:24:46.081 +C Initial\sexploration\sof\sblocky\sAPIs,\sstarting\swith\sa\svariant\sof\ssqlite3_exec. +D 2019-12-13T22:59:38.851 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -489,7 +489,7 @@ F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 5de3fd62bd1a692353c8f9c7bbde658f0b579f195620ca3cde1948a53015dddd -F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa +F src/legacy.c 70ff0890930967fa02a792d3b2c48208eb6a1c4d9f55a465a664b2ddc8b044a4 F src/loadext.c d74f5e7bd51f3c9d283442473eb65aef359664efd6513591c03f01881c4ae2da F src/main.c 868ae7db7a54fe859bf2ca8b7a4f24e9fa03a6134abfb7c9801d08411ef5dacb F src/malloc.c 550021fcae36f0ffe9f8563d83e6385f9df307a854d55d7d0abb7241ee8dbcc6 @@ -529,10 +529,10 @@ F src/resolve.c 86a7773d2892227ba9ad1721c41bb03c501830f1bf6de5f78dd0062b82e10c9d F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 0fe10579de20eb8dc04ec9ed29659fa782bee2bcc85a35734637f3e2cabc2762 F src/shell.c.in 4a3a9e1c11847b1904f2b01d087af1c052f660902755abab457cab1756817ded -F src/sqlite.h.in 2a23e8161775253d9cf383c2c6aa559005dc787d350dcb0be67a6c4cc3bd1d19 +F src/sqlite.h.in 44a53119d3fb6e2d855d8bfd4b94151338563a2fbe28638e3a24ee8d9e661ae1 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 72af51aa4e912e14cd495fb6e7fac65f0940db80ed950d90911aff292cc47ce2 -F src/sqliteInt.h 60d92fad64da7c3e77bbc35ee306340814cdaa5df32892b0ec58d306d99b5733 +F src/sqliteInt.h 6326f05f5924e779f5c3ba422f85adfdef38dbf1012be7d5e40a2d78d4d1a648 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1852,7 +1852,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c1014e80b26131200a115beb86929a8f0ded2dd65b075e47373346c0f170576a -R b59b4afd4c4fcaeb80758977b1b63c0a -U drh -Z 4fa57844859159ee82f87f0f14b6814f +P c29fc21288e37f81a1617c5e2961c575d3bca6a1d1b013b2e0a99774afb1dcdb +R e55adf2fcddc384393004665528a6995 +T *branch * blocky-exec +T *sym-blocky-exec * +T -sym-trunk * +U numist +Z 7fe9b43d252eee701000e10996724092 diff --git a/manifest.uuid b/manifest.uuid index ab11a63e58..e930527d01 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c29fc21288e37f81a1617c5e2961c575d3bca6a1d1b013b2e0a99774afb1dcdb \ No newline at end of file +fd849d5b6a891c57facbfbba1de855b4349577dbc7afaa7f503e23bc4ca74e8f \ No newline at end of file diff --git a/src/legacy.c b/src/legacy.c index 867587e5a2..f412e7c70d 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -139,3 +139,81 @@ exec_out: sqlite3_mutex_leave(db->mutex); return rc; } + +#if SQLITE_HAS_BLOCKS +int sqlite3_exec_b( + sqlite3 *db, + const char *zSql, + int (^xCallback)(sqlite3_stmt *) +){ + int rc = SQLITE_OK; /* Return code */ + const char *zLeftover; /* Tail of unprocessed SQL */ + sqlite3_stmt *pStmt = 0; /* The current SQL statement */ + const char **azCols = 0; /* Names of result columns */ + + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; + if( zSql==0 ) zSql = ""; +#ifdef SQLITE_ENABLE_SQLRR + SRRecExec(db, zSql); +#endif + sqlite3_mutex_enter(db->mutex); + sqlite3Error(db, SQLITE_OK); + while( rc==SQLITE_OK && zSql[0] ){ + int callbackIsInit = 0; + + pStmt = 0; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); + assert( rc==SQLITE_OK || pStmt==0 ); + if( rc!=SQLITE_OK ){ + continue; + } + if( !pStmt ){ + /* this happens for a comment or white-space */ + zSql = zLeftover; + continue; + } + + while( 1 ){ + rc = sqlite3_step(pStmt); + + /* Invoke the callback function if required */ + if( xCallback && (SQLITE_ROW==rc || + (SQLITE_DONE==rc && !callbackIsInit + && db->flags&SQLITE_NullCallback)) ){ + if( xCallback(pStmt) ){ + /* EVIDENCE-OF: R-38229-40159 If the callback function to + ** sqlite3_exec() returns non-zero, then sqlite3_exec() will + ** return SQLITE_ABORT. */ + rc = SQLITE_ABORT; + (void)sqlite3VdbeFinalize((Vdbe *)pStmt); + pStmt = 0; + sqlite3Error(db, rc); + goto exec_out; + } + } + + if( rc!=SQLITE_ROW ){ + rc = sqlite3VdbeFinalize((Vdbe *)pStmt); + pStmt = 0; + zSql = zLeftover; + while( sqlite3Isspace(zSql[0]) ) zSql++; + break; + } + } + } + +exec_out: + if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt); + sqlite3DbFree(db, azCols); +#ifdef SQLITE_ENABLE_SQLRR + SRRecExecEnd(db); +#endif + + rc = sqlite3ApiExit(db, rc); + + assert( (rc&db->errMask)==rc ); + sqlite3_mutex_leave(db->mutex); + return rc; + +} +#endif diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 944b5be3e5..496f08e4e5 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -34,6 +34,15 @@ #define SQLITE3_H #include /* Needed for the definition of va_list */ +/* Compatibility with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif +/* Compatibility with pre-3.0 versions of clang */ +#ifndef __has_extension +# define __has_extension __has_feature +#endif + /* ** Make sure we can call this stuff from C++. */ @@ -66,6 +75,13 @@ extern "C" { #ifndef SQLITE_SYSAPI # define SQLITE_SYSAPI #endif +#ifndef SQLITE_NOESCAPE +# if __has_feature(noescape) +# define SQLITE_NOESCAPE __attribute__((noescape)) +# else +# define SQLITE_NOESCAPE +# endif +#endif /* ** These no-op macros are used in front of interfaces to mark those @@ -345,21 +361,20 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** CAPI3REF: One-Step Query Execution Interface ** METHOD: sqlite3 ** -** The sqlite3_exec() interface is a convenience wrapper around -** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], +** The sqlite3_exec() and sqlite3_exec_b() interfaces are convenience wrappers +** around [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL ** without having to use a lot of C code. ** -** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, -** semicolon-separate SQL statements passed into its 2nd argument, -** in the context of the [database connection] passed in as its 1st -** argument. ^If the callback function of the 3rd argument to -** sqlite3_exec() is not NULL, then it is invoked for each result row +** ^The sqlite3_exec() and sqlite3_exec_b() interfaces run zero or more UTF-8 +** encoded, semicolon-separate SQL statements passed into their 2nd argument, +** in the context of the [database connection] passed in to their 1st +** argument. ^If the callback function of the 3rd argument to sqlite3_exec() +** or sqlite3_exec_b() is not NULL, then it is invoked for each result row ** coming out of the evaluated SQL statements. ^The 4th argument to -** sqlite3_exec() is relayed through to the 1st argument of each -** callback invocation. ^If the callback pointer to sqlite3_exec() -** is NULL, then no callback is ever invoked and result rows are -** ignored. +** sqlite3_exec() is relayed through to the 1st argument of each callback +** invocation. ^If the callback pointer to sqlite3_exec() or sqlite3_exec_b() +** is NULL, then no callback is ever invoked and result rows are ignored. ** ** ^If an error occurs while evaluating the SQL statements passed into ** sqlite3_exec(), then execution of the current statement stops and @@ -373,7 +388,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to ** NULL before returning. ** -** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() +** ^If an sqlite3_exec() or sqlite3_exec_b() callback returns non-zero, the ** routine returns SQLITE_ABORT without invoking the callback again and ** without running any subsequent SQL statements. ** @@ -387,20 +402,26 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** entry represents the name of corresponding result column as obtained ** from [sqlite3_column_name()]. ** -** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer -** to an empty string, or a pointer that contains only whitespace and/or -** SQL comments, then no SQL statements are evaluated and the database -** is not changed. +** ^The 1st argument to the sqlite3_exec_b() callback block is a prepared +** statement object stopped at the current result row. The +** [column access functions] may be used to extract the row's values. +** +** ^If the 2nd parameter to sqlite3_exec() or sqlite3_exec_b() is a NULL +** pointer, a pointer to an empty string, or a pointer that contains only +** whitespace and/or SQL comments, then no SQL statements are evaluated and +** the database is not changed. ** ** Restrictions: ** ** */ int sqlite3_exec( @@ -410,6 +431,13 @@ int sqlite3_exec( void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ ); +#if __has_extension(blocks) +int sqlite3_exec_b( + sqlite3*, /* An open database */ + const char *sql, /* SQL to be evaluated */ + SQLITE_NOESCAPE int (^callback)(sqlite3_stmt*) /* Callback block */ +); +#endif /* ** CAPI3REF: Result Codes diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4b4a9068cc..7f8672b2d9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -166,6 +166,17 @@ */ #include "sqlite3.h" +/* +** SQLITE_HAS_BLOCKS controls block API availability +*/ +#ifndef SQLITE_HAS_BLOCKS +# if __has_extension(blocks) +# define SQLITE_HAS_BLOCKS 1 +# else +# define SQLITE_HAS_BLOCKS 0 +# endif +#endif + /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build