161 lines
4.4 KiB
C
161 lines
4.4 KiB
C
#include "sckulya.h"
|
|
|
|
int64_t tri_sqlite_open(TString filename, TString *error) {
|
|
sqlite3* out_db = 0;
|
|
|
|
int rc = sqlite3_open((const char*) filename->body, &out_db);
|
|
|
|
if(rc != SQLITE_OK) {
|
|
if(out_db) {
|
|
sqlite3_close(out_db);
|
|
}
|
|
|
|
const char* msg = sqlite3_errmsg(out_db);
|
|
|
|
if(!msg) {
|
|
msg = "Unknown error";
|
|
}
|
|
|
|
int64_t len = (int64_t)strlen(msg);
|
|
*error = tri_newString(len, len, (char*)msg);
|
|
}
|
|
|
|
sqlite3_busy_timeout(out_db, 5000);
|
|
|
|
return (int64_t) out_db;
|
|
}
|
|
|
|
int tri_sqlite_close(int64_t db) {
|
|
if (!db) return SQLITE_MISUSE;
|
|
return sqlite3_close((sqlite3*) db);
|
|
}
|
|
|
|
void tri_sqlite_exec(int64_t db, TString query, TString *error) {
|
|
char* errmsg = NULL;
|
|
int rc = sqlite3_exec((sqlite3*) db, (const char*) query->body, NULL, NULL, &errmsg);
|
|
|
|
if (errmsg) {
|
|
int64_t len = (int64_t)strlen(errmsg);
|
|
*error = tri_newString(len, len, errmsg);
|
|
|
|
sqlite3_free(errmsg);
|
|
}
|
|
}
|
|
|
|
void escape_and_append (const unsigned char *s, char* buf, size_t* len) {
|
|
for (; *s; ++s) {
|
|
char esc = 0;
|
|
|
|
switch (*s) {
|
|
case '\\': esc = '\\'; break;
|
|
case '\b': esc = 'b'; break;
|
|
case '\f': esc = 'f'; break;
|
|
case '\n': esc = 'n'; break;
|
|
case '\r': esc = 'r'; break;
|
|
case '\t': esc = 't'; break;
|
|
default: break;
|
|
}
|
|
if (esc) {
|
|
buf[(*len)++] = '\\';
|
|
buf[(*len)++] = esc;
|
|
} else {
|
|
buf[(*len)++] = *s;
|
|
}
|
|
}
|
|
};
|
|
|
|
int tri_sqlite_query(int64_t db, TString query, TString *result, TString *error) {
|
|
sqlite3_stmt *stmt = NULL;
|
|
int rc = sqlite3_prepare_v2((sqlite3*)db, (const char*) query->body, -1, &stmt, NULL);
|
|
if (rc != SQLITE_OK) {
|
|
if (error) {
|
|
const char *msg = sqlite3_errmsg((sqlite3*)db);
|
|
if (!msg) msg = "Unknown error";
|
|
int64_t len = (int64_t)strlen(msg);
|
|
*error = tri_newString(len, len, (char*)msg);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
size_t cap = 1024;
|
|
size_t len = 0;
|
|
char *buf = malloc(cap);
|
|
|
|
if (!buf) {
|
|
sqlite3_finalize(stmt);
|
|
if (error) *error = tri_newString(0,0,"Out of memory");
|
|
return SQLITE_NOMEM;
|
|
}
|
|
|
|
buf[len++] = '[';
|
|
int first_row = 1;
|
|
|
|
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
|
if (!first_row) { buf[len++] = ','; } else first_row = 0;
|
|
buf[len++] = '{';
|
|
|
|
int ncol = sqlite3_column_count(stmt);
|
|
for (int i = 0; i < ncol; ++i) {
|
|
if (i) { buf[len++] = ','; }
|
|
const char *colname = sqlite3_column_name(stmt, i);
|
|
/* "colname": */
|
|
// strlen(colname) + 4;
|
|
buf[len++] = '\"';
|
|
escape_and_append((const unsigned char*)colname, buf, &len);
|
|
buf[len++] = '\"';
|
|
buf[len++] = ':';
|
|
|
|
int type = sqlite3_column_type(stmt, i);
|
|
if (type == SQLITE_INTEGER) {
|
|
long long v = sqlite3_column_int64(stmt, i);
|
|
char tmp[32];
|
|
int n = snprintf(tmp, sizeof(tmp), "%lld", v);
|
|
memcpy(buf + len, tmp, n); len += n;
|
|
} else if (type == SQLITE_FLOAT) {
|
|
double v = sqlite3_column_double(stmt, i);
|
|
char tmp[64];
|
|
int n = snprintf(tmp, sizeof(tmp), "%g", v);
|
|
memcpy(buf + len, tmp, n); len += n;
|
|
} else if (type == SQLITE_NULL) {
|
|
memcpy(buf + len, "null", 4); len += 4;
|
|
} else {
|
|
const unsigned char *txt = sqlite3_column_text(stmt, i);
|
|
if (!txt) {
|
|
memcpy(buf + len, "null", 4); len += 4;
|
|
} else {
|
|
buf[len++] = '\"';
|
|
escape_and_append(txt, buf, &len);
|
|
buf[len++] = '\"';
|
|
}
|
|
}
|
|
}
|
|
|
|
buf[len++] = '}';
|
|
}
|
|
|
|
/* finalize and handle errors */
|
|
if (rc != SQLITE_DONE) {
|
|
const char *msg = sqlite3_errmsg((sqlite3*)db);
|
|
if (error) {
|
|
if (!msg) msg = "Unknown error";
|
|
int64_t mlen = (int64_t)strlen(msg);
|
|
*error = tri_newString(mlen, mlen, (char*)msg);
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
free(buf);
|
|
return rc;
|
|
}
|
|
|
|
buf[len++] = ']';
|
|
buf[len] = '\0';
|
|
|
|
sqlite3_finalize(stmt);
|
|
|
|
if (result) {
|
|
*result = tri_newString((int64_t)len, (int64_t)len, buf);
|
|
}
|
|
|
|
free(buf);
|
|
return SQLITE_OK;
|
|
}
|