勇芳软件工作室.汉化:  SQLite3 API Functions > Database Connection >

sqlite3_prepare_v2

Previous pageReturn to chapter overviewNext page

描述

 

要执行SQL查询,必须首先使用其中一个准备函数将其编译成字节码程序。

 

C / C ++语法

 

int sqlite3_prepare_v2(

sqlite3 *db,

const char *zSql,

int nByte,

sqlite3_stmt **ppStmt,

const char **pzTail

);

 

PB语法

 

FUNCTION sqlite3_prepare_v2 ( _

BYVAL hDbc AS DWORD, _

BYREF szSql AS ASCIIZ, _

BYVAL nBytes AS LONG, _

BYREF ppStmt AS DWORD, _

BYREF pszTail AS DWORD _

) AS LONG

 

参数

 

pDb

 

[in]数据库连接句柄。必须是从sqlite3_opensqlite3_open16sqlite3_open_v2获取的sqlite3对象指针。 数据库连接不能关闭。

 

szSql

 

[in]要编译的语句,编码为UTF-8。

 

nBytes

 

[in]如果为nbytes参数小于零,则szSql读取到第一个零终止符。如果为nbytes为非负数,则为从szSql读取的最大字节数。当为nbytes为非负数时,szSql字符串以第一个“\\ 000”或“\\ u0000”字符或第nB字节结尾,以先到者为准。如果调用者知道提供的字符串是非终止的,那么通过传递等于输入字符串中包含Nul-Terminator字节的字节数的为nbytes参数可以获得较小的性能优势,因为这样保存SQLite不必制作输入字符串的副本。

 

ppStmt

 

[inout]ppStmt指向可以使用sqlite3_step执行的编译准备语句。如果有错误,ppStmt设置为NULL。如果输入文本不包含SQL(如果输入是空字符串或注释),则ppStmt设置为NULL。调用过程完成后,负责使用sqlite3_finalize删除编译的SQL语句。ppStmt可能不为空。

 

pszTail

 

[in]如果pzTail不为NULL,则指向szSql中第一个SQL语句结尾的第一个字节。这些函数仅在szSql中编译第一个语句,因此pzTail指向未编译的内容。

 

返回值

 

如果成功返回SQLITE_OK,否则返回错误代码。

 

C ++实现代码

 

/*

** Compile the UTF-8 encoded SQL statement zSql into a statement handle.

*/

static int sqlite3Prepare(

sqlite3 *db,              /* Database handle. */

const char *zSql,         /* UTF-8 encoded SQL statement. */

int nBytes,               /* Length of zSql in bytes. */

int saveSqlFlag,          /* True to copy SQL text into the sqlite3_stmt */

Vdbe *pReprepare,         /* VM being reprepared */

sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */

const char **pzTail       /* OUT: End of parsed string */

){

Parse *pParse;            /* Parsing context */

char *zErrMsg = 0;        /* Error message */

int rc = SQLITE_OK;       /* Result code */

int i;                    /* Loop counter */

 

/* Allocate the parsing context */

pParse = sqlite3StackAllocZero(db, sizeof(*pParse));

if( pParse==0 ){

  rc = SQLITE_NOMEM;

  goto end_prepare;

}

pParse->pReprepare = pReprepare;

assert( ppStmt && *ppStmt==0 );

assert( !db->mallocFailed );

assert( sqlite3_mutex_held(db->mutex) );

 

/* Check to verify that it is possible to get a read lock on all

** database schemas.  The inability to get a read lock indicates that

** some other database connection is holding a write-lock, which in

** turn means that the other connection has made uncommitted changes

** to the schema.

**

** Were we to proceed and prepare the statement against the uncommitted

** schema changes and if those schema changes are subsequently rolled

** back and different changes are made in their place, then when this

** prepared statement goes to run the schema cookie would fail to detect

** the schema change.  Disaster would follow.

**

** This thread is currently holding mutexes on all Btrees (because

** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it

** is not possible for another thread to start a new schema change

** while this function is running.  Hence, we do not need to hold

** locks on the schema, we just need to make sure nobody else is

** holding them.

**

** Note that setting READ_UNCOMMITTED overrides most lock detection,

** but it does *not* override schema lock detection, so this all still

** works even if READ_UNCOMMITTED is set.

*/

for(i=0; i<db->nDb; i++) {

  Btree *pBt = db->aDb[i].pBt;

  if( pBt ){

    assert( sqlite3BtreeHoldsMutex(pBt) );

    rc = sqlite3BtreeSchemaLocked(pBt);

    if( rc ){

      const char *zDb = db->aDb[i].zName;

      sqlite3Error(db, rc, "database schema is locked: %s", zDb);

      testcase( db->flags & SQLITE_ReadUncommitted );

      goto end_prepare;

    }

  }

}

 

sqlite3VtabUnlockList(db);

 

pParse->db = db;

pParse->nQueryLoop = (double)1;

if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){

  char *zSqlCopy;

  int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];

  testcase( nBytes==mxLen );

  testcase( nBytes==mxLen+1 );

  if( nBytes>mxLen ){

    sqlite3Error(db, SQLITE_TOOBIG, "statement too long");

    rc = sqlite3ApiExit(db, SQLITE_TOOBIG);

    goto end_prepare;

  }

  zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);

  if( zSqlCopy ){

    sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);

    sqlite3DbFree(db, zSqlCopy);

    pParse->zTail = &zSql[pParse->zTail-zSqlCopy];

  }else{

    pParse->zTail = &zSql[nBytes];

  }

}else{

  sqlite3RunParser(pParse, zSql, &zErrMsg);

}

assert( 1==(int)pParse->nQueryLoop );

 

if( db->mallocFailed ){

  pParse->rc = SQLITE_NOMEM;

}

if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;

if( pParse->checkSchema ){

  schemaIsValid(pParse);

}

if( db->mallocFailed ){

  pParse->rc = SQLITE_NOMEM;

}

if( pzTail ){

  *pzTail = pParse->zTail;

}

rc = pParse->rc;

 

#ifndef SQLITE_OMIT_EXPLAIN

if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){

  static const char * const azColName[] = {

     "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",

     "selectid", "order", "from", "detail"

  };

  int iFirst, mx;

  if( pParse->explain==2 ){

    sqlite3VdbeSetNumCols(pParse->pVdbe, 4);

    iFirst = 8;

    mx = 12;

  }else{

    sqlite3VdbeSetNumCols(pParse->pVdbe, 8);

    iFirst = 0;

    mx = 8;

  }

  for(i=iFirst; i<mx; i++){

    sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,

                          azColName[i], SQLITE_STATIC);

  }

}

#endif

 

assert( db->init.busy==0 || saveSqlFlag==0 );

if( db->init.busy==0 ){

  Vdbe *pVdbe = pParse->pVdbe;

  sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);

}

if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){

  sqlite3VdbeFinalize(pParse->pVdbe);

  assert(!(*ppStmt));

}else{

  *ppStmt = (sqlite3_stmt*)pParse->pVdbe;

}

 

if( zErrMsg ){

  sqlite3Error(db, rc, "%s", zErrMsg);

  sqlite3DbFree(db, zErrMsg);

}else{

  sqlite3Error(db, rc, 0);

}

 

/* Delete any TriggerPrg structures allocated while parsing this statement. */

while( pParse->pTriggerPrg ){

  TriggerPrg *pT = pParse->pTriggerPrg;

  pParse->pTriggerPrg = pT->pNext;

  sqlite3DbFree(db, pT);

}

 

end_prepare:

 

sqlite3StackFree(db, pParse);

rc = sqlite3ApiExit(db, rc);

assert( (rc&db->errMask)==rc );

return rc;

}

static int sqlite3LockAndPrepare(

sqlite3 *db,              /* Database handle. */

const char *zSql,         /* UTF-8 encoded SQL statement. */

int nBytes,               /* Length of zSql in bytes. */

int saveSqlFlag,          /* True to copy SQL text into the sqlite3_stmt */

Vdbe *pOld,               /* VM being reprepared */

sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */

const char **pzTail       /* OUT: End of parsed string */

){

int rc;

assert( ppStmt!=0 );

*ppStmt = 0;

if( !sqlite3SafetyCheckOk(db) ){

  return SQLITE_MISUSE_BKPT;

}

sqlite3_mutex_enter(db->mutex);

sqlite3BtreeEnterAll(db);

rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);

if( rc==SQLITE_SCHEMA ){

  sqlite3_finalize(*ppStmt);

  rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);

}

sqlite3BtreeLeaveAll(db);

sqlite3_mutex_leave(db->mutex);

assert( rc==SQLITE_OK || *ppStmt==0 );

return rc;

}

 

/*

** Two versions of the official API.  Legacy and new use.  In the legacy

** version, the original SQL text is not saved in the prepared statement

** and so if a schema change occurs, SQLITE_SCHEMA is returned by

** sqlite3_step().  In the new version, the original SQL text is retained

** and the statement is automatically recompiled if an schema change

** occurs.

*/

SQLITE_API int sqlite3_prepare(

sqlite3 *db,              /* Database handle. */

const char *zSql,         /* UTF-8 encoded SQL statement. */

int nBytes,               /* Length of zSql in bytes. */

sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */

const char **pzTail       /* OUT: End of parsed string */

){

int rc;

rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail);

assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */

return rc;

}

SQLITE_API int sqlite3_prepare_v2(

sqlite3 *db,              /* Database handle. */

const char *zSql,         /* UTF-8 encoded SQL statement. */

int nBytes,               /* Length of zSql in bytes. */

sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */

const char **pzTail       /* OUT: End of parsed string */

){

int rc;

rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);

assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */

return rc;

}