#include "get-table.h"
#include <assert.h>
#include <string.h>
typedef unsigned int u32;
#if defined(HAVE_STDINT_H)
#define SQLITE_INT_TO_PTR(X) ((void *)(intptr_t)(X))
#define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
#elif defined(__PTRDIFF_TYPE__)
#define SQLITE_INT_TO_PTR(X) ((void *)(__PTRDIFF_TYPE__)(X))
#define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__)
#define SQLITE_INT_TO_PTR(X) ((void *)&((char *)0)[X])
#define SQLITE_PTR_TO_INT(X) ((int)(((char *)X) - (char *)0))
#else
#define SQLITE_INT_TO_PTR(X) ((void *)(X))
#define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
static int sqlite3Strlen30(const char *z) {
if (z == 0) return 0;
return 0x3fffffff & (int)strlen(z);
}
typedef struct TabResult {
char **azResult;
char *zErrMsg;
u32 nAlloc;
u32 nRow;
u32 nColumn;
u32 nData;
int rc;
} TabResult;
static int crsql_get_table_cb(void *pArg, int nCol, char **argv, char **colv) {
TabResult *p = (TabResult *)pArg;
int need;
int i;
char *z;
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 (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 ((int)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;
}
if (argv != 0) {
for (i = 0; i < nCol; i++) {
if (argv[i] == 0) {
z = 0;
} else {
int n = sqlite3Strlen30(argv[i]) + 1;
z = sqlite3_malloc64(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;
}
int crsql_get_table(
sqlite3 *db,
const char *zSql,
char ***pazResult,
int *pnRow,
int *pnColumn,
char **pzErrMsg
) {
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_malloc64(sizeof(char *) * res.nAlloc);
if (res.azResult == 0) {
return SQLITE_NOMEM;
}
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, crsql_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) {
crsql_free_table(&res.azResult[1]);
if (res.zErrMsg) {
if (pzErrMsg) {
sqlite3_free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s", res.zErrMsg);
}
sqlite3_free(res.zErrMsg);
}
return res.rc;
}
sqlite3_free(res.zErrMsg);
if (rc != SQLITE_OK) {
crsql_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) {
crsql_free_table(&res.azResult[1]);
return SQLITE_NOMEM;
}
res.azResult = azNew;
}
*pazResult = &res.azResult[1];
if (pnColumn) *pnColumn = res.nColumn;
if (pnRow) *pnRow = res.nRow;
return rc;
}
void crsql_free_table(
char **azResult
) {
if (azResult) {
int i, n;
azResult--;
assert(azResult != 0);
n = SQLITE_PTR_TO_INT(azResult[0]);
for (i = 1; i < n; i++) {
if (azResult[i]) sqlite3_free(azResult[i]);
}
sqlite3_free(azResult);
}
}