sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
return SQLITE_OK;
}
- case CARRAY_BLOB: {
+ default: {
const struct iovec *p = (struct iovec*)pCur->pPtr;
+ assert( pCur->eType==CARRAY_BLOB );
sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base,
- (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT);
+ (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT);
return SQLITE_OK;
}
}
int mFlags,
void (*xDestroy)(void*)
){
- carray_bind *pNew;
+ carray_bind *pNew = 0;
int i;
+ int rc = SQLITE_OK;
+
+ /* Ensure that the mFlags value is acceptable. */
+ assert( CARRAY_INT32==0 && CARRAY_INT64==1 && CARRAY_DOUBLE==2 );
+ assert( CARRAY_TEXT==3 && CARRAY_BLOB==4 );
+ if( mFlags<CARRAY_INT32 || mFlags>CARRAY_BLOB ){
+ rc = SQLITE_ERROR;
+ goto carray_bind_error;
+ }
+
pNew = sqlite3_malloc64(sizeof(*pNew));
if( pNew==0 ){
- if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
- xDestroy(aData);
- }
- return SQLITE_NOMEM;
+ rc = SQLITE_NOMEM;
+ goto carray_bind_error;
}
+
pNew->nData = nData;
pNew->mFlags = mFlags;
if( xDestroy==SQLITE_TRANSIENT ){
sqlite3_int64 sz = nData;
- switch( mFlags & 0x07 ){
+ switch( mFlags ){
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;
+ default: sz *= sizeof(struct iovec); break;
}
- if( (mFlags & 0x07)==CARRAY_TEXT ){
+ if( mFlags==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 ){
+ }else if( mFlags==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;
+ rc = SQLITE_NOMEM;
+ goto carray_bind_error;
}
- if( (mFlags & 0x07)==CARRAY_TEXT ){
+
+ if( mFlags==CARRAY_TEXT ){
char **az = (char**)pNew->aData;
char *z = (char*)&az[nData];
for(i=0; i<nData; i++){
memcpy(z, zData, n+1);
z += n+1;
}
- }else if( (mFlags & 0x07)==CARRAY_BLOB ){
+ }else if( mFlags==CARRAY_BLOB ){
struct iovec *p = (struct iovec*)pNew->aData;
unsigned char *z = (unsigned char*)&p[nData];
for(i=0; i<nData; i++){
pNew->xDel = xDestroy;
}
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
+
+ carray_bind_error:
+ if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
+ xDestroy(aData);
+ }
+ sqlite3_free(pNew);
+ return rc;
}
-C Improve\sthe\sinvariant\schecker\smodule\sso\sthat\sso\sthat\sit\sadded\s"+"\sbefore\n"column\sISNULL"\sin\squeries\swhere\sthe\sbase\squery\scontains\sa\sGROUP\sBY,\sto\nprevent\sthe\sISNULL\sterm\sfrom\sbeing\spushed\sdown\sinto\sthe\ssubquery,\ssince\nthat\scan\scause\sambiguities\sif\scolumn\sis\sUNIQUE.
-D 2025-10-07T18:06:05.110
+C Add\stest\scases\sfor\sthe\scarray\smodule.
+D 2025-10-07T21:02:37.621
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
F ext/misc/btreeinfo.c 8f5e6da2c82ec2f06ee0216e922370a436dafdbb06ffa7a552203515ff9e7ddf
-F ext/misc/carray.c 6fd2be4dfa3e9ecf227221d92d808454e18710c123034fbb74999f6625f9143f
+F ext/misc/carray.c 9f7f838b3343660256c519f05aae05303d54a62770f64e8e4bbad255d5c78c94
F ext/misc/carray.h 4bef8af4e9ddda024f5540cc4d456c3e4a4a7624d6315edf85dce1ce8419beb8
F ext/misc/cksumvfs.c 9d7d0cf1a8893ac5d48922bfe9f3f217b4a61a6265f559263a02bb2001259913
F ext/misc/closure.c 5559daf1daf742228431db929d1aa86dd535a4224cc634a81d2fd0d1e6ad7839
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 3c604c49e6cf4211960a9ddb9505280fd22cde32175f40884c641c0f5a286036
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
-F src/test1.c 82d8aab7162a758d030728cab6ae6011785234854b7d6d2aebd877f985d1016a
+F src/test1.c ce9ccd92d48e4980ebd1924be3131739cfa70ac535059474155b596cdb4a529e
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
F src/test3.c 432646f581d8af1bb495e58fc98234380250954f5d5535e507fc785eccc3987a
F src/test4.c 0ac87fc13cdb334ab3a71823f99b6c32a6bebe5d603cd6a71d84c823d43a25a0
F test/capi3d.test 8b778794af891b0dca3d900bd345fbc8ebd2aa2aae425a9dccdd10d5233dfbde
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
F test/carray01.test 23ed7074307c4a829ba5ff2970993a9d87db7c5cdbbe1a2cbef672d0df6d6e31
+F test/carray02.test 6df8d1bf95f7c5f41f80b81e47f14332222ac820cf3de50af10ec2fb989a903c
+F test/carrayfault.test 52ef4956acbcb7b34eb177167e7af2b5ac8d9cbb80213ef4a3a9d7efb1a1f4be
F test/cast.test a2a3b32df86e3c0601ffa2e9f028a18796305d251801efea807092dbf374a040
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
F test/changes.test 4377d202a487f66fc2822c1bf57c46798c8b2caf7446f4f701723b1dbb6b86f6
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 06b4bd2aba22c57f5a5fed606c3bee225dee6fdc13bb16cc58194040ef0d7d85
-R 453915b0b72d47b5291d37cc0a19ae2f
-U drh
-Z 1eb68a79b24ce28ad8c3cdcce7ce295e
+P b4ff920fbeef9a8590219596d73c09976da3da53c08a685be56f6b2cd2cdc70c
+R 1dda2a73403b3668fbe9a0e2c83e251e
+U dan
+Z 20b6eca0d0874b62c280c82aff95f36b
# Remove this line to create a well-formed Fossil manifest.
-b4ff920fbeef9a8590219596d73c09976da3da53c08a685be56f6b2cd2cdc70c
+dcfc0164a95eddb5e924c606850fe2015e8f2f516d36b380cbb79d6bdfe034fc
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** These two are used by the -malloc option to sqlite3_carray_bind()
+*/
+static void *testCarrayAlloc(int n){
+ u8 *pRet = (u8*)sqlite3_malloc(n+16);
+ if( pRet ){
+ pRet = &pRet[16];
+ }
+ return (void*)pRet;
+}
+static void testCarrayFree(void *p){
+ if( p ){
+ u8 *p2 = (u8*)p;
+ sqlite3_free(&p2[-16]);
+ }
+}
+
+static void delIntptr(void *p){
+ ckfree(p);
+}
+
+/*
+** bind_carray_intptr STMT IPARAM INT0 INT1 INT2...
+*/
+static int SQLITE_TCLAPI bind_carray_intptr(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_stmt *pStmt = 0;
+ int iVar = 0;
+ int *aInt = 0;
+ int nInt = 0;
+ int ii = 0;
+ int rc = SQLITE_OK;
+
+ if( objc<3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "STMT");
+ return TCL_ERROR;
+ }
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iVar) ) return TCL_ERROR;
+ nInt = objc - 3;
+
+ aInt = ckalloc((nInt+1) * sizeof(int));
+ for(ii=0; ii<nInt; ii++){
+ if( Tcl_GetIntFromObj(interp, objv[3+ii], &aInt[ii]) ){
+ ckfree(aInt);
+ return TCL_ERROR;
+ }
+ }
+
+ rc = sqlite3_bind_pointer(pStmt, iVar, (void*)aInt, "carray", delIntptr);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
+
+ return TCL_OK;
+}
+
/*
** sqlite3_carray_bind [options...] STMT NAME VALUE ...
**
** Options:
+** -malloc
** -transient
** -static
** -int32
){
sqlite3_stmt *pStmt;
int eType = 0; /* CARRAY_INT32 */
+ int mFlagsOverride = 0;
int nData = 0;
void *aData = 0;
int isTransient = 0;
int isStatic = 0;
+ int isMalloc = 0; /* True to use custom xDel function */
int idx;
int i, j;
int rc;
isStatic = 1;
xDel = SQLITE_STATIC;
}else
+ if( strcmp(z, "-malloc")==0 ){
+ isMalloc = 1;
+ xDel = testCarrayFree;
+ }else
if( strcmp(z, "-int32")==0 ){
eType = 0; /* CARRAY_INT32 */
}else
if( strcmp(z, "-blob")==0 ){
eType = 4; /* CARRAY_BLOB */
}else
+ if( i<(objc-1) && strcmp(z, "-flags")==0 ){
+ i++;
+ if( Tcl_GetIntFromObj(interp, objv[i], &mFlagsOverride) ){
+ return TCL_ERROR;
+ }
+ }else
if( strcmp(z, "--")==0 ){
break;
}else
}
case 3: { /* TEXT */
char **a = sqlite3_malloc( sizeof(char*)*nData );
- if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
- for(j=0; j<nData; j++){
+ if( a==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(a, 0, sizeof(char*)*nData);
+ }
+ for(j=0; rc==SQLITE_OK && j<nData; j++){
const char *v = Tcl_GetString(objv[i+j]);
- a[j] = sqlite3_mprintf("%s", v);
+ if( v && strcmp(v, "NULL") ){
+ a[j] = sqlite3_mprintf("%s", v);
+ if( a[j]==0 ) rc = SQLITE_NOMEM;
+ }
}
aData = a;
break;
}
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++){
+ if( a==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(a, 0, sizeof(struct iovec)*nData);
+ }
+ for(j=0; rc==SQLITE_OK && j<nData; j++){
Tcl_Size n = 0;
unsigned char *v = Tcl_GetByteArrayFromObj(objv[i+i], &n);
a[j].iov_len = (size_t)n;
a[j].iov_base = sqlite3_malloc64( n );
if( a[j].iov_base==0 ){
a[j].iov_len = 0;
+ rc = SQLITE_NOMEM;
}else{
memcpy(a[j].iov_base, v, n);
}
break;
}
}
- if( isStatic ){
- aStaticData = aData;
- nStaticData = nData;
- eStaticType = eType;
+
+ if( rc==SQLITE_OK ){
+ if( isStatic ){
+ aStaticData = aData;
+ nStaticData = nData;
+ eStaticType = eType;
+ }
+ else if( isMalloc ){
+ int nByte = ((eType==0) ? sizeof(int) : sizeof(i64)) * nData;
+ void *aByte = testCarrayAlloc(nByte);
+ if( aByte==0 ){
+ sqlite3_free(aData);
+ rc = SQLITE_NOMEM;
+ }else{
+ memcpy(aByte, aData, nByte);
+ sqlite3_free(aData);
+ aData = aByte;
+ xDel = testCarrayFree;
+ }
+ assert( eType==0 || eType==1 || eType==2 );
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ if( mFlagsOverride==0 ) mFlagsOverride = eType;
+ rc = sqlite3_carray_bind(pStmt, idx, aData, nData, mFlagsOverride, xDel);
}
- rc = sqlite3_carray_bind(pStmt, idx, aData, nData, eType, xDel);
if( isTransient ){
- if( eType==3 ){
+ if( eType==3 && aData ){
for(i=0; i<nData; i++) sqlite3_free(((char**)aData)[i]);
}
- if( eType==4 ){
+ if( eType==4 && aData ){
for(i=0; i<nData; i++) sqlite3_free(((struct iovec*)aData)[i].iov_base);
}
sqlite3_free(aData);
{ "sqlite3_bind_value_from_preupdate",test_bind_value_from_preupdate ,0 },
#ifndef SQLITE_OMIT_VIRTUALTABLE
{ "sqlite3_carray_bind", test_carray_bind ,0 },
+ { "bind_carray_intptr", bind_carray_intptr ,0 },
#endif
{ "sqlite3_bind_parameter_count", test_bind_parameter_count, 0},
{ "sqlite3_bind_parameter_name", test_bind_parameter_name, 0},
--- /dev/null
+# 2025-10-07
+#
+# 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 file implements tests for CARRAY extension
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix carray02
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+load_static_extension db carray
+
+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]
+ }
+ }
+ sqlite3_reset $stmt
+ return $r
+}
+
+# Bind some text values using sqlite3_carray_bind(). Including a NULL pointer.
+#
+set STMT [
+ sqlite3_prepare_v2 db "SELECT value, value IS NULL FROM carray(?)" -1 TAIL
+]
+do_test 1.0 {
+ sqlite3_carray_bind -transient -text $STMT 1 "abc" NULL "def"
+ run_stmt $STMT
+} {abc 0 {} 1 def 0}
+sqlite3_finalize $STMT
+
+# Pass bad values as the "flags" parameter to sqlite3_carray_bind().
+#
+set STMT [sqlite3_prepare_v2 db "SELECT value FROM carray(?)" -1 TAIL]
+do_test 2.0 {
+ list [catch {sqlite3_carray_bind -flags 5 -int32 $STMT 1 1 2 3 4} msg] $msg
+} {1 {SQL logic error}}
+do_test 2.1 {
+ list [catch {sqlite3_carray_bind -flags -1 -int32 $STMT 1 1 2 3 4} msg] $msg
+} {1 {SQL logic error}}
+sqlite3_finalize $STMT
+
+# In each of the following, carray(?) contains integer values 1 to 5, bound
+# using sqlite3_carray_bind().
+#
+foreach {tn sql res} {
+ 1 { SELECT value FROM carray(?) WHERE value>2 } {3 4 5}
+ 2 {
+ WITH s(i) AS ( VALUES(1) UNION ALL VALUES(2) )
+ SELECT i, value FROM s, carray(?) WHERE i=value;
+ } {1 1 2 2}
+} {
+ do_test 2.2.$tn {
+ set STMT [sqlite3_prepare_v2 db $sql -1 TAIL]
+ sqlite3_carray_bind -int32 $STMT 1 1 2 3 4 5
+ set r [run_stmt $STMT]
+ sqlite3_finalize $STMT
+ set r
+ } $res
+}
+
+# In each of the following, ? is bound to an int array containing 1 to 5.
+# Bound using C code like:
+#
+# sqlite3_bind_pointer(pStmt, 1, aInt, "carray", SQLITE_TRANSIENT)
+#
+foreach {tn sql res} {
+ 1 { SELECT value FROM carray(?, 5) } {1 2 3 4 5}
+ 2 { SELECT value FROM carray(?, 3, 'int32') } {1 2 3}
+ 3 { SELECT value, pointer, count, ctype FROM carray(?, 5, 'int32') }
+ {1 {} 5 int32 2 {} 5 int32 3 {} 5 int32 4 {} 5 int32 5 {} 5 int32}
+ 4 { SELECT rowid, value FROM carray(?, 5, 'int32') }
+ {1 1 2 2 3 3 4 4 5 5}
+} {
+ do_test 2.3.$tn {
+ set STMT [sqlite3_prepare_v2 db $sql -1 TAIL]
+ bind_carray_intptr $STMT 1 1 2 3 4 5
+ set r [run_stmt $STMT]
+ sqlite3_finalize $STMT
+ set r
+ } $res
+}
+
+# In each of the following. Both carray(?1) and carray(?2) contain integer
+# values 1 to 5. Bound by sqlite3_carray_bind().
+#
+foreach {tn sql res} {
+ 1 {
+ SELECT * FROM carray(?1) AS a, carray(?2) AS b
+ WHERE a.value=b.value
+ } {1 1 2 2 3 3 4 4 5 5}
+
+ 2 {
+ SELECT * FROM carray(?1) AS a, carray(?2) AS b
+ WHERE a.value=b.value AND a.value<3 AND b.value<3
+ } {1 1 2 2 3 3}
+
+ 3 {
+ SELECT * FROM carray(?1) AS a, carray(?2) AS b
+ WHERE a.value<3 AND b.value<3 AND a.value=b.value
+ } {1 1 2 2 3 3}
+
+ 4 {
+ SELECT * FROM carray(?1) AS a, carray(?2, a.value) AS b
+ WHERE a.value=b.value
+ } {1 1 2 2 3 3}
+
+} {
+ do_test 2.4.$tn {
+ set STMT [sqlite3_prepare_v2 db {
+ SELECT * FROM carray(?1) AS a, carray(?2) AS b WHERE a.value=b.value
+ } -1 TAIL]
+ sqlite3_carray_bind $STMT 1 1 2 3 4 5
+ sqlite3_carray_bind $STMT 2 1 2 3 4 5
+ set r [run_stmt $STMT]
+ sqlite3_finalize $STMT
+ set r
+ } {1 1 2 2 3 3 4 4 5 5}
+}
+
+# Test that not binding any pointer, or passing a value that is not a bound
+# pointer to carray() produces no rows of output.
+#
+do_execsql_test 3.0.0 {
+ SELECT * FROM carray
+} {}
+do_execsql_test 3.0.1 {
+ SELECT * FROM carray('0xFFFF', 5)
+} {}
+do_execsql_test 3.0.2 {
+ SELECT * FROM carray('0xFFFF')
+} {}
+do_execsql_test 3.0.3 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES('0xFFFF');
+ SELECT * FROM t1, carray WHERE carray.pointer = t1.x;
+} {}
+
+# Test passing an unknown datatype.
+#
+do_test 3.1 {
+ set STMT [sqlite3_prepare_v2 db {SELECT * FROM carray(?, 5, 'apples')} -1 T]
+ sqlite3_carray_bind $STMT 1 1 2 3 4 5
+ sqlite3_step $STMT
+ list [sqlite3_finalize $STMT] [sqlite3_errmsg db]
+} {SQLITE_ERROR {unknown datatype: 'apples'}}
+
+finish_test
+
+
--- /dev/null
+# 2025-10-07
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix carrayfault
+
+
+# Check that OOM faults in sqlite3_carray_init() are handled.
+#
+do_faultsim_test 1 -faults oom* -prep {
+ sqlite3 db test.db
+} -body {
+ load_static_extension db carray
+} -test {
+ faultsim_test_result {0 {}} {1 {initialization of carray failed: }}
+}
+
+sqlite3 db test.db
+load_static_extension db carray
+
+do_execsql_test 2.0 {
+ CREATE TABLE t1(a);
+}
+
+set STMT [sqlite3_prepare_v2 db "SELECT value FROM carray(?)" -1 TAIL]
+
+# Test OOM faults in sqlite3_carray_bind() when binding an integer
+# array.
+#
+foreach {tn mem} {
+ 1 -static
+ 2 -transient
+ 3 -malloc
+} {
+ do_faultsim_test 2.$tn -faults oom* -prep {
+ } -body {
+ sqlite3_carray_bind $::mem -int64 $::STMT 1 100 200 300 400
+ } -test {
+ faultsim_test_result {0 {}} {1 {out of memory}}
+ }
+}
+
+# Test OOM faults in sqlite3_carray_bind() when binding a text array.
+#
+do_faultsim_test 3 -faults oom* -prep {
+} -body {
+ sqlite3_carray_bind -transient -text $::STMT 1 "hello" "world"
+} -test {
+ faultsim_test_result {0 {}} {1 {initialization of carray failed: }}
+}
+
+sqlite3_finalize $STMT
+
+
+# Test OOM faults when running queries against carray.
+#
+do_faultsim_test 4 -faults oom* -prep {
+ set ::STMT [sqlite3_prepare_v2 db "SELECT value FROM carray(?)" -1 TAIL]
+ sqlite3_carray_bind -transient -text $::STMT 1 "hello" "world"
+} -body {
+ set myres [list]
+ while { "SQLITE_ROW"==[sqlite3_step $::STMT] } {
+ lappend myres [sqlite3_column_text $::STMT 1]
+ }
+ sqlite3_reset $::STMT
+} -test {
+ faultsim_test_result {0 SQLITE_OK} {0 SQLITE_NOMEM}
+ sqlite3_finalize $::STMT
+}
+
+# Test OOM faults when preparing queries against carray.
+#
+do_faultsim_test 5 -faults oom* -prep {
+ sqlite3 db test.db
+ load_static_extension db carray
+} -body {
+ execsql "SELECT value FROM carray(?)"
+} -test {
+ faultsim_test_result {0 {}}
+}
+
+
+
+sqlite3_carray_bind
+
+finish_test