3c99b42015-10-14Martin Nilsson /* -*- c -*-
e576bb2002-10-11Martin Nilsson || 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. */
25ce501997-10-14Francesco Chemolli  /* All this code is pretty useless if we don't have a msql library...*/ #include "msql_config.h"
9f3c742005-11-15Martin Nilsson 
25ce501997-10-14Francesco Chemolli #ifdef HAVE_MSQL
73e49d2015-06-13Henrik Grubbström (Grubba) #include <msql.h> /* Avoid a redefinition */ #ifdef INT_TYPE #undef INT_TYPE #define MSQL_INT_TYPE 1 #endif /* INT_TYPE */
25ce501997-10-14Francesco Chemolli /* #define MSQL_DEBUG 1 */
73e49d2015-06-13Henrik Grubbström (Grubba) #endif /*HAVE_MSQL*/ #include "module.h" #include "program.h"
bab29c2017-02-11Henrik Grubbström (Grubba) #include "pike_compiler.h"
73e49d2015-06-13Henrik Grubbström (Grubba) #include "module_support.h" #ifdef HAVE_MSQL
ce5a401997-12-07Henrik Grubbström (Grubba) #include "threads.h" #include "interpret.h" #include "builtin_functions.h"
6715d61997-10-15Henrik Grubbström (Grubba) #include "operators.h"
73e49d2015-06-13Henrik Grubbström (Grubba) #include "pike_types.h"
25ce501997-10-14Francesco Chemolli  #ifdef _REENTRANT
dac9582016-02-04Henrik Grubbström (Grubba) PIKE_MUTEX_T pike_msql_mutex STATIC_MUTEX_INIT;
25ce501997-10-14Francesco Chemolli #define MSQL_LOCK() mt_lock(&pike_msql_mutex) #define MSQL_UNLOCK() mt_unlock(&pike_msql_mutex) #else #define MSQL_LOCK() /**/ #define MSQL_UNLOCK() /**/ #endif
d569182002-05-11Martin Nilsson #define sp Pike_sp
1e34db2001-12-08Martin Nilsson /*! @module Msql *! This is an interface to the mSQL database server.
2c228b2009-02-15Stephen R. van den Berg  *! This module may or may not be available on your Pike, depending
1e34db2001-12-08Martin Nilsson  *! whether the appropriate include and library files (msql.h and libmsql.a
2a3a822002-11-18Martin Nilsson  *! respectively) could be found at compile-time. Note that you @b{do not@}
1e34db2001-12-08Martin Nilsson  *! need to have a mSQL server running on your host to use this module: *! you can connect to the database over a TCP/IP socket *! *! Please notice that unless you wish to specifically connect to a mSQL
2a3a822002-11-18Martin Nilsson  *! server, you'd better use the @[Sql.Sql] program instead. Using @[Sql.Sql] *! ensures that your Pike applications will run with any supported SQL
1e34db2001-12-08Martin Nilsson  *! server without changing a single line of code. *! *! Also notice that some functions may be mSQL/2.0-specific, and thus missing *! on hosts running mSQL/1.0.* *! *! @note *! The mSQL C API has some extermal dependencies. *! They take the form of certain environment variables *! which, if defined in the environment of the pike interpreter, influence *! the interface's behavior. Those are "MSQL_TCP_PORT" which forces the *! server to connect to a port other than the default, "MSQL_UNIX_PORT", same *! as above, only referring to the UNIX domain sockets. If you built your *! mSQL server with the default setttings, you shouldn't worry about these. *! The variable MINERVA_DEBUG can be used to debug the mSQL API (you *! shouldn't worry about this either). Refer to the mSQL documentation *! for further details. *! *! Also note that THIS MODULE USES BLOCKING I/O to connect to the server. *! mSQL should be reasonably fast, but you might want to consider this *! particular aspect. It is thread-safe, and so it can be used *! in a multithread environment. *! *! @fixme *! Although it seems that mSQL/2.0 has some support for server statistics, *! it's really VERY VERY primitive, so it won't be added for now. *! *! @seealso
2a3a822002-11-18Martin Nilsson  *! @[Sql.Sql]
1e34db2001-12-08Martin Nilsson  */ /*! @class msql */
73e49d2015-06-13Henrik Grubbström (Grubba) DECLARATIONS; PIKECLASS msql {
25ce501997-10-14Francesco Chemolli static char * decode_msql_type (int msql_type) { switch (msql_type) {
1ed5d22015-11-09Martin Nilsson  case MSQL_INT_TYPE: return "int";
25ce501997-10-14Francesco Chemolli  case CHAR_TYPE: return "char"; case REAL_TYPE: return "real"; case IDENT_TYPE: return "ident"; case NULL_TYPE: return "null"; #ifdef MSQL_VERSION_2 case TEXT_TYPE: return "text"; case UINT_TYPE: return "unsigned int"; case IDX_TYPE: return "index"; case SYSVAR_TYPE: return "sysvar"; case ANY_TYPE: return "any"; #endif default: return "unknown"; }
4bf8151997-11-02Henrik Grubbström (Grubba) }
25ce501997-10-14Francesco Chemolli 
73e49d2015-06-13Henrik Grubbström (Grubba)  CVAR int socket; /* the communication socket between us and the database engine. */ CVAR unsigned int db_selected:1; /*flag: if we selected a database*/ CVAR unsigned int connected:1; /*flag: we connected to a server*/ CVAR struct pike_string *error_msg;
25ce501997-10-14Francesco Chemolli #ifdef MSQL_VERSION_2
73e49d2015-06-13Henrik Grubbström (Grubba)  CVAR int affected;
25ce501997-10-14Francesco Chemolli #endif
73e49d2015-06-13Henrik Grubbström (Grubba)  DECLARE_STORAGE;
25ce501997-10-14Francesco Chemolli 
bab29c2017-02-11Henrik Grubbström (Grubba)  /*! @decl inherit __builtin.Sql.Connection */ INHERIT "__builtin.Sql.Connection";
73e49d2015-06-13Henrik Grubbström (Grubba) INIT
25ce501997-10-14Francesco Chemolli { THIS->connected=0; THIS->db_selected=0; THIS->error_msg=NULL; }
73e49d2015-06-13Henrik Grubbström (Grubba) EXIT
25ce501997-10-14Francesco Chemolli { if (THIS->connected) { int socket=THIS->socket; THREADS_ALLOW(); MSQL_LOCK(); msqlClose(socket); MSQL_UNLOCK(); THREADS_DISALLOW(); } if (THIS->error_msg) free_string(THIS->error_msg); } static void report_error (void) { if (THIS->error_msg) free_string(THIS->error_msg); THIS->error_msg=make_shared_string(msqlErrMsg); /* msqlErrMsg is really a char[160] in mSQL/2.0, but I don't want to take any chances, even if I'm wasting some time here. */ } static void do_select_db(char * dbname) { /* NOTICE: We're assuming we're connected. CHECK before calling! */ int status,socket=THIS->socket; THREADS_ALLOW(); MSQL_LOCK(); status=msqlSelectDB(socket,dbname); MSQL_UNLOCK(); THREADS_DISALLOW(); if (status==-1) { THIS->db_selected=0; report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Could not select database.\n");
25ce501997-10-14Francesco Chemolli  } THIS->db_selected=1; }
1e34db2001-12-08Martin Nilsson /*! @decl void shutdown() *! *! This function shuts a SQL-server down. */
73e49d2015-06-13Henrik Grubbström (Grubba) PIKEFUN void shutdown()
25ce501997-10-14Francesco Chemolli /* Notice: the msqlShutdown() function is undocumented. I'll have to go through the source to find how to report errors.*/ { int status=0,socket=THIS->socket; if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected to any server.\n");
25ce501997-10-14Francesco Chemolli  THREADS_ALLOW(); MSQL_LOCK(); status=msqlShutdown(socket); if (status>=0) msqlClose(socket); /*DBserver is shut down, might as well close */ MSQL_UNLOCK(); THREADS_DISALLOW(); if (status<0) { report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Error while shutting down the DBserver, connection not closed.\n");
25ce501997-10-14Francesco Chemolli  } THIS->connected=0; THIS->db_selected=0; }
1e34db2001-12-08Martin Nilsson /*! @decl void reload_acl() *! *! This function forces a server to reload its ACLs. *! *! @note
2a3a822002-11-18Martin Nilsson  *! This function is @b{not@} part of the standard interface, so it is
2c228b2009-02-15Stephen R. van den Berg  *! @b{not@} available through the @[Sql.Sql] interface, but only through
2a3a822002-11-18Martin Nilsson  *! @[Sql.msql] and @[Msql.msql] programs.
1e34db2001-12-08Martin Nilsson  *! *! @seealso *! @[create] */
73e49d2015-06-13Henrik Grubbström (Grubba) PIKEFUN void reload_acl()
25ce501997-10-14Francesco Chemolli /* Undocumented mSQL function. */ { int socket,status=0;
c745692015-11-08Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected to any server.\n");
25ce501997-10-14Francesco Chemolli  socket=THIS->socket; THREADS_ALLOW(); MSQL_LOCK(); status=msqlReloadAcls(socket); MSQL_UNLOCK(); THREADS_DISALLOW(); if (status<0) { report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Could not reload ACLs.\n");
25ce501997-10-14Francesco Chemolli  } }
1e34db2001-12-08Martin Nilsson /*! @decl void create (void|string dbserver, void|string dbname,@ *! void|string username, void|string passwd) *! With one argument, this function *! tries to connect to the specified (use hostname or IP address) database *! server. To connect to a server running on the local host via UNIX domain
cbe8c92003-04-07Martin Nilsson  *! sockets use @expr{"localhost"@}. To connect to the local host via TCP/IP *! sockets *! you have to use the IP address @expr{"127.0.0.1"@}.
1e34db2001-12-08Martin Nilsson  *! With two arguments it also selects a database to use on the server. *! With no arguments it tries to connect to the server on localhost, using *! UNIX sockets. *! *! @throws *! You need to have a database selected before using the sql-object, *! otherwise you'll get exceptions when you try to query it. *! Also notice that this function @b{can@} raise exceptions if the db *! server doesn't respond, if the database doesn't exist or is not accessible *! by you. *! *! @note *! You don't need bothering about syncronizing the connection to the database: *! it is automatically closed (and the database is sync-ed) when the msql *! object is destroyed. *! *! @seealso *! @[select_db] */
73e49d2015-06-13Henrik Grubbström (Grubba)  /* 1st arg: hostname or "localhost", 2nd arg: dbname or nothing * CAN raise exception if there is no server listening, or no database * To connect using the UNIX socket instead of a localfunction use the * hostname "localhost", or use no argument. It will use UNIX sockets. * Third and fourth argument are currently ignored, since mSQL doesn't * support user/passwd authorization. The user will be the owner of * the current process. * The first argument can have the format "hostname:port". Since mSQL * doesn't support nonstandard ports, that portion is silently ignored, * and is provided only for generic-interface compliancy */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN void create(void|string(1..255) dbserver, void|string(1..255) dbname, void|string(1..255) username, void|string(1..255) passwd,
73e49d2015-06-13Henrik Grubbström (Grubba)  mapping|int|void options)
25ce501997-10-14Francesco Chemolli { struct pike_string * arg1=NULL, *arg2=NULL; int sock, status;
6602dc1997-11-24Francesco Chemolli  char *colon;
25ce501997-10-14Francesco Chemolli 
30223f2015-11-10Henrik Grubbström (Grubba)  if (dbserver) if (dbserver->len) arg1 = dbserver; if (dbname) if (dbname->len) arg2 = dbname;
25ce501997-10-14Francesco Chemolli  /*Okay. We had one or two arguments, and we must connect to a server and if needed select a database. First off let's check whether we are already connected. In this case, disconnect.*/ if (THIS->connected) { msqlClose (THIS->socket); THIS->connected=0; THIS->db_selected=0; }
13670c2015-05-25Martin Nilsson  /* msql won' support specifying a port number to connect to.
6602dc1997-11-24Francesco Chemolli  * As far as I know, ':' is not a legal character in an hostname, * so we'll silently ignore it. */ if (arg1) { colon=strchr(arg1->str,':');
a0bf102000-04-13Henrik Grubbström (Grubba)  if (colon) { arg1 = make_shared_binary_string(arg1->str, colon - arg1->str); free_string(sp[-args].u.string); sp[-args].u.string = arg1; }
6602dc1997-11-24Francesco Chemolli  }
a0bf102000-04-13Henrik Grubbström (Grubba)  THREADS_ALLOW();
25ce501997-10-14Francesco Chemolli  MSQL_LOCK(); /* Warning! If there were no args, we're deferencing a NULL pointer!*/ if (!arg1 || !strcmp (arg1->str,"localhost")) sock=msqlConnect(NULL); else sock=msqlConnect(arg1->str); MSQL_UNLOCK(); THREADS_DISALLOW(); if (sock==-1) { THIS->db_selected=0; THIS->connected=0; report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Error while connecting to mSQL server.\n");
25ce501997-10-14Francesco Chemolli  } THIS->socket=sock; THIS->connected=1;
a0bf102000-04-13Henrik Grubbström (Grubba)  if (arg2) do_select_db(arg2->str);
25ce501997-10-14Francesco Chemolli }
73e49d2015-06-13Henrik Grubbström (Grubba) /*! @decl array(string) list_dbs(void|string wild)
1e34db2001-12-08Martin Nilsson  *!
2c228b2009-02-15Stephen R. van den Berg  *! Returns an array containing the names of all databases available on
1e34db2001-12-08Martin Nilsson  *! the system. Will throw an exception if there is no server connected. *! If an argument is specified, it will return only those databases *! whose name matches the given glob. */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN array(string) list_dbs(string(1..255)|void wild)
25ce501997-10-14Francesco Chemolli { m_result * result; m_row row; int fields,numrows=0,socket=THIS->socket;
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected.\n");
30223f2015-11-10Henrik Grubbström (Grubba)  if (wild && !wild->len) wild = NULL; else {
25ce501997-10-14Francesco Chemolli  /* We have a glob. We should pop the arg and push it again for a later * call to glob() */
30223f2015-11-10Henrik Grubbström (Grubba)  pop_n_elems(args-1); /* Paranoia. */ args = 1;
25ce501997-10-14Francesco Chemolli  } THREADS_ALLOW(); MSQL_LOCK(); result=msqlListDBs(socket); MSQL_UNLOCK(); THREADS_DISALLOW(); if (!result) { f_aggregate(0); /*empty array if no databases*/ return; }
6715d61997-10-15Henrik Grubbström (Grubba)  while ((row=msqlFetchRow(result))) /*it's fast, we're in RAM*/
25ce501997-10-14Francesco Chemolli  { numrows++;
4bf8151997-11-02Henrik Grubbström (Grubba)  push_text((char *)row[0]);
25ce501997-10-14Francesco Chemolli  } f_aggregate(numrows); msqlFreeResult(result);
30223f2015-11-10Henrik Grubbström (Grubba)  if (wild)
25ce501997-10-14Francesco Chemolli  f_glob(2); }
73e49d2015-06-13Henrik Grubbström (Grubba) /*! @decl array(string) list_tables(void|string wild)
1e34db2001-12-08Martin Nilsson  *! *! Returns an array containing the names of all the tables in the currently *! selected database. Will throw an exception if we aren't connected to *! a database. *! If an argument is specified, it will return only those tables *! whose name matches the given glob. */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN array(string) list_tables(void|string(1..255) wild)
25ce501997-10-14Francesco Chemolli  /* ARGH! There's much code duplication here... but the subtle differences * between the various functions make it impervious to try to generalize..*/ { m_result * result; m_row row; int fields,numrows=0,socket=THIS->socket;
a12b1f2015-11-09Martin Nilsson  if (!THIS->db_selected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("No database selected.\n");
25ce501997-10-14Francesco Chemolli 
30223f2015-11-10Henrik Grubbström (Grubba)  if (wild && !wild->len) wild = NULL; else {
25ce501997-10-14Francesco Chemolli  /* We have a glob. We should pop the arg and push it again for a later * call to glob() */
30223f2015-11-10Henrik Grubbström (Grubba)  pop_n_elems(args-1); /* Paranoia. */ args = 1;
25ce501997-10-14Francesco Chemolli  } THREADS_ALLOW(); MSQL_LOCK(); result=msqlListTables(socket); MSQL_UNLOCK(); THREADS_DISALLOW(); if (!result) { f_aggregate(0); /*empty array if no databases*/ return; }
6715d61997-10-15Henrik Grubbström (Grubba)  while ((row=msqlFetchRow(result)))
25ce501997-10-14Francesco Chemolli  { numrows++;
4bf8151997-11-02Henrik Grubbström (Grubba)  push_text((char *)row[0]);
25ce501997-10-14Francesco Chemolli  } f_aggregate(numrows); msqlFreeResult(result);
30223f2015-11-10Henrik Grubbström (Grubba)  if (wild)
25ce501997-10-14Francesco Chemolli  f_glob(2); }
1e34db2001-12-08Martin Nilsson /*! @decl void select_db(string dbname) *! *! Before querying a database you have to select it. This can be accomplished *! in two ways: the first is calling the @[create] function with two arguments, *! another is calling it with one or no argument and then calling @[select_db]. *! You can also use this function to change the database you're querying, *! as long as it is on the same server you are connected to. *! *! @throws *! This function CAN raise exceptions in case something goes wrong *! (for example: unexistant database, insufficient permissions, whatever). *! *! @seealso *! @[create], @[error] */
73e49d2015-06-13Henrik Grubbström (Grubba) /* if no db was selected by connect, does it now. * CAN raise an exception if there's no such database or we haven't selected * an host. */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN void select_db(string(1..255) dbname)
25ce501997-10-14Francesco Chemolli {
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected.\n");
a12b1f2015-11-09Martin Nilsson  do_select_db(dbname->str);
25ce501997-10-14Francesco Chemolli }
bab29c2017-02-11Henrik Grubbström (Grubba)  /*! @class Result */ PIKECLASS Result { CVAR m_result *result; /*! @decl inherit __builtin.Sql.Result */ INHERIT "__builtin.Sql.Result"; EXIT { if (THIS->result) { msqlFreeResult(THIS->result); } } PIKEFUN int num_rows() { RETURN msqlNumRows(THIS->result); } PIKEFUN int num_fields() { RETURN msqlNumFields(THIS->result); } PIKEFUN array(mapping(string:mixed)) fetch_fields() { int i; int num_fields = msqlNumFields(THIS->result); msqlFieldSeek(THIS->result, 0); BEGIN_AGGREGATE_ARRAY(num_fields); for (i = 0; i < num_fields; i++) { m_field *field = msqlFetchField(THIS->result); push_text("name"); push_text(field->name); push_text("table"); push_text(field->table); f_aggregate_mapping(4); DO_AGGREGATE_ARRAY(100); } END_AGGREGATE_ARRAY; } PIKEFUN array(string|int(0..0)) fetch_row() { int num_fields = msqlNumFields(THIS->result); m_row row = msqlFetchRow(THIS->result); int i; BEGIN_AGGREGATE_ARRAY(num_fields); for (i = 0; i < num_fields; i++) { if (row[i]) { push_text(row[i]); } else { push_undefined(); } DO_AGGREGATE_ARRAY(100); } END_AGGREGATE_ARRAY; } } /*! @endclass Result */ /*! @decl variant Result big_query(string(8bit) sqlquery)
1e34db2001-12-08Martin Nilsson  *! *! This is all you need to query the database. It takes as argument an SQL
bab29c2017-02-11Henrik Grubbström (Grubba)  *! query string (e.g.: "SELECT foo,bar FROM baz WHERE name like '%kinkie%'"
1e34db2001-12-08Martin Nilsson  *! or "INSERT INTO baz VALUES ('kinkie','made','this')")
bab29c2017-02-11Henrik Grubbström (Grubba)  *! and returns an object containing the returned values.
1e34db2001-12-08Martin Nilsson  *! *! @throws *! Errors (both from the interface and the SQL server) are reported via *! exceptions, and you definitely want to catch them. Error messages are *! not particularly verbose, since they account only for errors inside the *! driver. To get server-related error messages, you have to use the *! @[error] function. *! *! @note *! Note that if the query is NOT a of SELECT type, but UPDATE or
bab29c2017-02-11Henrik Grubbström (Grubba)  *! MODIFY, the returned value is a @expr{0@} (zero).
1e34db2001-12-08Martin Nilsson  *! @b{This is not an error@}. Errors are reported @b{only@} via exceptions. *! *! @seealso *! @[error] */
bab29c2017-02-11Henrik Grubbström (Grubba)  PIKEFUN object big_query(string(1..255) sqlquery) flags ID_VARIANT; { int status, socket; m_result *result = NULL; struct object *o; struct Msql_msql_Result_struct *res;
25ce501997-10-14Francesco Chemolli 
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Must connect to database server before querying it.\n");
25ce501997-10-14Francesco Chemolli  if (!THIS->db_selected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Must select database before querying it.\n");
25ce501997-10-14Francesco Chemolli 
bab29c2017-02-11Henrik Grubbström (Grubba)  socket = THIS->socket;
25ce501997-10-14Francesco Chemolli  #ifdef MSQL_DEBUG
bab29c2017-02-11Henrik Grubbström (Grubba)  fprintf(stderr, "MSQLMod: Query is\"%s\"\n", sqlquery->str);
25ce501997-10-14Francesco Chemolli #endif THREADS_ALLOW(); MSQL_LOCK();
bab29c2017-02-11Henrik Grubbström (Grubba)  status = msqlQuery(socket, sqlquery->str); if (status != -1) { /*We have what we want. We need to construct the returned structure*/ result=msqlStoreResult(); }
25ce501997-10-14Francesco Chemolli  MSQL_UNLOCK(); THREADS_DISALLOW(); if (status==-1) { report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Error in SQL query.\n");
25ce501997-10-14Francesco Chemolli  } #ifdef MSQL_VERSION_2 THIS->affected=status; #endif
bab29c2017-02-11Henrik Grubbström (Grubba)  if (!result) { push_int(0); return;
25ce501997-10-14Francesco Chemolli  }
bab29c2017-02-11Henrik Grubbström (Grubba)  apply_current(Msql_msql_Result_program_fun_num, 0);
25ce501997-10-14Francesco Chemolli 
bab29c2017-02-11Henrik Grubbström (Grubba)  if ((TYPEOF(Pike_sp[-1]) != PIKE_T_OBJECT) || !(res = get_storage(Pike_sp[-1].u.object, Msql_msql_Result_program)) || res->result) { msqlFreeResult(result); Pike_error("Bad msql result object!\n");
25ce501997-10-14Francesco Chemolli  }
13670c2015-05-25Martin Nilsson 
bab29c2017-02-11Henrik Grubbström (Grubba)  res->result = result; }
25ce501997-10-14Francesco Chemolli 
1e34db2001-12-08Martin Nilsson /*! @decl string server_info() *! *! This function returns a string describing the server we are talking *! to. It has the form "servername/serverversion" (like the HTTP protocol *! description) and is most useful in conjunction with the generic SQL-server *! module. *! */
73e49d2015-06-13Henrik Grubbström (Grubba) PIKEFUN string server_info()
25ce501997-10-14Francesco Chemolli { char * info;
a12b1f2015-11-09Martin Nilsson  pop_n_elems(args);
25ce501997-10-14Francesco Chemolli  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected.\n");
5e9fc02015-08-18Per Hedbor  push_static_text("msql/");
25ce501997-10-14Francesco Chemolli  THREADS_ALLOW(); MSQL_LOCK(); info=msqlGetServerInfo(); MSQL_UNLOCK(); THREADS_DISALLOW(); push_text(info); f_add(2); }
1e34db2001-12-08Martin Nilsson /*! @decl string host_info() *! *! This function returns a string describing what host are we talking to, *! and how (TCP/IP or UNIX sockets). */
73e49d2015-06-13Henrik Grubbström (Grubba) PIKEFUN string host_info()
25ce501997-10-14Francesco Chemolli {
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected.\n");
25ce501997-10-14Francesco Chemolli  /*it's local to the client library. Not even worth allowing context switches*/
13670c2015-05-25Martin Nilsson  push_text(msqlGetHostInfo());
25ce501997-10-14Francesco Chemolli }
921eda2017-11-19Stephen R. van den Berg /*! @decl string error(void|int clear)
1e34db2001-12-08Martin Nilsson  *! *! This function returns the textual description of the last server-related *! error. Returns 0 if no error has occurred yet. It is not cleared upon *! reading (can be invoked multiple times, will return the same result *! until a new error occurs). *! *! @seealso *! @[query] */
921eda2017-11-19Stephen R. van den Berg PIKEFUN string error(void|int clear)
25ce501997-10-14Francesco Chemolli {
921eda2017-11-19Stephen R. van den Berg  int clearit = clear && clear->u.integer; pop_n_elems(args); if (THIS->error_msg) {
bb6b091998-03-02Francesco Chemolli  ref_push_string(THIS->error_msg);
921eda2017-11-19Stephen R. van den Berg  if (clearit) { free_string(THIS->error_msg); THIS->error_msg = 0; } } else
bb6b091998-03-02Francesco Chemolli  push_int(0);
25ce501997-10-14Francesco Chemolli }
1e34db2001-12-08Martin Nilsson /*! @decl void create_db(string dbname) *! *! This function creates a new database with the given name (assuming we *! have enough permissions to do this). *! *! @seealso *! @[drop_db] */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN void create_db(string(1..255) dbname)
25ce501997-10-14Francesco Chemolli { int dbresult;
a12b1f2015-11-09Martin Nilsson  int socket;
25ce501997-10-14Francesco Chemolli 
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Not connected.\n");
a12b1f2015-11-09Martin Nilsson  socket=THIS->socket;
25ce501997-10-14Francesco Chemolli  THREADS_ALLOW(); MSQL_LOCK();
a12b1f2015-11-09Martin Nilsson  dbresult=msqlCreateDB(socket,dbname->str);
25ce501997-10-14Francesco Chemolli  MSQL_UNLOCK(); THREADS_DISALLOW(); if (dbresult==-1) { report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Could not create database.\n");
25ce501997-10-14Francesco Chemolli  } }
1e34db2001-12-08Martin Nilsson /*! @decl void drop_db(string dbname) *! *! This function destroys a database and all the data it contains (assuming *! we have enough permissions to do so). USE WITH CAUTION! *! *! @seealso *! @[create_db] */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN void drop_db(string(1..255) dbname)
25ce501997-10-14Francesco Chemolli { int dbresult;
a12b1f2015-11-09Martin Nilsson  int socket;
25ce501997-10-14Francesco Chemolli 
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Not connected.\n");
a12b1f2015-11-09Martin Nilsson  socket=THIS->socket;
25ce501997-10-14Francesco Chemolli  THREADS_ALLOW(); MSQL_LOCK();
a12b1f2015-11-09Martin Nilsson  dbresult=msqlDropDB(socket,dbname->str);
25ce501997-10-14Francesco Chemolli  MSQL_UNLOCK(); THREADS_DISALLOW(); if (dbresult==-1) { report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Could not drop database.\n");
25ce501997-10-14Francesco Chemolli  } }
a12b1f2015-11-09Martin Nilsson /*! @decl mapping(string:mapping(string:mixed)) list_fields(string table)
1e34db2001-12-08Martin Nilsson  *! *! Returns a mapping describing the fields of a table in the database. *! The returned value is a mapping, indexed on the column name,
a12b1f2015-11-09Martin Nilsson  *! of mappings. These contain currently the fields:
1e34db2001-12-08Martin Nilsson  *! *! @mapping *! @member string "type" *! Describes the field's mSQL data type ("char","integer",...) *! @member int "length" *! It describes the field's length. It is only interesting for *! char() fields, in fact. Also *! notice that the strings returned by msql->query() have the correct length. *! This field only specifies the _maximum_ length a "char()" field can have. *! @member string "table" *! The table this field is in. Added only for interface compliancy. *! @member multiset(string) "flags" *! It's a multiset containing textual *! descriptions of the server's flags associated with the current field. *! Currently it can be empty, or contain "unique" or "not null". *! @endmapping *! *! @note
2a3a822002-11-18Martin Nilsson  *! The version of this function in the Msql.msql() program is @b{not@}
1e34db2001-12-08Martin Nilsson  *! sql-interface compliant (this is the main reason why using that program
2a3a822002-11-18Martin Nilsson  *! directly is deprecated). Use @[Sql.Sql] instead.
1e34db2001-12-08Martin Nilsson  *! *! @seealso *! @[query] */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN mapping(string:mapping(string:mixed)) list_fields(string(1..255) table, void|string glob)
25ce501997-10-14Francesco Chemolli { m_result * result; m_field * field;
a12b1f2015-11-09Martin Nilsson  int fields, j, socket=THIS->socket;
25ce501997-10-14Francesco Chemolli 
a12b1f2015-11-09Martin Nilsson  if (!THIS->connected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Not connected.\n");
25ce501997-10-14Francesco Chemolli  if (!THIS->db_selected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Must select a db first.\n");
25ce501997-10-14Francesco Chemolli #ifdef MSQL_DEBUG
30223f2015-11-10Henrik Grubbström (Grubba)  printf("list_fields: table=%s(%d)\n", table->str, table->len);
25ce501997-10-14Francesco Chemolli #endif THREADS_ALLOW(); MSQL_LOCK();
a12b1f2015-11-09Martin Nilsson  result=msqlListFields(socket,table->str);
25ce501997-10-14Francesco Chemolli  MSQL_UNLOCK(); THREADS_DISALLOW(); pop_n_elems(args); if (!result) { report_error();
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("No fields information.\n");
25ce501997-10-14Francesco Chemolli  }
13670c2015-05-25Martin Nilsson 
25ce501997-10-14Francesco Chemolli  fields = msqlNumFields(result); if (!fields)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("No such table.\n");
25ce501997-10-14Francesco Chemolli  for (j=0;j<fields;j++) { int flagsnum=0; field=msqlFetchField(result);
13670c2015-05-25Martin Nilsson 
1ed5d22015-11-09Martin Nilsson  push_static_text("name");
25ce501997-10-14Francesco Chemolli  push_text(field->name);
6a932b2014-08-18Martin Nilsson  ref_push_string(literal_type_string);
5e9fc02015-08-18Per Hedbor  push_static_text(decode_msql_type(field->type)); push_static_text("length");
25ce501997-10-14Francesco Chemolli  push_int(field->length);
5e9fc02015-08-18Per Hedbor  push_static_text("table");
25ce501997-10-14Francesco Chemolli  push_text(field->table);
5e9fc02015-08-18Per Hedbor  push_static_text("flags");
25ce501997-10-14Francesco Chemolli #ifdef IS_UNIQUE if (IS_UNIQUE(field->flags)) {
5e9fc02015-08-18Per Hedbor  push_static_text("unique");
25ce501997-10-14Francesco Chemolli  flagsnum++; } #endif #ifdef IS_NOT_NULL if (IS_NOT_NULL(field->flags)) {
5e9fc02015-08-18Per Hedbor  push_static_text("not_null");
25ce501997-10-14Francesco Chemolli  flagsnum++; } #endif #ifdef IS_PRI_KEY if (IS_PRI_KEY(field->flags)) {
5e9fc02015-08-18Per Hedbor  push_static_text("primary_key");
25ce501997-10-14Francesco Chemolli  flagsnum++; } #endif f_aggregate_multiset(flagsnum);
75d63a2001-01-02Francesco Chemolli  f_aggregate_mapping(10);
25ce501997-10-14Francesco Chemolli  }
1ed5d22015-11-09Martin Nilsson  f_aggregate(fields); msqlFreeResult(result);
25ce501997-10-14Francesco Chemolli } #ifdef MSQL_VERSION_2
1e34db2001-12-08Martin Nilsson  /*! @decl int affected_rows() *! *! This function returns how many rows in the database were affected by *! our last SQL query. *! *! @note
2c228b2009-02-15Stephen R. van den Berg  *! This function is available only if you're using mSQL version 2
1e34db2001-12-08Martin Nilsson  *! or later. (That means: if the includes and library of version 2 of mSQL
2c228b2009-02-15Stephen R. van den Berg  *! were available when the module was compiled).
1e34db2001-12-08Martin Nilsson  *! *! This function is @b{not@} part of the standard interface, so it is @b{not@}
2c228b2009-02-15Stephen R. van den Berg  *! available through the @[Sql.Sql] interface, but only through @[Sql.msql] and
1e34db2001-12-08Martin Nilsson  *! @[Msql.msql] programs */
73e49d2015-06-13Henrik Grubbström (Grubba) PIKEFUN int affected_rows()
25ce501997-10-14Francesco Chemolli {
a12b1f2015-11-09Martin Nilsson  pop_n_elems(args);
25ce501997-10-14Francesco Chemolli  push_int(THIS->affected); }
1e34db2001-12-08Martin Nilsson /*! @decl array list_index(string tablename, string indexname) *! *! This function returns an array describing the index structure for the *! given table and index name, as defined by the non-standard SQL query *! 'create index' (see the mSQL documentation for further informations). *! More than one index can be created for a table. There's currently NO way *! to have a listing of the indexes defined for a table (blame it on *! the mSQL API). *! *! @note
2c228b2009-02-15Stephen R. van den Berg  *! This function is available if you're using mSQL version 2
1e34db2001-12-08Martin Nilsson  *! or later. *! *! This function is @b{not@} part of the standard interface, so it is @b{not@}
2c228b2009-02-15Stephen R. van den Berg  *! available through the @[Sql.Sql] interface, but only through @[Sql.msql] and
1e34db2001-12-08Martin Nilsson  *! @[Msql.msql] programs. */
30223f2015-11-10Henrik Grubbström (Grubba) PIKEFUN array list_index(string(1..255) tablename, string(1..255) indexname)
25ce501997-10-14Francesco Chemolli {
a12b1f2015-11-09Martin Nilsson  m_result * result;
25ce501997-10-14Francesco Chemolli  m_row row; int sock, rows, j;
a12b1f2015-11-09Martin Nilsson  if (!THIS->db_selected)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("No database selected.\n");
a12b1f2015-11-09Martin Nilsson  sock=THIS->socket;
25ce501997-10-14Francesco Chemolli  THREADS_ALLOW(); MSQL_LOCK();
a12b1f2015-11-09Martin Nilsson  result=msqlListIndex(sock,tablename->str,indexname->str);
25ce501997-10-14Francesco Chemolli  MSQL_UNLOCK(); THREADS_DISALLOW(); pop_n_elems(args); if (!result || !(rows=msqlNumRows(result)) ) { f_aggregate(0); return; } msqlFetchRow(result); /*The first one is the internal type, useless*/ rows--; for (j=0; j<rows; j++) { row=msqlFetchRow(result); push_text(row[0]); } f_aggregate(rows); } #endif
73e49d2015-06-13Henrik Grubbström (Grubba) }
1e34db2001-12-08Martin Nilsson /*! @endclass */ /*! @decl constant version *! *! Should you need to report a bug to the author, please submit along with *! the report the driver version number, as returned by this call. */ /*! @endmodule */
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_INIT
25ce501997-10-14Francesco Chemolli {
73e49d2015-06-13Henrik Grubbström (Grubba)  INIT;
6602dc1997-11-24Francesco Chemolli 
ec1cd32015-12-27Martin Nilsson  /* Deprecated */ add_string_constant("version","mSQL/1.1.1",0);
25ce501997-10-14Francesco Chemolli }
73e49d2015-06-13Henrik Grubbström (Grubba) PIKE_MODULE_EXIT { EXIT; }
25ce501997-10-14Francesco Chemolli #else /*HAVE_MSQL*/
1fbe3e2005-11-14Martin Nilsson PIKE_MODULE_INIT {
ecb2c02014-10-05Martin Nilsson  HIDE_MODULE();
1fbe3e2005-11-14Martin Nilsson }
25ce501997-10-14Francesco Chemolli 
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_EXIT { }
73e49d2015-06-13Henrik Grubbström (Grubba) #endif /*HAVE_MSQL*/