描述
这是一个遗留功能,保留后向兼容性。不建议使用此界面。
C / C ++语法
int sqlite3_get_table( sqlite3 *db, const char *zSql, char ***pazResult, int *pnRow, int *pnColumn, char **pzErrmsg ); |
PB语法
FUNCTION sqlite3_get_table ( _ BYVAL hDbc AS DWORD, _ BYREF szSql AS ASCIIZ, _ BYREF pazResult AS DWORD, _ BYREF pnRow AS LONG, _ BYREF pnColumn AS LONG, _ BYREF pzErrmsg AS DWORD _ ) AS LONG |
参数
pDb
[in]数据库连接句柄。必须是从sqlite3_open,sqlite3_open16或sqlite3_open_v2获取的NULL指针或sqlite3对象指针。
szSql
[in]零终止的UTF-8字符串中的一个或多个分号分隔的SQL语句。
pazResult
[in]接收指向结果表的指针的指针变量。
pnRows
[out]指向一个LONG变量的指针,该变量接收结果集中的行数。
pnColumns
[out]指向一个LONG变量的指针,该变量接收结果集中的列数。
pzErrmsg
[in]如果不为NULL,任何错误消息都将写入从sqlite3_malloc获取并传回的内存中。为了避免内存泄漏,应用程序应该在不再需要错误消息字符串后调用sqlite3_free返回的错误消息字符串。如果此参数不为NULL并且没有发生错误,则sqlite3_get_table在返回前将该指针设置为NULL。
返回值
如果成功返回SQLITE_OK,否则返回错误代码。
备注
A 结果表是由sqlite3_get_table接口创建的内存数据结构。结果表记录来自一个或多个查询的完整查询结果。
这个表在概念上有许多行和列。但是这些数字不是结果表本身的一部分。这些数字是分开获得的。令N为行数,M为列数。
结果表是指向零终止的UTF-8字符串的指针数组。阵列中有(N + 1)* M个元素。第一个M指针指向包含列名称的零终止字符串。剩余的条目都指向查询结果。NULL值会导致NULL指针。所有其他值都是以sqlite3_column_text返回的UTF-8零终止字符串表示形式。
结果表可能包含一个或多个内存分配。将结果表直接传递给sqlite3_free是不安全的。结果表应使用sqlite3_free_table取消分配。
作为结果表格式的一个例子,假设查询结果如下:
Name | Age
-----------------------
Alice | 43
Bob | 28
Cindy | 21
有两列(M == 2)和三行(N == 3)。因此,结果表有8个条目。假设结果表存储在数组名称azResult中。那么azResult持有这个内容:
azResult(0) = "Name"
azResult(1) = "Age"
azResult(2) = "Alice"
azResult(3) = "43"
azResult(4) = "Bob"
azResult(5) = "28"
azResult(6) = "Cindy"
azResult(7) = "21"
sqlite3_get_table函数评估其第二个参数的零终止UTF-8字符串中的一个或多个以分号分隔的SQL语句,并将结果表返回给第3个参数中给出的指针。
在应用程序结束之后,sqlite3_get_table的结果,它必须将结果表指针传递给sqlite3_free_table才能释放出现的内存。由于sqlite3_malloc在sqlite3_get_table内发生的方式,呼叫功能不得直接调用sqlite3_free.只有sqlite3_free_table能够正确安全地释放内存。
sqlite3_get_table接口作为sqlite3_exec周围的包装器实现。sqlite3_get_table函数无法访问SQLite的任何内部数据结构。它只使用这里定义的公共接口。因此,在内部sqlite3_exec呼叫之外的包装层中发生的错误不会反映在对sqlite3_errcode或sqlite3_errmsg的后续调用中。
C ++实现代码
/*
** This function is called once for each row in the result table. Its job
** is to fill in the TabResult structure appropriately, allocating new
** memory as necessary.
*/
static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
TabResult *p = (TabResult*)pArg; /* Result accumulator */
int need; /* Slots needed in p->azResult[] */
int i; /* Loop counter */
char *z; /* A single column of result */
/* Make sure there is enough space in p->azResult to hold everything
** we need to remember from this invocation of the callback.
*/
if( p->nRow==0 && argv!=0 ){
need = nCol*2;
}else{
need = nCol;
}
if( p->nData + need > p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need;
azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
/* If this is the first row, then generate an extra row containing
** the names of all columns.
*/
if( p->nRow==0 ){
p->nColumn = nCol;
for(i=0; i<nCol; i++){
z = sqlite3_mprintf("%s", colv[i]);
if( z==0 ) goto malloc_failed;
p->azResult[p->nData++] = z;
}
}else if( p->nColumn!=nCol ){
sqlite3_free(p->zErrMsg);
p->zErrMsg = sqlite3_mprintf(
"sqlite3_get_table() called with two or more incompatible queries"
);
p->rc = SQLITE_ERROR;
return 1;
}
/* Copy over the row data
*/
if( argv!=0 ){
for(i=0; i<nCol; i++){
if( argv[i]==0 ){
z = 0;
}else{
int n = sqlite3Strlen30(argv[i])+1;
z = sqlite3_malloc( n );
if( z==0 ) goto malloc_failed;
memcpy(z, argv[i], n);
}
p->azResult[p->nData++] = z;
}
p->nRow++;
}
return 0;
malloc_failed:
p->rc = SQLITE_NOMEM;
return 1;
}
/*
** Query the database. But instead of invoking a callback for each row,
** malloc() for space to hold the result and return the entire results
** at the conclusion of the call.
**
** The result that is written to ***pazResult is held in memory obtained
** from malloc(). But the caller cannot free this memory directly.
** Instead, the entire table should be passed to sqlite3_free_table() when
** the calling procedure is finished using it.
*/
SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
char ***pazResult, /* Write the result table here */
int *pnRow, /* Write the number of rows in the result here */
int *pnColumn, /* Write the number of columns of result here */
char **pzErrMsg /* Write error messages here */
){
int rc;
TabResult res;
*pazResult = 0;
if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0;
if( pzErrMsg ) *pzErrMsg = 0;
res.zErrMsg = 0;
res.nRow = 0;
res.nColumn = 0;
res.nData = 1;
res.nAlloc = 20;
res.rc = SQLITE_OK;
res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
res.azResult[0] = SQLITE_INT_TO_PTR(res.nData);
if( (rc&0xff)==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){
if( pzErrMsg ){
sqlite3_free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
}
sqlite3_free(res.zErrMsg);
}
db->errCode = res.rc; /* Assume 32-bit assignment is atomic */
return res.rc;
}
sqlite3_free(res.zErrMsg);
if( rc!=SQLITE_OK ){
sqlite3_free_table(&res.azResult[1]);
return rc;
}
if( res.nAlloc>res.nData ){
char **azNew;
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*res.nData );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
res.azResult = azNew;
}
*pazResult = &res.azResult[1];
if( pnColumn ) *pnColumn = res.nColumn;
if( pnRow ) *pnRow = res.nRow;
return rc;
}