?? tclsqlite.c
字號(hào):
return TCL_ERROR;
}
if( choice==DB_EXISTS ){
pRet = Tcl_NewBooleanObj(0);
Tcl_IncrRefCount(pRet);
}else{
pRet = 0;
}
}
if( objc==3 ){
pArray = pScript = 0;
}else if( objc==4 ){
pArray = 0;
pScript = objv[3];
}else{
pArray = objv[3];
if( Tcl_GetString(pArray)[0]==0 ) pArray = 0;
pScript = objv[4];
}
Tcl_IncrRefCount(objv[2]);
zSql = Tcl_GetStringFromObj(objv[2], 0);
while( rc==TCL_OK && zSql[0] ){
int i; /* Loop counter */
int nVar; /* Number of bind parameters in the pStmt */
int nCol; /* Number of columns in the result set */
Tcl_Obj **apColName = 0; /* Array of column names */
int len; /* String length of zSql */
/* Try to find a SQL statement that has already been compiled and
** which matches the next sequence of SQL.
*/
pStmt = 0;
pPreStmt = pDb->stmtList;
len = strlen(zSql);
if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){
flushStmtCache(pDb);
pPreStmt = 0;
}
for(; pPreStmt; pPreStmt=pPreStmt->pNext){
int n = pPreStmt->nSql;
if( len>=n
&& memcmp(pPreStmt->zSql, zSql, n)==0
&& (zSql[n]==0 || zSql[n-1]==';')
){
pStmt = pPreStmt->pStmt;
zLeft = &zSql[pPreStmt->nSql];
/* When a prepared statement is found, unlink it from the
** cache list. It will later be added back to the beginning
** of the cache list in order to implement LRU replacement.
*/
if( pPreStmt->pPrev ){
pPreStmt->pPrev->pNext = pPreStmt->pNext;
}else{
pDb->stmtList = pPreStmt->pNext;
}
if( pPreStmt->pNext ){
pPreStmt->pNext->pPrev = pPreStmt->pPrev;
}else{
pDb->stmtLast = pPreStmt->pPrev;
}
pDb->nStmt--;
break;
}
}
/* If no prepared statement was found. Compile the SQL text
*/
if( pStmt==0 ){
if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
rc = TCL_ERROR;
break;
}
if( pStmt==0 ){
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
/* A compile-time error in the statement
*/
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
rc = TCL_ERROR;
break;
}else{
/* The statement was a no-op. Continue to the next statement
** in the SQL string.
*/
zSql = zLeft;
continue;
}
}
assert( pPreStmt==0 );
}
/* Bind values to parameters that begin with $ or :
*/
nVar = sqlite3_bind_parameter_count(pStmt);
nParm = 0;
if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){
apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0]));
}else{
apParm = aParm;
}
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){
Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0);
if( pVar ){
int n;
u8 *data;
char *zType = pVar->typePtr ? pVar->typePtr->name : "";
char c = zType[0];
if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
/* Only load a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
data = Tcl_GetByteArrayFromObj(pVar, &n);
sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
apParm[nParm++] = pVar;
}else if( (c=='b' && strcmp(zType,"boolean")==0) ||
(c=='i' && strcmp(zType,"int")==0) ){
Tcl_GetIntFromObj(interp, pVar, &n);
sqlite3_bind_int(pStmt, i, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
Tcl_GetDoubleFromObj(interp, pVar, &r);
sqlite3_bind_double(pStmt, i, r);
}else if( c=='w' && strcmp(zType,"wideInt")==0 ){
Tcl_WideInt v;
Tcl_GetWideIntFromObj(interp, pVar, &v);
sqlite3_bind_int64(pStmt, i, v);
}else{
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
apParm[nParm++] = pVar;
}
}else{
sqlite3_bind_null( pStmt, i );
}
}
}
/* Compute column names */
nCol = sqlite3_column_count(pStmt);
if( pScript ){
apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
if( apColName==0 ) break;
for(i=0; i<nCol; i++){
apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i));
Tcl_IncrRefCount(apColName[i]);
}
}
/* If results are being stored in an array variable, then create
** the array(*) entry for that array
*/
if( pArray ){
Tcl_Obj *pColList = Tcl_NewObj();
Tcl_Obj *pStar = Tcl_NewStringObj("*", -1);
Tcl_IncrRefCount(pColList);
for(i=0; i<nCol; i++){
Tcl_ListObjAppendElement(interp, pColList, apColName[i]);
}
Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0);
Tcl_DecrRefCount(pColList);
Tcl_DecrRefCount(pStar);
}
/* Execute the SQL
*/
while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){
for(i=0; i<nCol; i++){
Tcl_Obj *pVal;
/* Set pVal to contain the i'th column of this row. */
switch( sqlite3_column_type(pStmt, i) ){
case SQLITE_BLOB: {
int bytes = sqlite3_column_bytes(pStmt, i);
pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes);
break;
}
case SQLITE_INTEGER: {
sqlite_int64 v = sqlite3_column_int64(pStmt, i);
if( v>=-2147483647 && v<=2147483647 ){
pVal = Tcl_NewIntObj(v);
}else{
pVal = Tcl_NewWideIntObj(v);
}
break;
}
case SQLITE_FLOAT: {
double r = sqlite3_column_double(pStmt, i);
pVal = Tcl_NewDoubleObj(r);
break;
}
case SQLITE_NULL: {
pVal = dbTextToObj(pDb->zNull);
break;
}
default: {
pVal = dbTextToObj((char *)sqlite3_column_text(pStmt, i));
break;
}
}
if( pScript ){
if( pArray==0 ){
Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0);
}else{
Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0);
}
}else if( choice==DB_ONECOLUMN ){
assert( pRet==0 );
if( pRet==0 ){
pRet = pVal;
Tcl_IncrRefCount(pRet);
}
rc = TCL_BREAK;
i = nCol;
}else if( choice==DB_EXISTS ){
Tcl_DecrRefCount(pRet);
pRet = Tcl_NewBooleanObj(1);
Tcl_IncrRefCount(pRet);
rc = TCL_BREAK;
i = nCol;
}else{
Tcl_ListObjAppendElement(interp, pRet, pVal);
}
}
if( pScript ){
rc = Tcl_EvalObjEx(interp, pScript, 0);
if( rc==TCL_CONTINUE ){
rc = TCL_OK;
}
}
}
if( rc==TCL_BREAK ){
rc = TCL_OK;
}
/* Free the column name objects */
if( pScript ){
for(i=0; i<nCol; i++){
Tcl_DecrRefCount(apColName[i]);
}
Tcl_Free((char*)apColName);
}
/* Free the bound string and blob parameters */
for(i=0; i<nParm; i++){
Tcl_DecrRefCount(apParm[i]);
}
if( apParm!=aParm ){
Tcl_Free((char*)apParm);
}
/* Reset the statement. If the result code is SQLITE_SCHEMA, then
** flush the statement cache and try the statement again.
*/
rc2 = sqlite3_reset(pStmt);
if( SQLITE_SCHEMA==rc2 ){
/* After a schema change, flush the cache and try to run the
** statement again
*/
flushStmtCache( pDb );
sqlite3_finalize(pStmt);
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
continue;
}else if( SQLITE_OK!=rc2 ){
/* If a run-time error occurs, report the error and stop reading
** the SQL
*/
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
sqlite3_finalize(pStmt);
rc = TCL_ERROR;
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
break;
}else if( pDb->maxStmt<=0 ){
/* If the cache is turned off, deallocated the statement */
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
sqlite3_finalize(pStmt);
}else{
/* Everything worked and the cache is operational.
** Create a new SqlPreparedStmt structure if we need one.
** (If we already have one we can just reuse it.)
*/
if( pPreStmt==0 ){
len = zLeft - zSql;
pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len );
if( pPreStmt==0 ) return TCL_ERROR;
pPreStmt->pStmt = pStmt;
pPreStmt->nSql = len;
memcpy(pPreStmt->zSql, zSql, len);
pPreStmt->zSql[len] = 0;
}
/* Add the prepared statement to the beginning of the cache list
*/
pPreStmt->pNext = pDb->stmtList;
pPreStmt->pPrev = 0;
if( pDb->stmtList ){
pDb->stmtList->pPrev = pPreStmt;
}
pDb->stmtList = pPreStmt;
if( pDb->stmtLast==0 ){
assert( pDb->nStmt==0 );
pDb->stmtLast = pPreStmt;
}else{
assert( pDb->nStmt>0 );
}
pDb->nStmt++;
/* If we have too many statement in cache, remove the surplus from the
** end of the cache list.
*/
while( pDb->nStmt>pDb->maxStmt ){
sqlite3_finalize(pDb->stmtLast->pStmt);
pDb->stmtLast = pDb->stmtLast->pPrev;
Tcl_Free((char*)pDb->stmtLast->pNext);
pDb->stmtLast->pNext = 0;
pDb->nStmt--;
}
}
/* Proceed to the next statement */
zSql = zLeft;
}
Tcl_DecrRefCount(objv[2]);
if( pRet ){
if( rc==TCL_OK ){
Tcl_SetObjResult(interp, pRet);
}
Tcl_DecrRefCount(pRet);
}else if( rc==TCL_OK ){
Tcl_ResetResult(interp);
}
break;
}
/*
** $db function NAME SCRIPT
**
** Create a new SQL function called NAME. Whenever that function is
** called, invoke SCRIPT to evaluate the function.
*/
case DB_FUNCTION: {
SqlFunc *pFunc;
Tcl_Obj *pScript;
char *zName;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
return TCL_ERROR;
}
zName = Tcl_GetStringFromObj(objv[2], 0);
pScript = objv[3];
pFunc = findSqlFunc(pDb, zName);
if( pFunc==0 ) return TCL_ERROR;
if( pFunc->pScript ){
Tcl_DecrRefCount(pFunc->pScript);
}
pFunc->pScript = pScript;
Tcl_IncrRefCount(pScript);
pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8,
pFunc, tclSqlFunc, 0, 0);
if( rc!=SQLITE_OK ){
rc = TCL_ERROR;
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
}else{
/* Must flush any cached statements */
flushStmtCache( pDb );
}
break;
}
/*
** $db interrupt
**
** Interrupt the execution of the inner-most SQL interpreter. This
** causes the SQL statement to return an error of SQLITE_INTERRUPT.
*/
case DB_INTERRUPT: {
sqlite3_interrupt(pDb->db);
break;
}
/*
** $db nullvalue ?STRING?
**
** Change text used when a NULL comes back from the database. If ?STRING?
** is not present, then the current string used for NULL is returned.
** If STRING is present, then STRING is returned.
**
*/
case DB_NULLVALUE: {
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
return TCL_ERROR;
}
if( objc==3 ){
int len;
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
if( zNull && len>0 ){
pDb->zNull = Tcl_Alloc( len + 1 );
strncpy(pDb->zNull, zNull, len);
pDb->zNull[len] = '\0';
}else{
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -