| JSON | PATH | -> operator (all) | ->> operator (MySQL/PG) + | ->> operator (SQLite) | json_extract() (SQLite) + |
|---|---|---|---|---|---|
| **'{"a":123}'** | '$.a' | **'123'** | '123' | 123 | 123 + |
| **'{"a":4.5}'** | '$.a' | **'4.5'** | '4.5' | 4.5 | 4.5 + |
| **'{"a":"xyz"}'** | '$.a' | **'"xyz"'** | 'xyz' | 'xyz' | 'xyz' + |
| **'{"a":null}'** | '$.a' | **'null'** | NULL | NULL | NULL + |
| **'{"a":[6,7,8]}'** | '$.a' | **'[6,7,8]'** | '[6,7,8]' | '[6,7,8]' | **'[6,7,8]'** + |
| **'{"a":{"x":9}}'** | '$.a' | **'{"x":9}'** | '{"x":9}' | '{"x":9}' | **'{"x":9}'** + |
| **'{"b":999}'** | '$.a' | NULL | NULL | NULL | NULL + |
| SQL expression | Works in MySQL? | Works in PG? | Works in SQLite + |
|---|---|---|---|
| value1->'$.a' | yes | no | yes + |
| value1->'a' | no | yes | yes + |
| value2->'$[2]' | yes | no | yes + |
| value2->2 | no | yes | yes + |
| TEXT | BLOB | No change ** |
| BLOB | INTEGER | [CAST] to INTEGER ** |
| BLOB | FLOAT | [CAST] to REAL -** |
| BLOB | TEXT | Add a zero terminator if needed +** |
| BLOB | TEXT | [CAST] to TEXT, ensure zero terminator ** |
If the constraint comes from a WHERE clause expression that contains +** a [COLLATE operator], then the name of the collation specified by +** that COLLATE operator is returned. +**
If there is no COLLATE operator, but the column that is the subject +** of the constraint specifies an alternative collating sequence via +** a [COLLATE clause] on the column definition within the CREATE TABLE +** statement that was passed into [sqlite3_declare_vtab()], then the +** name of that alternative collating sequence is returned. +**
Otherwise, "BINARY" is returned. +**
+** ^If the sqlite3_vtab_distinct() interface returns 0, that means +** that the query planner needs the virtual table to return all rows in the +** sort order defined by the "nOrderBy" and "aOrderBy" fields of the +** [sqlite3_index_info] object. This is the default expectation. If the +** virtual table outputs all rows in sorted order, then it is always safe for +** the xBestIndex method to set the "orderByConsumed" flag, regardless of +** the return value from sqlite3_vtab_distinct(). +**
+** ^(If the sqlite3_vtab_distinct() interface returns 1, that means +** that the query planner does not need the rows to be returned in sorted order +** as long as all rows with the same values in all columns identified by the +** "aOrderBy" field are adjacent.)^ This mode is used when the query planner +** is doing a GROUP BY. +**
+** ^(If the sqlite3_vtab_distinct() interface returns 2, that means +** that the query planner does not need the rows returned in any particular +** order, as long as rows with the same values in all "aOrderBy" columns +** are adjacent.)^ ^(Furthermore, only a single row for each particular +** combination of values in the columns identified by the "aOrderBy" field +** needs to be returned.)^ ^It is always ok for two or more rows with the same +** values in all "aOrderBy" columns to be returned, as long as all such rows +** are adjacent. ^The virtual table may, if it chooses, omit extra rows +** that have the same value for all columns identified by "aOrderBy". +** ^However omitting the extra rows is optional. +** This mode is used for a DISTINCT query. +**
+** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) +** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint +** is an [IN operator] that can be processed all at once. ^In other words, +** sqlite3_vtab_in() with -1 in the third argument is a mechanism +** by which the virtual table can ask SQLite if all-at-once processing +** of the IN operator is even possible. +** +**
+** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates +** to SQLite that the virtual table does or does not want to process +** the IN operator all-at-once, respectively. ^Thus when the third +** parameter (F) is non-negative, this interface is the mechanism by +** which the virtual table tells SQLite how it wants to process the +** IN operator. +**
The P->aConstraintUsage[N].argvIndex value is set to a positive +** integer. This is how the virtual table tells SQLite that it wants to +** use the N-th constraint. +** +**
The last call to sqlite3_vtab_in(P,N,F) for which F was +** non-negative had F>=1. +**
+** for(rc=sqlite3_vtab_in_first(pList, &pVal);
+** rc==SQLITE_OK && pVal
+** rc=sqlite3_vtab_in_next(pList, &pVal)
+** ){
+** // do something with pVal
+** }
+** if( rc!=SQLITE_OK ){
+** // an error has occurred
+** }
+** )^
+**
+** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
+** routines return SQLITE_OK and set *P to point to the first or next value
+** on the RHS of the IN constraint. ^If there are no more values on the
+** right hand side of the IN constraint, then *P is set to NULL and these
+** routines return [SQLITE_DONE]. ^The return value might be
+** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
+**
+** The *ppOut values returned by these routines are only valid until the
+** next call to either of these routines or until the end of the xFilter
+** method from which these routines were called. If the virtual table
+** implementation needs to retain the *ppOut values for longer, it must make
+** copies. The *ppOut values are [protected sqlite3_value|protected].
+*/
+int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
+int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
+
+/*
+** CAPI3REF: Constraint values in xBestIndex()
+** METHOD: sqlite3_index_info
+**
+** This API may only be used from within the [xBestIndex|xBestIndex method]
+** of a [virtual table] implementation. The result of calling this interface
+** from outside of an xBestIndex method are undefined and probably harmful.
+**
+** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
+** the [xBestIndex] method of a [virtual table] implementation, with P being
+** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
+** J being a 0-based index into P->aConstraint[], then this routine
+** attempts to set *V to the value of the right-hand operand of
+** that constraint if the right-hand operand is known. ^If the
+** right-hand operand is not known, then *V is set to a NULL pointer.
+** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if
+** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
+** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
+** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
+** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
+** something goes wrong.
+**
+** The sqlite3_vtab_rhs_value() interface is usually only successful if
+** the right-hand operand of a constraint is a literal value in the original
+** SQL statement. If the right-hand operand is an expression or a reference
+** to some other column or a [host parameter], then sqlite3_vtab_rhs_value()
+** will probably return [SQLITE_NOTFOUND].
+**
+** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and
+** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such
+** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^
+**
+** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value
+** and remains valid for the duration of the xBestIndex method call.
+** ^When xBestIndex returns, the sqlite3_value object returned by
+** sqlite3_vtab_rhs_value() is automatically deallocated.
+**
+** The "_rhs_" in the name of this routine is an abbreviation for
+** "Right-Hand Side".
+*/
+int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
+
/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 9767daa0..2eac4f3f 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -344,6 +344,13 @@ struct sqlite3_api_routines {
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
+ /* Version 3.38.0 and later */
+ int (*error_offset)(sqlite3*);
+ int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
+ int (*vtab_distinct)(sqlite3_index_info*);
+ int (*vtab_in)(sqlite3_index_info*,int,int);
+ int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
+ int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
};
/*
@@ -655,6 +662,13 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
+/* Version 3.38.0 and later */
+#define sqlite3_error_offset sqlite3_api->error_offset
+#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
+#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
+#define sqlite3_vtab_in sqlite3_api->vtab_in
+#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
+#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 29ad7170..c73def49 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1231,10 +1231,11 @@ typedef struct With With;
/*
** A bit in a Bitmask
*/
-#define MASKBIT(n) (((Bitmask)1)<<(n))
-#define MASKBIT64(n) (((u64)1)<<(n))
-#define MASKBIT32(n) (((unsigned int)1)<<(n))
-#define ALLBITS ((Bitmask)-1)
+#define MASKBIT(n) (((Bitmask)1)<<(n))
+#define MASKBIT64(n) (((u64)1)<<(n))
+#define MASKBIT32(n) (((unsigned int)1)<<(n))
+#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0)
+#define ALLBITS ((Bitmask)-1)
/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
@@ -1527,6 +1528,7 @@ struct sqlite3 {
u32 nSchemaLock; /* Do not reset the schema when non-zero */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
+ int errByteOffset; /* Byte offset of error in SQL statement */
int errMask; /* & result codes with this before returning */
int iSysErrno; /* Errno value from last system error */
u32 dbOptFlags; /* Flags to enable/disable optimizations */
@@ -1761,6 +1763,9 @@ struct sqlite3 {
#define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */
#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */
/* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */
+#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */
+#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */
+#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -1934,7 +1939,7 @@ struct FuncDestructor {
** are interpreted in the same way as the first 4 parameters to
** FUNCTION().
**
-** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
+** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
** Used to create an aggregate function definition implemented by
** the C functions xStep and xFinal. The first four parameters
** are interpreted in the same way as the first 4 parameters to
@@ -1961,6 +1966,10 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
+#define JFUNCTION(zName, nArg, iArg, xFunc) \
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\
+ SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -2815,7 +2824,10 @@ struct Expr {
** TK_VARIABLE: variable number (always >= 1).
** TK_SELECT_COLUMN: column of the result vector */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
- int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
+ union {
+ int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
+ int iOfst; /* else: start of token from start of statement */
+ } w;
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
union {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
@@ -3577,6 +3589,7 @@ struct Parse {
**************************************************************************/
int aTempReg[8]; /* Holding area for temporary registers */
+ Parse *pOuterParse; /* Outer Parse object when nested */
Token sNameToken; /* Token with unqualified schema object name */
/************************************************************************
@@ -3627,7 +3640,8 @@ struct Parse {
/*
** Sizes and pointers of various parts of the Parse object.
*/
-#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
+#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg))
+#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/
#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */
@@ -3922,6 +3936,7 @@ struct Sqlite3Config {
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
int bLocaltimeFault; /* True to fail localtime() calls */
+ int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */
int iOnceResetThreshold; /* When to reset OP_Once counters */
u32 szSorterRef; /* Min size in bytes to use sorter-refs */
unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */
@@ -4402,7 +4417,7 @@ void sqlite3DequoteExpr(Expr*);
void sqlite3DequoteToken(Token*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
-int sqlite3RunParser(Parse*, const char*, char **);
+int sqlite3RunParser(Parse*, const char*);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);
void sqlite3ReleaseTempReg(Parse*,int);
@@ -4569,10 +4584,12 @@ void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
#endif
+void sqlite3CodeChangeCount(Vdbe*,int,const char*);
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
Upsert*);
-WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
+WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,
+ ExprList*,Select*,u16,int);
void sqlite3WhereEnd(WhereInfo*);
LogEst sqlite3WhereOutputRowCount(WhereInfo*);
int sqlite3WhereIsDistinct(WhereInfo*);
@@ -4687,9 +4704,14 @@ Select *sqlite3SelectDup(sqlite3*,const Select*,int);
FuncDef *sqlite3FunctionSearch(int,const char*);
void sqlite3InsertBuiltinFuncs(FuncDef*,int);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
+void sqlite3QuoteValue(StrAccum*,sqlite3_value*);
void sqlite3RegisterBuiltinFunctions(void);
void sqlite3RegisterDateTimeFunctions(void);
+void sqlite3RegisterJsonFunctions(void);
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
+ int sqlite3JsonTableFunctions(sqlite3*);
+#endif
int sqlite3SafetyCheckOk(sqlite3*);
int sqlite3SafetyCheckSickOrOk(sqlite3*);
void sqlite3ChangeCookie(Parse*, int);
@@ -4779,14 +4801,8 @@ int sqlite3Utf8CharLen(const char *pData, int nByte);
u32 sqlite3Utf8Read(const u8**);
LogEst sqlite3LogEst(u64);
LogEst sqlite3LogEstAdd(LogEst,LogEst);
-#ifndef SQLITE_OMIT_VIRTUALTABLE
LogEst sqlite3LogEstFromDouble(double);
-#endif
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT4) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
u64 sqlite3LogEstToInt(LogEst);
-#endif
VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
const char *sqlite3VListNumToName(VList*,int);
int sqlite3VListNameToNum(VList*,const char*,int);
@@ -4973,17 +4989,20 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
FuncDestructor *pDestructor
);
void sqlite3NoopDestructor(void*);
-void sqlite3OomFault(sqlite3*);
+void *sqlite3OomFault(sqlite3*);
void sqlite3OomClear(sqlite3*);
int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3OpenTempDatabase(Parse *);
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
+int sqlite3StrAccumEnlarge(StrAccum*, int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumSetError(StrAccum*, u8);
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
void sqlite3SelectDestInit(SelectDest*,int,int);
Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
+void sqlite3RecordErrorByteOffset(sqlite3*,const char*);
+void sqlite3RecordErrorOffsetOfExpr(sqlite3*,const Expr*);
void sqlite3BackupRestart(sqlite3_backup *);
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
@@ -5088,11 +5107,17 @@ int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, VTable *);
+
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
+#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
+ && !defined(SQLITE_OMIT_VIRTUALTABLE)
+ void sqlite3VtabWriteAll(sqlite3_index_info*);
+#endif
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
-void sqlite3ParserReset(Parse*);
+void sqlite3ParseObjectInit(Parse*,sqlite3*);
+void sqlite3ParseObjectReset(Parse*);
void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
#ifdef SQLITE_ENABLE_NORMALIZE
char *sqlite3Normalize(Vdbe*, const char*);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 46ae5f7e..f84a05c0 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -1943,15 +1943,16 @@ static int SQLITE_TCLAPI DbObjCmd(
"close", "collate", "collation_needed",
"commit_hook", "complete", "config",
"copy", "deserialize", "enable_load_extension",
- "errorcode", "eval", "exists",
- "function", "incrblob", "interrupt",
- "last_insert_rowid", "nullvalue", "onecolumn",
- "preupdate", "profile", "progress",
- "rekey", "restore", "rollback_hook",
- "serialize", "status", "timeout",
- "total_changes", "trace", "trace_v2",
- "transaction", "unlock_notify", "update_hook",
- "version", "wal_hook", 0
+ "errorcode", "erroroffset", "eval",
+ "exists", "function", "incrblob",
+ "interrupt", "last_insert_rowid", "nullvalue",
+ "onecolumn", "preupdate", "profile",
+ "progress", "rekey", "restore",
+ "rollback_hook", "serialize", "status",
+ "timeout", "total_changes", "trace",
+ "trace_v2", "transaction", "unlock_notify",
+ "update_hook", "version", "wal_hook",
+ 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
@@ -1959,15 +1960,15 @@ static int SQLITE_TCLAPI DbObjCmd(
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
- DB_ERRORCODE, DB_EVAL, DB_EXISTS,
- DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
- DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
- DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
- DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
- DB_SERIALIZE, DB_STATUS, DB_TIMEOUT,
- DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2,
- DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
- DB_VERSION, DB_WAL_HOOK
+ DB_ERRORCODE, DB_ERROROFFSET, DB_EVAL,
+ DB_EXISTS, DB_FUNCTION, DB_INCRBLOB,
+ DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE,
+ DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE,
+ DB_PROGRESS, DB_REKEY, DB_RESTORE,
+ DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS,
+ DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
+ DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY,
+ DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -2730,6 +2731,17 @@ deserialize_error:
break;
}
+ /*
+ ** $db erroroffset
+ **
+ ** Return the numeric error code that was returned by the most recent
+ ** call to sqlite3_exec().
+ */
+ case DB_ERROROFFSET: {
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_error_offset(pDb->db)));
+ break;
+ }
+
/*
** $db exists $sql
** $db onecolumn $sql
diff --git a/src/test1.c b/src/test1.c
index a9464c1a..5b8bb12e 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -1125,7 +1125,7 @@ static int SQLITE_TCLAPI test_drop_modules(
){
sqlite3 *db;
- if( argc!=2 ){
+ if( argc<2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB\"", 0);
return TCL_ERROR;
@@ -4005,6 +4005,102 @@ static int SQLITE_TCLAPI test_bind_blob(
return TCL_OK;
}
+/*
+** Usage: sqlite3_bind_value_from_preupdate STMT N NEW|OLD IDX
+**
+** Test the sqlite3_bind_value interface using sqlite3_value objects
+** obtained from either sqlite3_preupdate_new() (if arg[3]=="new") or
+** sqlite3_preupdate_old() if (arg[3]=="old"). IDX is the index to
+** pass to the sqlite3_preupdate_xxx() function.
+*/
+static int SQLITE_TCLAPI test_bind_value_from_preupdate(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_stmt *pStmt;
+ int idx;
+ int bidx;
+ const char *z3 = 0;
+ sqlite3 *db = 0;
+ sqlite3_value *pVal = 0;
+
+ if( objc!=5 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "STMT N NEW|OLD IDX");
+ return TCL_ERROR;
+ }
+
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
+ z3 = Tcl_GetString(objv[3]);
+ if( Tcl_GetIntFromObj(interp, objv[4], &bidx) ) return TCL_ERROR;
+ db = sqlite3_db_handle(pStmt);
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ if( z3[0]=='n' ){
+ sqlite3_preupdate_new(db, bidx, &pVal);
+ }else if( z3[0]=='o' ){
+ sqlite3_preupdate_old(db, bidx, &pVal);
+ }else{
+ Tcl_AppendResult(interp, "expected new or old, got: ", z3, (char*)0);
+ return TCL_ERROR;
+ }
+ sqlite3_bind_value(pStmt, idx, pVal);
+#endif
+
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_bind_value_from_select STMT N SELECT
+**
+** Test the sqlite3_bind_value interface. STMT is a prepared statement.
+** N is the index of a wildcard in the prepared statement.
+*/
+static int SQLITE_TCLAPI test_bind_value_from_select(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_stmt *pStmt;
+ sqlite3_stmt *pStmt2;
+ int idx;
+ const char *zSql = 0;
+ sqlite3 *db = 0;
+ int rc = SQLITE_OK;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "STMT N SELECT");
+ return TCL_ERROR;
+ }
+
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
+ zSql = Tcl_GetString(objv[3]);
+ db = sqlite3_db_handle(pStmt);
+
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt2, 0);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error in SQL: ", sqlite3_errmsg(db), (char*)0);
+ return TCL_ERROR;
+ }
+ if( sqlite3_step(pStmt2)==SQLITE_ROW ){
+ sqlite3_value *pVal = sqlite3_column_value(pStmt2, 0);
+ sqlite3_bind_value(pStmt, idx, pVal);
+ }
+ rc = sqlite3_finalize(pStmt2);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp,
+ "error runnning SQL: ", sqlite3_errmsg(db), (char*)0
+ );
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
@@ -4394,6 +4490,34 @@ static int SQLITE_TCLAPI test_errmsg(
return TCL_OK;
}
+
+/*
+** Usage: sqlite3_error_offset DB
+**
+** Return the byte offset into the input UTF8 SQL for the most recent
+** error, or -1 of the error does not refer to a specific token.
+*/
+static int SQLITE_TCLAPI test_error_offset(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ int iByteOffset;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+
+ iByteOffset = sqlite3_error_offset(db);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(iByteOffset));
+ return TCL_OK;
+}
+
/*
** Usage: test_errmsg16 DB
**
@@ -7111,6 +7235,55 @@ static int SQLITE_TCLAPI test_print_eqp(
}
#endif /* SQLITE_OMIT_EXPLAIN */
+#include