* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres.php,v 1.257 2005/03/18 19:51:57 xzilla Exp $
+ * $Id: Postgres.php,v 1.258 2005/03/26 10:47:03 chriskl Exp $
*/
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
* based on the REL7_4_STABLE src/bin/psql/mainloop.c lexer in\r
* the PostgreSQL source code.\r
* XXX: It does not handle multibyte languages properly.\r
- * @param $name Entry in $_FILES to use\r
- * @return Result of final query, false on any failure.\r
+ * @param $name Entry in $_FILES to use
+ * @param $callback (optional) Callback function to call with each query,
+ its result and line number.\r
+ * @return True for general success, false on any failure.\r
*/\r
- function executeScript($name) {\r
+ function executeScript($name, $callback = null) {\r
global $data;\r
\r
// This whole function isn't very encapsulated, but hey...\r
$len = 0;\r
$i = 0;\r
$prevlen = 0;\r
- $thislen = 0;\r
+ $thislen = 0;
+ $lineno = 0;\r
\r
// Loop over each line in the file\r
while (!feof($fd)) {\r
- $line = fgets($fd, 32768);\r
+ $line = fgets($fd, 32768);
+ $lineno++;\r
\r
// Nothing left on line? Then ignore...\r
if (trim($line) == '') continue;\r
\r
/* start of extended comment? */\r
else if (substr($line, $i, 2) == '/*')\r
- {\r
+ {
$in_xcomment++;\r
if ($in_xcomment == 1)\r
$this->advance_1($i, $prevlen, $thislen);\r
\r
/* in or end of extended comment? */\r
else if ($in_xcomment)\r
- {\r
+ {
if (substr($line, $i, 2) == '*/' && !--$in_xcomment)\r
$this->advance_1($i, $prevlen, $thislen);\r
}\r
\r
/* start of quote? */\r
- else if (substr($line, $i, 1) == '\'' || substr($line, $i, 1) == '"') {\r
+ else if (substr($line, $i, 1) == '\'' || substr($line, $i, 1) == '"') {
$in_quote = substr($line, $i, 1);\r
}\r
\r
\r
/* single-line comment? truncate line */\r
else if (substr($line, $i, 2) == '--')\r
- {\r
+ {
$line = substr($line, 0, $i); /* remove comment */\r
break;\r
} \r
\r
/* count nested parentheses */\r
- else if (substr($line, $i, 1) == '(') {\r
+ else if (substr($line, $i, 1) == '(') {
$paren_level++;\r
}\r
\r
- else if (substr($line, $i, 1) == ')' && $paren_level > 0) {\r
+ else if (substr($line, $i, 1) == ')' && $paren_level > 0) {
$paren_level--;\r
}\r
\r
/* semicolon? then send query */\r
else if (substr($line, $i, 1) == ';' && !$bslash_count && !$paren_level)\r
- {\r
+ {
$subline = substr(substr($line, 0, $i), $query_start);\r
/* is there anything else on the line? */\r
if (strspn($subline, " \t\n\r") != strlen($subline))\r
\r
// Execute the query (supporting 4.1.x PHP...). PHP cannot execute\r
// empty queries, unlike libpq
- if (function_exists('pg_query'))\r
- $res = pg_query($conn, $query_buf);\r
+ if (function_exists('pg_query'))
+ $res = @pg_query($conn, $query_buf);
else\r
- $res = pg_exec($conn, $query_buf); \r
+ $res = @pg_exec($conn, $query_buf); \r
+ // Call the callback function for display
+ if ($callback !== null) $callback($query_buf, $res, $lineno);\r
// Check for COPY request\r
if (pg_result_status($res) == 4) { // 4 == PGSQL_COPY_FROM\r
while (!feof($fd)) {\r
- $copy = fgets($fd, 32768);\r
+ $copy = fgets($fd, 32768);
+ $lineno++;\r
pg_put_line($conn, $copy);\r
if ($copy == "\\.\n" || $copy == "\\.\r\n") {\r
pg_end_copy($conn);\r
// XXX: multibyte here\r
else if (ereg('^[_[:alpha:]]$', substr($line, $i, 1))) {
$sub = substr($line, $i, $thislen);
- while (ereg('^[\$_[:alnum:]]$', $sub)) {
+ while (ereg('^[\$_A-Za-z0-9]$', $sub)) {
/* keep going while we still have identifier chars */\r
$this->advance_1($i, $prevlen, $thislen);\r
$sub = substr($line, $i, $thislen);
}
+ // Since we're now over the next character to be examined, it is necessary
+ // to move back one space.
+ $i-=$prevlen;
}\r
} // end for\r
\r
{\r
// Execute the query (supporting 4.1.x PHP...)\r
if (function_exists('pg_query'))\r
- $res = pg_query($conn, $query_buf);\r
+ $res = @pg_query($conn, $query_buf);\r
else\r
- $res = pg_exec($conn, $query_buf);\r
+ $res = @pg_exec($conn, $query_buf);
+ // Call the callback function for display
+ if ($callback !== null) $callback($query_buf, $res, $lineno);\r
// Check for COPY request\r
if (pg_result_status($res) == 4) { // 4 == PGSQL_COPY_FROM\r
while (!feof($fd)) {\r
- $copy = fgets($fd, 32768);\r
+ $copy = fgets($fd, 32768);
+ $lineno++;\r
pg_put_line($conn, $copy);\r
if ($copy == "\\.\n" || $copy == "\\.\r\n") {\r
pg_end_copy($conn);\r
\r
fclose($fd);\r
\r
- return new ADORecordSet_empty();\r
+ return true;\r
}
// Capabilities
* how many SQL statements have been strung together with semi-colons
* @param $query The SQL query string to execute
*
- * $Id: sql.php,v 1.29 2005/03/04 08:53:56 chriskl Exp $
+ * $Id: sql.php,v 1.30 2005/03/26 10:47:03 chriskl Exp $
*/
// Prevent timeouts on large exports (non-safe mode only)
// Include application functions
include_once('./libraries/lib.inc.php');
+ /**
+ * This is a callback function to display the result of each separate query
+ * @param ADORecordSet $rs The recordset returned by the script execetor
+ */
+ function sqlCallback($query, $rs, $lineno) {
+ global $data, $misc, $lang, $_connection;
+ // Check if $rs is false, if so then there was a fatal error
+ if ($rs === false) {
+ echo htmlspecialchars($_FILES['script']['name']), ':', $lineno, ': ', nl2br(htmlspecialchars($_connection->getLastError())), "<br/>\n";
+ }
+ else {
+ // Print query results
+ switch (pg_result_status($rs)) {
+ case PGSQL_TUPLES_OK:
+ // If rows returned, then display the results
+ $num_fields = pg_numfields($rs);
+ echo "<p><table>\n<tr>";
+ for ($k = 0; $k < $num_fields; $k++) {
+ echo "<th class=\"data\">", $misc->printVal(pg_fieldname($rs, $k)), "</th>";
+ }
+
+ $i = 0;
+ $row = pg_fetch_row($rs);
+ while ($row !== false) {
+ $id = (($i % 2) == 0 ? '1' : '2');
+ echo "<tr>\n";
+ foreach ($row as $k => $v) {
+ echo "<td class=\"data{$id}\" nowrap=\"nowrap\">", $misc->printVal($v, pg_fieldtype($rs, $k), array('null' => true)), "</td>";
+ }
+ echo "</tr>\n";
+ $row = pg_fetch_row($rs);
+ $i++;
+ };
+ echo "</table><br/>\n";
+ echo $i, " {$lang['strrows']}</p>\n";
+ break;
+ case PGSQL_COMMAND_OK:
+ // If we have the command completion tag
+ if (version_compare(phpversion(), '4.3', '>=')) {
+ echo htmlspecialchars(pg_result_status($rs, PGSQL_STATUS_STRING)), "<br/>\n";
+ }
+ // Otherwise if any rows have been affected
+ elseif ($data->conn->Affected_Rows() > 0) {
+ echo $data->conn->Affected_Rows(), " {$lang['strrowsaff']}<br/>\n";
+ }
+ // Otherwise output nothing...
+ break;
+ case PGSQL_EMPTY_QUERY:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
// Determine explain version of SQL
if ($data->hasFullExplain() && isset($_POST['explain']) && isset($_POST['query'])) {
$_POST['query'] = $data->getExplainSQL($_POST['query'], false);
}
}
- // Set fetch mode to NUM so that duplicate field names are properly returned
- $data->conn->setFetchMode(ADODB_FETCH_NUM);
-
// May as well try to time the query
if (function_exists('microtime')) {
list($usec, $sec) = explode(' ', microtime());
$start_time = ((float)$usec + (float)$sec);
}
else $start_time = null;
-
// Execute the query. If it's a script upload, special handling is necessary
if (isset($_FILES['script']) && $_FILES['script']['size'] > 0)
- $rs = $data->executeScript('script');
- else
+ $data->executeScript('script', 'sqlCallback');
+ else {
+ // Set fetch mode to NUM so that duplicate field names are properly returned
+ $data->conn->setFetchMode(ADODB_FETCH_NUM);
$rs = $data->conn->Execute($_POST['query']);
+ // $rs will only be an object if there is no error
+ if (is_object($rs)) {
+ // Now, depending on what happened do various things
+
+ // First, if rows returned, then display the results
+ if ($rs->recordCount() > 0) {
+ echo "<table>\n<tr>";
+ foreach ($rs->f as $k => $v) {
+ $finfo = $rs->fetchField($k);
+ echo "<th class=\"data\">", $misc->printVal($finfo->name), "</th>";
+ }
+
+ $i = 0;
+ while (!$rs->EOF) {
+ $id = (($i % 2) == 0 ? '1' : '2');
+ echo "<tr>\n";
+ foreach ($rs->f as $k => $v) {
+ $finfo = $rs->fetchField($k);
+ echo "<td class=\"data{$id}\" nowrap=\"nowrap\">", $misc->printVal($v, $finfo->type, array('null' => true)), "</td>";
+ }
+ echo "</tr>\n";
+ $rs->moveNext();
+ $i++;
+ }
+ echo "</table>\n";
+ echo "<p>", $rs->recordCount(), " {$lang['strrows']}</p>\n";
+ }
+ // Otherwise if any rows have been affected
+ elseif ($data->conn->Affected_Rows() > 0) {
+ echo "<p>", $data->conn->Affected_Rows(), " {$lang['strrowsaff']}</p>\n";
+ }
+ // Otherwise output nothing...
+ }
+ }
+
// May as well try to time the query
if ($start_time !== null) {
list($usec, $sec) = explode(' ', microtime());
// Reload the browser as we may have made schema changes
$_reload_browser = true;
- // $rs will only be an object if there is no error
- if (is_object($rs)) {
- // Now, depending on what happened do various things
-
- // First, if rows returned, then display the results
- if ($rs->recordCount() > 0) {
- echo "<table>\n<tr>";
- foreach ($rs->f as $k => $v) {
- $finfo = $rs->fetchField($k);
- echo "<th class=\"data\">", $misc->printVal($finfo->name), "</th>";
- }
-
- $i = 0;
- while (!$rs->EOF) {
- $id = (($i % 2) == 0 ? '1' : '2');
- echo "<tr>\n";
- foreach ($rs->f as $k => $v) {
- $finfo = $rs->fetchField($k);
- echo "<td class=\"data{$id}\" nowrap=\"nowrap\">", $misc->printVal($v, $finfo->type, array('null' => true)), "</td>";
- }
- echo "</tr>\n";
- $rs->moveNext();
- $i++;
- }
- echo "</table>\n";
- echo "<p>", $rs->recordCount(), " {$lang['strrows']}</p>\n";
- }
- // Otherwise if any rows have been affected
- elseif ($data->conn->Affected_Rows() > 0) {
- echo "<p>", $data->conn->Affected_Rows(), " {$lang['strrowsaff']}</p>\n";
- }
- // Else say success
- else echo "<p>{$lang['strsqlexecuted']}</p>\n";
-
- // Display duration if we know it
- if ($duration !== null) {
- echo "<p>", sprintf($lang['strruntime'], $duration), "</p>\n";
- }
+ // Display duration if we know it
+ if ($duration !== null) {
+ echo "<p>", sprintf($lang['strruntime'], $duration), "</p>\n";
}
-
+
+ echo "<p>{$lang['strsqlexecuted']}</p>\n";
+
echo "<p><a class=\"navlink\" href=\"database.php?database=", urlencode($_REQUEST['database']),
"&action=sql&query=", urlencode($_POST['query']), "\">{$lang['streditsql']}</a>";
if ($conf['show_reports'] && isset($rs) && is_object($rs) && $rs->recordCount() > 0) {