diff --git a/.gitattributes b/.gitattributes index 940945cda224b6df556eb0d00974ae1cc6b5602c..107e4b7e572c8c6374ec9e7c71cbfbfde38a2b08 100644 --- a/.gitattributes +++ b/.gitattributes @@ -47,6 +47,10 @@ testfont binary /src/modules/image/pnm.c foreign_ident /src/modules/image/quant.c foreign_ident /src/modules/image/togif.c foreign_ident +/src/modules/mysql/Makefile.src foreign_ident +/src/modules/mysql/mysql.c foreign_ident +/src/modules/mysql/precompiled_mysql.h foreign_ident +/src/modules/mysql/result.c foreign_ident /src/modules/pipe/pipe.c foreign_ident /src/modules/sprintf/sprintf.c foreign_ident /src/modules/ssleay/ssleay.c foreign_ident diff --git a/src/modules/mysql/Makefile.src b/src/modules/mysql/Makefile.src new file mode 100644 index 0000000000000000000000000000000000000000..25f66ccd26230584c34c4f906e062c853daeb2ae --- /dev/null +++ b/src/modules/mysql/Makefile.src @@ -0,0 +1,32 @@ +# +# $Id: Makefile.src,v 1.1 1996/12/28 18:51:39 grubba Exp $ +# + +SRCDIR=@srcdir@ +VPATH=@srcdir@:@srcdir@/../..:../.. +PREFLAGS=$(DEFINES) @DEFS@ -I. -I$(SRCDIR) -I$(SRCDIR)/../.. -I../.. @CPPFLAGS@ + +CFLAGS=$(PREFLAGS) $(OTHERFLAGS) + +OBJS=mysql.o result.o + +all: mysql.a linker_options + +mysql.a: $(OBJS) + -rm -f mysql.a + ar cq mysql.a $(OBJS) + -@RANLIB@ mysql.a + +linker_options: Makefile + echo >linker_options "@LDFLAGS@ @LIBS@" + +verify: + @echo No tests for the mysql-module. + +verbose_verify: verify + +clean: + -rm -f *.o *.a + +depend: + gcc -MM $(PREFLAGS) $(SRCDIR)/*.c | $(TMP_BINDIR)/fixdepends.sh $(SRCDIR) diff --git a/src/modules/mysql/configure.in b/src/modules/mysql/configure.in new file mode 100644 index 0000000000000000000000000000000000000000..5c481f62f9d409409d766539b0c35affa9eacbe9 --- /dev/null +++ b/src/modules/mysql/configure.in @@ -0,0 +1,62 @@ +AC_INIT(mysql.c) + +AC_PROG_CC +AC_PROG_RANLIB +AC_SUBST(RANLIB) + +AC_ARG_WITH(mysql, [ --without-mysql no support for the Mysql database],[],[with_mysql=yes]) + +if test x$with_mysql = xyes; then + AC_MSG_CHECKING(Checking for existance of Mysql) + + AC_CACHE_VAL(pike_cv_mysql_exists, + [ + if test -d /usr/local/mysql/. ; then + pike_cv_mysql_exists="yes" + else + pike_cv_mysql_exists="no" + fi + ]) + + AC_MSG_RESULT($pike_cv_mysql_exists) + + if test x$pike_cv_mysql_exists = xyes; then + + if test -d /usr/local/mysql/mach-lib-thread/. ; then + echo Added /usr/local/mysql/mach-lib-thread to the library search path. + LDFLAGS="-L/usr/local/mysql/mach-lib-thread ${LDFLAGS}" + fi + + if test -d /usr/local/mysql/include ; then + echo Added /usr/local/mysql/include to the include search path. + CPPFLAGS="-I/usr/local/mysql/include ${CPPFLAGS}" + fi + + pike_cv_mysql="yes" + + # System libs which might be needed + + AC_CHECK_LIB(pthread, pthread_self, [], []) + AC_CHECK_LIB(pthreads, pthread_self, [], []) + AC_CHECK_LIB(socket, socket, [], []) + AC_CHECK_LIB(nsl, gethostbyname, [], []) + AC_CHECK_LIB(m, floor, [], []) + + # Mysql libs + + AC_CHECK_LIB(strings, bchange, [], [ pike_cv_mysql="no" ]) + AC_CHECK_LIB(dbug, _db_doprnt_, [], [ pike_cv_mysql="no" ]) + AC_CHECK_LIB(mysys, my_init, [], [ pike_cv_mysql="no" ]) + AC_CHECK_LIB(mysql, mysql_connect, [], [ pike_cv_mysql="no" ]) + + AC_MSG_CHECKING(Supported version of Mysql) + + AC_MSG_RESULT($pike_cv_mysql) + + if test x$pike_cv_mysql = xyes; then + AC_DEFINE(HAVE_MYSQL) + fi + fi +fi + +AC_OUTPUT(Makefile,echo FOO >stamp-h ) diff --git a/src/modules/mysql/mysql.c b/src/modules/mysql/mysql.c new file mode 100644 index 0000000000000000000000000000000000000000..0d3a0a428000947bc0babebcb705d71297968eef --- /dev/null +++ b/src/modules/mysql/mysql.c @@ -0,0 +1,461 @@ +/* + * $Id: mysql.c,v 1.1 1996/12/28 18:51:41 grubba Exp $ + * + * SQL database functionality for Pike + * + * Henrik Grubbstr�m 1996-12-21 + */ + +#ifdef HAVE_MYSQL + +/* + * Includes + */ + +/* From the mysql-dist */ +#ifndef MYSQL_MYSQL_H +#define MYSQL_MYSQL_H +#include <mysql.h> +#endif + +/* dynamic_buffer.h contains a conflicting typedef for string + * we don't use any dynamic buffers, so we have this work-around + */ +#define DYNAMIC_BUFFER_H +typedef struct dynamic_buffer_s dynamic_buffer; + +#endif /* HAVE_MYSQL */ + +/* From the Pike-dist */ +#include <svalue.h> +#include <object.h> +#include <stralloc.h> +#include <interpret.h> +#include <port.h> +#include <error.h> +#include <las.h> + +/* Local includes */ +#include "precompiled_mysql.h" + +/* System includes */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif + +#ifdef HAVE_MYSQL + +/* + * Globals + */ + +struct program *mysql_program = NULL; + +/* + * Functions + */ + +/* + * State maintenance + */ + +static void init_mysql_struct(struct object *o) +{ + MEMSET(PIKE_MYSQL, 0, sizeof(struct precompiled_mysql)); +} + +static void exit_mysql_struct(struct object *o) +{ + if (PIKE_MYSQL->last_result) { + mysql_free_result(PIKE_MYSQL->last_result); + PIKE_MYSQL->last_result = NULL; + } + if (PIKE_MYSQL->socket) { + mysql_close(PIKE_MYSQL->socket); + PIKE_MYSQL->socket = NULL; + } +} + +/* + * Methods + */ + +/* void create(string|void host, string|void database, string|void password) */ +static void f_create(INT32 args) +{ + char *host = NULL; + char *database = NULL; + char *password = NULL; + + if (args >= 1) { + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql()\n"); + } + if (sp[-args].u.string->len) { + host = sp[-args].u.string->str; + } + + if (args >= 2) { + if (sp[1-args].type != T_STRING) { + error("Bad argument 2 to mysql()\n"); + } + if (sp[-args].u.string->len) { + database = sp[1-args].u.string->str; + } + + if (args >= 3) { + if (sp[2-args].type != T_STRING) { + error("Bad argument 3 to mysql()\n"); + } + if (sp[-args].u.string->len) { + password = sp[2-args].u.string->str; + } + } + } + } + + pop_n_elems(args); + + if (!(PIKE_MYSQL->socket = mysql_connect(&PIKE_MYSQL->mysql, host, + 0, password))) { + error("mysql(): Couldn't connect to SQL-server\n"); + } + if (database && (mysql_select_db(PIKE_MYSQL->socket, database) < 0)) { + mysql_close(PIKE_MYSQL->socket); + PIKE_MYSQL->socket = NULL; + error("mysql(): Couldn't select database \"%s\"\n", database); + } +} + +/* int affected_rows() */ +static void f_affected_rows(INT32 args) +{ + pop_n_elems(args); + push_int(mysql_affected_rows(PIKE_MYSQL->socket)); +} + +/* int insert_id() */ +static void f_insert_id(INT32 args) +{ + pop_n_elems(args); + push_int(mysql_insert_id(PIKE_MYSQL->socket)); +} + +/* string error() */ +static void f_error(INT32 args) +{ + pop_n_elems(args); + push_text(mysql_error(PIKE_MYSQL->socket)); +} + +/* void select_db(string database) */ +static void f_select_db(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql->select_db()\n"); + } + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->select_db()\n"); + } + + if (mysql_select_db(PIKE_MYSQL->socket, sp[-args].u.string->str) < 0) { + error("mysql->select_db(): Couldn't select database \"%s\"\n", + sp[-args].u.string->str); + } + + pop_n_elems(args); +} + +/* object(mysql_result) query(string q) */ +static void f_query(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql->query()\n"); + } + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->query()\n"); + } + if (mysql_query(PIKE_MYSQL->socket, sp[-args].u.string->str) < 0) { + error("mysql->query(): Query \"%s\" failed\n", + sp[-args].u.string->str); + } + + if (!(PIKE_MYSQL->last_result = mysql_store_result(PIKE_MYSQL->socket))) { + error("mysql->query(): Couldn't create result for query\n"); + } + + pop_n_elems(args); + + push_object(fp->current_object); + fp->current_object->refs++; + + push_object(clone(mysql_result_program, 1)); +} + +/* void create_db(string database) */ +static void f_create_db(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql->create_db()\n"); + } + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->create_db()\n"); + } + if (sp[-args].u.string->len > 127) { + error("Database name \"%s\" is too long (max 127 characters)\n", + sp[-args].u.string->str); + } + if (mysql_create_db(PIKE_MYSQL->socket, sp[-args].u.string->str) < 0) { + error("mysql->create_db(): Creation of database \"%s\" failed\n", + sp[-args].u.string->str); + } + pop_n_elems(args); +} + +/* void drop_db(string database) */ +static void f_drop_db(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql->drop_db()\n"); + } + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->drop_db()\n"); + } + if (sp[-args].u.string->len > 127) { + error("Database name \"%s\" is too long (max 127 characters)\n", + sp[-args].u.string->str); + } + if (mysql_drop_db(PIKE_MYSQL->socket, sp[-args].u.string->str) < 0) { + error("mysql->drop_db(): Drop of database \"%s\" failed\n", + sp[-args].u.string->str); + } + pop_n_elems(args); +} + +/* void shutdown() */ +static void f_shutdown(INT32 args) +{ + if (mysql_shutdown(PIKE_MYSQL->socket) < 0) { + error("mysql->shutdown(): Shutdown failed\n"); + } + + pop_n_elems(args); +} + +/* void reload() */ +static void f_reload(INT32 args) +{ + if (mysql_reload(PIKE_MYSQL->socket) < 0) { + error("mysql->reload(): Reload failed\n"); + } + + pop_n_elems(args); +} + +/* string statistics() */ +static void f_statistics(INT32 args) +{ + pop_n_elems(args); + + push_text(mysql_stat(PIKE_MYSQL->socket)); +} + +/* string server_info() */ +static void f_server_info(INT32 args) +{ + pop_n_elems(args); + + push_text(mysql_get_server_info(PIKE_MYSQL->socket)); +} + +/* string host_info() */ +static void f_host_info(INT32 args) +{ + pop_n_elems(args); + + push_text(mysql_get_host_info(PIKE_MYSQL->socket)); +} + +/* int protocol_info() */ +static void f_protocol_info(INT32 args) +{ + pop_n_elems(args); + + push_int(mysql_get_proto_info(PIKE_MYSQL->socket)); +} + +/* object(mysql_res) list_dbs(void|string wild) */ +static void f_list_dbs(INT32 args) +{ + char *wild = "*"; + + if (args) { + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->list_dbs()\n"); + } + if (sp[-args].u.string->len > 80) { + error("Wildcard \"%s\" is too long (max 80 characters)\n", + sp[-args].u.string->str); + } + wild = sp[-args].u.string->str; + } + pop_n_elems(args); + + if (!(PIKE_MYSQL->last_result = mysql_list_dbs(PIKE_MYSQL->socket, wild))) { + error("mysql->list_dbs(): Cannot list databases: %s\n", + mysql_error(PIKE_MYSQL->socket)); + } + + push_object(fp->current_object); + fp->current_object->refs++; + + push_object(clone(mysql_result_program, 1)); +} + +/* object(mysql_res) list_tables(void|string wild) */ +static void f_list_tables(INT32 args) +{ + char *wild = "*"; + + if (args) { + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->list_tables()\n"); + } + if (sp[-args].u.string->len > 80) { + error("Wildcard \"%s\" is too long (max 80 characters)\n", + sp[-args].u.string->str); + } + wild = sp[-args].u.string->str; + } + pop_n_elems(args); + + PIKE_MYSQL->last_result = mysql_list_tables(PIKE_MYSQL->socket, wild); + + push_object(fp->current_object); + fp->current_object->refs++; + + push_object(clone(mysql_result_program, 1)); +} + +#if 0 +/* DON'T USE! */ + +/* object(mysql_res) list_fields(void|string wild) */ +static void f_list_fields(INT32 args) +{ + char *wild = "*"; + + if (args) { + if (sp[-args].type != T_STRING) { + error("Bad argument 1 to mysql->list_fields()\n"); + } + if (sp[-args].u.string->len > 80) { + error("Wildcard \"%s\" is too long (max 80 characters)\n", + sp[-args].u.string->str); + } + wild = sp[-args].u.string->str; + } + pop_n_elems(args); + + PIKE_MYSQL->last_result = mysql_list_fields(PIKE_MYSQL->socket, wild); + + push_object(fp->current_object); + fp->current_object->refs++; + + push_object(clone(mysql_result_program, 1)); +} + +#endif /* 0 */ + +/* object(mysql_res) list_processes(void|string wild) */ +static void f_list_processes(INT32 args) +{ + pop_n_elems(args); + + PIKE_MYSQL->last_result = mysql_list_processes(PIKE_MYSQL->socket); + + push_object(fp->current_object); + fp->current_object->refs++; + + push_object(clone(mysql_result_program, 1)); +} + +#endif /* HAVE_MYSQL */ + +/* + * Module linkage + */ + +void init_mysql_efuns(void) +{ +#ifdef HAVE_MYSQL + init_mysql_res_efuns(); +#endif /* HAVE_MYSQL */ +} + +void init_mysql_programs(void) +{ +#ifdef HAVE_MYSQL + /* + * start_new_program(); + * + * add_storage(); + * + * add_function(); + * add_function(); + * ... + * + * set_init_callback(); + * set_exit_callback(); + * + * program = end_c_program(); + * program->refs++; + * + */ + + start_new_program(); + add_storage(sizeof(struct precompiled_mysql)); + + add_function("error", f_error, "function(void:string)", OPT_EXTERNAL_DEPEND); + add_function("create", f_create, "function(string|void, string|void, string|void:void)", OPT_SIDE_EFFECT); + add_function("affected_rows", f_affected_rows, "function(void:int)", OPT_EXTERNAL_DEPEND); + add_function("insert_id", f_insert_id, "function(void:int)", OPT_EXTERNAL_DEPEND); + add_function("select_db", f_select_db, "function(string:void)", OPT_SIDE_EFFECT); + add_function("query", f_query, "function(string:object)", OPT_EXTERNAL_DEPEND); + add_function("create_db", f_create_db, "function(string:void)", OPT_SIDE_EFFECT); + add_function("drop_db", f_drop_db, "function(string:void)", OPT_SIDE_EFFECT); + add_function("shutdown", f_shutdown, "function(void:void)", OPT_SIDE_EFFECT); + add_function("reload", f_reload, "function(void:void)", OPT_SIDE_EFFECT); + add_function("statistics", f_statistics, "function(void:string)", OPT_EXTERNAL_DEPEND); + add_function("server_info", f_server_info, "function(void:string)", OPT_EXTERNAL_DEPEND); + add_function("host_info", f_host_info, "function(void:string)", OPT_EXTERNAL_DEPEND); + add_function("protocol_info", f_protocol_info, "function(void:int)", OPT_EXTERNAL_DEPEND); + add_function("list_dbs", f_list_dbs, "function(void|string:object)", OPT_EXTERNAL_DEPEND); + add_function("list_tables", f_list_tables, "function(void|string:object)", OPT_EXTERNAL_DEPEND); + add_function("list_processes", f_list_processes, "function(void|string:object)", OPT_EXTERNAL_DEPEND); + + set_init_callback(init_mysql_struct); + set_exit_callback(exit_mysql_struct); + + mysql_program = end_c_program("/precompiled/mysql"); + mysql_program->refs++; + + init_mysql_res_programs(); +#endif /* HAVE_MYSQL */ +} + +void exit_mysql(void) +{ +#ifdef HAVE_MYSQL + exit_mysql_res(); + + if (mysql_program) { + free_program(mysql_program); + mysql_program = NULL; + } +#endif /* HAVE_MYSQL */ +} + diff --git a/src/modules/mysql/precompiled_mysql.h b/src/modules/mysql/precompiled_mysql.h new file mode 100644 index 0000000000000000000000000000000000000000..75fba7ca2e401c35ca72d1dc262b6a0686b5654d --- /dev/null +++ b/src/modules/mysql/precompiled_mysql.h @@ -0,0 +1,61 @@ +/* + * $Id: precompiled_mysql.h,v 1.1 1996/12/28 18:51:41 grubba Exp $ + * + * SQL database connectivity for Pike + * + * Henrik Grubbstr�m 1996-12-21 + */ + +#ifndef PRECOMPILED_MYSQL_H +#define PRECOMPILED_MYSQL_H + +/* + * Includes + */ + +/* From the mysql-dist */ +#ifndef MYSQL_MYSQL_H +#define MYSQL_MYSQL_H +#include <mysql.h> +#endif + +/* From the Pike-dist */ + +/* + * Structures + */ + +struct precompiled_mysql { + MYSQL mysql, *socket; + MYSQL_RES *last_result; /* UGLY way to pass arguments to create() */ +}; + +struct precompiled_mysql_result { + MYSQL_RES *result; +}; + +/* + * Defines + */ + +#define PIKE_MYSQL ((struct precompiled_mysql *)(fp->current_storage)) +#define PIKE_MYSQL_RES ((struct precompiled_mysql_result *)(fp->current_storage)) + +/* + * Globals + */ + +extern struct program *mysql_program; +extern struct program *mysql_result_program; + +/* + * Prototypes + */ + +/* From result.c */ + +void init_mysql_res_efuns(void); +void init_mysql_res_programs(void); +void exit_mysql_res(void); + +#endif /* PRECOMPILED_MYSQL_H */ diff --git a/src/modules/mysql/result.c b/src/modules/mysql/result.c new file mode 100644 index 0000000000000000000000000000000000000000..b0008b9eea885ee6ff432255f520bf5e22101693 --- /dev/null +++ b/src/modules/mysql/result.c @@ -0,0 +1,329 @@ +/* + * $Id: result.c,v 1.1 1996/12/28 18:51:42 grubba Exp $ + * + * mysql query result + * + * Henrik Grubbstr�m 1996-12-21 + */ + +#ifdef HAVE_MYSQL +/* + * Includes + */ + +/* From the mysql-dist */ +#ifndef MYSQL_MYSQL_H +#define MYSQL_MYSQL_H +#include <mysql.h> +#endif + +/* dynamic_buffer.h contains a conflicting typedef for string + * we don't use any dynamic buffers, so we have this work-around + */ +#define DYNAMIC_BUFFER_H +typedef struct dynamic_buffer_s dynamic_buffer; + +/* From the Pike-dist */ +#include <svalue.h> +#include <mapping.h> +#include <object.h> +#include <program.h> +#include <stralloc.h> +#include <interpret.h> +#include <error.h> +#include <builtin_functions.h> +#include <las.h> + +/* Local includes */ +#include "precompiled_mysql.h" + +/* System includes */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif + +/* + * Globals + */ + +struct program *mysql_result_program = NULL; + +/* + * Functions + */ + +/* + * State maintenance + */ + +static void init_res_struct(struct object *o) +{ + memset(PIKE_MYSQL_RES, 0, sizeof(struct precompiled_mysql_result)); +} + +static void exit_res_struct(struct object *o) +{ + if (PIKE_MYSQL_RES->result) { + mysql_free_result(PIKE_MYSQL_RES->result); + PIKE_MYSQL_RES->result = NULL; + } +} + +/* + * Methods + */ + +/* void create(object(mysql)) */ +static void f_create(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql_result()\n"); + } + if ((sp[-args].type != T_OBJECT) || + (sp[-args].u.object->prog != mysql_program)) { + error("Bad argument 1 to mysql_result()\n"); + } + + PIKE_MYSQL_RES->result = ((struct precompiled_mysql *)sp[-args].u.object->storage)->last_result; + ((struct precompiled_mysql *)sp[-args].u.object->storage)->last_result = NULL; + + pop_n_elems(args); + + if (!PIKE_MYSQL_RES->result) { + error("mysql_result(): No result to clone\n"); + } +} + +/* int num_rows() */ +static void f_num_rows(INT32 args) +{ + pop_n_elems(args); + push_int(mysql_num_rows(PIKE_MYSQL_RES->result)); +} + +/* int num_fields() */ +static void f_num_fields(INT32 args) +{ + pop_n_elems(args); + push_int(mysql_num_fields(PIKE_MYSQL_RES->result)); +} + +/* void field_seek(int fieldno) */ +static void f_field_seek(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql->field_seek()\n"); + } + if (sp[-args].type != T_INT) { + error("Bad argument 1 to mysql->field_seek()\n"); + } + mysql_field_seek(PIKE_MYSQL_RES->result, sp[-args].u.integer); + pop_n_elems(args); +} + +/* int eof() */ +static void f_eof(INT32 args) +{ + pop_n_elems(args); + push_int(mysql_eof(PIKE_MYSQL_RES->result)); +} + +/* array(int|mapping(string:mixed)) fetch_field() */ +static void f_fetch_field(INT32 args) +{ + unsigned int i; + + pop_n_elems(args); + + for (i=0; i < mysql_num_fields(PIKE_MYSQL_RES->result); i++) { + MYSQL_FIELD *field = mysql_fetch_field(PIKE_MYSQL_RES->result); + + if (field) { + push_text("name"); push_text(field->name); + push_text("table"); push_text(field->table); + push_text("def"); + if (field->def) { + push_text(field->def); + } else { + push_int(0); + } + push_text("type"); + switch(field->type) { + case FIELD_TYPE_DECIMAL: + push_text("decimal"); + break; + case FIELD_TYPE_CHAR: + push_text("char"); + break; + case FIELD_TYPE_SHORT: + push_text("short"); + break; + case FIELD_TYPE_LONG: + push_text("long"); + break; + case FIELD_TYPE_FLOAT: + push_text("float"); + break; + case FIELD_TYPE_DOUBLE: + push_text("double"); + break; + case FIELD_TYPE_NULL: + push_text("null"); + break; + case FIELD_TYPE_TIME: + push_text("time"); + break; + case FIELD_TYPE_LONGLONG: + push_text("longlong"); + break; + case FIELD_TYPE_INT24: + push_text("int24"); + break; + case FIELD_TYPE_TINY_BLOB: + push_text("tiny blob"); + break; + case FIELD_TYPE_MEDIUM_BLOB: + push_text("medium blob"); + break; + case FIELD_TYPE_LONG_BLOB: + push_text("long blob"); + break; + case FIELD_TYPE_BLOB: + push_text("blob"); + break; + case FIELD_TYPE_VAR_STRING: + push_text("var string"); + break; + case FIELD_TYPE_STRING: + push_text("string"); + break; + default: + push_text("unknown"); + break; + } + push_text("length"); push_int(field->length); + push_text("max_length"); push_int(field->max_length); + push_text("flags"); push_int(field->flags); /*************/ + push_text("decimals"); push_int(field->decimals); + + f_aggregate_mapping(8*2); + } else { + /* + * Should this be an error? + */ + push_int(0); + } + } + f_aggregate(mysql_num_fields(PIKE_MYSQL_RES->result)); + mysql_field_seek(PIKE_MYSQL_RES->result, 0); +} + +/* void seek(int row) */ +static void f_seek(INT32 args) +{ + if (!args) { + error("Too few arguments to mysql_result->seek()\n"); + } + if (sp[-args].type != T_INT) { + error("Bad argument 1 to mysql_result->seek()\n"); + } + if (sp[-args].u.integer < 0) { + error("Negative argument 1 to mysql_result->seek()\n"); + } + mysql_data_seek(PIKE_MYSQL_RES->result, sp[-args].u.integer); + + pop_n_elems(args); +} + +/* void|array(string|int) fetch_row() */ +static void f_fetch_row(INT32 args) +{ + /* I have no idea how this works. + * + * Stolen from Mysql.xs + */ + MYSQL_ROW row = mysql_fetch_row(PIKE_MYSQL_RES->result); + + pop_n_elems(args); + + if (row) { + int num_fields, i; + + /* Mysql.xs does a mysql_field_seek(result, 0) here, + * but that seems to be a NOOP. + */ + if ((num_fields = mysql_num_fields(PIKE_MYSQL_RES->result)) <= 0) { + num_fields = 1; + } + for (i=0; i < num_fields; i++) { + /* Mysql.xs does a mysql_fetch_field(result) here, + * but throws away the result. + */ + if (row[i]) { + push_text(row[i]); + } else { + push_int(0); + } + } + f_aggregate(num_fields); + } +} + +/* + * Module linkage + */ + +void init_mysql_res_efuns(void) +{ +} + +void init_mysql_res_programs(void) +{ + /* + * start_new_program(); + * + * add_storage(); + * + * add_function(); + * add_function(); + * ... + * + * set_init_callback(); + * set_exit_callback(); + * + * program = end_c_program(); + * program->refs++; + * + */ + + start_new_program(); + add_storage(sizeof(struct precompiled_mysql_result)); + + add_function("create", f_create, "function(object:void)", OPT_SIDE_EFFECT); + add_function("num_rows", f_num_rows, "function(void:int)", OPT_EXTERNAL_DEPEND); + add_function("num_fields", f_num_fields, "function(void:int)", OPT_EXTERNAL_DEPEND); + add_function("field_seek", f_field_seek, "function(int:void)", OPT_SIDE_EFFECT); + add_function("eof", f_eof, "function(void:int)", OPT_EXTERNAL_DEPEND); + add_function("fetch_field", f_fetch_field, "function(void:array(int|mapping(string:mixed)))", OPT_EXTERNAL_DEPEND); + add_function("seek", f_seek, "function(int:void)", OPT_SIDE_EFFECT); + add_function("fetch_row", f_fetch_row, "function(void:void|array(string|int))", OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); + + set_init_callback(init_res_struct); + set_exit_callback(exit_res_struct); + + mysql_result_program = end_c_program("/precompiled/mysql_res"); + mysql_result_program->refs++; +} + +void exit_mysql_res(void) +{ + if (mysql_result_program) { + free_program(mysql_result_program); + mysql_result_program = NULL; + } +} + +#endif /* HAVE_MYSQL */