8c2d94 | 2008-08-05 | Martin 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.
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
#include "global.h"
|
8f7db0 | 2017-03-04 | Henrik Grubbström (Grubba) | | #include "pike_compiler.h"
|
dc22e9 | 2004-10-14 | Martin Nilsson | | #include "interpret.h"
|
b1487a | 2006-06-22 | Marcus Agehall | | #include "backend.h"
|
dc22e9 | 2004-10-14 | Martin Nilsson | | #include "module_support.h"
#include "config.h"
#include "object.h"
#include "builtin_functions.h"
|
691995 | 2004-10-15 | Marcus Agehall | | #include "mapping.h"
|
cd927f | 2017-07-19 | Bill Welliver | | #include "multiset.h"
|
b1487a | 2006-06-22 | Marcus Agehall | | #include "threads.h"
|
5c2d9d | 2008-08-05 | Martin Stjernholm | | #include "bignum.h"
|
3ab15d | 2014-08-19 | Tobias S. Josefowitz | | #include "pike_types.h"
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
|
c1b170 | 2007-12-18 | Henrik Grubbström (Grubba) | | #if defined(HAVE_SQLITE3_H) && defined(HAVE_LIBSQLITE3)
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
|
a33b7c | 2017-05-19 | Henrik Grubbström (Grubba) | | #ifdef HAVE_STDINT_H
|
b1487a | 2006-06-22 | Marcus Agehall | | #include <stdint.h>
|
a33b7c | 2017-05-19 | Henrik Grubbström (Grubba) | | #endif
|
0eb91f | 2017-06-05 | Henrik Grubbström (Grubba) | |
|
dc22e9 | 2004-10-14 | Martin Nilsson | | #include <sqlite3.h>
#include <time.h>
|
371406 | 2010-02-18 | Stephen R. van den Berg | | #define SLEEP() sysleep(0.0001)
|
45dd96 | 2004-10-21 | Martin Nilsson | |
|
dc22e9 | 2004-10-14 | Martin Nilsson | | DECLARATIONS
|
0eb91f | 2017-06-05 | Henrik 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
|
b1487a | 2006-06-22 | Marcus Agehall | | #define ERR(X, db) \
if((X)!=SQLITE_OK) { \
SQLite_handle_error((db)); \
}
|
c1b170 | 2007-12-18 | Henrik Grubbström (Grubba) | | static void SQLite_handle_error(sqlite3 *db)
{
|
b1487a | 2006-06-22 | Marcus Agehall | | if (db) {
|
c1b170 | 2007-12-18 | Henrik Grubbström (Grubba) | | push_text(sqlite3_errmsg(db));
f_utf8_to_string(1);
Pike_error("Sql.SQLite: %S\n", Pike_sp[-1].u.string);
|
b1487a | 2006-06-22 | Marcus Agehall | | } else {
Pike_error("Sql.SQLite: Internal module error\n");
}
}
|
dc22e9 | 2004-10-14 | Martin Nilsson | | static int step(sqlite3_stmt *stmt) {
int ret;
|
8c2d94 | 2008-08-05 | Martin 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.
*/
|
b1487a | 2006-06-22 | Marcus Agehall | | while( (ret=sqlite3_step(stmt))==SQLITE_BUSY ) {
THREADS_ALLOW();
|
45dd96 | 2004-10-21 | Martin Nilsson | | SLEEP();
|
b1487a | 2006-06-22 | Marcus Agehall | | THREADS_DISALLOW();
}
|
dc22e9 | 2004-10-14 | Martin Nilsson | | return ret;
}
|
cb1be2 | 2017-07-06 | Bill 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
|
6aabe1 | 2017-07-08 | Martin Nilsson | | containing the binary data in a
String.Buffer/Stdio.Buffer/System.Memory object.
|
cb1be2 | 2017-07-06 | Bill Welliver | | */
|
b1487a | 2006-06-22 | Marcus Agehall | | static void bind_arguments(sqlite3 *db,
|
439d08 | 2017-07-25 | Martin Nilsson | | sqlite3_stmt *stmt,
struct mapping *bindings) {
|
b1487a | 2006-06-22 | Marcus Agehall | | struct mapping_data *md = bindings->data;
INT32 e;
struct keypair *k;
NEW_MAPPING_LOOP(md) {
int idx;
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | switch(TYPEOF(k->ind)) {
|
b1487a | 2006-06-22 | Marcus 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");
}
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | switch(TYPEOF(k->val)) {
|
b1487a | 2006-06-22 | Marcus 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;
|
cb1be2 | 2017-07-06 | Bill 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();
|
b1487a | 2006-06-22 | Marcus Agehall | | }
break;
case T_FLOAT:
ERR( sqlite3_bind_double(stmt, idx, (double)k->val.u.float_number),
db);
break;
|
61f220 | 2017-07-07 | Martin Nilsson | |
|
cd927f | 2017-07-19 | Bill 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,
|
aaa581 | 2017-07-22 | Martin Nilsson | | SQLITE_TRANSIENT),
|
cd927f | 2017-07-19 | Bill Welliver | | db);
}
|
aaa581 | 2017-07-22 | Martin Nilsson | | sub_msnode_ref(k->val.u.multiset);
if(s) break;
|
cd927f | 2017-07-19 | Bill Welliver | | }
Pike_error("Can only bind string|int|float or single-valued multiset(string)|String.Buffer|Stdio.Buffer|System.Memory as blob.\n");
|
aaa581 | 2017-07-22 | Martin Nilsson | | break;
|
6aabe1 | 2017-07-08 | Martin Nilsson | | case T_OBJECT:
{
size_t len;
void *ptr;
if( get_memory_object_memory(k->val.u.object, &ptr, &len, NULL)!=
MEMOBJ_NONE )
|
cb1be2 | 2017-07-06 | Bill Welliver | | {
|
439d08 | 2017-07-25 | Martin Nilsson | | ERR(sqlite3_bind_blob(stmt, idx, ptr, len, SQLITE_STATIC), db);
|
6aabe1 | 2017-07-08 | Martin Nilsson | | break;
}
|
cb1be2 | 2017-07-06 | Bill Welliver | | }
|
61f220 | 2017-07-07 | Martin Nilsson | | /* Fallthrough */
|
b1487a | 2006-06-22 | Marcus Agehall | | default:
|
cd927f | 2017-07-19 | Bill Welliver | | Pike_error("Can only bind string|int|float or single-valued multiset(string)|String.Buffer|Stdio.Buffer|System.Memory as blob.\n");
|
b1487a | 2006-06-22 | Marcus Agehall | | }
}
}
|
b2124f | 2015-08-26 | Martin 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:
|
f6b46b | 2017-03-19 | Henrik 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);
|
b2124f | 2015-08-26 | Martin Nilsson | | break;
}
}
|
75aa7a | 2008-08-05 | Henrik 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://"@}.
*/
|
b1487a | 2006-06-22 | Marcus Agehall | | PIKECLASS SQLite
{
CVAR sqlite3 *db;
|
25d814 | 2017-03-04 | Henrik Grubbström (Grubba) | | /*! @decl inherit __builtin.Sql.Connection
*/
INHERIT "__builtin.Sql.Connection";
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | /*! @class TypedResult
|
75aa7a | 2008-08-05 | Henrik Grubbström (Grubba) | | *!
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | *! Result object from @[typed_big_query()].
|
75aa7a | 2008-08-05 | Henrik Grubbström (Grubba) | | */
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | PIKECLASS TypedResult
|
ecc938 | 2008-06-29 | Martin Nilsson | | flags ID_PRIVATE | ID_PROTECTED | ID_HIDDEN;
|
dc22e9 | 2004-10-14 | Martin Nilsson | | {
|
45dd96 | 2004-10-21 | Martin Nilsson | | CVAR struct object *dbobj;
|
69e5a4 | 2004-10-23 | Martin Nilsson | | CVAR struct mapping *bindings;
|
dc22e9 | 2004-10-14 | Martin Nilsson | | CVAR sqlite3_stmt *stmt;
CVAR int eof;
CVAR int columns;
|
8f7db0 | 2017-03-04 | Henrik Grubbström (Grubba) | | /*! @decl inherit __builtin.Sql.Result
*/
INHERIT "__builtin.Sql.Result";
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | static void SQLite_TypedResult_handle_error(void) {
|
b1487a | 2006-06-22 | Marcus Agehall | | Pike_error("Sql.SQLite: %s\n",
sqlite3_errmsg(OBJ2_SQLITE(THIS->dbobj)->db));
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
|
45dd96 | 2004-10-21 | Martin Nilsson | | PIKEFUN void create()
|
ecc938 | 2008-06-29 | Martin Nilsson | | flags ID_PROTECTED;
|
45dd96 | 2004-10-21 | Martin Nilsson | | {
|
dc22e9 | 2004-10-14 | Martin Nilsson | | THIS->columns = sqlite3_column_count(THIS->stmt);
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl int num_rows()
*!
*! @note
*! This API is not supported for @[Sql.sqlite].
*!
*! @seealso
*! @[Sql.sql_result()->num_rows()]
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | | PIKEFUN int num_rows() {
Pike_error("Sql.SQLite: Number of rows not known in advance.\n");
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl int num_fields()
*!
*! @seealso
*! @[Sql.sql_result()->num_fields()]
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | | PIKEFUN int num_fields() {
RETURN THIS->columns;
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl int eof()
*!
*! @seealso
*! @[Sql.sql_result()->eof()]
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | | PIKEFUN int eof() {
RETURN THIS->eof;
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl array(mapping(string:mixed)) fetch_fields()
*!
*! @seealso
*! @[Sql.sql_result()->fetch_fields()]
*/
|
0d5804 | 2004-10-14 | Martin Nilsson | | PIKEFUN array(mapping(string:mixed)) fetch_fields() {
|
a83ab9 | 2008-07-31 | H. William Welliver III | | int i,t;
|
0d5804 | 2004-10-14 | Martin Nilsson | | for(i=0; i<THIS->columns; i++) {
push_constant_text("name");
push_text(sqlite3_column_name(THIS->stmt, i));
|
c36d50 | 2004-10-15 | Martin Nilsson | | f_utf8_to_string(1);
|
6a932b | 2014-08-18 | Martin Nilsson | | ref_push_string(literal_type_string);
|
6c6c72 | 2008-08-01 | Martin Nilsson | | t = sqlite3_column_type(THIS->stmt, i);
switch(t)
{
case SQLITE_INTEGER:
push_constant_text("integer");
break;
case SQLITE_FLOAT:
|
6a932b | 2014-08-18 | Martin Nilsson | | ref_push_string(literal_float_string);
|
6c6c72 | 2008-08-01 | Martin 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:
|
5e9fc0 | 2015-08-18 | Per Hedbor | | push_static_text("unknown");
|
6c6c72 | 2008-08-01 | Martin Nilsson | | break;
}
|
a83ab9 | 2008-07-31 | H. William Welliver III | | f_aggregate_mapping(4);
|
0d5804 | 2004-10-14 | Martin Nilsson | | }
f_aggregate(THIS->columns);
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl void seek(int skip)
*!
*! @seealso
*! @[Sql.sql_result()->seek()]
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | | PIKEFUN void seek(int skip) {
int i;
for(i=0; i<skip; i++)
if( step(THIS->stmt)==SQLITE_DONE ) {
THIS->eof = 1;
return;
}
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl array fetch_row()
*!
*! @seealso
*! @[Sql.sql_result()->fetch_row()]
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | | PIKEFUN array fetch_row() {
int i;
|
c36d50 | 2004-10-15 | Martin Nilsson | | sqlite3_stmt *stmt = THIS->stmt;
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
if(THIS->eof) {
push_int(0);
return;
}
|
c36d50 | 2004-10-15 | Martin Nilsson | | switch( step(stmt) ) {
|
dc22e9 | 2004-10-14 | Martin Nilsson | | case SQLITE_DONE:
THIS->eof = 1;
|
c36d50 | 2004-10-15 | Martin Nilsson | | sqlite3_finalize(stmt);
|
dc22e9 | 2004-10-14 | Martin Nilsson | | THIS->stmt = 0;
push_int(0);
return;
case SQLITE_ROW:
break;
default:
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | SQLite_TypedResult_handle_error();
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
|
b2124f | 2015-08-26 | Martin Nilsson | | for(i=0; i<THIS->columns; i++)
push_field(stmt, i);
|
dc22e9 | 2004-10-14 | Martin Nilsson | | f_aggregate(THIS->columns);
}
INIT {
THIS->columns = -1;
|
b46752 | 2017-06-25 | Martin Nilsson | | #ifdef PIKE_NULL_IS_SPECIAL
THIS->eof = 0;
|
45dd96 | 2004-10-21 | Martin Nilsson | | THIS->dbobj = NULL;
THIS->stmt = NULL;
|
69e5a4 | 2004-10-23 | Martin Nilsson | | THIS->bindings = NULL;
|
b46752 | 2017-06-25 | Martin Nilsson | | #endif
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
|
d858ae | 2008-05-30 | Martin Nilsson | |
EXIT
gc_trivial;
{
|
dc22e9 | 2004-10-14 | Martin Nilsson | | if(THIS->stmt)
sqlite3_finalize(THIS->stmt);
|
45dd96 | 2004-10-21 | Martin Nilsson | | if(THIS->dbobj)
free_object(THIS->dbobj);
|
69e5a4 | 2004-10-23 | Martin Nilsson | | if(THIS->bindings)
free_mapping(THIS->bindings);
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
}
|
75aa7a | 2008-08-05 | Henrik Grubbström (Grubba) | | /*! @endclass
*/
|
f6b46b | 2017-03-19 | Henrik 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
*/
|
a62744 | 2006-07-05 | Martin Stjernholm | | #undef THIS
#define THIS THIS_SQLITE
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl void create(string path, mixed ... ignored)
*!
*! Open the SQLite database stored at @[path].
|
dc22e9 | 2004-10-14 | Martin Nilsson | | */
|
0a5ec3 | 2012-04-12 | Henrik Grubbström (Grubba) | | PIKEFUN void create(string path, mixed|void a, mixed|void b, mixed|void c,
mapping|void options)
|
ecc938 | 2008-06-29 | Martin Nilsson | | flags ID_PROTECTED;
|
45dd96 | 2004-10-21 | Martin Nilsson | | {
|
c36d50 | 2004-10-15 | Martin Nilsson | | pop_n_elems(args-1);
f_string_to_utf8(1);
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /* FIXME: Does the following work if THIS->db is already open? */
|
2c3dd3 | 2016-02-04 | Martin Nilsson | | ERR( sqlite3_open(Pike_sp[-1].u.string->str, &THIS->db), THIS->db );
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
|
f6b46b | 2017-03-19 | Henrik 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)
|
ef8b3b | 2018-03-17 | Henrik Grubbström (Grubba) | | flags ID_VARIANT;
|
f6b46b | 2017-03-19 | Henrik 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);
}
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl array|int query(string query, @
*! mapping(string|int:mixed)|void bindings)
*!
*! Perform a query against a SQLite database.
*!
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | *! @note
*! In Pike 8.0 and earlier this function behaved as @[typed_query()].
*!
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | *! @seealso
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | *! @[Sql.Sql()->query()], @[typed_query()]
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | */
|
b1487a | 2006-06-22 | Marcus Agehall | | PIKEFUN array|int query(string query,
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | mapping(string|int:mixed)|void bindings)
|
ef8b3b | 2018-03-17 | Henrik Grubbström (Grubba) | | flags ID_VARIANT;
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | {
|
dc22e9 | 2004-10-14 | Martin Nilsson | | sqlite3_stmt *stmt;
const char *tail;
|
c36d50 | 2004-10-15 | Martin Nilsson | | struct pike_string *q;
|
7ddde3 | 2006-07-10 | Martin Nilsson | | INT32 res_count = 0;
|
e5e272 | 2008-08-03 | Henrik Grubbström (Grubba) | | INT32 columns;
|
7ddde3 | 2006-07-10 | Martin Nilsson | | INT32 i;
|
c36d50 | 2004-10-15 | Martin Nilsson | |
|
69e5a4 | 2004-10-23 | Martin Nilsson | | if(args==2) stack_swap();
|
c36d50 | 2004-10-15 | Martin Nilsson | | f_string_to_utf8(1);
q = Pike_sp[-1].u.string;
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
|
b1487a | 2006-06-22 | Marcus Agehall | | ERR( sqlite3_prepare(THIS->db, q->str, q->len, &stmt, &tail),
THIS->db);
|
dc22e9 | 2004-10-14 | Martin Nilsson | | if( tail[0] )
|
f1da34 | 2015-08-02 | Martin Nilsson | | Pike_error("Sql.SQLite->query: Trailing query data (\"%s\")\n",
|
dc22e9 | 2004-10-14 | Martin Nilsson | | tail);
|
69e5a4 | 2004-10-23 | Martin Nilsson | | pop_stack();
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
|
45dd96 | 2004-10-21 | Martin Nilsson | |
/* Add a reference to the database to prevent it from being
destroyed before the query object. */
|
69e5a4 | 2004-10-23 | Martin Nilsson | | if(bindings) {
|
b1487a | 2006-06-22 | Marcus Agehall | | bind_arguments(THIS->db, stmt, bindings);
}
|
e5e272 | 2008-08-03 | Henrik Grubbström (Grubba) | | columns = sqlite3_column_count(stmt);
|
b1487a | 2006-06-22 | Marcus 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;
|
69e5a4 | 2004-10-23 | Martin Nilsson | | break;
|
b1487a | 2006-06-22 | Marcus Agehall | |
case SQLITE_ROW:
for(i=0; i<columns; i++) {
|
b2124f | 2015-08-26 | Martin Nilsson | | push_text(sqlite3_column_name(stmt, i));
f_utf8_to_string(1);
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | push_string_field(stmt, i);
|
b2124f | 2015-08-26 | Martin Nilsson | | }
|
a83ab9 | 2008-07-31 | H. William Welliver III | | f_aggregate_mapping(columns*2);
|
b1487a | 2006-06-22 | Marcus Agehall | | DO_AGGREGATE_ARRAY(100);
|
69e5a4 | 2004-10-23 | Martin Nilsson | | break;
|
b1487a | 2006-06-22 | Marcus Agehall | |
case SQLITE_MISUSE:
Pike_error("Sql.SQLite: Library misuse.");
|
69e5a4 | 2004-10-23 | Martin Nilsson | | default:
|
b1487a | 2006-06-22 | Marcus Agehall | | Pike_error("Sql.SQLite: (%d) %s\n", sr, sqlite3_errmsg(THIS->db));
|
69e5a4 | 2004-10-23 | Martin Nilsson | | }
}
|
b1487a | 2006-06-22 | Marcus Agehall | | } END_AGGREGATE_ARRAY;
|
e5e272 | 2008-08-03 | Henrik Grubbström (Grubba) | | if (!Pike_sp[-1].u.array->size && !columns) {
/* No rows and no columns. */
|
b1487a | 2006-06-22 | Marcus Agehall | | pop_stack();
push_int(0);
}
}
|
f6b46b | 2017-03-19 | Henrik 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()]
*/
|
9a6c0b | 2017-03-27 | Henrik Grubbström (Grubba) | | PIKEFUN object big_typed_query(string query,
|
f6b46b | 2017-03-19 | Henrik 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, @
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | *! mapping(string|int:mixed)|void bindings)
*!
*! Perform a streaming query against a SQLite database.
*!
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | *! @note
*! In Pike 8.0 and earlier this function behaved as @[big_typed_query()].
*!
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | *! @seealso
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | *! @[Sql.Sql()->big_query()], @[big_typed_query()]
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | */
|
9a6c0b | 2017-03-27 | Henrik Grubbström (Grubba) | | PIKEFUN object big_query(string query,
|
8f7db0 | 2017-03-04 | Henrik Grubbström (Grubba) | | mapping(string|int:mixed)|void bindings)
flags ID_VARIANT;
{
|
b1487a | 2006-06-22 | Marcus Agehall | | struct object *res;
sqlite3_stmt *stmt;
const char *tail;
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | struct SQLite_TypedResult_struct *store;
|
b1487a | 2006-06-22 | Marcus 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();
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | res=fast_clone_object(SQLite_Result_program);
store = OBJ2_SQLITE_TYPEDRESULT(res);
|
b1487a | 2006-06-22 | Marcus Agehall | | store->stmt = stmt;
/* Add a reference to the database to prevent it from being
|
8f7db0 | 2017-03-04 | Henrik Grubbström (Grubba) | | * destroyed before the query object.
*
* FIXME: Use parent pointer instead?
*/
|
b1487a | 2006-06-22 | Marcus Agehall | | store->dbobj = this_object();
if(bindings) {
bind_arguments(THIS->db, stmt, bindings);
|
69e5a4 | 2004-10-23 | Martin 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;
}
|
f6b46b | 2017-03-19 | Henrik Grubbström (Grubba) | | apply_low(res, f_SQLite_TypedResult_create_fun_num, 0);
|
dc22e9 | 2004-10-14 | Martin Nilsson | | push_object(res);
}
|
0d5804 | 2004-10-14 | Martin Nilsson | |
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl int changes()
*!
*! Get the number of changes.
*!
*! @fixme
*! Document this function properly.
*/
|
4844bc | 2004-10-23 | Martin Nilsson | | PIKEFUN int changes()
optflags OPT_EXTERNAL_DEPEND;
{
|
0d5804 | 2004-10-14 | Martin Nilsson | | RETURN sqlite3_changes(THIS->db);
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl int total_changes()
*!
*! Get the total number of changes for this session.
*!
*! @fixme
*! Document this function properly.
*/
|
4844bc | 2004-10-23 | Martin Nilsson | | PIKEFUN int total_changes()
optflags OPT_EXTERNAL_DEPEND;
{
|
0d5804 | 2004-10-14 | Martin Nilsson | | RETURN sqlite3_total_changes(THIS->db);
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl void interrupt()
*!
*! @fixme
*! Document this function.
*/
|
4844bc | 2004-10-23 | Martin Nilsson | | PIKEFUN void interrupt()
optflags OPT_SIDE_EFFECT;
{
|
0d5804 | 2004-10-14 | Martin Nilsson | | sqlite3_interrupt(THIS->db);
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl string server_info()
*!
*! Get information about the SQLite library version.
*!
*! @seealso
*! @[Sql.Sql()->server_info()]
*/
|
4844bc | 2004-10-23 | Martin Nilsson | | PIKEFUN string server_info()
optflags OPT_TRY_OPTIMIZE;
{
|
7cf016 | 2014-05-22 | Per Hedbor | | push_text(sqlite3_libversion());
|
0d5804 | 2004-10-14 | Martin Nilsson | | }
|
75aa7a | 2008-08-05 | Henrik 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()
|
4844bc | 2004-10-23 | Martin Nilsson | | optflags OPT_EXTERNAL_DEPEND;
{
|
d38a32 | 2014-10-29 | Martin Nilsson | | push_int64 (sqlite3_last_insert_rowid(THIS->db));
|
0d5804 | 2004-10-14 | Martin Nilsson | | }
|
921eda | 2017-11-19 | Stephen R. van den Berg | | /*! @decl string error(void|int clear)
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | *!
*! Get the latest error message.
*!
*! @seealso
*! @[Sql.Sql()->error()]
*/
|
921eda | 2017-11-19 | Stephen R. van den Berg | | PIKEFUN string error(void|int clear)
|
4844bc | 2004-10-23 | Martin Nilsson | | optflags OPT_EXTERNAL_DEPEND;
{
|
921eda | 2017-11-19 | Stephen R. van den Berg | | int clearit = clear && clear->u.integer;
pop_n_elems(args);
|
0d5804 | 2004-10-14 | Martin Nilsson | | push_text(sqlite3_errmsg(THIS->db));
|
921eda | 2017-11-19 | Stephen R. van den Berg | | /* FIXME: any way to support clearit? */
|
c36d50 | 2004-10-15 | Martin Nilsson | | f_utf8_to_string(1);
|
0d5804 | 2004-10-14 | Martin Nilsson | | }
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl void select_db(string db)
*!
*! @note
*! This operation is not supported for SQLite.
*!
*! @seealso
*! @[Sql.Sql()->select_db()]
*/
|
0d5804 | 2004-10-14 | Martin Nilsson | | PIKEFUN void select_db(string db) {
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /* FIXME: This should be possible to support. */
|
0d5804 | 2004-10-14 | Martin Nilsson | | Pike_error("This operation is not possible with SQLite.\n");
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl void create_db(string db)
*!
*! @note
*! This operation is not supported for SQLite.
*!
*! @seealso
*! @[Sql.Sql()->create_db()]
*/
|
0d5804 | 2004-10-14 | Martin Nilsson | | PIKEFUN void create_db(string db) {
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /* FIXME: This should be possible to support. */
|
0d5804 | 2004-10-14 | Martin Nilsson | | Pike_error("This operation is not possible with SQLite.\n");
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl void drop_db(string db)
*!
*! @note
*! This operation is not supported for SQLite.
*!
*! @seealso
*! @[Sql.Sql()->drop_db()]
*/
|
0d5804 | 2004-10-14 | Martin Nilsson | | PIKEFUN void drop_db(string db) {
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /* FIXME: This should be possible to support. */
|
0d5804 | 2004-10-14 | Martin Nilsson | | Pike_error("This operation is not possible with SQLite.\n");
}
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /*! @decl array(string) list_dbs()
*!
*! @note
*! This operation is not supported for SQLite.
*!
*! @seealso
*! @[Sql.Sql()->list_dbs()]
*/
|
0d5804 | 2004-10-14 | Martin Nilsson | | PIKEFUN array(string) list_dbs() {
|
c284a7 | 2011-01-09 | Henrik Grubbström (Grubba) | | /* FIXME: This should be possible to support. */
|
2c3dd3 | 2016-02-04 | Martin Nilsson | | /* SELECT name FROM sqlite_master ? */
|
0d5804 | 2004-10-14 | Martin Nilsson | | Pike_error("This operation is not possible with SQLite.\n");
}
|
b46752 | 2017-06-25 | Martin Nilsson | | #ifndef PIKE_NULL_IS_ZERO
|
0e621d | 2004-10-15 | Martin Nilsson | | INIT {
|
45dd96 | 2004-10-21 | Martin Nilsson | | THIS->db = NULL;
|
0e621d | 2004-10-15 | Martin Nilsson | | }
|
b46752 | 2017-06-25 | Martin Nilsson | | #endif
|
d858ae | 2008-05-30 | Martin Nilsson | |
EXIT
gc_trivial;
{
|
45dd96 | 2004-10-21 | Martin Nilsson | | if(THIS->db) {
int i;
/* FIXME: sqlite3_close can fail. What do we do then? */
|
911970 | 2004-10-23 | Martin Nilsson | | for(i=0; i<5; i++) {
|
b1487a | 2006-06-22 | Marcus Agehall | | if( sqlite3_close(THIS->db)!=SQLITE_OK ) {
THREADS_ALLOW();
|
45dd96 | 2004-10-21 | Martin Nilsson | | SLEEP();
|
b1487a | 2006-06-22 | Marcus Agehall | | THREADS_DISALLOW();
} else break;
|
911970 | 2004-10-23 | Martin Nilsson | | }
|
45dd96 | 2004-10-21 | Martin Nilsson | | }
|
0e621d | 2004-10-15 | Martin Nilsson | | }
|
0d5804 | 2004-10-14 | Martin Nilsson | |
|
dc22e9 | 2004-10-14 | Martin Nilsson | | }
|
b2124f | 2015-08-26 | Martin Nilsson | | PIKEFUN string library_version()
{
push_text(sqlite3_libversion());
}
|
75aa7a | 2008-08-05 | Henrik Grubbström (Grubba) | | /*! @endclass
*/
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
|
c1b170 | 2007-12-18 | Henrik Grubbström (Grubba) | | #endif /* HAVE_SQLITE3_H && HAVE_LIBSQLITE3 */
|
dc22e9 | 2004-10-14 | Martin Nilsson | |
PIKE_MODULE_INIT {
INIT;
}
PIKE_MODULE_EXIT {
EXIT;
}
|