mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Initial work on the Tcl API interface to the new sqlite3_trace_v2() function.
FossilOrigin-Name: 7b59fa40a01c89cc98414d90a798169c26e04256
This commit is contained in:
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
|||||||
C Fix\scopy/paste\stypo\sin\sthe\snew\ssqlite3_expanded_sql()\sfunction.
|
C Initial\swork\son\sthe\sTcl\sAPI\sinterface\sto\sthe\snew\ssqlite3_trace_v2()\sfunction.
|
||||||
D 2016-07-14T09:22:16.664
|
D 2016-07-14T21:26:09.090
|
||||||
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
|
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
|
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
|
||||||
@ -392,7 +392,7 @@ F src/sqliteInt.h 48cd97eb134665348393dfe277b4c14d1085bfc7
|
|||||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||||
F src/status.c 5b18f9526900f61189ab0b83f1ef41d9f871a2ab
|
F src/status.c 5b18f9526900f61189ab0b83f1ef41d9f871a2ab
|
||||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||||
F src/tclsqlite.c 25fbbbb97f76dbfd113153fb63f52d7ecfac5dd0
|
F src/tclsqlite.c 361167055f0d0d9883b729f1db698edcd3b46065
|
||||||
F src/test1.c 5124aff86fba753a6994e9621696ccfdc8bbf24e
|
F src/test1.c 5124aff86fba753a6994e9621696ccfdc8bbf24e
|
||||||
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
|
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
|
||||||
F src/test3.c c75c8af0eadb335236c9e61b51044c58a8f7dd59
|
F src/test3.c c75c8af0eadb335236c9e61b51044c58a8f7dd59
|
||||||
@ -1505,7 +1505,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 989de2d5b5e7155654d3eebadb9651b23f422c58
|
P e7d18c70d2b8f09c9f5b978fe3d69d1088e42322
|
||||||
R 22fe35d8085a083776873f2a488c7041
|
R 85912bc13f3699d6087855b14808f819
|
||||||
U mistachkin
|
U mistachkin
|
||||||
Z 0cf3ee8d7f2e128326cc9e0cdcd59d22
|
Z 312d6409632132f635d6a5f40333e628
|
||||||
|
@ -1 +1 @@
|
|||||||
e7d18c70d2b8f09c9f5b978fe3d69d1088e42322
|
7b59fa40a01c89cc98414d90a798169c26e04256
|
303
src/tclsqlite.c
303
src/tclsqlite.c
@ -133,6 +133,7 @@ struct SqliteDb {
|
|||||||
char *zBusy; /* The busy callback routine */
|
char *zBusy; /* The busy callback routine */
|
||||||
char *zCommit; /* The commit hook callback routine */
|
char *zCommit; /* The commit hook callback routine */
|
||||||
char *zTrace; /* The trace callback routine */
|
char *zTrace; /* The trace callback routine */
|
||||||
|
char *zTraceV2; /* The trace_v2 callback routine */
|
||||||
char *zProfile; /* The profile callback routine */
|
char *zProfile; /* The profile callback routine */
|
||||||
char *zProgress; /* The progress callback routine */
|
char *zProgress; /* The progress callback routine */
|
||||||
char *zAuth; /* The authorization callback routine */
|
char *zAuth; /* The authorization callback routine */
|
||||||
@ -192,7 +193,7 @@ static void closeIncrblobChannels(SqliteDb *pDb){
|
|||||||
for(p=pDb->pIncrblob; p; p=pNext){
|
for(p=pDb->pIncrblob; p; p=pNext){
|
||||||
pNext = p->pNext;
|
pNext = p->pNext;
|
||||||
|
|
||||||
/* Note: Calling unregister here call Tcl_Close on the incrblob channel,
|
/* Note: Calling unregister here call Tcl_Close on the incrblob channel,
|
||||||
** which deletes the IncrblobChannel structure at *p. So do not
|
** which deletes the IncrblobChannel structure at *p. So do not
|
||||||
** call Tcl_Free() here.
|
** call Tcl_Free() here.
|
||||||
*/
|
*/
|
||||||
@ -233,8 +234,8 @@ static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
|
|||||||
** Read data from an incremental blob channel.
|
** Read data from an incremental blob channel.
|
||||||
*/
|
*/
|
||||||
static int incrblobInput(
|
static int incrblobInput(
|
||||||
ClientData instanceData,
|
ClientData instanceData,
|
||||||
char *buf,
|
char *buf,
|
||||||
int bufSize,
|
int bufSize,
|
||||||
int *errorCodePtr
|
int *errorCodePtr
|
||||||
){
|
){
|
||||||
@ -265,8 +266,8 @@ static int incrblobInput(
|
|||||||
** Write data to an incremental blob channel.
|
** Write data to an incremental blob channel.
|
||||||
*/
|
*/
|
||||||
static int incrblobOutput(
|
static int incrblobOutput(
|
||||||
ClientData instanceData,
|
ClientData instanceData,
|
||||||
CONST char *buf,
|
CONST char *buf,
|
||||||
int toWrite,
|
int toWrite,
|
||||||
int *errorCodePtr
|
int *errorCodePtr
|
||||||
){
|
){
|
||||||
@ -298,7 +299,7 @@ static int incrblobOutput(
|
|||||||
** Seek an incremental blob channel.
|
** Seek an incremental blob channel.
|
||||||
*/
|
*/
|
||||||
static int incrblobSeek(
|
static int incrblobSeek(
|
||||||
ClientData instanceData,
|
ClientData instanceData,
|
||||||
long offset,
|
long offset,
|
||||||
int seekMode,
|
int seekMode,
|
||||||
int *errorCodePtr
|
int *errorCodePtr
|
||||||
@ -323,8 +324,8 @@ static int incrblobSeek(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void incrblobWatch(ClientData instanceData, int mode){
|
static void incrblobWatch(ClientData instanceData, int mode){
|
||||||
/* NO-OP */
|
/* NO-OP */
|
||||||
}
|
}
|
||||||
static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
|
static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
@ -352,11 +353,11 @@ static Tcl_ChannelType IncrblobChannelType = {
|
|||||||
** Create a new incrblob channel.
|
** Create a new incrblob channel.
|
||||||
*/
|
*/
|
||||||
static int createIncrblobChannel(
|
static int createIncrblobChannel(
|
||||||
Tcl_Interp *interp,
|
Tcl_Interp *interp,
|
||||||
SqliteDb *pDb,
|
SqliteDb *pDb,
|
||||||
const char *zDb,
|
const char *zDb,
|
||||||
const char *zTable,
|
const char *zTable,
|
||||||
const char *zColumn,
|
const char *zColumn,
|
||||||
sqlite_int64 iRow,
|
sqlite_int64 iRow,
|
||||||
int isReadonly
|
int isReadonly
|
||||||
){
|
){
|
||||||
@ -438,7 +439,7 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
|
|||||||
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
|
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
|
||||||
pNew->zName = (char*)&pNew[1];
|
pNew->zName = (char*)&pNew[1];
|
||||||
memcpy(pNew->zName, zName, nName+1);
|
memcpy(pNew->zName, zName, nName+1);
|
||||||
for(p=pDb->pFunc; p; p=p->pNext){
|
for(p=pDb->pFunc; p; p=p->pNext){
|
||||||
if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
|
if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
|
||||||
Tcl_Free((char*)pNew);
|
Tcl_Free((char*)pNew);
|
||||||
return p;
|
return p;
|
||||||
@ -508,6 +509,9 @@ static void DbDeleteCmd(void *db){
|
|||||||
if( pDb->zTrace ){
|
if( pDb->zTrace ){
|
||||||
Tcl_Free(pDb->zTrace);
|
Tcl_Free(pDb->zTrace);
|
||||||
}
|
}
|
||||||
|
if( pDb->zTraceV2 ){
|
||||||
|
Tcl_Free(pDb->zTraceV2);
|
||||||
|
}
|
||||||
if( pDb->zProfile ){
|
if( pDb->zProfile ){
|
||||||
Tcl_Free(pDb->zProfile);
|
Tcl_Free(pDb->zProfile);
|
||||||
}
|
}
|
||||||
@ -587,6 +591,82 @@ static void DbTraceHandler(void *cd, const char *zSql){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
|
/*
|
||||||
|
** This routine is called by the SQLite trace_v2 handler whenever a new
|
||||||
|
** supported event is generated. Unsupported event types are ignored.
|
||||||
|
** The TCL script in pDb->zTraceV2 is executed, with the arguments for
|
||||||
|
** the event appended to it (as list elements).
|
||||||
|
*/
|
||||||
|
static int DbTraceV2Handler(
|
||||||
|
unsigned type, /* One of the SQLITE_TRACE_* event types. */
|
||||||
|
void *cd, /* The original context data pointer. */
|
||||||
|
void *pd, /* Primary event data, depends on event type. */
|
||||||
|
void *xd /* Extra event data, depends on event type. */
|
||||||
|
){
|
||||||
|
SqliteDb *pDb = (SqliteDb*)cd;
|
||||||
|
Tcl_Obj *pCmd;
|
||||||
|
|
||||||
|
switch( type ){
|
||||||
|
case SQLITE_TRACE_STMT: {
|
||||||
|
sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
|
||||||
|
char *zSql = (char *)xd;
|
||||||
|
|
||||||
|
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||||
|
Tcl_IncrRefCount(pCmd);
|
||||||
|
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||||
|
Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
|
||||||
|
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||||
|
Tcl_NewStringObj(zSql, -1));
|
||||||
|
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||||
|
Tcl_DecrRefCount(pCmd);
|
||||||
|
Tcl_ResetResult(pDb->interp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_TRACE_PROFILE: {
|
||||||
|
sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
|
||||||
|
sqlite3_int64 ns = (sqlite3_int64)xd;
|
||||||
|
|
||||||
|
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||||
|
Tcl_IncrRefCount(pCmd);
|
||||||
|
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||||
|
Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
|
||||||
|
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||||
|
Tcl_NewWideIntObj((Tcl_WideInt)ns));
|
||||||
|
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||||
|
Tcl_DecrRefCount(pCmd);
|
||||||
|
Tcl_ResetResult(pDb->interp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_TRACE_ROW: {
|
||||||
|
sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
|
||||||
|
|
||||||
|
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||||
|
Tcl_IncrRefCount(pCmd);
|
||||||
|
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||||
|
Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
|
||||||
|
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||||
|
Tcl_DecrRefCount(pCmd);
|
||||||
|
Tcl_ResetResult(pDb->interp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_TRACE_CLOSE: {
|
||||||
|
sqlite3 *db = (sqlite3 *)pd;
|
||||||
|
|
||||||
|
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||||
|
Tcl_IncrRefCount(pCmd);
|
||||||
|
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||||
|
Tcl_NewWideIntObj((Tcl_WideInt)db));
|
||||||
|
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||||
|
Tcl_DecrRefCount(pCmd);
|
||||||
|
Tcl_ResetResult(pDb->interp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRACE
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
/*
|
/*
|
||||||
** This routine is called by the SQLite profile handler after a statement
|
** This routine is called by the SQLite profile handler after a statement
|
||||||
@ -637,9 +717,9 @@ static void DbRollbackHandler(void *clientData){
|
|||||||
** This procedure handles wal_hook callbacks.
|
** This procedure handles wal_hook callbacks.
|
||||||
*/
|
*/
|
||||||
static int DbWalHandler(
|
static int DbWalHandler(
|
||||||
void *clientData,
|
void *clientData,
|
||||||
sqlite3 *db,
|
sqlite3 *db,
|
||||||
const char *zDb,
|
const char *zDb,
|
||||||
int nEntry
|
int nEntry
|
||||||
){
|
){
|
||||||
int ret = SQLITE_OK;
|
int ret = SQLITE_OK;
|
||||||
@ -653,7 +733,7 @@ static int DbWalHandler(
|
|||||||
Tcl_IncrRefCount(p);
|
Tcl_IncrRefCount(p);
|
||||||
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
|
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
|
||||||
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
|
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
|
||||||
if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|
if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|
||||||
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
|
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
|
||||||
){
|
){
|
||||||
Tcl_BackgroundError(interp);
|
Tcl_BackgroundError(interp);
|
||||||
@ -695,11 +775,11 @@ static void DbUnlockNotify(void **apArg, int nArg){
|
|||||||
** Pre-update hook callback.
|
** Pre-update hook callback.
|
||||||
*/
|
*/
|
||||||
static void DbPreUpdateHandler(
|
static void DbPreUpdateHandler(
|
||||||
void *p,
|
void *p,
|
||||||
sqlite3 *db,
|
sqlite3 *db,
|
||||||
int op,
|
int op,
|
||||||
const char *zDb,
|
const char *zDb,
|
||||||
const char *zTbl,
|
const char *zTbl,
|
||||||
sqlite_int64 iKey1,
|
sqlite_int64 iKey1,
|
||||||
sqlite_int64 iKey2
|
sqlite_int64 iKey2
|
||||||
){
|
){
|
||||||
@ -727,10 +807,10 @@ static void DbPreUpdateHandler(
|
|||||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||||
|
|
||||||
static void DbUpdateHandler(
|
static void DbUpdateHandler(
|
||||||
void *p,
|
void *p,
|
||||||
int op,
|
int op,
|
||||||
const char *zDb,
|
const char *zDb,
|
||||||
const char *zTbl,
|
const char *zTbl,
|
||||||
sqlite_int64 rowid
|
sqlite_int64 rowid
|
||||||
){
|
){
|
||||||
SqliteDb *pDb = (SqliteDb *)p;
|
SqliteDb *pDb = (SqliteDb *)p;
|
||||||
@ -815,7 +895,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
|||||||
** script object, lappend the arguments, then evaluate the copy.
|
** script object, lappend the arguments, then evaluate the copy.
|
||||||
**
|
**
|
||||||
** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
|
** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
|
||||||
** The new Tcl_Obj contains pointers to the original list elements.
|
** The new Tcl_Obj contains pointers to the original list elements.
|
||||||
** That way, when Tcl_EvalObjv() is run and shimmers the first element
|
** That way, when Tcl_EvalObjv() is run and shimmers the first element
|
||||||
** of the list to tclCmdNameType, that alternate representation will
|
** of the list to tclCmdNameType, that alternate representation will
|
||||||
** be preserved and reused on the next invocation.
|
** be preserved and reused on the next invocation.
|
||||||
@ -823,15 +903,15 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
|||||||
Tcl_Obj **aArg;
|
Tcl_Obj **aArg;
|
||||||
int nArg;
|
int nArg;
|
||||||
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
|
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
|
||||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pCmd = Tcl_NewListObj(nArg, aArg);
|
pCmd = Tcl_NewListObj(nArg, aArg);
|
||||||
Tcl_IncrRefCount(pCmd);
|
Tcl_IncrRefCount(pCmd);
|
||||||
for(i=0; i<argc; i++){
|
for(i=0; i<argc; i++){
|
||||||
sqlite3_value *pIn = argv[i];
|
sqlite3_value *pIn = argv[i];
|
||||||
Tcl_Obj *pVal;
|
Tcl_Obj *pVal;
|
||||||
|
|
||||||
/* Set pVal to contain the i'th column of this row. */
|
/* Set pVal to contain the i'th column of this row. */
|
||||||
switch( sqlite3_value_type(pIn) ){
|
switch( sqlite3_value_type(pIn) ){
|
||||||
case SQLITE_BLOB: {
|
case SQLITE_BLOB: {
|
||||||
@ -866,7 +946,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
|||||||
rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
|
rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
|
||||||
if( rc ){
|
if( rc ){
|
||||||
Tcl_DecrRefCount(pCmd);
|
Tcl_DecrRefCount(pCmd);
|
||||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -881,7 +961,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( rc && rc!=TCL_RETURN ){
|
if( rc && rc!=TCL_RETURN ){
|
||||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||||
}else{
|
}else{
|
||||||
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
|
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
|
||||||
int n;
|
int n;
|
||||||
@ -983,7 +1063,7 @@ static int auth_callback(
|
|||||||
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
|
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
|
||||||
#ifdef SQLITE_USER_AUTHENTICATION
|
#ifdef SQLITE_USER_AUTHENTICATION
|
||||||
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
|
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
|
||||||
#endif
|
#endif
|
||||||
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
|
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
|
||||||
Tcl_DStringFree(&str);
|
Tcl_DStringFree(&str);
|
||||||
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
|
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
|
||||||
@ -1075,12 +1155,12 @@ static int DbTransPostCmd(
|
|||||||
pDb->disableAuth++;
|
pDb->disableAuth++;
|
||||||
if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
|
if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
|
||||||
/* This is a tricky scenario to handle. The most likely cause of an
|
/* This is a tricky scenario to handle. The most likely cause of an
|
||||||
** error is that the exec() above was an attempt to commit the
|
** error is that the exec() above was an attempt to commit the
|
||||||
** top-level transaction that returned SQLITE_BUSY. Or, less likely,
|
** top-level transaction that returned SQLITE_BUSY. Or, less likely,
|
||||||
** that an IO-error has occurred. In either case, throw a Tcl exception
|
** that an IO-error has occurred. In either case, throw a Tcl exception
|
||||||
** and try to rollback the transaction.
|
** and try to rollback the transaction.
|
||||||
**
|
**
|
||||||
** But it could also be that the user executed one or more BEGIN,
|
** But it could also be that the user executed one or more BEGIN,
|
||||||
** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
|
** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
|
||||||
** this method's logic. Not clear how this would be best handled.
|
** this method's logic. Not clear how this would be best handled.
|
||||||
*/
|
*/
|
||||||
@ -1099,7 +1179,7 @@ static int DbTransPostCmd(
|
|||||||
** Unless SQLITE_TEST is defined, this function is a simple wrapper around
|
** Unless SQLITE_TEST is defined, this function is a simple wrapper around
|
||||||
** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
|
** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
|
||||||
** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
|
** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
|
||||||
** on whether or not the [db_use_legacy_prepare] command has been used to
|
** on whether or not the [db_use_legacy_prepare] command has been used to
|
||||||
** configure the connection.
|
** configure the connection.
|
||||||
*/
|
*/
|
||||||
static int dbPrepare(
|
static int dbPrepare(
|
||||||
@ -1155,7 +1235,7 @@ static int dbPrepareAndBind(
|
|||||||
|
|
||||||
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
|
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
|
||||||
int n = pPreStmt->nSql;
|
int n = pPreStmt->nSql;
|
||||||
if( nSql>=n
|
if( nSql>=n
|
||||||
&& memcmp(pPreStmt->zSql, zSql, n)==0
|
&& memcmp(pPreStmt->zSql, zSql, n)==0
|
||||||
&& (zSql[n]==0 || zSql[n-1]==';')
|
&& (zSql[n]==0 || zSql[n-1]==';')
|
||||||
){
|
){
|
||||||
@ -1181,7 +1261,7 @@ static int dbPrepareAndBind(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no prepared statement was found. Compile the SQL text. Also allocate
|
/* If no prepared statement was found. Compile the SQL text. Also allocate
|
||||||
** a new SqlPreparedStmt structure. */
|
** a new SqlPreparedStmt structure. */
|
||||||
if( pPreStmt==0 ){
|
if( pPreStmt==0 ){
|
||||||
@ -1227,7 +1307,7 @@ static int dbPrepareAndBind(
|
|||||||
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
|
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
|
||||||
assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
|
assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
|
||||||
|
|
||||||
/* Bind values to parameters that begin with $ or : */
|
/* Bind values to parameters that begin with $ or : */
|
||||||
for(i=1; i<=nVar; i++){
|
for(i=1; i<=nVar; i++){
|
||||||
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
|
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
|
||||||
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
|
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
|
||||||
@ -1315,8 +1395,8 @@ static void dbReleaseStmt(
|
|||||||
assert( pDb->nStmt>0 );
|
assert( pDb->nStmt>0 );
|
||||||
}
|
}
|
||||||
pDb->nStmt++;
|
pDb->nStmt++;
|
||||||
|
|
||||||
/* If we have too many statement in cache, remove the surplus from
|
/* If we have too many statement in cache, remove the surplus from
|
||||||
** the end of the cache list. */
|
** the end of the cache list. */
|
||||||
while( pDb->nStmt>pDb->maxStmt ){
|
while( pDb->nStmt>pDb->maxStmt ){
|
||||||
SqlPreparedStmt *pLast = pDb->stmtLast;
|
SqlPreparedStmt *pLast = pDb->stmtLast;
|
||||||
@ -1370,8 +1450,8 @@ static void dbReleaseColumnNames(DbEvalContext *p){
|
|||||||
** If pArray is not NULL, then it contains the name of a Tcl array
|
** If pArray is not NULL, then it contains the name of a Tcl array
|
||||||
** variable. The "*" member of this array is set to a list containing
|
** variable. The "*" member of this array is set to a list containing
|
||||||
** the names of the columns returned by the statement as part of each
|
** the names of the columns returned by the statement as part of each
|
||||||
** call to dbEvalStep(), in order from left to right. e.g. if the names
|
** call to dbEvalStep(), in order from left to right. e.g. if the names
|
||||||
** of the returned columns are a, b and c, it does the equivalent of the
|
** of the returned columns are a, b and c, it does the equivalent of the
|
||||||
** tcl command:
|
** tcl command:
|
||||||
**
|
**
|
||||||
** set ${pArray}(*) {a b c}
|
** set ${pArray}(*) {a b c}
|
||||||
@ -1492,7 +1572,7 @@ static int dbEvalStep(DbEvalContext *p){
|
|||||||
#if SQLITE_TEST
|
#if SQLITE_TEST
|
||||||
if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
|
if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
|
||||||
/* If the runtime error was an SQLITE_SCHEMA, and the database
|
/* If the runtime error was an SQLITE_SCHEMA, and the database
|
||||||
** handle is configured to use the legacy sqlite3_prepare()
|
** handle is configured to use the legacy sqlite3_prepare()
|
||||||
** interface, retry prepare()/step() on the same SQL statement.
|
** interface, retry prepare()/step() on the same SQL statement.
|
||||||
** This only happens once. If there is a second SQLITE_SCHEMA
|
** This only happens once. If there is a second SQLITE_SCHEMA
|
||||||
** error, the error will be returned to the caller. */
|
** error, the error will be returned to the caller. */
|
||||||
@ -1580,11 +1660,11 @@ static int DbUseNre(void){
|
|||||||
return( (major==8 && minor>=6) || major>8 );
|
return( (major==8 && minor>=6) || major>8 );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
** Compiling using headers earlier than 8.6. In this case NR cannot be
|
** Compiling using headers earlier than 8.6. In this case NR cannot be
|
||||||
** used, so DbUseNre() to always return zero. Add #defines for the other
|
** used, so DbUseNre() to always return zero. Add #defines for the other
|
||||||
** Tcl_NRxxx() functions to prevent them from causing compilation errors,
|
** Tcl_NRxxx() functions to prevent them from causing compilation errors,
|
||||||
** even though the only invocations of them are within conditional blocks
|
** even though the only invocations of them are within conditional blocks
|
||||||
** of the form:
|
** of the form:
|
||||||
**
|
**
|
||||||
** if( DbUseNre() ) { ... }
|
** if( DbUseNre() ) { ... }
|
||||||
@ -1630,11 +1710,11 @@ static int DbEvalNextCmd(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The required interpreter variables are now populated with the data
|
/* The required interpreter variables are now populated with the data
|
||||||
** from the current row. If using NRE, schedule callbacks to evaluate
|
** from the current row. If using NRE, schedule callbacks to evaluate
|
||||||
** script pScript, then to invoke this function again to fetch the next
|
** script pScript, then to invoke this function again to fetch the next
|
||||||
** row (or clean up if there is no next row or the script throws an
|
** row (or clean up if there is no next row or the script throws an
|
||||||
** exception). After scheduling the callbacks, return control to the
|
** exception). After scheduling the callbacks, return control to the
|
||||||
** caller.
|
** caller.
|
||||||
**
|
**
|
||||||
** If not using NRE, evaluate pScript directly and continue with the
|
** If not using NRE, evaluate pScript directly and continue with the
|
||||||
@ -1659,7 +1739,7 @@ static int DbEvalNextCmd(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function is used by the implementations of the following database
|
** This function is used by the implementations of the following database
|
||||||
** handle sub-commands:
|
** handle sub-commands:
|
||||||
**
|
**
|
||||||
** $db update_hook ?SCRIPT?
|
** $db update_hook ?SCRIPT?
|
||||||
@ -1726,9 +1806,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
"preupdate", "profile", "progress",
|
"preupdate", "profile", "progress",
|
||||||
"rekey", "restore", "rollback_hook",
|
"rekey", "restore", "rollback_hook",
|
||||||
"status", "timeout", "total_changes",
|
"status", "timeout", "total_changes",
|
||||||
"trace", "transaction", "unlock_notify",
|
"trace", "trace_v2", "transaction",
|
||||||
"update_hook", "version", "wal_hook",
|
"unlock_notify", "update_hook", "version",
|
||||||
0
|
"wal_hook",
|
||||||
|
0
|
||||||
};
|
};
|
||||||
enum DB_enum {
|
enum DB_enum {
|
||||||
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
|
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
|
||||||
@ -1741,8 +1822,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
|
DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
|
||||||
DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
|
DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
|
||||||
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
||||||
DB_TRACE, DB_TRANSACTION, DB_UNLOCK_NOTIFY,
|
DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
|
||||||
DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK,
|
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 */
|
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||||
|
|
||||||
@ -1928,7 +2010,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}else{
|
}else{
|
||||||
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
|
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
|
||||||
Tcl_AppendResult( interp, "cannot convert \"",
|
Tcl_AppendResult( interp, "cannot convert \"",
|
||||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
|
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}else{
|
}else{
|
||||||
@ -1942,7 +2024,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
Tcl_AppendResult( interp, "bad option \"",
|
Tcl_AppendResult( interp, "bad option \"",
|
||||||
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
|
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
|
||||||
(char*)0);
|
(char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
@ -1953,7 +2035,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
/* $db changes
|
/* $db changes
|
||||||
**
|
**
|
||||||
** Return the number of rows that were modified, inserted, or deleted by
|
** Return the number of rows that were modified, inserted, or deleted by
|
||||||
** the most recent INSERT, UPDATE or DELETE statement, not including
|
** the most recent INSERT, UPDATE or DELETE statement, not including
|
||||||
** any changes made by trigger programs.
|
** any changes made by trigger programs.
|
||||||
*/
|
*/
|
||||||
case DB_CHANGES: {
|
case DB_CHANGES: {
|
||||||
@ -2000,7 +2082,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
pCollate->zScript = (char*)&pCollate[1];
|
pCollate->zScript = (char*)&pCollate[1];
|
||||||
pDb->pCollate = pCollate;
|
pDb->pCollate = pCollate;
|
||||||
memcpy(pCollate->zScript, zScript, nScript+1);
|
memcpy(pCollate->zScript, zScript, nScript+1);
|
||||||
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
|
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
|
||||||
pCollate, tclSqlCollate) ){
|
pCollate, tclSqlCollate) ){
|
||||||
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
|
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
@ -2126,7 +2208,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
const char *zSep;
|
const char *zSep;
|
||||||
const char *zNull;
|
const char *zNull;
|
||||||
if( objc<5 || objc>7 ){
|
if( objc<5 || objc>7 ){
|
||||||
Tcl_WrongNumArgs(interp, 2, objv,
|
Tcl_WrongNumArgs(interp, 2, objv,
|
||||||
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
@ -2155,7 +2237,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
strcmp(zConflict, "fail" ) != 0 &&
|
strcmp(zConflict, "fail" ) != 0 &&
|
||||||
strcmp(zConflict, "ignore" ) != 0 &&
|
strcmp(zConflict, "ignore" ) != 0 &&
|
||||||
strcmp(zConflict, "replace" ) != 0 ) {
|
strcmp(zConflict, "replace" ) != 0 ) {
|
||||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||||
"\", conflict-algorithm must be one of: rollback, "
|
"\", conflict-algorithm must be one of: rollback, "
|
||||||
"abort, fail, ignore, or replace", (char*)0);
|
"abort, fail, ignore, or replace", (char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
@ -2244,7 +2326,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
for(i=0; i<nCol; i++){
|
for(i=0; i<nCol; i++){
|
||||||
/* check for null data, if so, bind as null */
|
/* check for null data, if so, bind as null */
|
||||||
if( (nNull>0 && strcmp(azCol[i], zNull)==0)
|
if( (nNull>0 && strcmp(azCol[i], zNull)==0)
|
||||||
|| strlen30(azCol[i])==0
|
|| strlen30(azCol[i])==0
|
||||||
){
|
){
|
||||||
sqlite3_bind_null(pStmt, i+1);
|
sqlite3_bind_null(pStmt, i+1);
|
||||||
}else{
|
}else{
|
||||||
@ -2323,7 +2405,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
** The onecolumn method is the equivalent of:
|
** The onecolumn method is the equivalent of:
|
||||||
** lindex [$db eval $sql] 0
|
** lindex [$db eval $sql] 0
|
||||||
*/
|
*/
|
||||||
case DB_EXISTS:
|
case DB_EXISTS:
|
||||||
case DB_ONECOLUMN: {
|
case DB_ONECOLUMN: {
|
||||||
Tcl_Obj *pResult = 0;
|
Tcl_Obj *pResult = 0;
|
||||||
DbEvalContext sEval;
|
DbEvalContext sEval;
|
||||||
@ -2351,7 +2433,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db eval $sql ?array? ?{ ...code... }?
|
** $db eval $sql ?array? ?{ ...code... }?
|
||||||
**
|
**
|
||||||
@ -2397,7 +2479,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
}
|
}
|
||||||
pScript = objv[objc-1];
|
pScript = objv[objc-1];
|
||||||
Tcl_IncrRefCount(pScript);
|
Tcl_IncrRefCount(pScript);
|
||||||
|
|
||||||
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
|
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
|
||||||
dbEvalInit(p, pDb, objv[2], pArray);
|
dbEvalInit(p, pDb, objv[2], pArray);
|
||||||
|
|
||||||
@ -2444,7 +2526,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
if( n>2 && strncmp(z, "-deterministic",n)==0 ){
|
if( n>2 && strncmp(z, "-deterministic",n)==0 ){
|
||||||
flags |= SQLITE_DETERMINISTIC;
|
flags |= SQLITE_DETERMINISTIC;
|
||||||
}else{
|
}else{
|
||||||
Tcl_AppendResult(interp, "bad option \"", z,
|
Tcl_AppendResult(interp, "bad option \"", z,
|
||||||
"\": must be -argcount or -deterministic", 0
|
"\": must be -argcount or -deterministic", 0
|
||||||
);
|
);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
@ -2553,7 +2635,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db last_insert_rowid
|
** $db last_insert_rowid
|
||||||
**
|
**
|
||||||
** Return an integer which is the ROWID for the most recent insert.
|
** Return an integer which is the ROWID for the most recent insert.
|
||||||
*/
|
*/
|
||||||
@ -2575,7 +2657,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* $db progress ?N CALLBACK?
|
/* $db progress ?N CALLBACK?
|
||||||
**
|
**
|
||||||
** Invoke the given callback every N virtual machine opcodes while executing
|
** Invoke the given callback every N virtual machine opcodes while executing
|
||||||
** queries.
|
** queries.
|
||||||
*/
|
*/
|
||||||
@ -2682,7 +2764,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
|
|
||||||
/* $db restore ?DATABASE? FILENAME
|
/* $db restore ?DATABASE? FILENAME
|
||||||
**
|
**
|
||||||
** Open a database file named FILENAME. Transfer the content
|
** Open a database file named FILENAME. Transfer the content
|
||||||
** of FILENAME into the local database DATABASE (default: "main").
|
** of FILENAME into the local database DATABASE (default: "main").
|
||||||
*/
|
*/
|
||||||
case DB_RESTORE: {
|
case DB_RESTORE: {
|
||||||
@ -2743,7 +2825,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
/*
|
/*
|
||||||
** $db status (step|sort|autoindex)
|
** $db status (step|sort|autoindex)
|
||||||
**
|
**
|
||||||
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
|
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
|
||||||
** SQLITE_STMTSTATUS_SORT for the most recent eval.
|
** SQLITE_STMTSTATUS_SORT for the most recent eval.
|
||||||
*/
|
*/
|
||||||
case DB_STATUS: {
|
case DB_STATUS: {
|
||||||
@ -2761,15 +2843,15 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
}else if( strcmp(zOp, "autoindex")==0 ){
|
}else if( strcmp(zOp, "autoindex")==0 ){
|
||||||
v = pDb->nIndex;
|
v = pDb->nIndex;
|
||||||
}else{
|
}else{
|
||||||
Tcl_AppendResult(interp,
|
Tcl_AppendResult(interp,
|
||||||
"bad argument: should be autoindex, step, or sort",
|
"bad argument: should be autoindex, step, or sort",
|
||||||
(char*)0);
|
(char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
|
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db timeout MILLESECONDS
|
** $db timeout MILLESECONDS
|
||||||
**
|
**
|
||||||
@ -2785,11 +2867,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
sqlite3_busy_timeout(pDb->db, ms);
|
sqlite3_busy_timeout(pDb->db, ms);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db total_changes
|
** $db total_changes
|
||||||
**
|
**
|
||||||
** Return the number of rows that were modified, inserted, or deleted
|
** Return the number of rows that were modified, inserted, or deleted
|
||||||
** since the database handle was created.
|
** since the database handle was created.
|
||||||
*/
|
*/
|
||||||
case DB_TOTAL_CHANGES: {
|
case DB_TOTAL_CHANGES: {
|
||||||
@ -2842,6 +2924,53 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* $db trace_v2 ?CALLBACK? ?MASK?
|
||||||
|
**
|
||||||
|
** Make arrangements to invoke the CALLBACK routine for each trace event
|
||||||
|
** matching the mask that is generated. The parameters are appended to
|
||||||
|
** CALLBACK before it is executed.
|
||||||
|
*/
|
||||||
|
case DB_TRACE_V2: {
|
||||||
|
if( objc>4 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}else if( objc==2 ){
|
||||||
|
if( pDb->zTraceV2 ){
|
||||||
|
Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Tcl_WideInt wMask;
|
||||||
|
char *zTraceV2;
|
||||||
|
int len;
|
||||||
|
if( objc==4 ){
|
||||||
|
if( TCL_OK!=Tcl_GetWideIntFromObj(interp, objv[3], &wMask) ){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
wMask = SQLITE_TRACE_STMT;
|
||||||
|
}
|
||||||
|
if( pDb->zTraceV2 ){
|
||||||
|
Tcl_Free(pDb->zTraceV2);
|
||||||
|
}
|
||||||
|
zTraceV2 = Tcl_GetStringFromObj(objv[2], &len);
|
||||||
|
if( zTraceV2 && len>0 ){
|
||||||
|
pDb->zTraceV2 = Tcl_Alloc( len + 1 );
|
||||||
|
memcpy(pDb->zTraceV2, zTraceV2, len+1);
|
||||||
|
}else{
|
||||||
|
pDb->zTraceV2 = 0;
|
||||||
|
}
|
||||||
|
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||||
|
if( pDb->zTraceV2 ){
|
||||||
|
pDb->interp = interp;
|
||||||
|
sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb);
|
||||||
|
}else{
|
||||||
|
sqlite3_trace_v2(pDb->db, 0, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
|
/* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
|
||||||
**
|
**
|
||||||
** Start a new transaction (if we are not already in the midst of a
|
** Start a new transaction (if we are not already in the midst of a
|
||||||
@ -2894,7 +3023,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
/* If using NRE, schedule a callback to invoke the script pScript, then
|
/* If using NRE, schedule a callback to invoke the script pScript, then
|
||||||
** a second callback to commit (or rollback) the transaction or savepoint
|
** a second callback to commit (or rollback) the transaction or savepoint
|
||||||
** opened above. If not using NRE, evaluate the script directly, then
|
** opened above. If not using NRE, evaluate the script directly, then
|
||||||
** call function DbTransPostCmd() to commit (or rollback) the transaction
|
** call function DbTransPostCmd() to commit (or rollback) the transaction
|
||||||
** or savepoint. */
|
** or savepoint. */
|
||||||
if( DbUseNre() ){
|
if( DbUseNre() ){
|
||||||
Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
|
Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
|
||||||
@ -2925,14 +3054,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
Tcl_DecrRefCount(pDb->pUnlockNotify);
|
Tcl_DecrRefCount(pDb->pUnlockNotify);
|
||||||
pDb->pUnlockNotify = 0;
|
pDb->pUnlockNotify = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( objc==3 ){
|
if( objc==3 ){
|
||||||
xNotify = DbUnlockNotify;
|
xNotify = DbUnlockNotify;
|
||||||
pNotifyArg = (void *)pDb;
|
pNotifyArg = (void *)pDb;
|
||||||
pDb->pUnlockNotify = objv[2];
|
pDb->pUnlockNotify = objv[2];
|
||||||
Tcl_IncrRefCount(pDb->pUnlockNotify);
|
Tcl_IncrRefCount(pDb->pUnlockNotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
|
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
|
||||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||||
rc = TCL_ERROR;
|
rc = TCL_ERROR;
|
||||||
@ -3031,13 +3160,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
** $db update_hook ?script?
|
** $db update_hook ?script?
|
||||||
** $db rollback_hook ?script?
|
** $db rollback_hook ?script?
|
||||||
*/
|
*/
|
||||||
case DB_WAL_HOOK:
|
case DB_WAL_HOOK:
|
||||||
case DB_UPDATE_HOOK:
|
case DB_UPDATE_HOOK:
|
||||||
case DB_ROLLBACK_HOOK: {
|
case DB_ROLLBACK_HOOK: {
|
||||||
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
|
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
|
||||||
** whether [$db update_hook] or [$db rollback_hook] was invoked.
|
** whether [$db update_hook] or [$db rollback_hook] was invoked.
|
||||||
*/
|
*/
|
||||||
Tcl_Obj **ppHook = 0;
|
Tcl_Obj **ppHook = 0;
|
||||||
if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook;
|
if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook;
|
||||||
if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook;
|
if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook;
|
||||||
if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook;
|
if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook;
|
||||||
@ -3198,7 +3327,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( objc<3 || (objc&1)!=1 ){
|
if( objc<3 || (objc&1)!=1 ){
|
||||||
Tcl_WrongNumArgs(interp, 1, objv,
|
Tcl_WrongNumArgs(interp, 1, objv,
|
||||||
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
|
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
|
||||||
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
|
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
|
||||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||||
@ -3490,7 +3619,7 @@ static void MD5Init(MD5Context *ctx){
|
|||||||
* Update context to reflect the concatenation of another buffer full
|
* Update context to reflect the concatenation of another buffer full
|
||||||
* of bytes.
|
* of bytes.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||||
uint32 t;
|
uint32 t;
|
||||||
|
|
||||||
@ -3536,7 +3665,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||||
*/
|
*/
|
||||||
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
||||||
@ -3612,7 +3741,7 @@ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** A TCL command for md5. The argument is the text to be hashed. The
|
** A TCL command for md5. The argument is the text to be hashed. The
|
||||||
** Result is the hash in base64.
|
** Result is the hash in base64.
|
||||||
*/
|
*/
|
||||||
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
||||||
MD5Context ctx;
|
MD5Context ctx;
|
||||||
@ -3621,7 +3750,7 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
|||||||
void (*converter)(unsigned char*, char*);
|
void (*converter)(unsigned char*, char*);
|
||||||
|
|
||||||
if( argc!=2 ){
|
if( argc!=2 ){
|
||||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||||
" TEXT\"", (char*)0);
|
" TEXT\"", (char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
@ -3646,13 +3775,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
|
|||||||
char zBuf[10240];
|
char zBuf[10240];
|
||||||
|
|
||||||
if( argc!=2 ){
|
if( argc!=2 ){
|
||||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||||
" FILENAME\"", (char*)0);
|
" FILENAME\"", (char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
in = fopen(argv[1],"rb");
|
in = fopen(argv[1],"rb");
|
||||||
if( in==0 ){
|
if( in==0 ){
|
||||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||||
"\" for reading", (char*)0);
|
"\" for reading", (char*)0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
@ -3719,7 +3848,7 @@ static void md5finalize(sqlite3_context *context){
|
|||||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
int Md5_Register(sqlite3 *db){
|
int Md5_Register(sqlite3 *db){
|
||||||
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
||||||
md5step, md5finalize);
|
md5step, md5finalize);
|
||||||
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
|
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
|
||||||
return rc;
|
return rc;
|
||||||
@ -3870,7 +3999,7 @@ static int db_last_stmt_ptr(
|
|||||||
** Configure the interpreter passed as the first argument to have access
|
** Configure the interpreter passed as the first argument to have access
|
||||||
** to the commands and linked variables that make up:
|
** to the commands and linked variables that make up:
|
||||||
**
|
**
|
||||||
** * the [sqlite3] extension itself,
|
** * the [sqlite3] extension itself,
|
||||||
**
|
**
|
||||||
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
|
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
|
||||||
**
|
**
|
||||||
|
Reference in New Issue
Block a user