|
|
@@ -1,55 +1,24 @@
|
|
|
/* Code generated by script */
|
|
|
-#include "squirrel.h"
|
|
|
-#include "sqlite3.h"
|
|
|
-#include <string.h>
|
|
|
-#include <stdio.h>
|
|
|
-#include "sqstdblobimpl.h"
|
|
|
|
|
|
-typedef struct sq_sqlite3_sdb sq_sqlite3_sdb;
|
|
|
-typedef struct sq_sqlite3_sdb_func sq_sqlite3_sdb_func;
|
|
|
+#include "sq_sqlite3.h"
|
|
|
|
|
|
-/* to use as C user data so i know what function sqlite is calling */
|
|
|
-struct sq_sqlite3_sdb_func
|
|
|
+//return error if parameter exists but is not a blob
|
|
|
+//return 1 if the parameter exists and is a blob
|
|
|
+//return 0 if the parameter doesn't exists and creates a new blob
|
|
|
+static SQRESULT getOptionalBlob(HSQUIRRELVM v, SQInteger idx, SQBlob **blob)
|
|
|
{
|
|
|
- /* references to associated lua values */
|
|
|
- HSQOBJECT fn_step;
|
|
|
- HSQOBJECT fn_finalize;
|
|
|
- HSQOBJECT udata;
|
|
|
-
|
|
|
- sq_sqlite3_sdb *sdb;
|
|
|
- sq_sqlite3_sdb_func *next;
|
|
|
-};
|
|
|
-
|
|
|
-/* information about database */
|
|
|
-struct sq_sqlite3_sdb
|
|
|
-{
|
|
|
- /* associated squirrel vm */
|
|
|
- HSQUIRRELVM v;
|
|
|
- /* sqlite database handle */
|
|
|
- sqlite3 *db;
|
|
|
-
|
|
|
- /* sql functions stack usage */
|
|
|
- sq_sqlite3_sdb_func *func; /* top SQL function being called */
|
|
|
-
|
|
|
- /* references */
|
|
|
- HSQOBJECT busy_cb; /* busy callback */
|
|
|
- HSQOBJECT busy_udata;
|
|
|
-
|
|
|
- HSQOBJECT progress_cb; /* progress handler */
|
|
|
- HSQOBJECT progress_udata;
|
|
|
-
|
|
|
- HSQOBJECT trace_cb; /* trace callback */
|
|
|
- HSQOBJECT trace_udata;
|
|
|
- HSQOBJECT null_value;
|
|
|
-};
|
|
|
-
|
|
|
-SQ_OPT_STRING_STRLEN();
|
|
|
-
|
|
|
-static const SQChar *SQLite3_TAG = "SQLite3";
|
|
|
-static const SQChar *SQLite3_Stmt_TAG = "SQLite3Stmt";
|
|
|
+ if(sq_gettop(v) >= idx) {
|
|
|
+ if(SQ_FAILED(sq_getinstanceup(v,3,(SQUserPointer*)blob,(SQUserPointer)SQBlob::SQBlob_TAG)))
|
|
|
+ return sq_throwerror(v,_SC("expect a blob as second parameter"));
|
|
|
+ if(!(*blob) || !(*blob)->IsValid())
|
|
|
+ return sq_throwerror(v,_SC("the blob is invalid"));
|
|
|
+ } else {
|
|
|
+ *blob = new SQBlob(0, 8192);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
|
|
|
-static const SQChar sqlite3_NULL_Name[] = _SC("sqlite3_NULL");
|
|
|
-static const SQChar nullName[] = _SC("Null");
|
|
|
static SQRESULT sqlite3_NULL_tostring(HSQUIRRELVM v)
|
|
|
{
|
|
|
sq_pushstring(v, "", 0);
|
|
|
@@ -102,22 +71,43 @@ enum e_type_result {tr_first_row_first_col, tr_first_row, tr_all_rows, tr_ddml};
|
|
|
#define AS_STRING_ALWAYS 0x01
|
|
|
#define NULL_AS_EMPTY_STR 0x02
|
|
|
#define WITH_COL_NAMES 0x04
|
|
|
+#define WITH_BLOB_AS_NULL 0x08
|
|
|
+#define WITH_SQ_NULL 0x100
|
|
|
|
|
|
static void sqlite3_stmt_push_string(HSQUIRRELVM v, sqlite3_stmt *stmt, int col, int flags)
|
|
|
{
|
|
|
const char *value = (const char*) sqlite3_column_text(stmt, col);
|
|
|
if(value) sq_pushstring(v, value, sqlite3_column_bytes(stmt, col));
|
|
|
- else push_sqlite3_null(v);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(flags & AS_STRING_ALWAYS) sq_pushliteral(v, "");
|
|
|
+ else push_sqlite3_null(v);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static SQRESULT sqlite3_stmt_push_value(HSQUIRRELVM v, sqlite3_stmt *stmt, int col, int flags)
|
|
|
{
|
|
|
const char *value;
|
|
|
-
|
|
|
- if(flags & AS_STRING_ALWAYS) sqlite3_stmt_push_string(v, stmt, col, flags);
|
|
|
+ int col_type = 0;
|
|
|
+ if(flags & WITH_BLOB_AS_NULL)
|
|
|
+ {
|
|
|
+ col_type = sqlite3_column_type(stmt, col);
|
|
|
+ if(col_type == SQLITE_BLOB)
|
|
|
+ {
|
|
|
+ if(flags & AS_STRING_ALWAYS) sq_pushliteral(v, "");
|
|
|
+ else push_sqlite3_null(v);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(flags & AS_STRING_ALWAYS)
|
|
|
+ {
|
|
|
+ sqlite3_stmt_push_string(v, stmt, col, flags);
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
- switch (sqlite3_column_type(stmt, col))
|
|
|
+ if(!col_type) col_type = sqlite3_column_type(stmt, col);
|
|
|
+
|
|
|
+ switch (col_type)
|
|
|
{
|
|
|
case SQLITE_INTEGER:
|
|
|
{
|
|
|
@@ -141,10 +131,12 @@ static SQRESULT sqlite3_stmt_push_value(HSQUIRRELVM v, sqlite3_stmt *stmt, int c
|
|
|
else push_sqlite3_null(v);
|
|
|
break;
|
|
|
case SQLITE_NULL:
|
|
|
- push_sqlite3_null(v);
|
|
|
+ if(flags & WITH_SQ_NULL) sq_pushnull(v);
|
|
|
+ else push_sqlite3_null(v);
|
|
|
break;
|
|
|
default:
|
|
|
- push_sqlite3_null(v);
|
|
|
+ if(flags & WITH_SQ_NULL) sq_pushnull(v);
|
|
|
+ else push_sqlite3_null(v);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -495,6 +487,57 @@ static SQRESULT sq_sqlite3_stmt_col_count(HSQUIRRELVM v)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+static SQRESULT sq_sqlite3_stmt_col_name(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS_NO_TOP(v);
|
|
|
+ GET_sqlite3_stmt_INSTANCE();
|
|
|
+ SQ_GET_INTEGER(v, 2, col);
|
|
|
+ sq_pushstring(v, sqlite3_column_name(self, col), -1);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static SQRESULT sq_sqlite3_stmt_col_type(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS_NO_TOP(v);
|
|
|
+ GET_sqlite3_stmt_INSTANCE();
|
|
|
+ SQ_GET_INTEGER(v, 2, col);
|
|
|
+ sq_pushinteger(v, sqlite3_column_type(self, col));
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static const char *get_column_type(sqlite3_stmt *stmt, int col)
|
|
|
+{
|
|
|
+ const char *column_type;
|
|
|
+ int icol_type = sqlite3_column_type(stmt, col);
|
|
|
+ switch(icol_type)
|
|
|
+ {
|
|
|
+ case SQLITE_INTEGER: column_type = "INTEGER"; break;
|
|
|
+ case SQLITE_FLOAT: column_type = "FLOAT"; break;
|
|
|
+ case SQLITE_BLOB: column_type = "BLOB"; break;
|
|
|
+ case SQLITE_TEXT: column_type = "TEXT"; break;
|
|
|
+ case SQLITE_NULL: column_type = "NULL"; break;
|
|
|
+ default:
|
|
|
+ column_type = "unknown";
|
|
|
+ }
|
|
|
+ return column_type;
|
|
|
+}
|
|
|
+
|
|
|
+static const char *get_column_dcltype(sqlite3_stmt *stmt, int col)
|
|
|
+{
|
|
|
+ const char *column_type = sqlite3_column_decltype(stmt, col);
|
|
|
+ if(!column_type) column_type = get_column_type(stmt, col);
|
|
|
+ return column_type;
|
|
|
+}
|
|
|
+
|
|
|
+static SQRESULT sq_sqlite3_stmt_col_declared_type(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS_NO_TOP(v);
|
|
|
+ GET_sqlite3_stmt_INSTANCE();
|
|
|
+ SQ_GET_INTEGER(v, 2, col);
|
|
|
+ sq_pushstring(v, get_column_dcltype(self, col), -1);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
static SQRESULT sq_sqlite3_stmt_colsAsArray(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
@@ -509,45 +552,60 @@ static SQRESULT sq_sqlite3_stmt_colsAsArray(HSQUIRRELVM v)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_sqlite3_stmt_colsAsTable(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_sqlite3_stmt_colsTypeAsArray(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
GET_sqlite3_stmt_INSTANCE();
|
|
|
int col_count = sqlite3_column_count(self);
|
|
|
- sq_newtable(v);
|
|
|
+ sq_newarray(v, col_count);
|
|
|
for(int i=0; i<col_count; ++i)
|
|
|
{
|
|
|
- sq_pushstring(v, sqlite3_column_name(self, i), -1);
|
|
|
- sq_pushinteger(v, i);
|
|
|
- sq_rawset(v, -3);
|
|
|
+ sq_pushstring(v, get_column_type(self, i), -1);
|
|
|
+ sq_arrayset(v, -2, i);
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_sqlite3_stmt_col_name(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_sqlite3_stmt_colsDeclTypeAsArray(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
GET_sqlite3_stmt_INSTANCE();
|
|
|
- SQ_GET_INTEGER(v, 2, col);
|
|
|
- sq_pushstring(v, sqlite3_column_name(self, col), -1);
|
|
|
+ int col_count = sqlite3_column_count(self);
|
|
|
+ sq_newarray(v, col_count);
|
|
|
+ for(int i=0; i<col_count; ++i)
|
|
|
+ {
|
|
|
+ sq_pushstring(v, get_column_dcltype(self, i), -1);
|
|
|
+ sq_arrayset(v, -2, i);
|
|
|
+ }
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_sqlite3_stmt_col_type(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_sqlite3_stmt_colsNameAsArray(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
GET_sqlite3_stmt_INSTANCE();
|
|
|
- SQ_GET_INTEGER(v, 2, col);
|
|
|
- sq_pushinteger(v, sqlite3_column_type(self, col));
|
|
|
+ int col_count = sqlite3_column_count(self);
|
|
|
+ sq_newarray(v, col_count);
|
|
|
+ for(int i=0; i<col_count; ++i)
|
|
|
+ {
|
|
|
+ sq_pushstring(v, sqlite3_column_name(self, i), -1);
|
|
|
+ sq_arrayset(v, -2, i);
|
|
|
+ }
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_sqlite3_stmt_col_declared_type(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_sqlite3_stmt_colsAsTable(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
GET_sqlite3_stmt_INSTANCE();
|
|
|
- SQ_GET_INTEGER(v, 2, col);
|
|
|
- sq_pushstring(v, sqlite3_column_decltype(self, col), -1);
|
|
|
+ int col_count = sqlite3_column_count(self);
|
|
|
+ sq_newtable(v);
|
|
|
+ for(int i=0; i<col_count; ++i)
|
|
|
+ {
|
|
|
+ sq_pushstring(v, sqlite3_column_name(self, i), -1);
|
|
|
+ sq_pushinteger(v, i);
|
|
|
+ sq_rawset(v, -3);
|
|
|
+ }
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
@@ -703,6 +761,9 @@ static void append_escaping_json(SQBlob &json, const char *sz)
|
|
|
case '"':
|
|
|
case '\n':
|
|
|
case '\r':
|
|
|
+ case '\t':
|
|
|
+ case '\b':
|
|
|
+ case '\f':
|
|
|
case '\\':
|
|
|
{
|
|
|
json.Write(sz+last_idx, idx-last_idx);
|
|
|
@@ -712,9 +773,24 @@ static void append_escaping_json(SQBlob &json, const char *sz)
|
|
|
json.Write("\\n", 2);
|
|
|
++last_idx;
|
|
|
}
|
|
|
+ else if(c == '\t')
|
|
|
+ {
|
|
|
+ json.Write("\\t", 2);
|
|
|
+ ++last_idx;
|
|
|
+ }
|
|
|
+ else if(c == '\b')
|
|
|
+ {
|
|
|
+ json.Write("\\b", 2);
|
|
|
+ ++last_idx;
|
|
|
+ }
|
|
|
+ else if(c == '\f')
|
|
|
+ {
|
|
|
+ json.Write("\\f", 2);
|
|
|
+ ++last_idx;
|
|
|
+ }
|
|
|
else if(c == '\r')
|
|
|
{
|
|
|
- //skip it
|
|
|
+ json.Write("\\r", 2);
|
|
|
++last_idx;
|
|
|
}
|
|
|
else
|
|
|
@@ -735,64 +811,74 @@ static SQRESULT sq_sqlite3_stmt_asJsonArray(HSQUIRRELVM v)
|
|
|
GET_sqlite3_stmt_INSTANCE();
|
|
|
SQ_OPT_BOOL(v, 2, withMetadata, 0);
|
|
|
int col_count = sqlite3_column_count(self);
|
|
|
- int i;
|
|
|
+ int i, value_type;
|
|
|
const char* value;
|
|
|
|
|
|
- SQBlob json(0, 8192);
|
|
|
+ SQBlob *json = NULL;
|
|
|
+ int has_blob = getOptionalBlob(v, 3, &json);
|
|
|
+ if(has_blob == SQ_ERROR) return SQ_ERROR;
|
|
|
|
|
|
if(withMetadata)
|
|
|
{
|
|
|
- json.WriteZstr("{\n\"columns\":[\n");
|
|
|
+ json->WriteZstr("{\n\"columns\":[\n");
|
|
|
for(i=0; i < col_count; ++i)
|
|
|
{
|
|
|
- json.WriteZstr((i == 0 ? "\"" : ",\""));
|
|
|
- json.WriteZstr(sqlite3_column_name(self, i));
|
|
|
- json.WriteZstr("\"");
|
|
|
+ json->WriteZstr((i == 0 ? "\"" : ",\""));
|
|
|
+ const char *column_name = sqlite3_column_name(self, i);
|
|
|
+ json->WriteZstr(column_name ? column_name : "unknown");
|
|
|
+ json->WriteZstr("\"");
|
|
|
}
|
|
|
|
|
|
- json.WriteZstr("\n],\n\"column_types\":[\n");
|
|
|
+ json->WriteZstr("\n],\n\"column_types\":[\n");
|
|
|
for(i=0; i < col_count; ++i)
|
|
|
{
|
|
|
- json.WriteZstr((i == 0 ? "\"" : ",\""));
|
|
|
- json.WriteZstr(sqlite3_column_decltype(self, i));
|
|
|
- json.WriteZstr("\"");
|
|
|
+ json->WriteZstr((i == 0 ? "\"" : ",\""));
|
|
|
+ json->WriteZstr(get_column_dcltype(self, i));
|
|
|
+ json->WriteZstr("\"");
|
|
|
}
|
|
|
|
|
|
- json.WriteZstr("\n],\n\"rows\":[\n");
|
|
|
+ json->WriteZstr("\n],\n\"rows\":[\n");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- json.WriteZstr("[\n");
|
|
|
+ json->WriteZstr("[\n");
|
|
|
}
|
|
|
int row_count = 0;
|
|
|
while(sqlite3_step(self) == SQLITE_ROW)
|
|
|
{
|
|
|
- json.WriteZstr((row_count++ == 0 ? "[" : ",["));
|
|
|
+ json->WriteZstr((row_count++ == 0 ? "[" : ",["));
|
|
|
for(i=0; i < col_count; ++i)
|
|
|
{
|
|
|
- json.WriteZstr((i == 0 ? "\"" : ",\""));
|
|
|
+ json->WriteZstr((i == 0 ? "\"" : ",\""));
|
|
|
+ //if get the type after sqlite3_column_text it always returns SQLITE_TEXT
|
|
|
+ value_type = sqlite3_column_type(self, i);
|
|
|
value = (const char*)sqlite3_column_text(self, i);
|
|
|
if(value)
|
|
|
{
|
|
|
- switch(sqlite3_column_type(self, i))
|
|
|
+ switch(value_type)
|
|
|
{
|
|
|
+ case SQLITE_BLOB:
|
|
|
+ break; //no blobs in json
|
|
|
case SQLITE_TEXT:
|
|
|
{
|
|
|
- append_escaping_json(json, value);
|
|
|
+ append_escaping_json(*json, value);
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
- json.WriteZstr(value);
|
|
|
+ json->WriteZstr(value);
|
|
|
}
|
|
|
}
|
|
|
- json.WriteZstr("\"");
|
|
|
+ json->WriteZstr("\"");
|
|
|
}
|
|
|
- json.WriteZstr("]\n");
|
|
|
+ json->WriteZstr("]\n");
|
|
|
}
|
|
|
- json.WriteZstr("]");
|
|
|
- if(withMetadata) json.WriteZstr("\n}");
|
|
|
+ json->WriteZstr("]");
|
|
|
+ if(withMetadata) json->WriteZstr("\n}");
|
|
|
+
|
|
|
+ if(has_blob) return 0;
|
|
|
+ sq_pushstring(v, (const SQChar*)json->GetBuf(), json->Len());
|
|
|
+ delete json;
|
|
|
|
|
|
- sq_pushstring(v, (const SQChar*)json.GetBuf(), json.Len());
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
@@ -801,39 +887,50 @@ static SQRESULT sq_sqlite3_stmt_asJsonObject(HSQUIRRELVM v)
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
GET_sqlite3_stmt_INSTANCE();
|
|
|
int col_count = sqlite3_column_count(self);
|
|
|
- int i;
|
|
|
+ int i, value_type, record_count = 0;
|
|
|
const char* value;
|
|
|
|
|
|
- SQBlob json(0, 8192);
|
|
|
+ SQBlob *json = NULL;
|
|
|
+ int has_blob = getOptionalBlob(v, 2, &json);
|
|
|
+ if(has_blob == SQ_ERROR) return SQ_ERROR;
|
|
|
|
|
|
- json.WriteZstr("{");
|
|
|
+ json->WriteZstr("{");
|
|
|
if(sqlite3_step(self) == SQLITE_ROW)
|
|
|
{
|
|
|
+ ++record_count;
|
|
|
for(i=0; i < col_count; ++i)
|
|
|
{
|
|
|
- json.WriteZstr((i == 0 ? "\"" : "\",\""));
|
|
|
- append_escaping_json(json, (const char*)sqlite3_column_name(self, i));
|
|
|
- json.WriteZstr("\":\"");
|
|
|
+ json->WriteZstr((i == 0 ? "\"" : "\",\""));
|
|
|
+ append_escaping_json(*json, (const char*)sqlite3_column_name(self, i));
|
|
|
+ json->WriteZstr("\":\"");
|
|
|
+ //if get the type after sqlite3_column_text it always returns SQLITE_TEXT
|
|
|
+ value_type = sqlite3_column_type(self, i);
|
|
|
value = (const char*)sqlite3_column_text(self, i);
|
|
|
if(value)
|
|
|
{
|
|
|
- switch(sqlite3_column_type(self, i))
|
|
|
+ switch(value_type)
|
|
|
{
|
|
|
+ case SQLITE_BLOB:
|
|
|
+ break; //no blobs in json
|
|
|
case SQLITE_TEXT:
|
|
|
{
|
|
|
- append_escaping_json(json, value);
|
|
|
+ append_escaping_json(*json, value);
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
- json.WriteZstr(value);
|
|
|
+ json->WriteZstr(value);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- json.WriteZstr("\"");
|
|
|
+ json->WriteZstr("\"");
|
|
|
}
|
|
|
- json.WriteZstr("}");
|
|
|
+ json->WriteZstr("}");
|
|
|
+
|
|
|
+ if(has_blob) return 0;
|
|
|
+ if(record_count) sq_pushstring(v, (const SQChar*)json->GetBuf(), json->Len());
|
|
|
+ else sq_pushnull(v);
|
|
|
+ delete json;
|
|
|
|
|
|
- sq_pushstring(v, (const SQChar*)json.GetBuf(), json.Len());
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
@@ -1102,41 +1199,75 @@ static SQRESULT sq_sqlite3_stmt_asSleArray(HSQUIRRELVM v)
|
|
|
int i;
|
|
|
const char *value;
|
|
|
|
|
|
- SQBlob sle(0, 8192);
|
|
|
+ SQBlob *sle = NULL;
|
|
|
+ int has_blob = getOptionalBlob(v, 2, &sle);
|
|
|
+ if(has_blob == SQ_ERROR) return SQ_ERROR;
|
|
|
|
|
|
- sle.WriteZstr("[[");
|
|
|
+ sle->WriteZstr("[[");
|
|
|
for(i=0; i < col_count; ++i)
|
|
|
{
|
|
|
value = sqlite3_column_name(self, i);
|
|
|
- add2sle(sle, value, strlen(value));
|
|
|
+ add2sle(*sle, value, strlen(value));
|
|
|
}
|
|
|
- sle.WriteChar(SLEEND);
|
|
|
- sle.WriteChar(']');
|
|
|
+ sle->WriteChar(SLEEND);
|
|
|
+ sle->WriteChar(']');
|
|
|
|
|
|
while(sqlite3_step(self) == SQLITE_ROW)
|
|
|
{
|
|
|
- sle.WriteChar('[');
|
|
|
+ sle->WriteChar('[');
|
|
|
for(i=0; i < col_count; ++i)
|
|
|
{
|
|
|
switch(sqlite3_column_type(self, i))
|
|
|
{
|
|
|
case SQLITE_BLOB:
|
|
|
{
|
|
|
- add2sle(sle, (const char*)sqlite3_column_blob(self, i),
|
|
|
+ add2sle(*sle, (const char*)sqlite3_column_blob(self, i),
|
|
|
sqlite3_column_bytes(self, i));
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
- add2sle(sle, (const char*)sqlite3_column_text(self, i),
|
|
|
+ add2sle(*sle, (const char*)sqlite3_column_text(self, i),
|
|
|
sqlite3_column_bytes(self, i));
|
|
|
}
|
|
|
}
|
|
|
- sle.WriteChar(SLEEND);
|
|
|
- sle.WriteChar(']');
|
|
|
+ sle->WriteChar(SLEEND);
|
|
|
+ sle->WriteChar(']');
|
|
|
}
|
|
|
- sle.WriteChar(']');
|
|
|
+ sle->WriteChar(']');
|
|
|
+
|
|
|
+ if(has_blob) return 0;
|
|
|
+ sq_pushstring(v, (const SQChar*)sle->GetBuf(), sle->Len());
|
|
|
+ delete sle;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
|
|
|
- sq_pushstring(v, (const SQChar*)sle.GetBuf(), sle.Len());
|
|
|
+static SQRESULT sq_sqlite3_stmt_all_blobs_size(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS(v);
|
|
|
+ GET_sqlite3_stmt_INSTANCE();
|
|
|
+ int total_size = 0, col_count = sqlite3_column_count(self);
|
|
|
+ for(int i=0; i < col_count; ++i)
|
|
|
+ {
|
|
|
+ if(sqlite3_column_type(self, i) == SQLITE_BLOB)
|
|
|
+ {
|
|
|
+ total_size += sqlite3_column_bytes(self, i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ sq_pushinteger(v, total_size);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static SQRESULT sq_sqlite3_stmt_colsSizeAsArray(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS_NO_TOP(v);
|
|
|
+ GET_sqlite3_stmt_INSTANCE();
|
|
|
+ int col_count = sqlite3_column_count(self);
|
|
|
+ sq_newarray(v, col_count);
|
|
|
+ for(int i=0; i<col_count; ++i)
|
|
|
+ {
|
|
|
+ sq_pushinteger(v, sqlite3_column_bytes(self, i));
|
|
|
+ sq_arrayset(v, -2, i);
|
|
|
+ }
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
@@ -1161,23 +1292,29 @@ static SQRegFunction sq_sqlite3_stmt_methods[] =
|
|
|
_DECL_FUNC(next_row, 1, _SC("x"), SQFalse),
|
|
|
_DECL_FUNC(colsAsArray, 1, _SC("x"), SQFalse),
|
|
|
_DECL_FUNC(colsAsTable, 1, _SC("x"), SQFalse),
|
|
|
+ _DECL_FUNC(colsTypeAsArray, 1, _SC("x"), SQFalse),
|
|
|
+ _DECL_FUNC(colsDeclTypeAsArray, 1, _SC("x"), SQFalse),
|
|
|
_DECL_FUNC(col_count, 1, _SC("x"), SQFalse),
|
|
|
_DECL_FUNC(col_name, 2, _SC("xi"), SQFalse),
|
|
|
+ _DECL_FUNC(colsNameAsArray, 1, _SC("x"), SQFalse),
|
|
|
_DECL_FUNC(col_type, 2, _SC("xi"), SQFalse),
|
|
|
_DECL_FUNC(col_declared_type, 2, _SC("xi"), SQFalse),
|
|
|
_DECL_FUNC(asArray, -1, _SC("xi"), SQFalse),
|
|
|
_DECL_FUNC(asTable, -1, _SC("xi"), SQFalse),
|
|
|
_DECL_FUNC(asArrayOfArrays, -1, _SC("xi"), SQFalse),
|
|
|
_DECL_FUNC(asArrayOfTables, -1, _SC("xi"), SQFalse),
|
|
|
- _DECL_FUNC(asSleArray, 1, _SC("x"), SQFalse),
|
|
|
- _DECL_FUNC(asJsonArray, -1, _SC("x"), SQFalse),
|
|
|
- _DECL_FUNC(asJsonObject, 1, _SC("x"), SQFalse),
|
|
|
+ _DECL_FUNC(asSleArray, -1, _SC("xx"), SQFalse),
|
|
|
+ //todo manage/skip blobs for json
|
|
|
+ _DECL_FUNC(asJsonArray, -1, _SC("xbx"), SQFalse),
|
|
|
+ _DECL_FUNC(asJsonObject, -1, _SC("xx"), SQFalse),
|
|
|
_DECL_FUNC(col, 2, _SC("x i|s"), SQFalse),
|
|
|
_DECL_FUNC(asString, 2, _SC("x i|s"), SQFalse),
|
|
|
_DECL_FUNC(asStringOrNull, 2, _SC("x i|s"), SQFalse),
|
|
|
_DECL_FUNC(asInteger, 2, _SC("x i|s"), SQFalse),
|
|
|
_DECL_FUNC(asBool, 2, _SC("x i|s"), SQFalse),
|
|
|
_DECL_FUNC(asFloat, 2, _SC("x i|s"), SQFalse),
|
|
|
+ _DECL_FUNC(all_blobs_size, 1, _SC("x"), SQFalse),
|
|
|
+ _DECL_FUNC(colsSizeAsArray, 1, _SC("x"), SQFalse),
|
|
|
{0,0}
|
|
|
};
|
|
|
#undef _DECL_FUNC
|
|
|
@@ -1246,7 +1383,8 @@ static SQRESULT sq_sqlite3_close_release(HSQUIRRELVM v, sq_sqlite3_sdb *sdb)
|
|
|
{
|
|
|
//do no close statements because garbage collector will do it
|
|
|
//on MacOSX we get segfaults finalizing statements here
|
|
|
- //sqlite3_finalize(statement);
|
|
|
+ printf("sq_sqlite3_close_release:stmt:%s\n", sqlite3_sql(statement));
|
|
|
+ sqlite3_finalize(statement);
|
|
|
count++;
|
|
|
}
|
|
|
if (count) return sq_throwerror(v, _SC("closing database with %d statements not closed."), count);
|
|
|
@@ -1283,6 +1421,8 @@ static SQRESULT sq_sqlite3_close_release(HSQUIRRELVM v, sq_sqlite3_sdb *sdb)
|
|
|
sq_release(sdb->v, &sdb->progress_udata);
|
|
|
sq_release(sdb->v, &sdb->trace_cb);
|
|
|
sq_release(sdb->v, &sdb->trace_udata);
|
|
|
+ sq_release(sdb->v, &sdb->update_hook_cb);
|
|
|
+ sq_release(sdb->v, &sdb->update_hook_udata);
|
|
|
sq_release(sdb->v, &sdb->null_value);
|
|
|
|
|
|
sq_free(sdb, sizeof(sq_sqlite3_sdb));
|
|
|
@@ -1318,6 +1458,8 @@ static SQRESULT sq_sqlite3_constructor(HSQUIRRELVM v)
|
|
|
sq_resetobject(&sdb->progress_udata);
|
|
|
sq_resetobject(&sdb->trace_cb);
|
|
|
sq_resetobject(&sdb->trace_udata);
|
|
|
+ sq_resetobject(&sdb->update_hook_cb);
|
|
|
+ sq_resetobject(&sdb->update_hook_udata);
|
|
|
sq_resetobject(&sdb->null_value);
|
|
|
|
|
|
sq_setinstanceup(v, 1, sdb);
|
|
|
@@ -1677,7 +1819,79 @@ static SQRESULT sq_sqlite3_trace(HSQUIRRELVM v)
|
|
|
}
|
|
|
|
|
|
/* set trace callback */
|
|
|
- sqlite3_trace(self, db_trace_callback, sdb);
|
|
|
+ if(_top_ > 3)
|
|
|
+ {
|
|
|
+ SQBool b;
|
|
|
+ sq_getbool(v, 4, &b);
|
|
|
+ sqlite3_trace_v2(self, db_trace_callback, sdb, b == SQTrue);
|
|
|
+ }
|
|
|
+ else sqlite3_trace(self, db_trace_callback, sdb);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+** update hook callback:
|
|
|
+** Params: database, callback function, userdata
|
|
|
+**
|
|
|
+** callback function:
|
|
|
+** Params: userdata, sql
|
|
|
+*/
|
|
|
+static void db_update_hook_callback(void *user, int update_type,
|
|
|
+ char const *db_name, char const *table_name, sqlite3_int64 rowid)
|
|
|
+{
|
|
|
+ sq_sqlite3_sdb *sdb = (sq_sqlite3_sdb*)user;
|
|
|
+ HSQUIRRELVM v = sdb->v;
|
|
|
+ int top = sq_gettop(v);
|
|
|
+
|
|
|
+ /* setup squirrel callback call */
|
|
|
+ sq_pushobject(v, sdb->update_hook_cb);
|
|
|
+ sq_pushroottable(v);
|
|
|
+ sq_pushobject(v, sdb->update_hook_udata);
|
|
|
+ sq_pushinteger(v, update_type);
|
|
|
+ sq_pushstring(v, db_name, -1);
|
|
|
+ sq_pushstring(v, table_name, -1);
|
|
|
+ sq_pushinteger(v, rowid);
|
|
|
+
|
|
|
+ /* call squirrel function */
|
|
|
+ sq_call(v, 6, SQFalse, SQFalse);
|
|
|
+ /* ignore any error generated by this function */
|
|
|
+
|
|
|
+ sq_settop(v, top);
|
|
|
+}
|
|
|
+
|
|
|
+static SQRESULT sq_sqlite3_update_hook(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS(v);
|
|
|
+ GET_sqlite3_INSTANCE();
|
|
|
+
|
|
|
+ if (_top_ < 2 || sq_gettype(v, 2) == OT_NULL)
|
|
|
+ {
|
|
|
+ sq_release(v, &sdb->update_hook_cb);
|
|
|
+ sq_release(v, &sdb->update_hook_udata);
|
|
|
+
|
|
|
+ sq_resetobject(&sdb->update_hook_cb);
|
|
|
+ sq_resetobject(&sdb->update_hook_udata);
|
|
|
+
|
|
|
+ /* clear trace handler */
|
|
|
+ sqlite3_update_hook(self, NULL, NULL);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(sq_gettype(v, 2) != OT_CLOSURE)
|
|
|
+ return sq_throwerror(v, _SC("invalid fisrt parameter expected closure"));
|
|
|
+
|
|
|
+ sq_getstackobj(v, 2, &sdb->update_hook_cb);
|
|
|
+ sq_addref(v, &sdb->update_hook_cb);
|
|
|
+ if(_top_ > 2)
|
|
|
+ {
|
|
|
+ sq_getstackobj(v, 3, &sdb->update_hook_udata);
|
|
|
+ sq_addref(v, &sdb->update_hook_udata);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* set update_hook callback */
|
|
|
+ sqlite3_update_hook(self, db_update_hook_callback, sdb);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
@@ -2301,6 +2515,7 @@ static SQRegFunction sq_sqlite3_methods[] =
|
|
|
_DECL_FUNC(interrupt, 1, _SC("x")),
|
|
|
_DECL_FUNC(progress_handler, -2, _SC("x i|o c .")),
|
|
|
_DECL_FUNC(trace, -2, _SC("x c|o .")),
|
|
|
+ _DECL_FUNC(update_hook, -2, _SC("x c|o .")),
|
|
|
_DECL_FUNC(busy_handler, -2, _SC("x c|o .")),
|
|
|
_DECL_FUNC(busy_timeout, 2, _SC("xi")),
|
|
|
_DECL_FUNC(create_function, -4, _SC("xsic.")),
|
|
|
@@ -2422,6 +2637,9 @@ extern "C" {
|
|
|
INT_CONST(v,SQLITE_NOTICE_RECOVER_WAL);
|
|
|
INT_CONST(v,SQLITE_NOTICE_RECOVER_ROLLBACK);
|
|
|
INT_CONST(v,SQLITE_WARNING_AUTOINDEX);
|
|
|
+ INT_CONST(v,SQLITE_INSERT);
|
|
|
+ INT_CONST(v,SQLITE_UPDATE);
|
|
|
+ INT_CONST(v,SQLITE_DELETE);
|
|
|
//push sqlite3_NULL as a member
|
|
|
sq_pushstring(v, nullName,-1);
|
|
|
sq_pushobject(v, sqlite3_NULL);
|
|
|
@@ -2434,12 +2652,19 @@ extern "C" {
|
|
|
sq_settypetag(v,-1,(void*)SQLite3_Stmt_TAG);
|
|
|
sq_insert_reg_funcs(v, sq_sqlite3_stmt_methods);
|
|
|
|
|
|
+ INT_CONST(v,SQLITE_INTEGER);
|
|
|
+ INT_CONST(v,SQLITE_FLOAT);
|
|
|
+ INT_CONST(v,SQLITE_NULL);
|
|
|
+ INT_CONST(v,SQLITE_TEXT);
|
|
|
+ INT_CONST(v,SQLITE_BLOB);
|
|
|
INT_CONST(v,SQLITE_OK);
|
|
|
INT_CONST(v,SQLITE_DONE);
|
|
|
INT_CONST(v,SQLITE_ROW);
|
|
|
INT_CONST(v,AS_STRING_ALWAYS);
|
|
|
INT_CONST(v,NULL_AS_EMPTY_STR);
|
|
|
INT_CONST(v,WITH_COL_NAMES);
|
|
|
+ INT_CONST(v,WITH_BLOB_AS_NULL);
|
|
|
+ INT_CONST(v,WITH_SQ_NULL);
|
|
|
|
|
|
//push sqlite3_NULL as a member
|
|
|
sq_pushstring(v, nullName,-1);
|