tclsqlite.c

来自「sqlite最新源码」· C语言 代码 · 共 2,068 行 · 第 1/5 页

C
2,068
字号
          /* 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_v2(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]==':' || 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( zVar[0]=='@' ||               (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){              /* Load a BLOB type if the Tcl variable is a bytearray and              ** it has no string representation or the host              ** parameter name begins with "@". */              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 ){              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) ||                  (c=='i' && strcmp(zType,"int")==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 );          }        }      }      /* Execute the SQL      */      while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){	/* Compute column names. This must be done after the first successful	** call to sqlite3_step(), in case the query is recompiled and the        ** number or names of the returned columns changes.         */        assert(!pArray||pScript);        if (nCol < 0) {          Tcl_Obj ***ap = (pScript?&apColName:0);          nCol = computeColumnNames(interp, pStmt, ap, pArray);        }        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);              const char *zBlob = sqlite3_column_blob(pStmt, i);              if( !zBlob ) bytes = 0;              pVal = Tcl_NewByteArrayObj((u8*)zBlob, 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 ){          pDb->nStep = sqlite3_stmt_status(pStmt,                                   SQLITE_STMTSTATUS_FULLSCAN_STEP, 0);          pDb->nSort = sqlite3_stmt_status(pStmt,                                  SQLITE_STMTSTATUS_SORT, 0);          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 ){        /* If the query returned no rows, but an array variable was         ** specified, call computeColumnNames() now to populate the         ** arrayname(*) variable.        */        if (pArray && nCol < 0) {          Tcl_Obj ***ap = (pScript?&apColName:0);          nCol = computeColumnNames(interp, pStmt, ap, pArray);        }        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);      pDb->nStep = sqlite3_stmt_status(pStmt,                                   SQLITE_STMTSTATUS_FULLSCAN_STEP, 1);      pDb->nSort = sqlite3_stmt_status(pStmt,                                  SQLITE_STMTSTATUS_SORT, 1);      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) );          if( pPreStmt==0 ) return TCL_ERROR;          pPreStmt->pStmt = pStmt;          pPreStmt->nSql = len;          pPreStmt->zSql = sqlite3_sql(pStmt);          assert( strlen30(pPreStmt->zSql)==len );          assert( 0==memcmp(pPreStmt->zSql, zSql, len) );        }        /* 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 [-argcount N] 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;    int nArg = -1;    if( objc==6 ){      const char *z = Tcl_GetString(objv[3]);      int n = strlen30(z);      if( n>2 && strncmp(z, "-argcount",n)==0 ){        if( Tcl_GetIntFromObj(interp, objv[4], &nArg) ) return TCL_ERROR;        if( nArg<0 ){          Tcl_AppendResult(interp, "number of arguments must be non-negative",                           (char*)0);          return TCL_ERROR;        }      }      pScript = objv[5];    }else if( objc!=4 ){      Tcl_WrongNumArgs(interp, 2, objv, "NAME [-argcount N] SCRIPT");      return TCL_ERROR;    }else{      pScript = objv[3];    }    zName = Tcl_GetStringFromObj(objv[2], 0);    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, nArg, SQLITE_UTF8,        pFunc, tclSqlFunc, 0, 0);    if( rc!=SQLITE_OK ){      rc = TCL_ERROR;      Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);    }    break;  }  /*  **     $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID  */  case DB_INCRBLOB: {#ifdef SQLITE_OMIT_INCRBLOB    Tcl_AppendResult(interp, "incrblob not available in this build", 0);    return TCL_ERROR;#else    int isReadonly = 0;    const char *zDb = "main";    const char *zTable;    const char *zColumn;    sqlite_int64 iRow;    /* Check for the -readonly option */    if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){      isReadonly = 1;    }    if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){      Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID");      return TCL_ERROR;    }    if( objc==(6+isReadonly) ){      zDb = Tcl_GetString(objv[2]);    }    zTable = Tcl_GetString(objv[objc-3]);    zColumn = Tcl_GetString(objv[objc-2]);    rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow);    if( rc==TCL_OK ){      rc = createIncrblobChannel(          interp, pDb, zDb, zTable, zColumn, iRow, isReadonly      );    }#endif    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 );        strn

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?