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

sqlite3_blob_open

Previous pageReturn to chapter overviewNext page

描述

 

此函数打开位于数据库深发展qRowszColumn,表szTable中的BLOB的句柄;换句话说,相同的BLOB将被选择:

 

SELECT szColumn FROM szDb.szTable WHERE rowid = qRow;

 

C / C ++语法

 

int sqlite3_blob_open(

sqlite3*,

const char *zDb,

const char *zTable,

const char *zColumn,

sqlite3_int64 iRow,

int flags,

sqlite3_blob **ppBlob

);

 

PB语法

 

FUNCTION sqlite3_blob_open ( _

BYVAL hDbc AS DWORD, _

BYREF szDb AS ASCIIZ, _

BYREF szTable AS ASCIIZ, _

BYREF szColumn AS ASCIIZ, _

BYVAL qRow AS QUAD, _

BYVAL flags AS LONG, _

BYREF ppBlob AS DWORD _

) AS LONG

 

参数

 

pDb

 

[in]??数据库连接句柄。必须是从sqlite3_opensqlite3_open16sqlite3_open_v2获取的NULL指针或sqlite3对象指针,而不是先前关闭。使用NULL指针参数调用sqlite3_close是无害的操作。

 

szDb

 

[in]数据库名称。请注意,数据库名称不是包含数据库的文件名,而是使用ATTACH连接数据库时AS关键字后出现的数据库的符号名称。对于主数据库文件,数据库名称为“main”。对于TEMP表,数据库名称为“temp”。

 

szTable

 

[in]表名。

 

szColumn

 

[in]列名称。

 

qRow

 

[in]行号。如果BLOB句柄指向的行由UPDATE,DELETE或ON CONFLICT副作用修改,则BLOB句柄被标记为“已过期”。如果行的任何列都被更改,即使是除了BLOB句柄打开的列之外的列也是如此。调用sqlite3_blob_readsqlite3_blob_write过期的BLOB句柄失败,返回代码为SQLITE_ABORT。在BLOB到期之前写入BLOB的更改在BLOB到期之前不会回滚。如果交易继续完成,这些更改将终止。

 

flags

 

[in]如果flags参数不为零,则打开BLOB进行读写访问。如果为零,则BLOB被打开以进行读取访问。不可能打开作为索引或主键的一部分进行写入的列。如果启用外键约束,则无法打开作为子键的一部分进行写入的列。

 

ppBlob

 

[out]指向接收de blob指针的变量的指针。

 

返回值

 

成功后,返回SQLITE_OK,并将新的BLOB句柄写入ppBlob.否则返回错误代码,ppBlob设置为空指针。此函数设置数据库连接错误代码和可通过sqlite3_errcodesqlite3_errmsg和相关功能访问的消息。请注意,ppBlob变量始终被初始化为使ppBlobsqlite3_blob_close调用sqlite3_blob_close的安全性无论此函数的成功或失败如何。

 

备注

 

使用sqlite3_blob_bytes函数确定打开的Blob的大小。blob的大小可能不会被此函数更改。使用UPDATE SQL命令更改blob的大小。

 

如果需要,可以使用sqlite3_bind_zeroblobsqlite3_result_zeroblob函数和内置的zeroblob SQL函数来创建一个空的零填充blob,使用此函数读取或写入。

 

为了避免资源泄漏,最终将通过调用sqlite3_blob_close释放每个开放的BLOB句柄。

 

C ++实现代码

 

/*

** Open a blob handle.

*/

SQLITE_API int sqlite3_blob_open(

sqlite3* db,            /* The database connection */

const char *zDb,        /* The attached database containing the blob */

const char *zTable,     /* The table containing the blob */

const char *zColumn,    /* The column containing the blob */

sqlite_int64 iRow,      /* The row containing the glob */

int flags,              /* True -> read/write access, false -> read-only */

sqlite3_blob **ppBlob   /* Handle for accessing the blob returned here */

){

int nAttempt = 0;

int iCol;               /* Index of zColumn in row-record */

 

/* This VDBE program seeks a btree cursor to the identified

** db/table/row entry. The reason for using a vdbe program instead

** of writing code to use the b-tree layer directly is that the

** vdbe program will take advantage of the various transaction,

** locking and error handling infrastructure built into the vdbe.

**

** After seeking the cursor, the vdbe executes an OP_ResultRow.

** Code external to the Vdbe then "borrows" the b-tree cursor and

** uses it to implement the blob_read(), blob_write() and

** blob_bytes() functions.

**

** The sqlite3_blob_close() function finalizes the vdbe program,

** which closes the b-tree cursor and (possibly) commits the

** transaction.

*/

static const VdbeOpList openBlob[] = {

  {OP_Transaction, 0, 0, 0},     /* 0: Start a transaction */

  {OP_VerifyCookie, 0, 0, 0},    /* 1: Check the schema cookie */

  {OP_TableLock, 0, 0, 0},       /* 2: Acquire a read or write lock */

 

  /* One of the following two instructions is replaced by an OP_Noop. */

  {OP_OpenRead, 0, 0, 0},        /* 3: Open cursor 0 for reading */

  {OP_OpenWrite, 0, 0, 0},       /* 4: Open cursor 0 for read/write */

 

  {OP_Variable, 1, 1, 1},        /* 5: Push the rowid to the stack */

  {OP_NotExists, 0, 10, 1},      /* 6: Seek the cursor */

  {OP_Column, 0, 0, 1},          /* 7  */

  {OP_ResultRow, 1, 0, 0},       /* 8  */

  {OP_Goto, 0, 5, 0},            /* 9  */

  {OP_Close, 0, 0, 0},           /* 10 */

  {OP_Halt, 0, 0, 0},            /* 11 */

};

 

int rc = SQLITE_OK;

char *zErr = 0;

Table *pTab;

Parse *pParse = 0;

Incrblob *pBlob = 0;

 

flags = !!flags;                /* flags = (flags ? 1 : 0); */

*ppBlob = 0;

 

sqlite3_mutex_enter(db->mutex);

 

pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));

if( !pBlob ) goto blob_open_out;

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

if( !pParse ) goto blob_open_out;

 

do {

  memset(pParse, 0, sizeof(Parse));

  pParse->db = db;

  sqlite3DbFree(db, zErr);

  zErr = 0;

 

  sqlite3BtreeEnterAll(db);

  pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);

  if( pTab && IsVirtual(pTab) ){

    pTab = 0;

    sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);

  }

#ifndef SQLITE_OMIT_VIEW

  if( pTab && pTab->pSelect ){

    pTab = 0;

    sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);

  }

#endif

  if( !pTab ){

    if( pParse->zErrMsg ){

      sqlite3DbFree(db, zErr);

      zErr = pParse->zErrMsg;

      pParse->zErrMsg = 0;

    }

    rc = SQLITE_ERROR;

    sqlite3BtreeLeaveAll(db);

    goto blob_open_out;

  }

 

  /* Now search pTab for the exact column. */

  for(iCol=0; iCol<pTab->nCol; iCol++) {

    if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){

      break;

    }

  }

  if( iCol==pTab->nCol ){

    sqlite3DbFree(db, zErr);

    zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);

    rc = SQLITE_ERROR;

    sqlite3BtreeLeaveAll(db);

    goto blob_open_out;

  }

 

  /* If the value is being opened for writing, check that the

  ** column is not indexed, and that it is not part of a foreign key.

  ** It is against the rules to open a column to which either of these

  ** descriptions applies for writing.  */

  if( flags ){

    const char *zFault = 0;

    Index *pIdx;

#ifndef SQLITE_OMIT_FOREIGN_KEY

    if( db->flags&SQLITE_ForeignKeys ){

      /* Check that the column is not part of an FK child key definition. It

      ** is not necessary to check if it is part of a parent key, as parent

      ** key columns must be indexed. The check below will pick up this

      ** case.  */

      FKey *pFKey;

      for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){

        int j;

        for(j=0; j<pFKey->nCol; j++){

          if( pFKey->aCol[j].iFrom==iCol ){

            zFault = "foreign key";

          }

        }

      }

    }

#endif

    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){

      int j;

      for(j=0; j<pIdx->nColumn; j++){

        if( pIdx->aiColumn[j]==iCol ){

          zFault = "indexed";

        }

      }

    }

    if( zFault ){

      sqlite3DbFree(db, zErr);

      zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault);

      rc = SQLITE_ERROR;

      sqlite3BtreeLeaveAll(db);

      goto blob_open_out;

    }

  }

 

  pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);

  assert( pBlob->pStmt || db->mallocFailed );

  if( pBlob->pStmt ){

    Vdbe *v = (Vdbe *)pBlob->pStmt;

    int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);

 

    sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);

 

 

    /* Configure the OP_Transaction */

    sqlite3VdbeChangeP1(v, 0, iDb);

    sqlite3VdbeChangeP2(v, 0, flags);

 

    /* Configure the OP_VerifyCookie */

    sqlite3VdbeChangeP1(v, 1, iDb);

    sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);

    sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);

 

    /* Make sure a mutex is held on the table to be accessed */

    sqlite3VdbeUsesBtree(v, iDb);

 

    /* Configure the OP_TableLock instruction */

#ifdef SQLITE_OMIT_SHARED_CACHE

    sqlite3VdbeChangeToNoop(v, 2);

#else

    sqlite3VdbeChangeP1(v, 2, iDb);

    sqlite3VdbeChangeP2(v, 2, pTab->tnum);

    sqlite3VdbeChangeP3(v, 2, flags);

    sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);

#endif

 

    /* Remove either the OP_OpenWrite or OpenRead. Set the P2

    ** parameter of the other to pTab->tnum.  */

    sqlite3VdbeChangeToNoop(v, 4 - flags);

    sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);

    sqlite3VdbeChangeP3(v, 3 + flags, iDb);

 

    /* Configure the number of columns. Configure the cursor to

    ** think that the table has one more column than it really

    ** does. An OP_Column to retrieve this imaginary column will

    ** always return an SQL NULL. This is useful because it means

    ** we can invoke OP_Column to fill in the vdbe cursors type

    ** and offset cache without causing any IO.

    */

    sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);

    sqlite3VdbeChangeP2(v, 7, pTab->nCol);

    if( !db->mallocFailed ){

      pParse->nVar = 1;

      pParse->nMem = 1;

      pParse->nTab = 1;

      sqlite3VdbeMakeReady(v, pParse);

    }

  }

 

  pBlob->flags = flags;

  pBlob->iCol = iCol;

  pBlob->db = db;

  sqlite3BtreeLeaveAll(db);

  if( db->mallocFailed ){

    goto blob_open_out;

  }

  sqlite3_bind_int64(pBlob->pStmt, 1, iRow);

  rc = blobSeekToRow(pBlob, iRow, &zErr);

} while( (++nAttempt)<5 && rc==SQLITE_SCHEMA );

 

blob_open_out:

if( rc==SQLITE_OK && db->mallocFailed==0 ){

  *ppBlob = (sqlite3_blob *)pBlob;

}else{

  if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);

  sqlite3DbFree(db, pBlob);

}

sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);

sqlite3DbFree(db, zErr);

sqlite3StackFree(db, pParse);

rc = sqlite3ApiExit(db, rc);

sqlite3_mutex_leave(db->mutex);

return rc;

}