f4866c1999-12-08Martin Nilsson // This is a roxen module. Copyright © 1997-1999, Idonex AB. //
e6a1712000-02-02Per Hedbor // A module for Roxen, which gives the tags
f4866c1999-12-08Martin Nilsson // <sqltable>, <sqlquery> and <sqloutput>. // // Henrik Grubbström 1997-01-12
78c9971997-02-20Henrik Grubbström (Grubba) 
5e2d652000-02-20Kenneth Johansson constant cvs_version="$Id: sqltag.pike,v 1.45 2000/02/20 22:46:05 kuntri Exp $";
07bf511997-08-31Peter Bortas constant thread_safe=1;
78c9971997-02-20Henrik Grubbström (Grubba) #include <module.h>
7a7c651999-11-05Martin Nilsson // Compatibility with old versions of the sqltag module.
f5effc1997-10-15Henrik Grubbström (Grubba) // #define SQL_TAG_COMPAT
78c9971997-02-20Henrik Grubbström (Grubba) inherit "module"; inherit "roxenlib";
f4866c1999-12-08Martin Nilsson Configuration conf;
a03ea41998-09-29Johan Schön 
7a7c651999-11-05Martin Nilsson // Module interface functions
78c9971997-02-20Henrik Grubbström (Grubba) 
9424ab2000-02-05Martin Nilsson constant module_type=MODULE_PARSER|MODULE_PROVIDER; constant module_name="SQL tag module"; constant module_desc="This module gives the three tags &lt;SQLQUERY&gt;, " "&lt;SQLOUTPUT&gt;, and &lt;SQLTABLE&gt;.<br>\n";
f4866c1999-12-08Martin Nilsson  TAGDOCUMENTATION #ifdef manual
5e2d652000-02-20Kenneth Johansson constant tagdoc=([ "sqltable":" <desc tag> Creates an HTML or ASCII table from the results of an SQL query. </desc> <attr name=ascii> Create an ASCII table rather than a HTML table. Useful for interacting with the <ref type=tag>diagram</ref> and <ref type=tag>tablify</ref> tags. </attr> <attr name=host type=database> Which database to connect to, usually a symbolic name. If omitted the default database will be used. </attr> <attr name=query> The actual SQL-query. </attr> <attr name=quiet> Do not show any errors in the page, in case the query fails. </attr> <attribute name=parse> If specified, the query will be parsed by the RXML parser. Useful if you wish to dynamically build the query. </attribute>", "sqlquery":" <desc tag> Executes an SQL query, but doesn't do anything with the result. This is mostly used for SQL queries that change the contents of the database, for example INSERT or UPDATE. </desc> <attr name=host type=database> Which database to connect to, usually a symbolic name. If omitted the default database will be used. </attr> <attr name=query type=SQL query> The actual SQL-query. </attr> <attr name=quiet> Do not show any errors in the page, in case the query fails. </attr> <attr name=parse> If specified, the query will be parsed by the RXML parser. Useful if you wish to dynamically build the query. </attr>"]);
f4866c1999-12-08Martin Nilsson /*
5e2d652000-02-20Kenneth Johansson 
f5effc1997-10-15Henrik Grubbström (Grubba)  "<tr><td valign=top><b>&lt;sqlquery&gt;</b></td>\n"
bc53801999-09-28Martin Stjernholm  "<td>Executes an SQL query, but "
f5effc1997-10-15Henrik Grubbström (Grubba)  "doesn't do anything with the result. This is useful if " "you do queries like INSERT and CREATE.</td></tr>\n" "<tr><td valign=top><b>&lt;sqltable&gt;</td>"
bc53801999-09-28Martin Stjernholm  "<td>Executes an SQL query, and makes " "an HTML table from the result.</td></tr>\n"
f5effc1997-10-15Henrik Grubbström (Grubba)  "</table></ul>\n" "The following attributes are used by the above tags:<ul>\n" "<table border=0>\n" "<tr><td valign=top><b>query</b></td>"
bc53801999-09-28Martin Stjernholm  "<td>The actual SQL query. (<b>REQUIRED</b>)</td></tr>\n"
f5effc1997-10-15Henrik Grubbström (Grubba)  "<tr><td valign=top><b>host<b></td>"
bc53801999-09-28Martin Stjernholm  "<td>The hostname of the machine the SQL server runs on.<br>\n" "This argument can also be used to specify which SQL server " "to use by specifying an \"SQL URL\":<br><ul>\n"
f5effc1997-10-15Henrik Grubbström (Grubba)  "<pre>[<i>sqlserver</i>://][[<i>user</i>][:<i>password</i>]@]" "[<i>host</i>[:<i>port</i>]]/<i>database</i></pre><br>\n" "</ul>Valid values for \"sqlserver\" depend on which "
bc53801999-09-28Martin Stjernholm  "SQL servers your pike has support for, but the following "
f5effc1997-10-15Henrik Grubbström (Grubba)  "might exist: msql, mysql, odbc, oracle, postgres.</td></tr>\n" "<tr><td valign=top><b>database</b></td>" "<td>The name of the database to use.</td></tr>\n" "<tr><td valign=top><b>user</b></td>" "<td>The name of the user to access the database with.</td></tr>\n" "<tr><td valign=top><b>password</b></td>" "<td>The password to access the database.</td></tr>\n"
961fd31997-11-29Henrik Grubbström (Grubba)  "<tr><td valign=top><b>parse</b></td>" "<td>If specified, the query will be parsed by the "
bc53801999-09-28Martin Stjernholm  "RXML parser</td></tr>\n"
2ca4ca1998-02-10Henrik Grubbström (Grubba)  "<tr><td valign=top><b>quiet</b></td>"
bc53801999-09-28Martin Stjernholm  "<td>If specified, SQL errors will be kept quiet.</td></tr>\n"
f5effc1997-10-15Henrik Grubbström (Grubba)  "</table></ul><p>\n" "The &lt;sqltable&gt; tag has an additional attribute "
bc53801999-09-28Martin Stjernholm  "<b>ascii</b>, which generates a tab separated table (usefull "
655b721997-10-15Henrik Grubbström (Grubba)  "with eg the &lt;diagram&gt; tag).<p>\n"
f5effc1997-10-15Henrik Grubbström (Grubba)  "\n" "<b>NOTE</b>: Specifying passwords in the documents may prove " "to be a security hole if the module is not loaded for some "
961fd31997-11-29Henrik Grubbström (Grubba)  "reason.<br>\n" "<b>SEE ALSO</b>: The &lt;FORMOUTPUT&gt; tag can be "
f4866c1999-12-08Martin Nilsson  "useful to generate the queries.<br>\n" */ #endif
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson array|string|object do_sql_query(string tag, mapping args, RequestID id)
78c9971997-02-20Henrik Grubbström (Grubba) {
7a7c651999-11-05Martin Nilsson  if (!args->query) return rxml_error(tag, "No query.", id);
3f094d1998-08-10Per Hedbor 
7a7c651999-11-05Martin Nilsson  if (args->parse) args->query = parse_rxml(args->query, id);
961fd31997-11-29Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  string host = query("hostname");
9424ab2000-02-05Martin Nilsson  Sql.sql con;
7a7c651999-11-05Martin Nilsson  array(mapping(string:mixed)) result; function sql_connect = id->conf->sql_connect; mixed error;
961fd31997-11-29Henrik Grubbström (Grubba) 
f5effc1997-10-15Henrik Grubbström (Grubba) #ifdef SQL_TAG_COMPAT
7a7c651999-11-05Martin Nilsson  string database = query("database"); string user = query("user"); string password = query("password"); if (args->host) { host = args->host; user = ""; password = ""; } if (args->database) { database = args->database; user = ""; password = ""; sql_connect = 0; } if (args->user) { user = args->user; sql_connect = 0; } if (args->password) { password = args->password; sql_connect = 0;
78c9971997-02-20Henrik Grubbström (Grubba)  }
961fd31997-11-29Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if (sql_connect) error = catch(con = sql_connect(host)); else { host = (lower_case(host) == "localhost")?"":host;
9424ab2000-02-05Martin Nilsson  error = catch(con = Sql.sql(host, database, user, password));
7a7c651999-11-05Martin Nilsson  } #else if (args->host) host=args->host; if(sql_connect) error = catch(con = sql_connect(host)); else
9424ab2000-02-05Martin Nilsson  error = catch(con = Sql.sql(lower_case(host)=="localhost"?"":host));
7a7c651999-11-05Martin Nilsson #endif if (error) { if (!args->quiet) { if (args->log_error && QUERY(log_error)) { report_error(sprintf("SQLTAG: Couldn't connect to SQL server:\n" "%s\n", describe_backtrace(error))); } return "<h3>Couldn't connect to SQL server</h3><br>\n" + html_encode_string(error[0]) + "<false>";
961fd31997-11-29Henrik Grubbström (Grubba)  }
7a7c651999-11-05Martin Nilsson  return rxml_error(tag, "Couldn't connect to SQL server. "+html_encode_string(error[0]), id); }
961fd31997-11-29Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if (error = catch(result = tag=="sqltable"?con->big_query(args->query):con->query(args->query))) {
f8a75a1999-11-23Henrik Grubbström (Grubba)  error = html_encode_string(sprintf("Query %O failed. %s", args->query, con->error()||""));
7a7c651999-11-05Martin Nilsson  if (!args->quiet) { if (args->log_error && QUERY(log_error)) { report_error(sprintf("SQLTAG: Query %O failed:\n" "%s\n", args->query, describe_backtrace(error)));
2ca4ca1998-02-10Henrik Grubbström (Grubba)  }
7a7c651999-11-05Martin Nilsson  return "<h3>"+error+"</h3>\n<false>";
78c9971997-02-20Henrik Grubbström (Grubba)  }
7a7c651999-11-05Martin Nilsson  return rxml_error(tag, error, id);
78c9971997-02-20Henrik Grubbström (Grubba)  }
7a7c651999-11-05Martin Nilsson  if(tag=="sqlquery") args["dbobj"]=con; return result;
78c9971997-02-20Henrik Grubbström (Grubba) }
c7f4e51997-10-15Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson // -------------------------------- Tag handlers ------------------------------------
3f094d1998-08-10Per Hedbor 
7a7c651999-11-05Martin Nilsson array|string container_sqloutput(string tag, mapping args, string contents, RequestID id) { NOCACHE();
3f094d1998-08-10Per Hedbor 
7a7c651999-11-05Martin Nilsson  string|array res=do_sql_query(tag, args, id); if(stringp(res)) return res;
3f094d1998-08-10Per Hedbor 
7a7c651999-11-05Martin Nilsson  if (res && sizeof(res)) { array ret = ({ do_output_tag(args, res, contents, id) }); id->misc->defines[" _ok"] = 1; // The effect of <true>, since res isn't parsed.
c7f4e51997-10-15Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if( args["rowinfo"] ) id->variables[args->rowinfo]=sizeof(res);
961fd31997-11-29Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  return ret; }
961fd31997-11-29Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if (args["do-once"]) return do_output_tag( args, ({([])}), contents, id )+ "<true>";
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  return rxml_error(tag, "No SQL return values.", id); }
78c9971997-02-20Henrik Grubbström (Grubba) 
9424ab2000-02-05Martin Nilsson class TagSqlplugin { inherit RXML.Tag; constant name = "emit"; constant plugin_name = "sql"; array get_dataset(mapping m, RequestID id) { array|string res=do_sql_query("sqloutput", m, id); if(stringp(res)) { // rxml_error(res); return ({}); } if(m->rowinfo) id->variables[m->rowinfo] = sizeof(res); return res; } }
7a7c651999-11-05Martin Nilsson string tag_sqlquery(string tag, mapping args, RequestID id) { NOCACHE();
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  string|array res=do_sql_query(tag, args, id); if(stringp(res)) return res;
07245f1997-09-28Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if(args["mysql-insert-id"]) if(args->dbobj && args->dbobj->master_sql) id->variables[args["mysql-insert-id"]] = args->dbobj->master_sql->insert_id(); else return rxml_error(tag, "No insert_id present.", id);
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  return "<true>";
78c9971997-02-20Henrik Grubbström (Grubba) }
7a7c651999-11-05Martin Nilsson string tag_sqltable(string tag, mapping args, RequestID id)
07245f1997-09-28Henrik Grubbström (Grubba) {
7a7c651999-11-05Martin Nilsson  NOCACHE();
07245f1997-09-28Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  string|object res=do_sql_query(tag, args, id); if(stringp(res)) return res;
0d90ed1998-01-17Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  int ascii=!!args->ascii; string ret="";
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if (res) { string nullvalue=args->nullvalue||""; array(mixed) row;
0d90ed1998-01-17Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if (!ascii) { ret="<tr>"; foreach(map(res->fetch_fields(), lambda (mapping m) { return m->name; } ), string name) ret += "<th>"+name+"</th>"; ret += "</tr>\n"; }
2a9ddf1998-07-15Johan Schön 
7a7c651999-11-05Martin Nilsson  if( args["rowinfo"] ) id->variables[args->rowinfo]=res->num_rows(); while(arrayp(row=res->fetch_row())) { if (ascii) ret += row * "\t" + "\n"; else { ret += "<tr>"; foreach(row, mixed value) ret += "<td>"+(value==""?nullvalue:value)+"</td>"; ret += "</tr>\n"; } }
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  if (!ascii) ret=make_container("table", args-(["host":"", "database":"", "user":"", "password":"", "query":"", "nullvalue":""]), ret);
78c9971997-02-20Henrik Grubbström (Grubba) 
7a7c651999-11-05Martin Nilsson  return ret+"<true>"; } return rxml_error(tag, "No SQL return values.", id);
78c9971997-02-20Henrik Grubbström (Grubba) }
2a9ddf1998-07-15Johan Schön 
7a7c651999-11-05Martin Nilsson // ------------------- Callback functions -------------------------
2a9ddf1998-07-15Johan Schön 
9424ab2000-02-05Martin Nilsson Sql.sql sql_object(void|string host)
2a9ddf1998-07-15Johan Schön {
a03ea41998-09-29Johan Schön  string host = stringp(host)?host:query("hostname");
9424ab2000-02-05Martin Nilsson  Sql.sql con;
a03ea41998-09-29Johan Schön  function sql_connect = conf->sql_connect;
2a9ddf1998-07-15Johan Schön  mixed error;
a788ad2000-01-11Martin Stjernholm  /* Is this really a good idea? /mast
2a9ddf1998-07-15Johan Schön  error = catch(con = sql_connect(host)); if(error) return 0; return con;
a788ad2000-01-11Martin Stjernholm  */ return sql_connect(host);
2a9ddf1998-07-15Johan Schön } string query_provides() { return "sql"; }
7a7c651999-11-05Martin Nilsson  // ------------------------ Setting the defaults -------------------------
78c9971997-02-20Henrik Grubbström (Grubba)  void create() {
bc53801999-09-28Martin Stjernholm  defvar("hostname", "localhost", "Default SQL database host", TYPE_STRING, "Specifies the default host to use for SQL queries.\n" "This argument can also be used to specify which SQL server to " "use by specifying an \"SQL URL\":<ul>\n"
47d81d1997-09-05Henrik Grubbström (Grubba)  "<pre>[<i>sqlserver</i>://][[<i>user</i>][:<i>password</i>]@]" "[<i>host</i>[:<i>port</i>]]/<i>database</i></pre></ul><br>\n"
a2533f1997-09-23Henrik Grubbström (Grubba)  "Valid values for \"sqlserver\" depend on which "
bc53801999-09-28Martin Stjernholm  "SQL servers your pike has support for, but the following "
47d81d1997-09-05Henrik Grubbström (Grubba)  "might exist: msql, mysql, odbc, oracle, postgres.\n");
7763b41998-07-23Henrik Grubbström (Grubba) 
a788ad2000-01-11Martin Stjernholm  defvar("log_error", 0, "Log errors to the event log", TYPE_FLAG, "Enable this to log database connection and SQL " "errors to the event log.\n");
7763b41998-07-23Henrik Grubbström (Grubba) 
f5effc1997-10-15Henrik Grubbström (Grubba) #ifdef SQL_TAG_COMPAT
bc53801999-09-28Martin Stjernholm  defvar("database", "", "Default SQL database (deprecated)",
a788ad2000-01-11Martin Stjernholm  TYPE_STRING,
bc53801999-09-28Martin Stjernholm  "Specifies the name of the default SQL database.\n");
c7f4e51997-10-15Henrik Grubbström (Grubba)  defvar("user", "", "Default username (deprecated)",
a788ad2000-01-11Martin Stjernholm  TYPE_STRING,
c7f4e51997-10-15Henrik Grubbström (Grubba)  "Specifies the default username to use for access.\n"); defvar("password", "", "Default password (deprecated)",
a788ad2000-01-11Martin Stjernholm  TYPE_STRING,
c7f4e51997-10-15Henrik Grubbström (Grubba)  "Specifies the default password to use for access.\n");
7a7c651999-11-05Martin Nilsson #endif // SQL_TAG_COMPAT
78c9971997-02-20Henrik Grubbström (Grubba) }
7a7c651999-11-05Martin Nilsson // --------------------- More interface functions --------------------------
12ac991997-11-26Henrik Grubbström (Grubba)  void start(int level, object _conf)
78c9971997-02-20Henrik Grubbström (Grubba) {
12ac991997-11-26Henrik Grubbström (Grubba)  if (_conf) { conf = _conf; }
2a9ddf1998-07-15Johan Schön //add_api_function("sql_query", api_sql_query, ({ "string", 0,"int" }));
78c9971997-02-20Henrik Grubbström (Grubba) } void stop() { } string status() {
a788ad2000-01-11Martin Stjernholm  if (mixed err = catch {
12ac991997-11-26Henrik Grubbström (Grubba)  object o;
7a7c651999-11-05Martin Nilsson  if (conf->sql_connect)
12ac991997-11-26Henrik Grubbström (Grubba)  o = conf->sql_connect(QUERY(hostname));
7a7c651999-11-05Martin Nilsson  else
12ac991997-11-26Henrik Grubbström (Grubba)  o = Sql.sql(QUERY(hostname)
c7f4e51997-10-15Henrik Grubbström (Grubba) #ifdef SQL_TAG_COMPAT
12ac991997-11-26Henrik Grubbström (Grubba)  , QUERY(database), QUERY(user), QUERY(password)
7a7c651999-11-05Martin Nilsson #endif // SQL_TAG_COMPAT
a788ad2000-01-11Martin Stjernholm  );
bc53801999-09-28Martin Stjernholm  return(sprintf("Connected to %s server on %s<br>\n",
fa40051997-06-20Henrik Grubbström (Grubba)  o->server_info(), o->host_info()));
7a7c651999-11-05Martin Nilsson  })
a788ad2000-01-11Martin Stjernholm  return "<font color=red>Not connected:</font> " + replace (html_encode_string (describe_error(err)), "\n", "<br>\n") + "<br>\n";
78c9971997-02-20Henrik Grubbström (Grubba) }