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

sqlite3_get_table (legacy)

Previous pageReturn to chapter overviewNext page

描述

 

这是一个遗留功能,保留后向兼容性。不建议使用此界面。

 

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_opensqlite3_open16sqlite3_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_mallocsqlite3_get_table内发生的方式,呼叫功能不得直接调用sqlite3_free.只有sqlite3_free_table能够正确安全地释放内存。

 

sqlite3_get_table接口作为sqlite3_exec周围的包装器实现。sqlite3_get_table函数无法访问SQLite的任何内部数据结构。它只使用这里定义的公共接口。因此,在内部sqlite3_exec呼叫之外的包装层中发生的错误不会反映在对sqlite3_errcodesqlite3_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;

}