diff options
-rw-r--r-- | ext/misc/carray.c | 51 | ||||
-rw-r--r-- | manifest | 16 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/test1.c | 43 | ||||
-rw-r--r-- | test/carray01.test | 81 |
5 files changed, 145 insertions, 48 deletions
diff --git a/ext/misc/carray.c b/ext/misc/carray.c index b6eb0453a..709c894f2 100644 --- a/ext/misc/carray.c +++ b/ext/misc/carray.c @@ -28,7 +28,7 @@ ** ** There is an optional third parameter to determine the datatype of ** the C-language array. Allowed values of the third parameter are -** 'int32', 'int64', 'double', 'char*'. Example: +** 'int32', 'int64', 'double', 'char*', 'struct iovec'. Example: ** ** SELECT * FROM carray($ptr,10,'char*'); ** @@ -56,6 +56,14 @@ SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> +#ifdef _WIN32 + struct iovec { + void *iov_base; + size_t iov_len; + }; +#else +# include <sys/uio.h> +#endif /* Allowed values for the mFlags parameter to sqlite3_carray_bind(). ** Must exactly match the definitions in carray.h. @@ -65,6 +73,7 @@ SQLITE_EXTENSION_INIT1 # define CARRAY_INT64 1 /* Data is 64-bit signed integers */ # define CARRAY_DOUBLE 2 /* Data is doubles */ # define CARRAY_TEXT 3 /* Data is char* */ +# define CARRAY_BLOB 4 /* Data is struct iovec* */ #endif #ifndef SQLITE_API @@ -80,7 +89,8 @@ SQLITE_EXTENSION_INIT1 /* ** Names of allowed datatypes */ -static const char *azType[] = { "int32", "int64", "double", "char*" }; +static const char *azType[] = { "int32", "int64", "double", "char*", + "struct iovec" }; /* ** Structure used to hold the sqlite3_carray_bind() information @@ -224,6 +234,12 @@ static int carrayColumn( sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT); return SQLITE_OK; } + case CARRAY_BLOB: { + const struct iovec *p = (struct iovec*)pCur->pPtr; + sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base, + (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT); + return SQLITE_OK; + } } } } @@ -268,7 +284,7 @@ static int carrayFilter( if( pBind==0 ) break; pCur->pPtr = pBind->aData; pCur->iCnt = pBind->nData; - pCur->eType = pBind->mFlags & 0x03; + pCur->eType = pBind->mFlags & 0x07; break; } case 2: @@ -431,24 +447,29 @@ SQLITE_API int sqlite3_carray_bind( pNew->mFlags = mFlags; if( xDestroy==SQLITE_TRANSIENT ){ sqlite3_int64 sz = nData; - switch( mFlags & 0x03 ){ - case CARRAY_INT32: sz *= 4; break; - case CARRAY_INT64: sz *= 8; break; - case CARRAY_DOUBLE: sz *= 8; break; - case CARRAY_TEXT: sz *= sizeof(char*); break; + switch( mFlags & 0x07 ){ + case CARRAY_INT32: sz *= 4; break; + case CARRAY_INT64: sz *= 8; break; + case CARRAY_DOUBLE: sz *= 8; break; + case CARRAY_TEXT: sz *= sizeof(char*); break; + case CARRAY_BLOB: sz *= sizeof(struct iovec); break; } - if( (mFlags & 0x03)==CARRAY_TEXT ){ + if( (mFlags & 0x07)==CARRAY_TEXT ){ for(i=0; i<nData; i++){ const char *z = ((char**)aData)[i]; if( z ) sz += strlen(z) + 1; } + }else if( (mFlags & 0x07)==CARRAY_BLOB ){ + for(i=0; i<nData; i++){ + sz += ((struct iovec*)aData)[i].iov_len; + } } pNew->aData = sqlite3_malloc64( sz ); if( pNew->aData==0 ){ sqlite3_free(pNew); return SQLITE_NOMEM; } - if( (mFlags & 0x03)==CARRAY_TEXT ){ + if( (mFlags & 0x07)==CARRAY_TEXT ){ char **az = (char**)pNew->aData; char *z = (char*)&az[nData]; for(i=0; i<nData; i++){ @@ -463,6 +484,16 @@ SQLITE_API int sqlite3_carray_bind( memcpy(z, zData, n+1); z += n+1; } + }else if( (mFlags & 0x07)==CARRAY_BLOB ){ + struct iovec *p = (struct iovec*)pNew->aData; + unsigned char *z = (unsigned char*)&p[nData]; + for(i=0; i<nData; i++){ + size_t n = ((struct iovec*)aData)[i].iov_len; + p[i].iov_len = n; + p[i].iov_base = z; + z += n; + memcpy(p[i].iov_base, ((struct iovec*)aData)[i].iov_base, n); + } }else{ memcpy(pNew->aData, aData, sz); } @@ -1,5 +1,5 @@ -C Two\sbranches\sassociated\swith\smemdb\sare\snow\salways\staken\s(I\sbelieve).\s\sTag\nthem\swith\sALWAYS()\sto\sverify\sthis. -D 2023-01-20T19:19:24.597 +C Extend\sthe\scarray\sextension\sto\sallow\sthe\suse\sof\sBLOB\svalues\sto\sbe\sbound\nas\san\sarray\sof\s"struct\siovec"\sobjects. +D 2023-01-20T21:00:03.027 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -268,7 +268,7 @@ F ext/misc/base85.c 4b53d66c50e120e8697dd2a8ea6ddbc8750a4a1f6bcc6e0b7202a3998b08 F ext/misc/basexx.c 5e859e1820620aa8080fb9145eb47089de426ae808f6abb01a8e12921c3a8e67 F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9 -F ext/misc/carray.c b752f46411e4e47e34dce6f0c88bc8e51bb821ba9e49bfcd882506451c928f69 +F ext/misc/carray.c 0ba03f1e6647785d4e05b51be567f5652f06941314ff9d3d3763900aa353b6b5 F ext/misc/carray.h d2b1b12486d531367c37832d3d0dad34eea4bdd83ed839d445521ef01f0bc4e3 F ext/misc/cksumvfs.c 9224e33cc0cb6aa61ff1d7d7b8fd6fe56beca9f9c47954fa4ae0a69bef608f69 F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243 @@ -630,7 +630,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/tclsqlite.c 8522a04fb9c84faa1d80354430ae0ee9349727a3a4b32e3cfe39b9be8324cabd -F src/test1.c 39c13c25f5c4e75a07cb6bd34cfc1b8aa97ecc6f80f08953fa164db7e92ce71e +F src/test1.c 06645f545329458c8c445c125d8af4fe066ffd5f16df596dd26ca5319d18c288 F src/test2.c 827446e259a3b7ab949da1542953edda7b5117982576d3e6f1c24a0dd20a5cef F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664 @@ -838,7 +838,7 @@ F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test 31d3a6778f2d06f2d9222bd7660c41a516d1518a059b069e96ebbeadb5a490f7 F test/capi3d.test 8b778794af891b0dca3d900bd345fbc8ebd2aa2aae425a9dccdd10d5233dfbde F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe -F test/carray01.test d55d57bf66b1af1c7ac55fae66ff4910884a8f5d21a90a18797ce386212a2634 +F test/carray01.test 23ed7074307c4a829ba5ff2970993a9d87db7c5cdbbe1a2cbef672d0df6d6e31 F test/cast.test e3a7e452f37efec0df0a89e55aa2f04861ba6613deb16075101414668bf4bb24 F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef F test/changes.test 9dd8e597d84072122fc8a4fcdea837f4a54a461e6e536053ea984303e8ca937b @@ -2043,8 +2043,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a02da71f3a80dd8e817e89cdaa775c95e38c90d2471f8fec516bed086539e2c0 -R bf07522ded69fabebaa5b325f6b73b2b +P 20b9b5aa4fa6136059cf1123f00d86cb7bd8fb0f0f86f971e9714f22725e60b5 +R b63d4e1bb53a7ee90a20a60e3fcee608 U drh -Z e4cafc4e045b3b49d125bdbd66067c68 +Z 70e393e1d3aa605a996a878e1787d9d5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 077c1fe31..4eb51b78b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -20b9b5aa4fa6136059cf1123f00d86cb7bd8fb0f0f86f971e9714f22725e60b5
\ No newline at end of file +e117a03ca6560e958884f277db827c51ae337a970c17143a0a5f9b150f52f87a
\ No newline at end of file diff --git a/src/test1.c b/src/test1.c index dda77a90a..2f384a2c0 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4137,6 +4137,14 @@ static int SQLITE_TCLAPI test_bind_value_from_select( return TCL_OK; } +#ifdef _WIN32 + struct iovec { + void *iov_base; + size_t iov_len; + }; +#else +# include <sys/uio.h> +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* @@ -4149,6 +4157,7 @@ static int SQLITE_TCLAPI test_bind_value_from_select( ** -int64 ** -double ** -text +** -blob ** ** Each call clears static data. Called with no options does nothing ** but clear static data. @@ -4188,6 +4197,11 @@ static int SQLITE_TCLAPI test_carray_bind( sqlite3_free(((char**)aStaticData)[i]); } } + if( eStaticType==4 ){ + for(i=0; i<nStaticData; i++){ + sqlite3_free(((struct iovec*)aStaticData)[i].iov_base); + } + } sqlite3_free(aStaticData); aStaticData = 0; nStaticData = 0; @@ -4217,6 +4231,9 @@ static int SQLITE_TCLAPI test_carray_bind( if( strcmp(z, "-text")==0 ){ eType = 3; /* CARRAY_TEXT */ }else + if( strcmp(z, "-blob")==0 ){ + eType = 4; /* CARRAY_BLOB */ + }else if( strcmp(z, "--")==0 ){ break; }else @@ -4230,6 +4247,11 @@ static int SQLITE_TCLAPI test_carray_bind( (char*)0); return TCL_ERROR; } + if( eType==4 && !isStatic && !isTransient ){ + Tcl_AppendResult(interp, "blob data must be either -static or -transient", + (char*)0); + return TCL_ERROR; + } if( isStatic && isTransient ){ Tcl_AppendResult(interp, "cannot be both -static and -transient", (char*)0); @@ -4244,7 +4266,7 @@ static int SQLITE_TCLAPI test_carray_bind( if( Tcl_GetIntFromObj(interp, objv[i], &idx) ) return TCL_ERROR; i++; nData = objc - i; - switch( eType + 4*(nData<=0) ){ + switch( eType + 5*(nData<=0) ){ case 0: { /* INT32 */ int *a = sqlite3_malloc( sizeof(int)*nData ); if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; } @@ -4297,7 +4319,24 @@ static int SQLITE_TCLAPI test_carray_bind( aData = a; break; } - case 4: { /* nData==0 */ + case 4: { /* BLOB */ + struct iovec *a = sqlite3_malloc( sizeof(struct iovec)*nData ); + if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; } + for(j=0; j<nData; j++){ + int n = 0; + unsigned char *v = Tcl_GetByteArrayFromObj(objv[i+i], &n); + a[j].iov_len = n; + a[j].iov_base = sqlite3_malloc64( n ); + if( a[j].iov_base==0 ){ + a[j].iov_len = 0; + }else{ + memcpy(a[j].iov_base, v, n); + } + } + aData = a; + break; + } + case 5: { /* nData==0 */ aData = ""; xDel = SQLITE_STATIC; isTransient = 0; diff --git a/test/carray01.test b/test/carray01.test index d6243eb27..1af9cb66e 100644 --- a/test/carray01.test +++ b/test/carray01.test @@ -23,110 +23,137 @@ ifcapable !vtab { load_static_extension db carray # Parameter $stmt must be a prepared statement created using -# the sqlite3_prepare_v2 command and with parameters fullly bound. +# the sqlite3_prepare_v2 command and with parameters fully bound. # This routine simply runs the statement, gathers the result, and # returns a list containing the result. # # If the optional second argument is true, then the stmt is finalized # after it is run. # -proc run_stmt {stmt {finalizeFlag 0}} { +proc run_stmt {stmt} { set r {} while {[sqlite3_step $stmt]=="SQLITE_ROW"} { for {set i 0} {$i<[sqlite3_data_count $stmt]} {incr i} { lappend r [sqlite3_column_text $stmt $i] } } - if {$finalizeFlag} { - sqlite3_finalize $stmt - } else { - sqlite3_reset $stmt - } + sqlite3_reset $stmt return $r } do_test 100 { set STMT [sqlite3_prepare_v2 db {SELECT 5 IN carray(?3)} -1] sqlite3_carray_bind $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 101 { sqlite3_carray_bind -static $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} +do_test 102 { + set STMT2 [sqlite3_prepare_v2 db { + SELECT DISTINCT typeof(value) FROM carray(?3)} -1] + sqlite3_carray_bind $STMT2 3 1 2 3 4 5 6 7 + run_stmt $STMT2 +} {integer} do_test 110 { sqlite3_carray_bind $STMT 3 1 2 3 4 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} do_test 120 { sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} +do_test 120b { + sqlite3_carray_bind -int64 $STMT2 3 1 2 3 4 5 6 7 + run_stmt $STMT2 +} {integer} do_test 121 { sqlite3_carray_bind -int64 -transient $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 122 { sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 123 { sqlite3_carray_bind -int32 -transient $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 124 { sqlite3_carray_bind -int32 -static $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 125 { sqlite3_carray_bind -int32 $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 130 { sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} do_test 131 { sqlite3_carray_bind -int64 -transient $STMT 3 1 2 3 4 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} do_test 131 { sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} do_test 140 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 141 { sqlite3_carray_bind -double -transient $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 142 { sqlite3_carray_bind -double -static $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} +do_test 143 { + sqlite3_carray_bind -double $STMT2 3 1 2 3 4 5 6 7 + run_stmt $STMT2 +} {real} do_test 150 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} do_test 160 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {1} do_test 170 { sqlite3_carray_bind -text -static $STMT 3 1 2 3 4 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} +do_test 171 { + sqlite3_carray_bind -text -static $STMT2 3 1 2 3 4 6 7 + run_stmt $STMT2 +} {text} do_test 180 { sqlite3_carray_bind -text -transient $STMT 3 1 2 3 4 5 6 7 - run_stmt $STMT 0 + run_stmt $STMT } {0} do_test 190 { + sqlite3_carray_bind -blob -static $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT +} {0} +do_test 191 { + sqlite3_carray_bind -blob -static $STMT2 3 1 2 3 4 5 6 7 + run_stmt $STMT2 +} {blob} +do_test 200 { + sqlite3_carray_bind -blob -transient $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT +} {0} +do_test 300 { sqlite3_carray_bind $STMT 3 - run_stmt $STMT 0 + run_stmt $STMT } {0} sqlite3_finalize $STMT +sqlite3_finalize $STMT2 finish_test |