8c2d942008-08-05Martin Stjernholm /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
dc22e92004-10-14Martin Nilsson  #include "global.h"
8f7db02017-03-04Henrik Grubbström (Grubba) #include "pike_compiler.h"
dc22e92004-10-14Martin Nilsson #include "interpret.h"
b1487a2006-06-22Marcus Agehall #include "backend.h"
dc22e92004-10-14Martin Nilsson #include "module_support.h" #include "config.h" #include "object.h" #include "builtin_functions.h"
6919952004-10-15Marcus Agehall #include "mapping.h"
cd927f2017-07-19Bill Welliver #include "multiset.h"
b1487a2006-06-22Marcus Agehall #include "threads.h"
5c2d9d2008-08-05Martin Stjernholm #include "bignum.h"
3ab15d2014-08-19Tobias S. Josefowitz #include "pike_types.h"
dc22e92004-10-14Martin Nilsson 
c1b1702007-12-18Henrik Grubbström (Grubba) #if defined(HAVE_SQLITE3_H) && defined(HAVE_LIBSQLITE3)
dc22e92004-10-14Martin Nilsson 
a33b7c2017-05-19Henrik Grubbström (Grubba) #ifdef HAVE_STDINT_H
b1487a2006-06-22Marcus Agehall #include <stdint.h>
a33b7c2017-05-19Henrik Grubbström (Grubba) #endif
0eb91f2017-06-05Henrik Grubbström (Grubba) 
dc22e92004-10-14Martin Nilsson #include <sqlite3.h> #include <time.h>
3714062010-02-18Stephen R. van den Berg #define SLEEP() sysleep(0.0001)
45dd962004-10-21Martin Nilsson 
dc22e92004-10-14Martin Nilsson DECLARATIONS
0eb91f2017-06-05Henrik Grubbström (Grubba) /* NB: On Solaris 11 with __EXTENSIONS__ defined <stdlib.h> et el indirectly * include <sys/regset.h> which has a conflicting definition of ERR... */ #undef ERR
b1487a2006-06-22Marcus Agehall #define ERR(X, db) \ if((X)!=SQLITE_OK) { \ SQLite_handle_error((db)); \ }
c1b1702007-12-18Henrik Grubbström (Grubba) static void SQLite_handle_error(sqlite3 *db) {
b1487a2006-06-22Marcus Agehall  if (db) {
c1b1702007-12-18Henrik Grubbström (Grubba)  push_text(sqlite3_errmsg(db)); f_utf8_to_string(1); Pike_error("Sql.SQLite: %S\n", Pike_sp[-1].u.string);
b1487a2006-06-22Marcus Agehall  } else { Pike_error("Sql.SQLite: Internal module error\n"); } }
dc22e92004-10-14Martin Nilsson static int step(sqlite3_stmt *stmt) { int ret;
8c2d942008-08-05Martin Stjernholm  /* FIXME: This is not always a good way to handle SQLITE_BUSY: * * SQLITE_BUSY means that the database engine was unable to * acquire the database locks it needs to do its job. If the * statement is a COMMIT or occurs outside of an explicit * transaction, then you can retry the statement. If the statement * is not a COMMIT and occurs within a explicit transaction then * you should rollback the transaction before continuing. */
b1487a2006-06-22Marcus Agehall  while( (ret=sqlite3_step(stmt))==SQLITE_BUSY ) { THREADS_ALLOW();
45dd962004-10-21Martin Nilsson  SLEEP();
b1487a2006-06-22Marcus Agehall  THREADS_DISALLOW(); }
dc22e92004-10-14Martin Nilsson  return ret; }
cb1be22017-07-06Bill Welliver /* NOTE: SQLite is flexible about the data stored within any field and as such, any field in any row may hold any type of data, regardless of the field's definition. Thus, when using bindings, this module will use the datatype of the value to determine the type stored in the field: ints and floats as numbers, strings as text. Binary (blob) data may be stored by wrapping the string
6aabe12017-07-08Martin Nilsson  containing the binary data in a String.Buffer/Stdio.Buffer/System.Memory object.
cb1be22017-07-06Bill Welliver */
b1487a2006-06-22Marcus Agehall static void bind_arguments(sqlite3 *db,
439d082017-07-25Martin Nilsson  sqlite3_stmt *stmt, struct mapping *bindings) {
b1487a2006-06-22Marcus Agehall  struct mapping_data *md = bindings->data; INT32 e; struct keypair *k; NEW_MAPPING_LOOP(md) { int idx;
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(k->ind)) {
b1487a2006-06-22Marcus Agehall  case T_INT: idx = k->ind.u.integer; break; case T_STRING: ref_push_string(k->ind.u.string); f_string_to_utf8(1); idx = sqlite3_bind_parameter_index(stmt, Pike_sp[-1].u.string->str); pop_stack(); if(!idx) Pike_error("Unknown bind index \"%S\".\n", k->ind.u.string); break; default: Pike_error("Bind index is not int|string.\n"); }
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(k->val)) {
b1487a2006-06-22Marcus Agehall  case T_INT: ERR( sqlite3_bind_int64(stmt, idx, k->val.u.integer), db ); break; case T_STRING: { struct pike_string *s = k->val.u.string;
cb1be22017-07-06Bill Welliver  ref_push_string(s); f_string_to_utf8(1); s = Pike_sp[-1].u.string; ERR( sqlite3_bind_text(stmt, idx, s->str, s->len, SQLITE_TRANSIENT), db); pop_stack();
b1487a2006-06-22Marcus Agehall  } break; case T_FLOAT: ERR( sqlite3_bind_double(stmt, idx, (double)k->val.u.float_number), db); break;
61f2202017-07-07Martin Nilsson 
cd927f2017-07-19Bill Welliver  case T_MULTISET: if(multiset_sizeof(k->val.u.multiset) == 1) { struct pike_string *s; { struct svalue tmp; if (TYPEOF(*use_multiset_index (k->val.u.multiset, multiset_first (k->val.u.multiset), tmp)) == T_STRING) s = tmp.u.string; else s = NULL; } if(s) { ERR(sqlite3_bind_blob(stmt, idx, s->str, s->len,
aaa5812017-07-22Martin Nilsson  SQLITE_TRANSIENT),
cd927f2017-07-19Bill Welliver  db); }
aaa5812017-07-22Martin Nilsson  sub_msnode_ref(k->val.u.multiset); if(s) break;
cd927f2017-07-19Bill Welliver  } Pike_error("Can only bind string|int|float or single-valued multiset(string)|String.Buffer|Stdio.Buffer|System.Memory as blob.\n");
aaa5812017-07-22Martin Nilsson  break;
6aabe12017-07-08Martin Nilsson  case T_OBJECT: { size_t len; void *ptr; if( get_memory_object_memory(k->val.u.object, &ptr, &len, NULL)!= MEMOBJ_NONE )
cb1be22017-07-06Bill Welliver  {
439d082017-07-25Martin Nilsson  ERR(sqlite3_bind_blob(stmt, idx, ptr, len, SQLITE_STATIC), db);
6aabe12017-07-08Martin Nilsson  break; }
cb1be22017-07-06Bill Welliver  }
61f2202017-07-07Martin Nilsson  /* Fallthrough */
b1487a2006-06-22Marcus Agehall  default:
cd927f2017-07-19Bill Welliver  Pike_error("Can only bind string|int|float or single-valued multiset(string)|String.Buffer|Stdio.Buffer|System.Memory as blob.\n");
b1487a2006-06-22Marcus Agehall  } } }
b2124f2015-08-26Martin Nilsson static void push_field(sqlite3_stmt *stmt, int field) { switch( sqlite3_column_type(stmt, field) ) { case SQLITE_INTEGER: push_int64( sqlite3_column_int64(stmt, field) ); break; case SQLITE_FLOAT: push_float( sqlite3_column_double(stmt, field) ); break; case SQLITE_BLOB: case SQLITE_TEXT: push_string( make_shared_binary_string ( sqlite3_column_blob(stmt, field), sqlite3_column_bytes(stmt, field) ) ); if( sqlite3_column_type(stmt, field)==SQLITE_TEXT ) f_utf8_to_string(1); break; case SQLITE_NULL:
f6b46b2017-03-19Henrik Grubbström (Grubba)  push_int(0); /* FIXME: Ought to be Val.Null. */ break; } } static void push_string_field(sqlite3_stmt *stmt, int field) { switch( sqlite3_column_type(stmt, field) ) { case SQLITE_INTEGER: case SQLITE_FLOAT: push_text( (char*)sqlite3_column_text(stmt, field) ); break; case SQLITE_BLOB: case SQLITE_TEXT: push_string( make_shared_binary_string ( sqlite3_column_blob(stmt, field), sqlite3_column_bytes(stmt, field) ) ); if( sqlite3_column_type(stmt, field)==SQLITE_TEXT ) f_utf8_to_string(1); break; case SQLITE_NULL: push_int(0);
b2124f2015-08-26Martin Nilsson  break; } }
75aa7a2008-08-05Henrik Grubbström (Grubba) /*! @class SQLite *! *! Low-level interface to SQLite3 databases. *! *! This class should typically not be accessed directly, but instead *! via @[Sql.Sql()] with the scheme @expr{"sqlite://"@}. */
b1487a2006-06-22Marcus Agehall PIKECLASS SQLite { CVAR sqlite3 *db;
25d8142017-03-04Henrik Grubbström (Grubba)  /*! @decl inherit __builtin.Sql.Connection */ INHERIT "__builtin.Sql.Connection";
f6b46b2017-03-19Henrik Grubbström (Grubba) /*! @class TypedResult
75aa7a2008-08-05Henrik Grubbström (Grubba)  *!
f6b46b2017-03-19Henrik Grubbström (Grubba)  *! Result object from @[typed_big_query()].
75aa7a2008-08-05Henrik Grubbström (Grubba)  */
f6b46b2017-03-19Henrik Grubbström (Grubba) PIKECLASS TypedResult
ecc9382008-06-29Martin Nilsson  flags ID_PRIVATE | ID_PROTECTED | ID_HIDDEN;
dc22e92004-10-14Martin Nilsson {
45dd962004-10-21Martin Nilsson  CVAR struct object *dbobj;
69e5a42004-10-23Martin Nilsson  CVAR struct mapping *bindings;
dc22e92004-10-14Martin Nilsson  CVAR sqlite3_stmt *stmt; CVAR int eof; CVAR int columns;
8f7db02017-03-04Henrik Grubbström (Grubba)  /*! @decl inherit __builtin.Sql.Result */ INHERIT "__builtin.Sql.Result";
f6b46b2017-03-19Henrik Grubbström (Grubba)  static void SQLite_TypedResult_handle_error(void) {
b1487a2006-06-22Marcus Agehall  Pike_error("Sql.SQLite: %s\n", sqlite3_errmsg(OBJ2_SQLITE(THIS->dbobj)->db));
dc22e92004-10-14Martin Nilsson  }
45dd962004-10-21Martin Nilsson  PIKEFUN void create()
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
45dd962004-10-21Martin Nilsson  {
dc22e92004-10-14Martin Nilsson  THIS->columns = sqlite3_column_count(THIS->stmt); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl int num_rows() *! *! @note *! This API is not supported for @[Sql.sqlite]. *! *! @seealso *! @[Sql.sql_result()->num_rows()] */
dc22e92004-10-14Martin Nilsson  PIKEFUN int num_rows() { Pike_error("Sql.SQLite: Number of rows not known in advance.\n"); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl int num_fields() *! *! @seealso *! @[Sql.sql_result()->num_fields()] */
dc22e92004-10-14Martin Nilsson  PIKEFUN int num_fields() { RETURN THIS->columns; }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl int eof() *! *! @seealso *! @[Sql.sql_result()->eof()] */
dc22e92004-10-14Martin Nilsson  PIKEFUN int eof() { RETURN THIS->eof; }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl array(mapping(string:mixed)) fetch_fields() *! *! @seealso *! @[Sql.sql_result()->fetch_fields()] */
0d58042004-10-14Martin Nilsson  PIKEFUN array(mapping(string:mixed)) fetch_fields() {
a83ab92008-07-31H. William Welliver III  int i,t;
0d58042004-10-14Martin Nilsson  for(i=0; i<THIS->columns; i++) { push_constant_text("name"); push_text(sqlite3_column_name(THIS->stmt, i));
c36d502004-10-15Martin Nilsson  f_utf8_to_string(1);
6a932b2014-08-18Martin Nilsson  ref_push_string(literal_type_string);
6c6c722008-08-01Martin Nilsson  t = sqlite3_column_type(THIS->stmt, i); switch(t) { case SQLITE_INTEGER: push_constant_text("integer"); break; case SQLITE_FLOAT:
6a932b2014-08-18Martin Nilsson  ref_push_string(literal_float_string);
6c6c722008-08-01Martin Nilsson  break; case SQLITE_BLOB: push_constant_text("blob"); break; case SQLITE_NULL: push_constant_text("null"); break; case SQLITE_TEXT: push_constant_text("text"); break; default:
5e9fc02015-08-18Per Hedbor  push_static_text("unknown");
6c6c722008-08-01Martin Nilsson  break; }
a83ab92008-07-31H. William Welliver III  f_aggregate_mapping(4);
0d58042004-10-14Martin Nilsson  } f_aggregate(THIS->columns);
dc22e92004-10-14Martin Nilsson  }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl void seek(int skip) *! *! @seealso *! @[Sql.sql_result()->seek()] */
dc22e92004-10-14Martin Nilsson  PIKEFUN void seek(int skip) { int i; for(i=0; i<skip; i++) if( step(THIS->stmt)==SQLITE_DONE ) { THIS->eof = 1; return; } }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl array fetch_row() *! *! @seealso *! @[Sql.sql_result()->fetch_row()] */
dc22e92004-10-14Martin Nilsson  PIKEFUN array fetch_row() { int i;
c36d502004-10-15Martin Nilsson  sqlite3_stmt *stmt = THIS->stmt;
dc22e92004-10-14Martin Nilsson  if(THIS->eof) { push_int(0); return; }
c36d502004-10-15Martin Nilsson  switch( step(stmt) ) {
dc22e92004-10-14Martin Nilsson  case SQLITE_DONE: THIS->eof = 1;
c36d502004-10-15Martin Nilsson  sqlite3_finalize(stmt);
dc22e92004-10-14Martin Nilsson  THIS->stmt = 0; push_int(0); return; case SQLITE_ROW: break; default:
f6b46b2017-03-19Henrik Grubbström (Grubba)  SQLite_TypedResult_handle_error();
dc22e92004-10-14Martin Nilsson  }
b2124f2015-08-26Martin Nilsson  for(i=0; i<THIS->columns; i++) push_field(stmt, i);
dc22e92004-10-14Martin Nilsson  f_aggregate(THIS->columns); } INIT { THIS->columns = -1;
b467522017-06-25Martin Nilsson #ifdef PIKE_NULL_IS_SPECIAL THIS->eof = 0;
45dd962004-10-21Martin Nilsson  THIS->dbobj = NULL; THIS->stmt = NULL;
69e5a42004-10-23Martin Nilsson  THIS->bindings = NULL;
b467522017-06-25Martin Nilsson #endif
dc22e92004-10-14Martin Nilsson  }
d858ae2008-05-30Martin Nilsson  EXIT gc_trivial; {
dc22e92004-10-14Martin Nilsson  if(THIS->stmt) sqlite3_finalize(THIS->stmt);
45dd962004-10-21Martin Nilsson  if(THIS->dbobj) free_object(THIS->dbobj);
69e5a42004-10-23Martin Nilsson  if(THIS->bindings) free_mapping(THIS->bindings);
dc22e92004-10-14Martin Nilsson  } }
75aa7a2008-08-05Henrik Grubbström (Grubba) /*! @endclass */
f6b46b2017-03-19Henrik Grubbström (Grubba) /*! @class Result *! *! Result object from @[big_query()]. */ PIKECLASS Result flags ID_PRIVATE | ID_PROTECTED | ID_HIDDEN; { /*! @decl inherit TypedResult */ INHERIT SQLite_TypedResult; /* Access the inherited variables directly... */ #undef THIS #define THIS THIS_SQLITE_TYPEDRESULT /*! @decl array fetch_row() *! *! @seealso *! @[Sql.sql_result()->fetch_row()] */ PIKEFUN array fetch_row() { int i; sqlite3_stmt *stmt = THIS->stmt; if(THIS->eof) { push_int(0); return; } switch( step(stmt) ) { case SQLITE_DONE: THIS->eof = 1; sqlite3_finalize(stmt); THIS->stmt = 0; push_int(0); return; case SQLITE_ROW: break; default: SQLite_TypedResult_handle_error(); } for(i=0; i<THIS->columns; i++) push_string_field(stmt, i); f_aggregate(THIS->columns); } } /*! @endclass */
a627442006-07-05Martin Stjernholm #undef THIS #define THIS THIS_SQLITE
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl void create(string path, mixed ... ignored) *! *! Open the SQLite database stored at @[path].
dc22e92004-10-14Martin Nilsson  */
0a5ec32012-04-12Henrik Grubbström (Grubba)  PIKEFUN void create(string path, mixed|void a, mixed|void b, mixed|void c, mapping|void options)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
45dd962004-10-21Martin Nilsson  {
c36d502004-10-15Martin Nilsson  pop_n_elems(args-1); f_string_to_utf8(1);
c284a72011-01-09Henrik Grubbström (Grubba)  /* FIXME: Does the following work if THIS->db is already open? */
2c3dd32016-02-04Martin Nilsson  ERR( sqlite3_open(Pike_sp[-1].u.string->str, &THIS->db), THIS->db );
dc22e92004-10-14Martin Nilsson  }
f6b46b2017-03-19Henrik Grubbström (Grubba)  /*! @decl array|int typed_query(string query, @ *! mapping(string|int:mixed)|void bindings) *! *! Perform a typed_query against a SQLite database. *! *! @note *! This was the behavior of @[query()] in Pike 8.0 and earlier. *! *! @seealso *! @[Sql.Sql()->query()], @[query()] */ PIKEFUN array|int typed_query(string query, mapping(string|int:mixed)|void bindings)
ef8b3b2018-03-17Henrik Grubbström (Grubba)  flags ID_VARIANT;
f6b46b2017-03-19Henrik Grubbström (Grubba)  { sqlite3_stmt *stmt; const char *tail; struct pike_string *q; INT32 res_count = 0; INT32 columns; INT32 i; if(args==2) stack_swap(); f_string_to_utf8(1); q = Pike_sp[-1].u.string; ERR( sqlite3_prepare(THIS->db, q->str, q->len, &stmt, &tail), THIS->db); if( tail[0] ) Pike_error("Sql.SQLite->typed_query: Trailing query data (\"%s\")\n", tail); pop_stack(); /* Add a reference to the database to prevent it from being destroyed before the query object. */ if(bindings) { bind_arguments(THIS->db, stmt, bindings); } columns = sqlite3_column_count(stmt); check_stack(128); BEGIN_AGGREGATE_ARRAY(100) { while(stmt) { int sr=step(stmt); switch(sr) { case SQLITE_OK: /* Fallthrough */ case SQLITE_DONE: sqlite3_finalize(stmt); stmt = 0; break; case SQLITE_ROW: for(i=0; i<columns; i++) { push_text(sqlite3_column_name(stmt, i)); f_utf8_to_string(1); push_field(stmt, i); } f_aggregate_mapping(columns*2); DO_AGGREGATE_ARRAY(100); break; case SQLITE_MISUSE: Pike_error("Sql.SQLite: Library misuse."); default: Pike_error("Sql.SQLite: (%d) %s\n", sr, sqlite3_errmsg(THIS->db)); } } } END_AGGREGATE_ARRAY; if (!Pike_sp[-1].u.array->size && !columns) { /* No rows and no columns. */ pop_stack(); push_int(0); } }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl array|int query(string query, @ *! mapping(string|int:mixed)|void bindings) *! *! Perform a query against a SQLite database. *!
f6b46b2017-03-19Henrik Grubbström (Grubba)  *! @note *! In Pike 8.0 and earlier this function behaved as @[typed_query()]. *!
c284a72011-01-09Henrik Grubbström (Grubba)  *! @seealso
f6b46b2017-03-19Henrik Grubbström (Grubba)  *! @[Sql.Sql()->query()], @[typed_query()]
c284a72011-01-09Henrik Grubbström (Grubba)  */
b1487a2006-06-22Marcus Agehall  PIKEFUN array|int query(string query,
f6b46b2017-03-19Henrik Grubbström (Grubba)  mapping(string|int:mixed)|void bindings)
ef8b3b2018-03-17Henrik Grubbström (Grubba)  flags ID_VARIANT;
f6b46b2017-03-19Henrik Grubbström (Grubba)  {
dc22e92004-10-14Martin Nilsson  sqlite3_stmt *stmt; const char *tail;
c36d502004-10-15Martin Nilsson  struct pike_string *q;
7ddde32006-07-10Martin Nilsson  INT32 res_count = 0;
e5e2722008-08-03Henrik Grubbström (Grubba)  INT32 columns;
7ddde32006-07-10Martin Nilsson  INT32 i;
c36d502004-10-15Martin Nilsson 
69e5a42004-10-23Martin Nilsson  if(args==2) stack_swap();
c36d502004-10-15Martin Nilsson  f_string_to_utf8(1); q = Pike_sp[-1].u.string;
dc22e92004-10-14Martin Nilsson 
b1487a2006-06-22Marcus Agehall  ERR( sqlite3_prepare(THIS->db, q->str, q->len, &stmt, &tail), THIS->db);
dc22e92004-10-14Martin Nilsson  if( tail[0] )
f1da342015-08-02Martin Nilsson  Pike_error("Sql.SQLite->query: Trailing query data (\"%s\")\n",
dc22e92004-10-14Martin Nilsson  tail);
69e5a42004-10-23Martin Nilsson  pop_stack();
dc22e92004-10-14Martin Nilsson 
45dd962004-10-21Martin Nilsson  /* Add a reference to the database to prevent it from being destroyed before the query object. */
69e5a42004-10-23Martin Nilsson  if(bindings) {
b1487a2006-06-22Marcus Agehall  bind_arguments(THIS->db, stmt, bindings); }
e5e2722008-08-03Henrik Grubbström (Grubba)  columns = sqlite3_column_count(stmt);
b1487a2006-06-22Marcus Agehall  check_stack(128); BEGIN_AGGREGATE_ARRAY(100) { while(stmt) { int sr=step(stmt); switch(sr) { case SQLITE_OK: /* Fallthrough */ case SQLITE_DONE: sqlite3_finalize(stmt); stmt = 0;
69e5a42004-10-23Martin Nilsson  break;
b1487a2006-06-22Marcus Agehall  case SQLITE_ROW: for(i=0; i<columns; i++) {
b2124f2015-08-26Martin Nilsson  push_text(sqlite3_column_name(stmt, i)); f_utf8_to_string(1);
f6b46b2017-03-19Henrik Grubbström (Grubba)  push_string_field(stmt, i);
b2124f2015-08-26Martin Nilsson  }
a83ab92008-07-31H. William Welliver III  f_aggregate_mapping(columns*2);
b1487a2006-06-22Marcus Agehall  DO_AGGREGATE_ARRAY(100);
69e5a42004-10-23Martin Nilsson  break;
b1487a2006-06-22Marcus Agehall  case SQLITE_MISUSE: Pike_error("Sql.SQLite: Library misuse.");
69e5a42004-10-23Martin Nilsson  default:
b1487a2006-06-22Marcus Agehall  Pike_error("Sql.SQLite: (%d) %s\n", sr, sqlite3_errmsg(THIS->db));
69e5a42004-10-23Martin Nilsson  } }
b1487a2006-06-22Marcus Agehall  } END_AGGREGATE_ARRAY;
e5e2722008-08-03Henrik Grubbström (Grubba)  if (!Pike_sp[-1].u.array->size && !columns) { /* No rows and no columns. */
b1487a2006-06-22Marcus Agehall  pop_stack(); push_int(0); } }
f6b46b2017-03-19Henrik Grubbström (Grubba)  /*! @decl TypedResult big_typed_query(string query, @ *! mapping(string|int:mixed)|void bindings) *! *! Perform a streaming typed query against a SQLite database. *! *! @note *! This was the behavior of @[big_query()] in Pike 8.0 and earlier. *! *! @seealso *! @[Sql.Sql()->big_typed_query()], @[big_query()] */
9a6c0b2017-03-27Henrik Grubbström (Grubba)  PIKEFUN object big_typed_query(string query,
f6b46b2017-03-19Henrik Grubbström (Grubba)  mapping(string|int:mixed)|void bindings) flags ID_VARIANT; { struct object *res; sqlite3_stmt *stmt; const char *tail; struct SQLite_TypedResult_struct *store; struct pike_string *q; if(args==2) stack_swap(); f_string_to_utf8(1); q = Pike_sp[-1].u.string; ERR( sqlite3_prepare(THIS->db, q->str, q->len, &stmt, &tail), THIS->db); if( tail[0] ) Pike_error("Sql.SQLite->big_query: Trailing query data (\"%s\")\n", tail); pop_stack(); res=fast_clone_object(SQLite_TypedResult_program); store = OBJ2_SQLITE_TYPEDRESULT(res); store->stmt = stmt; /* Add a reference to the database to prevent it from being * destroyed before the query object. * * FIXME: Use parent pointer instead? */ store->dbobj = this_object(); if(bindings) { bind_arguments(THIS->db, stmt, bindings); /* Add a reference so that the bound strings are kept, which in turn allows us to use SQLITE_STATIC. */ add_ref(bindings); store->bindings = bindings; } apply_low(res, f_SQLite_TypedResult_create_fun_num, 0); push_object(res); } /*! @decl Result big_query(string query, @
c284a72011-01-09Henrik Grubbström (Grubba)  *! mapping(string|int:mixed)|void bindings) *! *! Perform a streaming query against a SQLite database. *!
f6b46b2017-03-19Henrik Grubbström (Grubba)  *! @note *! In Pike 8.0 and earlier this function behaved as @[big_typed_query()]. *!
c284a72011-01-09Henrik Grubbström (Grubba)  *! @seealso
f6b46b2017-03-19Henrik Grubbström (Grubba)  *! @[Sql.Sql()->big_query()], @[big_typed_query()]
c284a72011-01-09Henrik Grubbström (Grubba)  */
9a6c0b2017-03-27Henrik Grubbström (Grubba)  PIKEFUN object big_query(string query,
8f7db02017-03-04Henrik Grubbström (Grubba)  mapping(string|int:mixed)|void bindings) flags ID_VARIANT; {
b1487a2006-06-22Marcus Agehall  struct object *res; sqlite3_stmt *stmt; const char *tail;
f6b46b2017-03-19Henrik Grubbström (Grubba)  struct SQLite_TypedResult_struct *store;
b1487a2006-06-22Marcus Agehall  struct pike_string *q; if(args==2) stack_swap(); f_string_to_utf8(1); q = Pike_sp[-1].u.string; ERR( sqlite3_prepare(THIS->db, q->str, q->len, &stmt, &tail), THIS->db); if( tail[0] ) Pike_error("Sql.SQLite->big_query: Trailing query data (\"%s\")\n", tail); pop_stack();
f6b46b2017-03-19Henrik Grubbström (Grubba)  res=fast_clone_object(SQLite_Result_program); store = OBJ2_SQLITE_TYPEDRESULT(res);
b1487a2006-06-22Marcus Agehall  store->stmt = stmt; /* Add a reference to the database to prevent it from being
8f7db02017-03-04Henrik Grubbström (Grubba)  * destroyed before the query object. * * FIXME: Use parent pointer instead? */
b1487a2006-06-22Marcus Agehall  store->dbobj = this_object(); if(bindings) { bind_arguments(THIS->db, stmt, bindings);
69e5a42004-10-23Martin Nilsson  /* Add a reference so that the bound strings are kept, which in turn allows us to use SQLITE_STATIC. */ add_ref(bindings); store->bindings = bindings; }
f6b46b2017-03-19Henrik Grubbström (Grubba)  apply_low(res, f_SQLite_TypedResult_create_fun_num, 0);
dc22e92004-10-14Martin Nilsson  push_object(res); }
0d58042004-10-14Martin Nilsson 
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl int changes() *! *! Get the number of changes. *! *! @fixme *! Document this function properly. */
4844bc2004-10-23Martin Nilsson  PIKEFUN int changes() optflags OPT_EXTERNAL_DEPEND; {
0d58042004-10-14Martin Nilsson  RETURN sqlite3_changes(THIS->db); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl int total_changes() *! *! Get the total number of changes for this session. *! *! @fixme *! Document this function properly. */
4844bc2004-10-23Martin Nilsson  PIKEFUN int total_changes() optflags OPT_EXTERNAL_DEPEND; {
0d58042004-10-14Martin Nilsson  RETURN sqlite3_total_changes(THIS->db); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl void interrupt() *! *! @fixme *! Document this function. */
4844bc2004-10-23Martin Nilsson  PIKEFUN void interrupt() optflags OPT_SIDE_EFFECT; {
0d58042004-10-14Martin Nilsson  sqlite3_interrupt(THIS->db); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl string server_info() *! *! Get information about the SQLite library version. *! *! @seealso *! @[Sql.Sql()->server_info()] */
4844bc2004-10-23Martin Nilsson  PIKEFUN string server_info() optflags OPT_TRY_OPTIMIZE; {
7cf0162014-05-22Per Hedbor  push_text(sqlite3_libversion());
0d58042004-10-14Martin Nilsson  }
75aa7a2008-08-05Henrik Grubbström (Grubba)  /*! @decl int insert_id() *! *! Returns the value of the @tt{ROWID@} (aka @tt{OID@}, aka @tt{_ROWID_@}, *! or declared @tt{INTEGER PRIMARY KEY@}) column for the most recent *! successful @tt{INSERT@} operation, or @expr{0@} (zero) if no @tt{INSERT@} *! operations have been performed on the connection yet. */ PIKEFUN int insert_id()
4844bc2004-10-23Martin Nilsson  optflags OPT_EXTERNAL_DEPEND; {
d38a322014-10-29Martin Nilsson  push_int64 (sqlite3_last_insert_rowid(THIS->db));
0d58042004-10-14Martin Nilsson  }
921eda2017-11-19Stephen R. van den Berg  /*! @decl string error(void|int clear)
c284a72011-01-09Henrik Grubbström (Grubba)  *! *! Get the latest error message. *! *! @seealso *! @[Sql.Sql()->error()] */
921eda2017-11-19Stephen R. van den Berg  PIKEFUN string error(void|int clear)
4844bc2004-10-23Martin Nilsson  optflags OPT_EXTERNAL_DEPEND; {
921eda2017-11-19Stephen R. van den Berg  int clearit = clear && clear->u.integer; pop_n_elems(args);
0d58042004-10-14Martin Nilsson  push_text(sqlite3_errmsg(THIS->db));
921eda2017-11-19Stephen R. van den Berg  /* FIXME: any way to support clearit? */
c36d502004-10-15Martin Nilsson  f_utf8_to_string(1);
0d58042004-10-14Martin Nilsson  }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl void select_db(string db) *! *! @note *! This operation is not supported for SQLite. *! *! @seealso *! @[Sql.Sql()->select_db()] */
0d58042004-10-14Martin Nilsson  PIKEFUN void select_db(string db) {
c284a72011-01-09Henrik Grubbström (Grubba)  /* FIXME: This should be possible to support. */
0d58042004-10-14Martin Nilsson  Pike_error("This operation is not possible with SQLite.\n"); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl void create_db(string db) *! *! @note *! This operation is not supported for SQLite. *! *! @seealso *! @[Sql.Sql()->create_db()] */
0d58042004-10-14Martin Nilsson  PIKEFUN void create_db(string db) {
c284a72011-01-09Henrik Grubbström (Grubba)  /* FIXME: This should be possible to support. */
0d58042004-10-14Martin Nilsson  Pike_error("This operation is not possible with SQLite.\n"); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl void drop_db(string db) *! *! @note *! This operation is not supported for SQLite. *! *! @seealso *! @[Sql.Sql()->drop_db()] */
0d58042004-10-14Martin Nilsson  PIKEFUN void drop_db(string db) {
c284a72011-01-09Henrik Grubbström (Grubba)  /* FIXME: This should be possible to support. */
0d58042004-10-14Martin Nilsson  Pike_error("This operation is not possible with SQLite.\n"); }
c284a72011-01-09Henrik Grubbström (Grubba)  /*! @decl array(string) list_dbs() *! *! @note *! This operation is not supported for SQLite. *! *! @seealso *! @[Sql.Sql()->list_dbs()] */
0d58042004-10-14Martin Nilsson  PIKEFUN array(string) list_dbs() {
c284a72011-01-09Henrik Grubbström (Grubba)  /* FIXME: This should be possible to support. */
2c3dd32016-02-04Martin Nilsson  /* SELECT name FROM sqlite_master ? */
0d58042004-10-14Martin Nilsson  Pike_error("This operation is not possible with SQLite.\n"); }
b467522017-06-25Martin Nilsson #ifndef PIKE_NULL_IS_ZERO
0e621d2004-10-15Martin Nilsson  INIT {
45dd962004-10-21Martin Nilsson  THIS->db = NULL;
0e621d2004-10-15Martin Nilsson  }
b467522017-06-25Martin Nilsson #endif
d858ae2008-05-30Martin Nilsson  EXIT gc_trivial; {
45dd962004-10-21Martin Nilsson  if(THIS->db) { int i; /* FIXME: sqlite3_close can fail. What do we do then? */
9119702004-10-23Martin Nilsson  for(i=0; i<5; i++) {
b1487a2006-06-22Marcus Agehall  if( sqlite3_close(THIS->db)!=SQLITE_OK ) { THREADS_ALLOW();
45dd962004-10-21Martin Nilsson  SLEEP();
b1487a2006-06-22Marcus Agehall  THREADS_DISALLOW(); } else break;
9119702004-10-23Martin Nilsson  }
45dd962004-10-21Martin Nilsson  }
0e621d2004-10-15Martin Nilsson  }
0d58042004-10-14Martin Nilsson 
dc22e92004-10-14Martin Nilsson }
b2124f2015-08-26Martin Nilsson PIKEFUN string library_version() { push_text(sqlite3_libversion()); }
75aa7a2008-08-05Henrik Grubbström (Grubba) /*! @endclass */
dc22e92004-10-14Martin Nilsson 
c1b1702007-12-18Henrik Grubbström (Grubba) #endif /* HAVE_SQLITE3_H && HAVE_LIBSQLITE3 */
dc22e92004-10-14Martin Nilsson  PIKE_MODULE_INIT { INIT; } PIKE_MODULE_EXIT { EXIT; }