8a37531997-03-06Henrik Grubbström (Grubba) /* * Implements the generic parts of the SQL-interface * * Henrik Grubbström 1996-01-09 */
5038e72017-03-09Henrik Grubbström (Grubba) #pike 8.1
a20af62000-09-26Fredrik Hübinette (Hubbe) 
3d08a42019-04-13Henrik Grubbström (Grubba) #pragma no_deprecation_warnings
a6d6bd2011-03-05Martin Stjernholm //! This class encapsulates a connection to an SQL server. It is a //! generic interface on top of the DB server specific //! implementations. That doesn't mean that there aren't plenty of //! server specific characteristics that still shine through, though. //! //! This class also serves as an interface guideline for the DB server //! specific connection classes. //! //! @section Untyped and typed mode //! //! The query results are returned in different ways depending on the //! query functions used: The @tt{..typed_query@} functions select //! typed mode, while the other query functions uses the older untyped //! mode. //! //! In untyped mode, all values except SQL NULL are returned as //! strings in their display representation, and SQL NULL is returned //! as zero. //! //! In typed mode, values are returned in pike native form where it //! works well. That means at least that SQL integer fields are //! returned as pike integers, floats as floats, SQL NULL as //! @[Val.null], and of course strings still as strings. The
53f9642017-11-09Stephen R. van den Berg //! representation of other SQL types depends on the capabilities of
a6d6bd2011-03-05Martin Stjernholm //! the server specific backends. It's also possible that floats in //! some cases are represented in other ways if too much precision is //! lost in the conversion to pike floats. //! //! @endsection //! //! @note //! For historical reasons, there may be server specific backends that //! operate differently from what is described here, e.g. some that //! return a bit of typed data in untyped mode. //! //! @note //! Typed operation was not supported at all prior to Pike 7.8.363, //! and may not be supported for all databases.
fd82ce1997-03-30Henrik Grubbström (Grubba) 
5d16962003-04-22Martin Nilsson #define ERROR(X ...) predef::error(X)
8a37531997-03-06Henrik Grubbström (Grubba) 
a6d6bd2011-03-05Martin Stjernholm //! Server specific connection object used for the actual SQL queries.
8a37531997-03-06Henrik Grubbström (Grubba) object master_sql;
1778472001-01-08Henrik Grubbström (Grubba) //! Convert all field names in mappings to lower_case. //! Only relevant to databases which only implement big_query(), //! and use upper/mixed-case fieldnames (eg Oracle). //! @int //! @value 0 //! No (default) //! @value 1 //! Yes //! @endint
0e43482003-07-30Martin Nilsson int(0..1) case_convert;
198b901997-06-08Henrik Grubbström (Grubba) 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl string quote(string s) //! Quote a string @[s] so that it can safely be put in a query.
023c532003-10-26Peter Lundqvist //! //! All input that is used in SQL-querys should be quoted to prevent //! SQL injections.
3524712015-05-26Martin Nilsson //!
023c532003-10-26Peter Lundqvist //! Consider this harmfull code: //! @code //! string my_input = "rob' OR name!='rob"; //! string my_query = "DELETE FROM tblUsers WHERE name='"+my_input+"'"; //! my_db->query(my_query); //! @endcode
3524712015-05-26Martin Nilsson //!
023c532003-10-26Peter Lundqvist //! This type of problems can be avoided by quoting @tt{my_input@}.
3524712015-05-26Martin Nilsson //! @tt{my_input@} would then probably read something like //! @i{rob\' OR name!=\'rob@}
023c532003-10-26Peter Lundqvist //! //! Usually this is done - not by calling quote explicitly - but through //! using a @[sprintf] like syntax //! @code //! string my_input = "rob' OR name!='rob"; //! my_db->query("DELETE FROM tblUsers WHERE name=%s",my_input); //! @endcode
7dc3162001-04-27Henrik Grubbström (Grubba) 
8785481999-07-01Henrik Grubbström (Grubba) function(string:string) quote = .sql_util.quote;
fd98191998-03-19Henrik Grubbström (Grubba) 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl string encode_time(int t, int|void is_utc) //! Converts a system time value to an appropriately formatted time //! spec for the database.
0e43482003-07-30Martin Nilsson //! @param t //! Time to encode. //! @param is_utc //! If nonzero then time is taken as a "full" unix time spec //! (where the date part is ignored), otherwise it's converted as a //! seconds-since-midnight value.
7dc3162001-04-27Henrik Grubbström (Grubba) 
b8554b1998-07-08Martin Stjernholm function(int,void|int:string) encode_time;
93f5441998-07-03Martin Stjernholm 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl int decode_time(string t, int|void want_utc) //! Converts a database time spec to a system time value.
0e43482003-07-30Martin Nilsson //! @param t //! Time spec to decode. //! @param want_utc //! Take the date part from this system time value. If zero, a //! seconds-since-midnight value is returned.
7dc3162001-04-27Henrik Grubbström (Grubba) 
b8554b1998-07-08Martin Stjernholm function(string,void|int:int) decode_time;
93f5441998-07-03Martin Stjernholm 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl string encode_date(int t) //! Converts a system time value to an appropriately formatted //! date-only spec for the database.
0e43482003-07-30Martin Nilsson //! @param t //! Time to encode.
7dc3162001-04-27Henrik Grubbström (Grubba) 
b8554b1998-07-08Martin Stjernholm function(int:string) encode_date;
93f5441998-07-03Martin Stjernholm 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl int decode_date(string d) //! Converts a database date-only spec to a system time value.
0e43482003-07-30Martin Nilsson //! @param d //! Date spec to decode.
7dc3162001-04-27Henrik Grubbström (Grubba) 
b8554b1998-07-08Martin Stjernholm function(string:int) decode_date;
93f5441998-07-03Martin Stjernholm 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl string encode_datetime(int t) //! Converts a system time value to an appropriately formatted //! date and time spec for the database.
0e43482003-07-30Martin Nilsson //! @param t //! Time to encode.
7dc3162001-04-27Henrik Grubbström (Grubba) 
b8554b1998-07-08Martin Stjernholm function(int:string) encode_datetime;
93f5441998-07-03Martin Stjernholm 
1778472001-01-08Henrik Grubbström (Grubba) //! @decl int decode_datetime(string datetime) //! Converts a database date and time spec to a system time value.
0e43482003-07-30Martin Nilsson //! @param datetime //! Date and time spec to decode.
7dc3162001-04-27Henrik Grubbström (Grubba) 
b8554b1998-07-08Martin Stjernholm function(string:int) decode_datetime;
93f5441998-07-03Martin Stjernholm 
9eaf1d2008-06-28Martin Nilsson protected program find_dbm(string program_name) {
b00be82004-06-14Stephen R. van den Berg  program p; // we look in Sql.type and Sql.Provider.type.type for a valid sql class. p = Sql[program_name];
6f8d2c2005-10-05Martin Nilsson  if(!p && Sql["Provider"] && Sql["Provider"][program_name]) p = Sql["Provider"][program_name][program_name];
b00be82004-06-14Stephen R. van den Berg  return p; }
962f482002-03-18Henrik Grubbström (Grubba) //! @decl void create(string host) //! @decl void create(string host, string db) //! @decl void create(string host, mapping(string:int|string) options) //! @decl void create(string host, string db, string user) //! @decl void create(string host, string db, string user, @ //! string password) //! @decl void create(string host, string db, string user, @ //! string password, mapping(string:int|string) options) //! @decl void create(object host) //! @decl void create(object host, string db) //!
ba65c92001-09-06Martin Nilsson //! Create a new generic SQL object.
7dc3162001-04-27Henrik Grubbström (Grubba) //! //! @param host
ba65c92001-09-06Martin Nilsson //! @mixed //! @type object //! Use this object to access the SQL-database. //! @type string
76f5812003-06-10Martin Stjernholm //! Connect to the server specified. The string should be on the //! format:
ba65c92001-09-06Martin Nilsson //! @tt{dbtype://[user[:password]@@]hostname[:port][/database]@}
76f5812003-06-10Martin Stjernholm //! Use the @i{dbtype@} protocol to connect to the database //! server on the specified host. If the hostname is @expr{""@} //! then the port can be a file name to access through a //! UNIX-domain socket or similar, e g //! @expr{"mysql://root@@:/tmp/mysql.sock/"@}.
86a6db2003-04-26Marcus Agehall //!
76f5812003-06-10Martin Stjernholm //! There is a special dbtype @expr{"mysqls"@} which works like //! @expr{"mysql"@} but sets the @tt{CLIENT_SSL@} option and //! loads the @tt{/etc/my.cnf@} config file to find the SSL //! parameters. The same function can be achieved using the //! @expr{"mysql"@} dbtype.
7e90ee2004-04-16Henrik Grubbström (Grubba) //! @type int(0..0) //! Access through a UNIX-domain socket or similar.
ba65c92001-09-06Martin Nilsson //! @endmixed
7dc3162001-04-27Henrik Grubbström (Grubba) //!
ee2b302001-11-08Anders Johansson //! @param db
1778472001-01-08Henrik Grubbström (Grubba) //! Select this database.
7dc3162001-04-27Henrik Grubbström (Grubba) //! //! @param user
1778472001-01-08Henrik Grubbström (Grubba) //! User name to access the database as.
ba65c92001-09-06Martin Nilsson //!
7dc3162001-04-27Henrik Grubbström (Grubba) //! @param password
1778472001-01-08Henrik Grubbström (Grubba) //! Password to access the database.
ba65c92001-09-06Martin Nilsson //!
962f482002-03-18Henrik Grubbström (Grubba) //! @param options //! Optional mapping of options. //! See the SQL-database documentation for the supported options. //! (eg @[Mysql.mysql()->create()]). //!
fdc7d52001-08-23Henrik Grubbström (Grubba) //! @note //! In versions of Pike prior to 7.2 it was possible to leave out the //! dbtype, but that has been deprecated, since it never worked well. //!
962f482002-03-18Henrik Grubbström (Grubba) //! @note
28a0112014-08-25Per Hedbor //! Exactly which databases are supported by pike depends on the //! installed set of client libraries when pike was compiled. //! //! The possible ones are //! @dl //! @item mysql //! libmysql based mysql connection //! @item mysqls //! libmysql based mysql connection, using SSL //! @item dsn //! @[ODBC] based connection //! @item msql //! @[Msql] //! @item odbc //! @[ODBC] based connection //! @item oracle //! @[Oracle] using oracle libraries //! @item pgsql //! PostgreSQL direct network access. //! This module is independent of any external libraries. //! @item postgres //! PostgreSQL libray access. Uses the @[Postgres] module. //! @item rsql //! Remote SQL api, requires a rsql server running on another host. //! This is an API that uses sockets to communicate with a remote pike //! running pike -x rsqld on another host. //! @item sqlite //! In-process SQLite database, uses the @[SQLite] module //! @item sybase //! Uses the @[sybase] module to access sybase //! @item tds //! Sybase and Microsoft SQL direct network access using the TDS protocol. //! This module is independent of any external libraries. //! @enddl //! //! @note
962f482002-03-18Henrik Grubbström (Grubba) //! Support for @[options] was added in Pike 7.3. //!
083eb12008-01-09Henrik Grubbström (Grubba) void create(string|object host, void|string|mapping(string:int|string) db,
1dc3fb2008-01-09Martin Stjernholm  void|string user, void|string _password,
96a9672002-03-18Tomas Nilsson  void|mapping(string:int|string) options)
8a37531997-03-06Henrik Grubbström (Grubba) {
083eb12008-01-09Henrik Grubbström (Grubba)  // Note: No need to censor host here, since it is rewritten below if // it contains an SQL-URL.
1dc3fb2008-01-09Martin Stjernholm  string password = _password; _password = "CENSORED";
8a37531997-03-06Henrik Grubbström (Grubba)  if (objectp(host)) { master_sql = host;
962f482002-03-18Henrik Grubbström (Grubba)  if ((user && user != "") || (password && password != "") || (options && sizeof(options))) {
5d16962003-04-22Martin Nilsson  ERROR("Only the database argument is supported when "
2bfbf22005-04-10Martin Nilsson  "first argument is an object.\n");
8a37531997-03-06Henrik Grubbström (Grubba)  } if (db && db != "") { master_sql->select_db(db); }
b7a44c1997-06-27Henrik Grubbström (Grubba)  }
9e97701998-07-17Martin Stjernholm  else {
962f482002-03-18Henrik Grubbström (Grubba)  if (mappingp(db)) { options = db; db = 0; }
9e97701998-07-17Martin Stjernholm  if (db == "") { db = 0; } if (user == "") { user = 0; } if (password == "") { password = 0; }
b7a44c1997-06-27Henrik Grubbström (Grubba) 
fdc7d52001-08-23Henrik Grubbström (Grubba)  string program_name;
b7a44c1997-06-27Henrik Grubbström (Grubba) 
0e43482003-07-30Martin Nilsson  if (host && (host != replace(host, ([ ":":"", "/":"", "@":"" ]) ))) {
b7a44c1997-06-27Henrik Grubbström (Grubba) 
9e97701998-07-17Martin Stjernholm  // The hostname is on the format: //
da61e52002-03-18Henrik Grubbström (Grubba)  // dbtype://[user[:password]@]hostname[:port][/database]
b7a44c1997-06-27Henrik Grubbström (Grubba) 
9e97701998-07-17Martin Stjernholm  array(string) arr = host/"://"; if ((sizeof(arr) > 1) && (arr[0] != "")) { if (sizeof(arr[0]/".pike") > 1) {
fdc7d52001-08-23Henrik Grubbström (Grubba)  program_name = (arr[0]/".pike")[0];
9e97701998-07-17Martin Stjernholm  } else {
fdc7d52001-08-23Henrik Grubbström (Grubba)  program_name = arr[0];
9e97701998-07-17Martin Stjernholm  } host = arr[1..] * "://";
b7a44c1997-06-27Henrik Grubbström (Grubba)  }
9e97701998-07-17Martin Stjernholm  arr = host/"@"; if (sizeof(arr) > 1) { // User and/or password specified host = arr[-1];
8a531a2006-11-04Martin Nilsson  arr = (arr[..<1]*"@")/":";
9e97701998-07-17Martin Stjernholm  if (!user && sizeof(arr[0])) { user = arr[0]; } if (!password && (sizeof(arr) > 1)) { password = arr[1..]*":"; if (password == "") { password = 0; }
b7a44c1997-06-27Henrik Grubbström (Grubba)  } }
9e97701998-07-17Martin Stjernholm  arr = host/"/"; if (sizeof(arr) > 1) {
8a531a2006-11-04Martin Nilsson  host = arr[..<1]*"/";
9e97701998-07-17Martin Stjernholm  if (!db) { db = arr[-1]; }
b7a44c1997-06-27Henrik Grubbström (Grubba)  } }
ec9f201997-04-23Henrik Grubbström (Grubba) 
9e97701998-07-17Martin Stjernholm  if (host == "") { host = 0; }
b7a44c1997-06-27Henrik Grubbström (Grubba) 
fdc7d52001-08-23Henrik Grubbström (Grubba)  if (!program_name) {
5d16962003-04-22Martin Nilsson  ERROR("No protocol specified.\n");
fdc7d52001-08-23Henrik Grubbström (Grubba)  }
2bfbf22005-04-10Martin Nilsson  // Don't call ourselves...
fdc7d52001-08-23Henrik Grubbström (Grubba)  if ((sizeof(program_name / "_result") != 1) ||
3dde842003-12-21H. William Welliver III  ((< "Sql", "sql", "sql_util", "module" >)[program_name]) ) {
2bfbf22005-04-10Martin Nilsson  ERROR("Unsupported protocol %O.\n", program_name);
eea2481998-11-04Henrik Grubbström (Grubba)  }
8a37531997-03-06Henrik Grubbström (Grubba) 
fdc7d52001-08-23Henrik Grubbström (Grubba)  program p;
b00be82004-06-14Stephen R. van den Berg  if (p = find_dbm(program_name)) {
962f482002-03-18Henrik Grubbström (Grubba)  if (options) { master_sql = p(host||"", db||"", user||"", password||"", options); } else if (password) {
fdc7d52001-08-23Henrik Grubbström (Grubba)  master_sql = p(host||"", db||"", user||"", password); } else if (user) { master_sql = p(host||"", db||"", user); } else if (db) { master_sql = p(host||"", db); } else if (host) { master_sql = p(host);
9e97701998-07-17Martin Stjernholm  } else {
fdc7d52001-08-23Henrik Grubbström (Grubba)  master_sql = p();
9e97701998-07-17Martin Stjernholm  }
89c5692009-11-18Henrik Grubbström (Grubba)  if (!master_sql->query && !master_sql->big_query) { master_sql = UNDEFINED; ERROR("Failed to index module Sql.%s or Sql.Provider.%s.\n", program_name, program_name); }
fdc7d52001-08-23Henrik Grubbström (Grubba)  } else {
2bfbf22005-04-10Martin Nilsson  ERROR("Failed to index module Sql.%s or Sql.Provider.%s.\n", program_name, program_name);
fdc7d52001-08-23Henrik Grubbström (Grubba)  }
b7a44c1997-06-27Henrik Grubbström (Grubba)  }
b8554b1998-07-08Martin Stjernholm  if (master_sql->quote) quote = master_sql->quote;
8785481999-07-01Henrik Grubbström (Grubba)  encode_time = master_sql->encode_time || .sql_util.fallback; decode_time = master_sql->decode_time || .sql_util.fallback; encode_date = master_sql->encode_date || .sql_util.fallback; decode_date = master_sql->decode_date || .sql_util.fallback; encode_datetime = master_sql->encode_datetime || .sql_util.fallback; decode_datetime = master_sql->decode_datetime || .sql_util.fallback;
8a37531997-03-06Henrik Grubbström (Grubba) }
c071bc2017-11-05Henrik Grubbström (Grubba) protected void _destruct() {
b43f882016-02-17Stephen R. van den Berg  if (master_sql) destruct(master_sql); }
ebecf82011-08-25Henrik Grubbström (Grubba) //! Returns true if the connection seems to be open. //! //! @note //! This function only checks that there's an open connection, //! and that the other end hasn't closed it yet. No data is //! sent over the connection. //! //! For a more reliable check of whether the connection //! is alive, please use @[ping()]. //! //! @seealso //! @[ping()] int is_open() { if (!master_sql) return 0; if (master_sql->is_open) return master_sql->is_open(); return 1; } //! @decl int ping() //! //! Check whether the connection is alive. //! //! @returns //! Returns one of the following: //! @int //! @value 0 //! Everything ok. //! @value 1 //! The connection reconnected automatically. //! @value -1 //! The server has gone away, and the connection is dead. //! @endint //! //! @seealso //! @[is_open()] int ping() { if (!master_sql) return -1; if (master_sql->ping) return master_sql->ping(); catch { return sizeof(query("SELECT 0 AS zero") || ({})) - 1; }; master_sql = UNDEFINED; // Inform is_open(). return -1; }
d50a272006-09-15Martin Stjernholm void set_charset (string charset) //! Changes the charset that the connection uses for queries and //! returned text strings. //! //! @param charset //! The charset to use. The valid values and their meanings depends //! on the database brand. However, the special value //! @expr{"unicode"@} (if supported) selects a mode where the query //! and result strings are unencoded (and possibly wide) unicode //! strings. //! //! @throws //! An error is thrown if the connection doesn't support the //! specified charset, or doesn't support charsets being set this //! way at all. //! //! @note //! See the @expr{set_charset@} functions for each database //! connection type for further details about the effects on the //! connection. //! //! @seealso //! @[get_charset], @[Sql.mysql.set_charset] { if (!master_sql->set_charset) predef::error ("This database connection does not " "support charset switching.\n"); master_sql->set_charset (charset); } string get_charset() //! Returns the (database dependent) name of the charset used for (at //! least) query strings. Returns zero if the connection doesn't //! support charsets this way (typically means that a call to //! @[set_charset] will throw an error). //! //! @seealso //! @[set_charset], @[Sql.mysql.get_charset] { return master_sql->get_charset && master_sql->get_charset(); }
9eaf1d2008-06-28Martin Nilsson protected string _sprintf(int type, mapping|void flags)
09d21c2002-04-11Johan Sundström {
ce3fd32002-11-29Martin Nilsson  if(type=='O' && master_sql && master_sql->_sprintf) return sprintf("Sql.%O", master_sql);
09d21c2002-04-11Johan Sundström }
9eaf1d2008-06-28Martin Nilsson protected array(mapping(string:mixed)) res_obj_to_array(object res_obj)
8a37531997-03-06Henrik Grubbström (Grubba) {
39a78e2015-04-15Henrik Grubbström (Grubba)  if (!res_obj) return 0; array(mapping(string:mixed)) res = ({}); while (res_obj)
65dd6d1999-07-01Per Hedbor  {
2bfbf22005-04-10Martin Nilsson  // Not very efficient, but sufficient
8a37531997-03-06Henrik Grubbström (Grubba)  array(string) fieldnames; array(mixed) row;
59eb3b2005-11-25Martin Nilsson 
1e1a5b1999-06-27Henrik Grubbström (Grubba)  array(mapping) fields = res_obj->fetch_fields();
59eb3b2005-11-25Martin Nilsson  if(!sizeof(fields)) return ({}); int has_table = fields[0]->table && fields[0]->table!="";
1e1a5b1999-06-27Henrik Grubbström (Grubba) 
59eb3b2005-11-25Martin Nilsson  if(has_table) fieldnames = (map(fields, lambda (mapping(string:mixed) m) { return (m->table||"") + "." + m->name; }) + fields->name); else fieldnames = fields->name;
1e1a5b1999-06-27Henrik Grubbström (Grubba) 
65dd6d1999-07-01Per Hedbor  if (case_convert)
981f832005-04-10Martin Nilsson  fieldnames = map(fieldnames, lower_case);
8a37531997-03-06Henrik Grubbström (Grubba) 
59eb3b2005-11-25Martin Nilsson  if(has_table) while (row = res_obj->fetch_row()) res += ({ mkmapping(fieldnames, row + row) }); else while (row = res_obj->fetch_row()) res += ({ mkmapping(fieldnames, row) });
1e1a5b1999-06-27Henrik Grubbström (Grubba) 
39a78e2015-04-15Henrik Grubbström (Grubba)  // Try the next result. res_obj = res_obj->next_result && res_obj->next_result();
8a37531997-03-06Henrik Grubbström (Grubba)  }
39a78e2015-04-15Henrik Grubbström (Grubba)  return res;
8a37531997-03-06Henrik Grubbström (Grubba) }
fd82ce1997-03-30Henrik Grubbström (Grubba) 
ba65c92001-09-06Martin Nilsson //! Return last error message.
8a37531997-03-06Henrik Grubbström (Grubba) int|string error() {
9436db2009-01-06Stephen R. van den Berg  if (master_sql && functionp (master_sql->error))
37ca012000-03-06Martin Stjernholm  return master_sql->error(); return "Unknown error";
8a37531997-03-06Henrik Grubbström (Grubba) }
506e342013-10-13Arne Goedeke //! Return last SQLSTATE. //! //! The SQLSTATE error codes are specified in ANSI SQL. string sqlstate() { if (master_sql && functionp(master_sql->sqlstate)) { return master_sql->sqlstate(); } return "IM001"; // "driver does not support this function" }
ba65c92001-09-06Martin Nilsson //! Select database to access.
8a37531997-03-06Henrik Grubbström (Grubba) void select_db(string db) { master_sql->select_db(db); }
ba65c92001-09-06Martin Nilsson //! Compiles the query (if possible). Otherwise returns it as is.
a6d6bd2011-03-05Martin Stjernholm //! The resulting object can be used multiple times to the query //! functions.
ba65c92001-09-06Martin Nilsson //! //! @param q
1778472001-01-08Henrik Grubbström (Grubba) //! SQL-query to compile.
a6d6bd2011-03-05Martin Stjernholm //! //! @seealso //! @[query], @[typed_query], @[big_query], @[big_typed_query], //! @[streaming_query], @[streaming_typed_query]
597c1e1997-04-23Henrik Grubbström (Grubba) string|object compile_query(string q) { if (functionp(master_sql->compile_query)) {
0e43482003-07-30Martin Nilsson  return master_sql->compile_query(q);
597c1e1997-04-23Henrik Grubbström (Grubba)  }
0e43482003-07-30Martin Nilsson  return q;
597c1e1997-04-23Henrik Grubbström (Grubba) }
2f1e252011-05-15Martin Stjernholm array(string|mapping(string|int:mixed))
d6beb92012-09-19Martin Stjernholm  handle_extraargs(string query, array(mixed) extraargs) // Compat wrapper. { return .sql_util.handle_extraargs (query, extraargs);
0e434c2000-04-30Francesco Chemolli }
a6d6bd2011-03-05Martin Stjernholm //! Sends an SQL query synchronously to the underlying SQL-server and //! returns the results in untyped mode.
bfca322009-11-06Henrik Grubbström (Grubba) //!
ba65c92001-09-06Martin Nilsson //! @param q //! Query to send to the SQL-server. This can either be a string with the
412eab2009-04-18Henrik Grubbström (Grubba) //! query, or a previously compiled query (see @[compile_query()]).
ba65c92001-09-06Martin Nilsson //! @param extraargs //! This parameter, if specified, can be in two forms: //! //! @ol //! @item //! A mapping containing bindings of variables used in the query. //! A variable is identified by a colon (:) followed by a name or number. //! Each index in the mapping corresponds to one such variable, and the //! value for that index is substituted (quoted) into the query wherever //! the variable is used. //!
e5ef062003-04-01Martin Nilsson //! @code
749ed52006-09-15Martin Stjernholm //! res = query("SELECT foo FROM bar WHERE gazonk=:baz", //! ([":baz":"value"]));
e5ef062003-04-01Martin Nilsson //! @endcode
ba65c92001-09-06Martin Nilsson //! //! Binary values (BLOBs) may need to be placed in multisets. //! //! @item //! Arguments as you would use in sprintf. They are automatically //! quoted. //!
e5ef062003-04-01Martin Nilsson //! @code
749ed52006-09-15Martin Stjernholm //! res = query("select foo from bar where gazonk=%s","value");
e5ef062003-04-01Martin Nilsson //! @endcode
ba65c92001-09-06Martin Nilsson //! @endol
023c532003-10-26Peter Lundqvist //! //! @returns //! Returns one of the following on success: //! @mixed //! @type array(mapping(string:string))
a6d6bd2011-03-05Martin Stjernholm //! The result as an array of mappings indexed on the name of //! the columns. The values are either strings with the display //! representations or zero for the SQL NULL value.
023c532003-10-26Peter Lundqvist //! @type zero //! The value @expr{0@} (zero) if the query didn't return any //! result (eg @tt{INSERT@} or similar). //! @endmixed //! //! @throws //! Throws an exception if the query fails.
420a542005-04-10Martin Nilsson //! //! @seealso
a6d6bd2011-03-05Martin Stjernholm //! @[typed_query], @[big_query], @[streaming_query]
9f98952007-02-27Henrik Grubbström (Grubba) array(mapping(string:string)) query(object|string q, mixed ... extraargs)
8a37531997-03-06Henrik Grubbström (Grubba) {
3b52622003-10-23Martin Nilsson  if (sizeof(extraargs)) {
2bfbf22005-04-10Martin Nilsson  mapping(string|int:mixed) bindings;
3b52622003-10-23Martin Nilsson  if (mappingp(extraargs[0]))
0e434c2000-04-30Francesco Chemolli  bindings=extraargs[0];
3b52622003-10-23Martin Nilsson  else
d6beb92012-09-19Martin Stjernholm  [q,bindings]=.sql_util.handle_extraargs(q,extraargs);
3b52622003-10-23Martin Nilsson 
2bfbf22005-04-10Martin Nilsson  if(bindings) { if(master_sql->query) return master_sql->query(q, bindings); return res_obj_to_array(master_sql->big_query(q, bindings)); }
d8fca41998-06-17Henrik Grubbström (Grubba)  }
3b52622003-10-23Martin Nilsson 
2bfbf22005-04-10Martin Nilsson  if (master_sql->query)
bfca322009-11-06Henrik Grubbström (Grubba)  return master_sql->query(q);
3b52622003-10-23Martin Nilsson  return res_obj_to_array(master_sql->big_query(q));
8a37531997-03-06Henrik Grubbström (Grubba) }
9c89a22011-03-05Martin Stjernholm //! Sends an SQL query synchronously to the underlying SQL-server and //! returns the results in typed mode. //! //! For the arguments, please see the @[query()] function. //! //! @returns //! Returns one of the following on success: //! @mixed //! @type array(mapping(string:mixed)) //! The result as an array of mappings indexed on the name of //! the columns. The values have the appropriate native pike
a6d6bd2011-03-05Martin Stjernholm //! types where they fit the SQL data types - see the class doc //! for details on typed mode.
9c89a22011-03-05Martin Stjernholm //! @type zero //! The value @expr{0@} (zero) if the query didn't return any //! result (eg @tt{INSERT@} or similar). //! @endmixed //!
2753c82011-03-05Martin Stjernholm //! @note //! Typed mode is not supported by all sql databases. If not //! supported, an error is thrown. //!
9c89a22011-03-05Martin Stjernholm //! @seealso //! @[query], @[big_typed_query] array(mapping(string:mixed)) typed_query(object|string q, mixed ... extraargs) { if (!master_sql->big_typed_query)
2753c82011-03-05Martin Stjernholm  ERROR ("Typed mode not supported by the backend %O.\n", master_sql);
9c89a22011-03-05Martin Stjernholm  if (sizeof(extraargs)) { mapping(string|int:mixed) bindings; if (mappingp(extraargs[0])) bindings=extraargs[0]; else
d6beb92012-09-19Martin Stjernholm  [q,bindings]=.sql_util.handle_extraargs(q,extraargs);
9c89a22011-03-05Martin Stjernholm  if(bindings) { if(master_sql->typed_query) return master_sql->typed_query(q, bindings); return res_obj_to_array(master_sql->big_typed_query(q, bindings)); } } if (master_sql->typed_query) return master_sql->typed_query(q); return res_obj_to_array(master_sql->big_typed_query(q)); }
a6d6bd2011-03-05Martin Stjernholm //! Sends an SQL query synchronously to the underlying SQL-server and //! returns the results in untyped mode.
bfca322009-11-06Henrik Grubbström (Grubba) //! //! For the arguments, please see the @[query()] function. //!
a6d6bd2011-03-05Martin Stjernholm //! The result is returned as an @[Sql.sql_result] object in untyped //! mode. This allows for having some more info about the result as //! well as processing the result in a streaming fashion, although the //! result itself wasn't obtained streamingly from the server. Returns //! @expr{0@} if the query didn't return any result (e.g. @tt{INSERT@} //! or similar). //! //! @note //! Despite the name, this function is not only useful for "big" //! queries. It typically has less overhead than @[query] also for //! ones that return only a few rows.
420a542005-04-10Martin Nilsson //! //! @seealso //! @[query], @[streaming_query]
0e434c2000-04-30Francesco Chemolli int|object big_query(object|string q, mixed ... extraargs)
8a37531997-03-06Henrik Grubbström (Grubba) {
bfca322009-11-06Henrik Grubbström (Grubba)  mapping(string|int:mixed) bindings;
2bfbf22005-04-10Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  if (sizeof(extraargs)) {
3b52622003-10-23Martin Nilsson  if (mappingp(extraargs[0]))
bfca322009-11-06Henrik Grubbström (Grubba)  bindings = extraargs[0];
3b52622003-10-23Martin Nilsson  else
d6beb92012-09-19Martin Stjernholm  [q, bindings] = .sql_util.handle_extraargs(q, extraargs);
bfca322009-11-06Henrik Grubbström (Grubba)  }
ff9f5d1998-06-17Henrik Grubbström (Grubba) 
bfca322009-11-06Henrik Grubbström (Grubba)  object|array(mapping) pre_res;
420a542005-04-10Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  if(bindings) { if(master_sql->big_query) pre_res = master_sql->big_query(q, bindings); else pre_res = master_sql->query(q, bindings); } else {
2bfbf22005-04-10Martin Nilsson  if (master_sql->big_query)
ff9f5d1998-06-17Henrik Grubbström (Grubba)  pre_res = master_sql->big_query(q);
2bfbf22005-04-10Martin Nilsson  else pre_res = master_sql->query(q);
3b52622003-10-23Martin Nilsson  }
2bfbf22005-04-10Martin Nilsson  if(pre_res) { if(objectp(pre_res)) return .sql_object_result(pre_res); else return .sql_array_result(pre_res); } return 0;
8a37531997-03-06Henrik Grubbström (Grubba) }
a6d6bd2011-03-05Martin Stjernholm //! Sends an SQL query synchronously to the underlying SQL-server and //! returns the results in typed mode.
bfca322009-11-06Henrik Grubbström (Grubba) //! //! For the arguments, please see the @[query()] function. //!
a6d6bd2011-03-05Martin Stjernholm //! The result is returned as an @[Sql.sql_result] object in typed //! mode. This allows for having some more info about the result as //! well as processing the result in a streaming fashion, although the //! result itself wasn't obtained streamingly from the server. Returns //! @expr{0@} if the query didn't return any result (e.g. @tt{INSERT@} //! or similar).
bfca322009-11-06Henrik Grubbström (Grubba) //! //! @note
2753c82011-03-05Martin Stjernholm //! Typed mode is not supported by all sql databases. If not //! supported, an error is thrown.
bfca322009-11-06Henrik Grubbström (Grubba) //!
a6d6bd2011-03-05Martin Stjernholm //! @note //! Despite the name, this function is not only useful for "big" //! queries. It typically has less overhead than @[typed_query] also //! for ones that return only a few rows.
bfca322009-11-06Henrik Grubbström (Grubba) //! //! @seealso
a6d6bd2011-03-05Martin Stjernholm //! @[query], @[typed_query], @[big_query], @[streaming_query]
bfca322009-11-06Henrik Grubbström (Grubba) int|object big_typed_query(object|string q, mixed ... extraargs) {
2753c82011-03-05Martin Stjernholm  if (!master_sql->big_typed_query) ERROR ("Typed mode not supported by the backend %O.\n", master_sql);
bfca322009-11-06Henrik Grubbström (Grubba)  mapping(string|int:mixed) bindings; if (sizeof(extraargs)) { if (mappingp(extraargs[0])) bindings = extraargs[0]; else
d6beb92012-09-19Martin Stjernholm  [q, bindings] = .sql_util.handle_extraargs(q, extraargs);
bfca322009-11-06Henrik Grubbström (Grubba)  }
3524712015-05-26Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  object|array(mapping) pre_res; if (bindings) { pre_res = master_sql->big_typed_query(q, bindings); } else { pre_res = master_sql->big_typed_query(q); }
a40f4d2009-11-06Henrik Grubbström (Grubba)  if(pre_res) return .sql_object_result(pre_res);
bfca322009-11-06Henrik Grubbström (Grubba)  return 0; }
a6d6bd2011-03-05Martin Stjernholm //! Sends an SQL query synchronously to the underlying SQL-server and //! returns the results streaming in untyped mode. //! //! For the arguments, please see the @[query()] function. //! //! The result is returned as a streaming @[Sql.sql_result] object in //! untyped mode. This allows for having results larger than the //! available memory, and returning some more info about the result. //! Returns @expr{0@} if the query didn't return any result (e.g. //! INSERT or similar). For the other arguments, they are the same as //! for the @[query()] function.
420a542005-04-10Martin Nilsson //!
bfca322009-11-06Henrik Grubbström (Grubba) //! @note //! Streaming operation is not supported by all sql databases. //! If not supported, this function will fall back to calling //! @[big_query()]. //!
420a542005-04-10Martin Nilsson //! @seealso
a6d6bd2011-03-05Martin Stjernholm //! @[big_query], @[streaming_typed_query]
420a542005-04-10Martin Nilsson int|object streaming_query(object|string q, mixed ... extraargs) {
bfca322009-11-06Henrik Grubbström (Grubba)  if(!master_sql->streaming_query) return big_query(q, @extraargs); mapping(string|int:mixed) bindings; if (sizeof(extraargs)) { if(mappingp(extraargs[0])) bindings = extraargs[0]; else
d6beb92012-09-19Martin Stjernholm  [q, bindings] = .sql_util.handle_extraargs(q, extraargs);
bfca322009-11-06Henrik Grubbström (Grubba)  }
420a542005-04-10Martin Nilsson  object pre_res;
bfca322009-11-06Henrik Grubbström (Grubba)  if(bindings) { pre_res = master_sql->streaming_query(q, bindings); } else { pre_res = master_sql->streaming_query(q); }
420a542005-04-10Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  if(pre_res) return .sql_object_result(pre_res); return 0; }
a6d6bd2011-03-05Martin Stjernholm //! Sends an SQL query synchronously to the underlying SQL-server and //! returns the results streaming in typed mode. //! //! For the arguments, please see the @[query()] function. //! //! The result is returned as a streaming @[Sql.sql_result] object in //! typed mode. This allows for having results larger than the //! available memory, and returning some more info about the result. //! Returns @expr{0@} if the query didn't return any result (e.g. //! INSERT or similar).
bfca322009-11-06Henrik Grubbström (Grubba) //! //! @note //! Neither streaming operation nor typed results are supported //! by all sql databases. If not supported, this function will
2753c82011-03-05Martin Stjernholm //! fall back to calling @[big_typed_query()].
bfca322009-11-06Henrik Grubbström (Grubba) //! //! @seealso
a6d6bd2011-03-05Martin Stjernholm //! @[streaming_query], @[big_typed_query]
bfca322009-11-06Henrik Grubbström (Grubba) int|object streaming_typed_query(object|string q, mixed ... extraargs) { if(!master_sql->streaming_typed_query) return big_typed_query(q, @extraargs); mapping(string|int:mixed) bindings;
420a542005-04-10Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  if (sizeof(extraargs)) {
420a542005-04-10Martin Nilsson  if(mappingp(extraargs[0]))
bfca322009-11-06Henrik Grubbström (Grubba)  bindings = extraargs[0];
420a542005-04-10Martin Nilsson  else
d6beb92012-09-19Martin Stjernholm  [q, bindings] = .sql_util.handle_extraargs(q, extraargs);
bfca322009-11-06Henrik Grubbström (Grubba)  }
420a542005-04-10Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  object pre_res;
420a542005-04-10Martin Nilsson 
bfca322009-11-06Henrik Grubbström (Grubba)  if(bindings) { pre_res = master_sql->streaming_typed_query(q, bindings); } else { pre_res = master_sql->streaming_typed_query(q);
420a542005-04-10Martin Nilsson  }
bfca322009-11-06Henrik Grubbström (Grubba)  if(pre_res) return .sql_object_result(pre_res);
420a542005-04-10Martin Nilsson  return 0; }
ba65c92001-09-06Martin Nilsson //! Create a new database. //! //! @param db
1778472001-01-08Henrik Grubbström (Grubba) //! Name of database to create.
8a37531997-03-06Henrik Grubbström (Grubba) void create_db(string db) { master_sql->create_db(db); }
ba65c92001-09-06Martin Nilsson //! Drop database //! //! @param db
1778472001-01-08Henrik Grubbström (Grubba) //! Name of database to drop.
8a37531997-03-06Henrik Grubbström (Grubba) void drop_db(string db) { master_sql->drop_db(db); }
ba65c92001-09-06Martin Nilsson //! Shutdown a database server.
8a37531997-03-06Henrik Grubbström (Grubba) void shutdown() { if (functionp(master_sql->shutdown)) { master_sql->shutdown(); } else {
2bfbf22005-04-10Martin Nilsson  ERROR("Not supported by this database.\n");
8a37531997-03-06Henrik Grubbström (Grubba)  } }
ba65c92001-09-06Martin Nilsson //! Reload the tables.
8a37531997-03-06Henrik Grubbström (Grubba) void reload() { if (functionp(master_sql->reload)) { master_sql->reload(); } else {
2bfbf22005-04-10Martin Nilsson  // Probably safe to make this a NOOP
8a37531997-03-06Henrik Grubbström (Grubba)  } }
ba65c92001-09-06Martin Nilsson //! Return info about the current SQL-server.
8a37531997-03-06Henrik Grubbström (Grubba) string server_info() { if (functionp(master_sql->server_info)) {
0e43482003-07-30Martin Nilsson  return master_sql->server_info() ;
8a37531997-03-06Henrik Grubbström (Grubba)  }
0e43482003-07-30Martin Nilsson  return "Unknown SQL-server";
8a37531997-03-06Henrik Grubbström (Grubba) }
ba65c92001-09-06Martin Nilsson //! Return info about the connection to the SQL-server.
8a37531997-03-06Henrik Grubbström (Grubba) string host_info() { if (functionp(master_sql->host_info)) {
0e43482003-07-30Martin Nilsson  return master_sql->host_info();
3524712015-05-26Martin Nilsson  }
0e43482003-07-30Martin Nilsson  return "Unknown connection to host";
8a37531997-03-06Henrik Grubbström (Grubba) }
ba65c92001-09-06Martin Nilsson //! List available databases on this SQL-server. //! //! @param wild
1778472001-01-08Henrik Grubbström (Grubba) //! Optional wildcard to match against.
8a37531997-03-06Henrik Grubbström (Grubba) array(string) list_dbs(string|void wild) { array(string)|array(mapping(string:mixed))|object res;
3524712015-05-26Martin Nilsson 
8a37531997-03-06Henrik Grubbström (Grubba)  if (functionp(master_sql->list_dbs)) { if (objectp(res = master_sql->list_dbs())) { res = res_obj_to_array(res); } } else {
0715472001-10-03Henrik Grubbström (Grubba)  catch { res = query("show databases"); };
8a37531997-03-06Henrik Grubbström (Grubba)  }
0715472001-10-03Henrik Grubbström (Grubba)  if (res && sizeof(res) && mappingp(res[0])) {
2bfbf22005-04-10Martin Nilsson  res = map(res, lambda (mapping m) { return values(m)[0]; // Hope that there's only one field } );
8a37531997-03-06Henrik Grubbström (Grubba)  }
0715472001-10-03Henrik Grubbström (Grubba)  if (res && wild) {
1778472001-01-08Henrik Grubbström (Grubba)  res = filter(res,
0efb432001-01-08Martin Stjernholm  Regexp(replace(wild, ({"%", "_"}), ({".*", "."})))->match);
8a37531997-03-06Henrik Grubbström (Grubba)  }
0e43482003-07-30Martin Nilsson  return res;
8a37531997-03-06Henrik Grubbström (Grubba) }
ba65c92001-09-06Martin Nilsson //! List tables available in the current database. //! //! @param wild
1778472001-01-08Henrik Grubbström (Grubba) //! Optional wildcard to match against.
8a37531997-03-06Henrik Grubbström (Grubba) array(string) list_tables(string|void wild) { array(string)|array(mapping(string:mixed))|object res;
3524712015-05-26Martin Nilsson 
8a37531997-03-06Henrik Grubbström (Grubba)  if (functionp(master_sql->list_tables)) { if (objectp(res = master_sql->list_tables())) { res = res_obj_to_array(res); } } else {
0715472001-10-03Henrik Grubbström (Grubba)  catch { res = query("show tables"); };
8a37531997-03-06Henrik Grubbström (Grubba)  }
0715472001-10-03Henrik Grubbström (Grubba)  if (res && sizeof(res) && mappingp(res[0])) {
5ad14e2015-04-14Henrik Grubbström (Grubba)  string col_name = indices(res[0])[0]; if (sizeof(res[0]) > 1) { if (!zero_type(res[0]["TABLE_NAME"])) { // MSSQL. col_name = "TABLE_NAME"; } } res = map(res, lambda (mapping m, string col_name) { return m[col_name]; }, col_name);
8a37531997-03-06Henrik Grubbström (Grubba)  }
0715472001-10-03Henrik Grubbström (Grubba)  if (res && wild) {
1778472001-01-08Henrik Grubbström (Grubba)  res = filter(res,
0efb432001-01-08Martin Stjernholm  Regexp(replace(wild, ({"%", "_"}), ({".*", "."})))->match);
8a37531997-03-06Henrik Grubbström (Grubba)  }
0e43482003-07-30Martin Nilsson  return res;
8a37531997-03-06Henrik Grubbström (Grubba) }
ba65c92001-09-06Martin Nilsson //! List fields available in the specified table //! //! @param table
1778472001-01-08Henrik Grubbström (Grubba) //! Table to list the fields of.
ba65c92001-09-06Martin Nilsson //! //! @param wild
1778472001-01-08Henrik Grubbström (Grubba) //! Optional wildcard to match against.
8a37531997-03-06Henrik Grubbström (Grubba) array(mapping(string:mixed)) list_fields(string table, string|void wild) { array(mapping(string:mixed))|object res; if (functionp(master_sql->list_fields)) { if (objectp(res = master_sql->list_fields(table))) { res = res_obj_to_array(res); } if (wild) {
124cc22002-06-17H. William Welliver III  res = filter(res, lambda(mapping row, function(string:int) match) { return match(row->name); },
1778472001-01-08Henrik Grubbström (Grubba)  Regexp(replace(wild, ({"%", "_"}), ({".*", "."})))->match);
8a37531997-03-06Henrik Grubbström (Grubba)  }
0e43482003-07-30Martin Nilsson  return res;
8a37531997-03-06Henrik Grubbström (Grubba)  }
0715472001-10-03Henrik Grubbström (Grubba)  catch { if (wild) { res = query("show fields from \'" + table + "\' like \'" + wild + "\'"); } else { res = query("show fields from \'" + table + "\'"); } };
981f832005-04-10Martin Nilsson  res = res && map(res, lambda (mapping m, string table) {
8a37531997-03-06Henrik Grubbström (Grubba)  foreach(indices(m), string str) {
2bfbf22005-04-10Martin Nilsson  // Add the lower case variants
8a37531997-03-06Henrik Grubbström (Grubba)  string low_str = lower_case(str);
981f832005-04-10Martin Nilsson  if (low_str != str && !m[low_str]) m[low_str] = m_delete(m, str);
8a37531997-03-06Henrik Grubbström (Grubba)  }
981f832005-04-10Martin Nilsson  if ((!m->name) && m->field) m["name"] = m_delete(m, "field"); if (!m->table)
8a37531997-03-06Henrik Grubbström (Grubba)  m["table"] = table;
981f832005-04-10Martin Nilsson 
0e43482003-07-30Martin Nilsson  return m;
8a37531997-03-06Henrik Grubbström (Grubba)  }, table);
0e43482003-07-30Martin Nilsson  return res;
8a37531997-03-06Henrik Grubbström (Grubba) }