mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Add a single-argument form to the CARRAY table-valued function, with
content bound using the sqlite3_carray_bind() interface that is included with the extension. FossilOrigin-Name: 7b229cb1202be203a87b8f47d284313f357deb1e6dfeb94bba7b46744c33512e
This commit is contained in:
@ -57,21 +57,32 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
** Must exactly match the definitions in carray.h.
|
||||
*/
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Allowed datatypes
|
||||
*/
|
||||
#define CARRAY_INT32 0
|
||||
#define CARRAY_INT64 1
|
||||
#define CARRAY_DOUBLE 2
|
||||
#define CARRAY_TEXT 3
|
||||
|
||||
/*
|
||||
** Names of types
|
||||
** Names of allowed datatypes
|
||||
*/
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*" };
|
||||
|
||||
/*
|
||||
** Structure used to hold the sqlite3_carray_bind() information
|
||||
*/
|
||||
typedef struct carray_bind carray_bind;
|
||||
struct carray_bind {
|
||||
void *aData; /* The data */
|
||||
int nData; /* Number of elements */
|
||||
int mFlags; /* Control flags */
|
||||
void (*xDel)(void*); /* Destructor for aData */
|
||||
};
|
||||
|
||||
|
||||
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
@ -239,7 +250,19 @@ static int carrayFilter(
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
|
||||
if( idxNum ){
|
||||
pCur->pPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
switch( idxNum ){
|
||||
case 1: {
|
||||
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
|
||||
if( pBind==0 ) break;
|
||||
pCur->pPtr = pBind->aData;
|
||||
pCur->iCnt = pBind->nData;
|
||||
pCur->eType = pBind->mFlags & 0x03;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3: {
|
||||
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
|
||||
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
|
||||
if( idxNum<3 ){
|
||||
@ -258,9 +281,8 @@ static int carrayFilter(
|
||||
pCur->eType = i;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pCur->pPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pCur->iRowid = 1;
|
||||
return SQLITE_OK;
|
||||
@ -275,9 +297,16 @@ static int carrayFilter(
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** idxNum is 2 if the pointer= and count= constraints exist,
|
||||
** 3 if the ctype= constraint also exists, and is 0 otherwise.
|
||||
** If idxNum is 0, then carray becomes an empty table.
|
||||
** idxNum is:
|
||||
**
|
||||
** 1 If only the pointer= constraint exists. In this case, the
|
||||
** parameter must be bound using sqlite3_carray_bind().
|
||||
**
|
||||
** 2 if the pointer= and count= constraints exist.
|
||||
**
|
||||
** 3 if the ctype= constraint also exists.
|
||||
**
|
||||
** idxNum is 0 otherwise and carray becomes an empty table.
|
||||
*/
|
||||
static int carrayBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
@ -305,19 +334,22 @@ static int carrayBestIndex(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ptrIdx>=0 && cntIdx>=0 ){
|
||||
if( ptrIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->estimatedCost = (double)1;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 1;
|
||||
if( cntIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 2;
|
||||
if( ctypeIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
pIdxInfo->estimatedRows = 2147483647;
|
||||
@ -353,6 +385,89 @@ static sqlite3_module carrayModule = {
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
/*
|
||||
** Destructor for the carray_bind object
|
||||
*/
|
||||
static void carrayBindDel(void *pPtr){
|
||||
carray_bind *p = (carray_bind*)pPtr;
|
||||
if( p->xDel!=SQLITE_STATIC ){
|
||||
p->xDel(p->aData);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY().
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
carray_bind *pNew;
|
||||
int i;
|
||||
pNew = sqlite3_malloc64(sizeof(*pNew));
|
||||
if( pNew==0 ){
|
||||
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
|
||||
xDestroy(aData);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pNew->nData = nData;
|
||||
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;
|
||||
}
|
||||
if( (mFlags & 0x03)==CARRAY_TEXT ){
|
||||
for(i=0; i<nData; i++){
|
||||
const char *z = ((char**)aData)[i];
|
||||
if( z ) sz += strlen(z) + 1;
|
||||
}
|
||||
}
|
||||
pNew->aData = sqlite3_malloc64( sz );
|
||||
if( pNew->aData==0 ){
|
||||
sqlite3_free(pNew);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( (mFlags & 0x03)==CARRAY_TEXT ){
|
||||
char **az = (char**)pNew->aData;
|
||||
char *z = (char*)&az[nData];
|
||||
for(i=0; i<nData; i++){
|
||||
const char *zData = ((char**)aData)[i];
|
||||
sqlite3_int64 n;
|
||||
if( zData==0 ){
|
||||
az[i] = 0;
|
||||
continue;
|
||||
}
|
||||
az[i] = z;
|
||||
n = strlen(zData);
|
||||
memcpy(z, zData, n+1);
|
||||
z += n+1;
|
||||
}
|
||||
}else{
|
||||
memcpy(pNew->aData, aData, sz*nData);
|
||||
}
|
||||
pNew->xDel = sqlite3_free;
|
||||
}else{
|
||||
pNew->aData = aData;
|
||||
pNew->xDel = xDestroy;
|
||||
}
|
||||
sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** For testing purpose in the TCL test harness, we need a method for
|
||||
** setting the pointer value. The inttoptr(X) SQL function accomplishes
|
||||
|
23
ext/misc/carray.h
Normal file
23
ext/misc/carray.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
** Interface definitions for the CARRAY table-valued function
|
||||
** extension.
|
||||
*/
|
||||
|
||||
/* Use this interface to bind an array to the single-argument version
|
||||
** of CARRAY().
|
||||
*/
|
||||
int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt, /* Statement to be bound */
|
||||
int i, /* Parameter index */
|
||||
void *aData, /* Pointer to array data */
|
||||
int nData, /* Number of data elements */
|
||||
int mFlags, /* CARRAY flags */
|
||||
void (*xDel)(void*) /* Destructgor for aData*/
|
||||
);
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
*/
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C Improved\sdiagnostics\soutput\swith\s".wheretrace\s0x800".\s\sNo\schanges\sto\nnon-debug\sbuilds.
|
||||
D 2020-11-12T18:16:01.196
|
||||
C Add\sa\ssingle-argument\sform\sto\sthe\sCARRAY\stable-valued\sfunction,\swith\ncontent\sbound\susing\sthe\ssqlite3_carray_bind()\sinterface\sthat\sis\sincluded\nwith\sthe\sextension.
|
||||
D 2020-11-17T14:41:37.097
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -287,7 +287,8 @@ F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a2
|
||||
F ext/misc/appendvfs.c 55121d311d408ba9c62c3cfa367408887638f02f9522dd9859891d0ee69a7eba
|
||||
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
|
||||
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
|
||||
F ext/misc/carray.c 91e9a7f512fda934894bed30464552fffa7d3073b5be04189ae0bd0c59f26bfd
|
||||
F ext/misc/carray.c 6b3cb5217466f687f48e3c3a87c43fb628ae80db68a95e30bbd8074d099c29a4
|
||||
F ext/misc/carray.h de74ac70b2338f416723f7d538026e8ec0b7f1d388319f8f140c9a4d7677f02e
|
||||
F ext/misc/cksumvfs.c 910848f3d9739908cf77cad66a76dd45001546f46ff5ef4ca5c20c5476e77e98
|
||||
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
|
||||
F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
|
||||
@ -547,7 +548,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71
|
||||
F src/test1.c 9e52fb797bf74fa327295df38881aa3ade0824bfb0c14abd0719e555b169fd55
|
||||
F src/test1.c 385533d17fb06529c909defc73ef47dd2712dc198eedff94fc6df5bc23687c71
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
|
||||
@ -740,6 +741,7 @@ F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 54e2dc0c8fd7c34ad1590d1be6864397da2438c95a9f5aee2f8fbc60c112e44b
|
||||
F test/capi3d.test aba917805573a03deed961a21f07a5a84505ad0a616f7e3fc1508844a15bccc4
|
||||
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
||||
F test/carray01.test 3f2658bbddd75a013735a296ae2178ff441aca3f00ba623cfbae00b732ede792
|
||||
F test/cast.test 336fa21989b5170ebcaf90c24266be22dd97b3e23d1fad5ecf6ad4efb04c4423
|
||||
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
|
||||
F test/check.test 4a2a91ed67eee84a6be16057c48d5198b6fb24849cd6da6cd855981de3fbb416
|
||||
@ -1883,7 +1885,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 572f1ed59d29e74f810c74ef9e72ebc94c2d3e04befc03a1f88034f04a9c60a8
|
||||
R 4901674d935be395f9df3d7654b8445e
|
||||
P 772ae83c61c87a9004a614d8ec120ba843286bff1edbd20b987fd592ced84d79
|
||||
R dda1ed32688d23b76f833a4d9835bd2c
|
||||
U drh
|
||||
Z 60f97595458aa54172137f4d47d1e884
|
||||
Z 69dc23c53e350f7672399c3847d987a1
|
||||
|
@ -1 +1 @@
|
||||
772ae83c61c87a9004a614d8ec120ba843286bff1edbd20b987fd592ced84d79
|
||||
7b229cb1202be203a87b8f47d284313f357deb1e6dfeb94bba7b46744c33512e
|
190
src/test1.c
190
src/test1.c
@ -3940,7 +3940,7 @@ static int SQLITE_TCLAPI test_bind_blob(
|
||||
char zBuf[200];
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf,
|
||||
"cannot use %d blob bytes, have %d", bytes, len);
|
||||
Tcl_AppendResult(interp, zBuf, -1);
|
||||
Tcl_AppendResult(interp, zBuf, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@ -3953,6 +3953,193 @@ static int SQLITE_TCLAPI test_bind_blob(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** sqlite3_carray_bind [options...] STMT NAME VALUE ...
|
||||
**
|
||||
** Options:
|
||||
** -transient
|
||||
** -static
|
||||
** -int32
|
||||
** -int64
|
||||
** -double
|
||||
** -text
|
||||
**
|
||||
** Each call clears static data. Called with no options does nothing
|
||||
** but clear static data.
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_carray_bind(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int eType = 0; /* CARRAY_INT32 */
|
||||
int nData = 0;
|
||||
void *aData = 0;
|
||||
int isTransient = 0;
|
||||
int isStatic = 0;
|
||||
int idx;
|
||||
int i, j;
|
||||
int rc;
|
||||
void (*xDel)(void*) = sqlite3_free;
|
||||
static void *aStaticData = 0;
|
||||
static int nStaticData = 0;
|
||||
static int eStaticType = 0;
|
||||
extern int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*)
|
||||
);
|
||||
|
||||
if( aStaticData ){
|
||||
/* Always clear preexisting static data on every call */
|
||||
if( eStaticType==3 ){
|
||||
for(i=0; i<nStaticData; i++){
|
||||
sqlite3_free(((char**)aStaticData)[i]);
|
||||
}
|
||||
}
|
||||
sqlite3_free(aStaticData);
|
||||
aStaticData = 0;
|
||||
nStaticData = 0;
|
||||
eStaticType = 0;
|
||||
}
|
||||
if( objc==1 ) return TCL_OK;
|
||||
|
||||
for(i=1; i<objc && Tcl_GetString(objv[i])[0]=='-'; i++){
|
||||
const char *z = Tcl_GetString(objv[i]);
|
||||
if( strcmp(z, "-transient")==0 ){
|
||||
isTransient = 1;
|
||||
xDel = SQLITE_TRANSIENT;
|
||||
}else
|
||||
if( strcmp(z, "-static")==0 ){
|
||||
isStatic = 1;
|
||||
xDel = SQLITE_STATIC;
|
||||
}else
|
||||
if( strcmp(z, "-int32")==0 ){
|
||||
eType = 0; /* CARRAY_INT32 */
|
||||
}else
|
||||
if( strcmp(z, "-int64")==0 ){
|
||||
eType = 1; /* CARRAY_INT64 */
|
||||
}else
|
||||
if( strcmp(z, "-double")==0 ){
|
||||
eType = 2; /* CARRAY_DOUBLE */
|
||||
}else
|
||||
if( strcmp(z, "-text")==0 ){
|
||||
eType = 3; /* CARRAY_TEXT */
|
||||
}else
|
||||
if( strcmp(z, "--")==0 ){
|
||||
break;
|
||||
}else
|
||||
{
|
||||
Tcl_AppendResult(interp, "unknown option: ", z, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
if( eType==3 && !isStatic && !isTransient ){
|
||||
Tcl_AppendResult(interp, "text 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);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc-i < 2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "[OPTIONS] STMT IDX VALUE ...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[i]), &pStmt) ) return TCL_ERROR;
|
||||
i++;
|
||||
if( Tcl_GetIntFromObj(interp, objv[i], &idx) ) return TCL_ERROR;
|
||||
i++;
|
||||
nData = objc - i;
|
||||
switch( eType + 4*(nData<=0) ){
|
||||
case 0: { /* INT32 */
|
||||
int *a = sqlite3_malloc( sizeof(int)*nData );
|
||||
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
|
||||
for(j=0; j<nData; j++){
|
||||
int v;
|
||||
if( Tcl_GetIntFromObj(interp, objv[i+j], &v) ){
|
||||
sqlite3_free(a);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
a[j] = v;
|
||||
}
|
||||
aData = a;
|
||||
break;
|
||||
}
|
||||
case 1: { /* INT64 */
|
||||
sqlite3_int64 *a = sqlite3_malloc( sizeof(sqlite3_int64)*nData );
|
||||
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
|
||||
for(j=0; j<nData; j++){
|
||||
Tcl_WideInt v;
|
||||
if( Tcl_GetWideIntFromObj(interp, objv[i+j], &v) ){
|
||||
sqlite3_free(a);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
a[j] = v;
|
||||
}
|
||||
aData = a;
|
||||
break;
|
||||
}
|
||||
case 2: { /* DOUBLE */
|
||||
double *a = sqlite3_malloc( sizeof(double)*nData );
|
||||
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
|
||||
for(j=0; j<nData; j++){
|
||||
double v;
|
||||
if( Tcl_GetDoubleFromObj(interp, objv[i+j], &v) ){
|
||||
sqlite3_free(a);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
a[j] = v;
|
||||
}
|
||||
aData = a;
|
||||
break;
|
||||
}
|
||||
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++){
|
||||
const char *v = Tcl_GetString(objv[i+j]);
|
||||
a[j] = sqlite3_mprintf("%s", v);
|
||||
}
|
||||
aData = a;
|
||||
break;
|
||||
}
|
||||
case 4: { /* nData==0 */
|
||||
aData = "";
|
||||
xDel = SQLITE_STATIC;
|
||||
isTransient = 0;
|
||||
isStatic = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( isStatic ){
|
||||
aStaticData = aData;
|
||||
nStaticData = nData;
|
||||
eStaticType = eType;
|
||||
}
|
||||
rc = sqlite3_carray_bind(pStmt, idx, aData, nData, eType, xDel);
|
||||
if( isTransient ){
|
||||
if( eType==3 ){
|
||||
for(i=0; i<nData; i++) sqlite3_free(((char**)aData)[i]);
|
||||
}
|
||||
sqlite3_free(aData);
|
||||
}
|
||||
carray_bind_done:
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_bind_parameter_count STMT
|
||||
**
|
||||
@ -8029,6 +8216,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_bind_text", test_bind_text ,0 },
|
||||
{ "sqlite3_bind_text16", test_bind_text16 ,0 },
|
||||
{ "sqlite3_bind_blob", test_bind_blob ,0 },
|
||||
{ "sqlite3_carray_bind", test_carray_bind ,0 },
|
||||
{ "sqlite3_bind_parameter_count", test_bind_parameter_count, 0},
|
||||
{ "sqlite3_bind_parameter_name", test_bind_parameter_name, 0},
|
||||
{ "sqlite3_bind_parameter_index", test_bind_parameter_index, 0},
|
||||
|
100
test/carray01.test
Normal file
100
test/carray01.test
Normal file
@ -0,0 +1,100 @@
|
||||
# 2020-11-17
|
||||
#
|
||||
# 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 carray01
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
load_static_extension db carray
|
||||
|
||||
# Parameter $stmt must be a prepared statement created using
|
||||
# the sqlite3_prepare_v2 command and with parameters fullly 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}} {
|
||||
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
|
||||
}
|
||||
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
|
||||
} {1}
|
||||
do_test 101 {
|
||||
sqlite3_carray_bind -static $STMT 3 1 2 3 4 5 6 7
|
||||
run_stmt $STMT 0
|
||||
} {1}
|
||||
do_test 110 {
|
||||
sqlite3_carray_bind $STMT 3 1 2 3 4 6 7
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
do_test 120 {
|
||||
sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 5 6 7
|
||||
run_stmt $STMT 0
|
||||
} {1}
|
||||
do_test 130 {
|
||||
sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 6 7
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
do_test 131 {
|
||||
sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 6 7
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
do_test 140 {
|
||||
sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7
|
||||
run_stmt $STMT 0
|
||||
} {1}
|
||||
do_test 150 {
|
||||
sqlite3_carray_bind -double $STMT 3 1 2 3 4 6 7
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
do_test 160 {
|
||||
sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7
|
||||
run_stmt $STMT 0
|
||||
} {1}
|
||||
do_test 170 {
|
||||
sqlite3_carray_bind -text -static $STMT 3 1 2 3 4 6 7
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
do_test 180 {
|
||||
sqlite3_carray_bind -text -transient $STMT 3 1 2 3 4 5 6 7
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
do_test 190 {
|
||||
sqlite3_carray_bind $STMT 3
|
||||
run_stmt $STMT 0
|
||||
} {0}
|
||||
|
||||
sqlite3_finalize $STMT
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user