#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; }