Przeglądaj źródła

Added the sqlite3 blob io interface

mingodad 9 lat temu
rodzic
commit
56638af838
1 zmienionych plików z 215 dodań i 0 usunięć
  1. 215 0
      SquiLu-ext/sq_sqlite3.cpp

+ 215 - 0
SquiLu-ext/sq_sqlite3.cpp

@@ -9,6 +9,7 @@ SQ_OPT_STRING_STRLEN();
 
 const SQChar *SQLite3_TAG = "SQLite3";
 static const SQChar *SQLite3_Stmt_TAG = "SQLite3Stmt";
+static const SQChar *SQLite3_Blob_TAG = "SQLite3Blob";
 
 static const SQChar sqlite3_NULL_Name[] = _SC("sqlite3_NULL");
 static const SQChar nullName[] = _SC("Null");
@@ -57,6 +58,14 @@ static SQRESULT get_sqlite3_stmt_instance(HSQUIRRELVM v, SQInteger idx, sqlite3_
     return _rc_;
 }
 
+static SQRESULT get_sqlite3_blob_instance(HSQUIRRELVM v, SQInteger idx, sqlite3_blob **blob)
+{
+    SQRESULT _rc_;
+    if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)blob,(void*)SQLite3_Blob_TAG)) < 0) return _rc_;
+    if(!*blob) return sq_throwerror(v, _SC("blob is closed"));
+    return _rc_;
+}
+
 //#define push_sqlite3_null(v) sq_getonregistrytable(v, sqlite3_NULL_Name, sizeof(sqlite3_NULL_Name)-1);
 //#define push_sqlite3_null(v) sq_pushobject(v, sqlite3_NULL);
 //#define push_sqlite3_null(v) sq_getbyname(v, 1, nullName, sizeof(nullName)-1)
@@ -79,6 +88,11 @@ static SQRESULT get_sqlite3_stmt_instance(HSQUIRRELVM v, SQInteger idx, sqlite3_
 	if((_rc_ = get_sqlite3_stmt_instance(v,idx,&var_name)) < 0) return _rc_;
 #define GET_sqlite3_stmt_INSTANCE() GET_sqlite3_stmt_INSTANCE_AT(1, self)
 
+#define GET_sqlite3_blob_INSTANCE_AT(idx, var_name)  \
+	sqlite3_blob *var_name=NULL; \
+	if((_rc_ = get_sqlite3_blob_instance(v,idx,&var_name)) < 0) return _rc_;
+#define GET_sqlite3_blob_INSTANCE() GET_sqlite3_blob_INSTANCE_AT(1, self)
+
 enum e_type_result {tr_first_row_first_col, tr_first_row, tr_all_rows, tr_ddml};
 
 #define AS_STRING_ALWAYS 0x01
@@ -446,6 +460,20 @@ static SQRESULT sq_sqlite3_stmt_bind_blob(HSQUIRRELVM v)
     return SQ_OK;
 }
 
+static SQRESULT sq_sqlite3_stmt_bind_zeroblob(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS_NO_TOP(v);
+    GET_sqlite3_stmt_INSTANCE();
+    SQ_GET_INTEGER(v, 2, npar);
+    SQ_GET_INTEGER(v, 3, nsize);
+    if(sqlite3_bind_zeroblob(self, npar, nsize))
+    {
+        sqlite3 *db = sqlite3_db_handle(self);
+        return sq_throwerror(v, sqlite3_errmsg(db));
+    }
+    return SQ_OK;
+}
+
 static SQRESULT sq_sqlite3_stmt_bind_values0(HSQUIRRELVM v, int isExec)
 {
     SQ_FUNC_VARS(v);
@@ -1418,6 +1446,7 @@ static SQRegFunction sq_sqlite3_stmt_methods[] =
     _DECL_FUNC(bind_exec_stmt,  2, _SC("xx"), SQFalse),
     _DECL_FUNC(bind_empty_null,  3, _SC("xi s|n|b|o|u"), SQFalse),
     _DECL_FUNC(bind_blob,  3, _SC("xis|u"), SQFalse),
+    _DECL_FUNC(bind_zeroblob,  3, _SC("xii"), SQFalse),
     _DECL_FUNC(bind_values,  -2, _SC("x s|n|b|o|u"), SQFalse),
     _DECL_FUNC(bind_exec,  -2, _SC("x s|n|b|o|u"), SQFalse),
     _DECL_FUNC(bind_names,  2, _SC("x t|a"), SQFalse),
@@ -1956,6 +1985,104 @@ static SQRESULT sq_sqlite3_prepare(HSQUIRRELVM v)
     return 1;
 }
 
+//sqlite3_blob
+static SQRESULT sq_sqlite3_blob_releasehook(SQUserPointer p, SQInteger size, void */*ep*/)
+{
+    sqlite3_blob *self = ((sqlite3_blob *)p);
+    if(self) sqlite3_blob_close(self);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_blob_close(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS_NO_TOP(v);
+    GET_sqlite3_blob_INSTANCE();
+    sq_setinstanceup(v, 1, 0); //next calls will fail with "blob is closed"
+    sq_pushinteger(v, sqlite3_blob_close(self));
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_blob_reopen(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS_NO_TOP(v);
+    GET_sqlite3_blob_INSTANCE();
+    SQ_GET_INTEGER(v, 2, iRow);
+    int rc = sqlite3_blob_reopen(self, iRow);
+    if(rc != SQLITE_OK) return sq_sqlite3_blob_close(v);
+    sq_pushinteger(v, rc);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_blob_bytes(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS_NO_TOP(v);
+    GET_sqlite3_blob_INSTANCE();
+    sq_pushinteger(v, sqlite3_blob_bytes(self));
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_blob_read(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sqlite3_blob_INSTANCE();
+    SQ_OPT_INTEGER(v, 2, size, 0);
+    SQ_OPT_INTEGER(v, 3, offset, 0);
+    if(!size) size = sqlite3_blob_bytes(self);
+    SQChar *buf = sq_getscratchpad(v, size);
+    int rc = sqlite3_blob_read(self, buf, size, offset);
+    if(rc == SQLITE_OK) sq_pushstring(v, buf, size);
+    else sq_pushnull(v);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_blob_write(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sqlite3_blob_INSTANCE();
+    SQ_GET_STRING(v, 2, buf);
+    SQ_OPT_INTEGER(v, 3, size, buf_size);
+    SQ_OPT_INTEGER(v, 4, offset, 0);
+    int rc = sqlite3_blob_write(self, buf, size, offset);
+    sq_pushinteger(v, rc);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_blob_open(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sqlite3_INSTANCE();
+    SQ_GET_STRING(v, 2, zDb);
+    SQ_GET_STRING(v, 3, zTable);
+    SQ_GET_STRING(v, 4, zColumn);
+    SQ_GET_INTEGER(v, 5, iRow);
+    SQ_OPT_INTEGER(v, 6, flags, 0);
+
+    sqlite3_blob *pBlob;
+    int rc = sqlite3_blob_open(self, zDb, zTable, zColumn, iRow, flags, &pBlob);
+    if(rc == SQLITE_OK)
+    {
+        sq_pushstring(v, SQLite3_Blob_TAG, -1);
+        if(sq_getonregistrytable(v) == SQ_ERROR) return SQ_ERROR;
+        sq_createinstance(v, -1);
+        sq_setinstanceup(v, -1, pBlob);
+        sq_setreleasehook(v, -1, sq_sqlite3_blob_releasehook);
+    }
+    else sq_pushnull(v);
+    return 1;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),  sq_sqlite3_blob_##name,nparams,tycheck}
+static SQRegFunction sq_sqlite3_blob_methods[] =
+{
+    _DECL_FUNC(close,  1, _SC("x")),
+    _DECL_FUNC(reopen,  2, _SC("xi")),
+    _DECL_FUNC(bytes,  1, _SC("x")),
+    _DECL_FUNC(read,  -1, _SC("xii")),
+    _DECL_FUNC(write,  -2, _SC("xsii")),
+    {0,0}
+};
+#undef _DECL_FUNC
+
 /* void set_busy_timeout( int nMillisecs  ) */
 static SQRESULT sq_sqlite3_set_busy_timeout(HSQUIRRELVM v)
 {
@@ -3088,6 +3215,86 @@ static SQRESULT sq_sqlite3_enable_load_extension(HSQUIRRELVM v)
 }
 #endif
 
+#if 0
+/**
+The number/order of fields should be the same to use this function
+it'll save temporary data convertion.
+*/
+static SQRESULT sq_sqlite3_exec_loop(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sqlite3_INSTANCE();
+    SQ_GET_STRING(v, 2, outer_sql);
+    SQ_GET_STRING(v, 3, inner1_sql);
+    SQ_OPT_STRING(v, 4, inner2_sql, NULL);
+
+    sqlite3_stmt *stmt_outer = NULL, *stmt_inner1 = NULL, *stmt_inner2 = NULL;
+
+    int rc = sqlite3_prepare_v2(self, outer_sql, outer_sql_size, &stmt_outer, NULL);
+    if(rc == SQLITE_OK)
+    {
+        rc = sqlite3_prepare_v2(self, inner1_sql, inner1_sql_size, &stmt_inner1, NULL);
+        if(rc == SQLITE_OK)
+        {
+            if(inner2_sql)
+            {
+                rc = sqlite3_prepare_v2(self, inner2_sql, inner2_sql_size, &stmt_inner2, NULL);
+            }
+            if(rc == SQLITE_OK)
+            {
+                int outer_col_count = sqlite3_column_count(stmt_outer);
+                int inner1_param_count = sqlite3_bind_parameter_count(stmt_inner1);
+                int inner2_param_count = stmt_inner2 ? sqlite3_bind_parameter_count(stmt_inner2) : -1;
+                if( (inner1_param_count <= outer_col_count) && ((inner2_param_count > 0)
+                                            && (inner2_param_count <= outer_col_count) ) )
+                {
+                    while(sqlite3_step(stmt_outer) == SQLITE_ROW)
+                    {
+                        for(int i=0; i < inner1_param_count; ++i)
+                        {
+                            rc = sqlite3_bind_value(stmt_inner1, i+1, sqlite3_column_value(stmt_outer, i));
+                            if(rc != SQLITE_OK) break;
+                        }
+                        if(rc == SQLITE_OK)
+                        {
+                            rc = sqlite3_step(stmt_inner1);
+                            sqlite3_reset(stmt_inner1);
+                        }
+                        if(rc != SQLITE_DONE) break;
+                        if((inner2_param_count > 0) && (sqlite3_changes(self) == 0))
+                        {
+                            for(int i=0; i < inner2_param_count; ++i)
+                            {
+                                rc = sqlite3_bind_value(stmt_inner2, i+1, sqlite3_column_value(stmt_outer, i));
+                                if(rc != SQLITE_OK) break;
+                            }
+                            if(rc == SQLITE_OK)
+                            {
+                                rc = sqlite3_step(stmt_inner2);
+                                sqlite3_reset(stmt_inner2);
+                            }
+                            if(rc != SQLITE_DONE) break;
+                        }
+                    }
+                }
+                else
+                {
+                    return sq_throwerror(v, _SC("bind parameter count mismatch expect %d : %d but got outer %d"),
+                                    inner1_param_count, inner2_param_count, outer_col_count);
+                }
+            }
+        }
+    }
+
+    if(stmt_outer) sqlite3_finalize(stmt_outer);
+    if(stmt_inner1) sqlite3_finalize(stmt_inner1);
+    if(stmt_inner2) sqlite3_finalize(stmt_inner2);
+
+    sq_pushinteger(v, rc);
+    return 1;
+}
+#endif // 0
+
 #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),  sq_sqlite3_##name,nparams,tycheck}
 static SQRegFunction sq_sqlite3_methods[] =
 {
@@ -3123,9 +3330,11 @@ static SQRegFunction sq_sqlite3_methods[] =
     _DECL_FUNC(exec_one_dml,  -2, _SC("x s|x")),
     _DECL_FUNC(exec_get_first_row,  -2, _SC("x s|x")),
     _DECL_FUNC(exec_get_one,  -2, _SC("x s|x")),
+    //_DECL_FUNC(exec_loop,  -3, _SC("x sss")),
     _DECL_FUNC(get_db_name,  1, _SC("x")),
     _DECL_FUNC(last_row_id,  1, _SC("x")),
     _DECL_FUNC(prepare,  2, _SC("xs")),
+    _DECL_FUNC(blob_open, -5, _SC("xsssii")),
     _DECL_FUNC(set_busy_timeout,  -1, _SC("xi")),
     _DECL_FUNC(total_changes,  1, _SC("x")),
     _DECL_FUNC(backup,  -2, _SC("xss")),
@@ -3188,6 +3397,12 @@ extern "C" {
         sq_insert_reg_funcs(v, sq_sqlite3_context_methods);
         sq_newslot(v,-3,SQTrue);
 
+        sq_pushstring(v,SQLite3_Blob_TAG,-1);
+        sq_newclass(v,SQFalse);
+        sq_settypetag(v,-1,(SQUserPointer)SQLite3_Blob_TAG);
+        sq_insert_reg_funcs(v, sq_sqlite3_blob_methods);
+        sq_newslot(v,-3,SQTrue);
+
         sq_poptop(v); //remove registrytable
 
         sq_pushstring(v,SQLite3_TAG,-1);