* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres.php,v 1.263 2005/06/16 14:40:11 chriskl Exp $
+ * $Id: Postgres.php,v 1.264 2005/07/15 08:03:13 chriskl Exp $
*/
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
return $arr;
}
+ /**
+ * Escapes bytea data for display on the screen
+ * @param $data The bytea data
+ * @return Data formatted for on-screen display
+ */
+ function escapeBytea($data) {
+ if (false && function_exists('pg_escape_bytea'))
+ return stripslashes(pg_escape_bytea($data));
+ else {
+ $translations = array('\\a' => '\\007', '\\b' => '\\010', '\\t' => '\\011', '\\n' => '\\012', '\\v' => '\\013', '\\f' => '\\014', '\\r' => '\\015');
+ return strtr(addCSlashes($data, "\0..\37\177..\377"), $translations);
+ }
+ }
+
/**
* Outputs the HTML code for a particular field
* @param $name The name to give the field
}
break;
case 'bytea':
- // addCSlashes converts all weird ASCII characters to octal representation,
- // EXCEPT the 'special' ones like \r \n \t, etc.
- $value = addCSlashes($value, "\0..\37\177..\377");
+ $value = $this->escapeBytea($value);
case 'text':
$n = substr_count($value, "\n");
$n = $n < 5 ? 5 : $n;
*/
function isSuperUser($username) {
$this->clean($username);
+
+ if (function_exists('pg_parameter_status')) {
+ $val = pg_parameter_status($this->conn->_connectionID, 'is_superuser');
+ if ($val !== false) return $val == 'on';
+ }
$sql = "SELECT usesuper FROM pg_user WHERE usename='{$username}'";
return $this->selectSet($sql);
}
- /** \r
- * Private helper method to detect a valid $foo$ quote delimiter at\r
- * the start of the parameter dquote\r
- * @return True if valid, false otherwise\r
- */ \r
+ /**
+ * Private helper method to detect a valid $foo$ quote delimiter at
+ * the start of the parameter dquote
+ * @return True if valid, false otherwise
+ */
function valid_dolquote($dquote) {
- // XXX: support multibyte\r
- return (ereg('^[$][$]', $dquote) || ereg('^[$][_[:alpha:]][_[:alnum:]]*[$]', $dquote));\r
- }\r
- \r
- /**\r
- * A private helper method for executeScript that advances the\r
- * character by 1. In psql this is careful to take into account\r
- * multibyte languages, but we don't at the moment, so this function\r
- * is someone redundant, since it will always advance by 1\r
- * @param &$i The current character position in the line\r
- * @param &$prevlen Length of previous character (ie. 1)\r
- * @param &$thislen Length of current character (ie. 1) \r
- */\r
+ // XXX: support multibyte
+ return (ereg('^[$][$]', $dquote) || ereg('^[$][_[:alpha:]][_[:alnum:]]*[$]', $dquote));
+ }
+
+ /**
+ * A private helper method for executeScript that advances the
+ * character by 1. In psql this is careful to take into account
+ * multibyte languages, but we don't at the moment, so this function
+ * is someone redundant, since it will always advance by 1
+ * @param &$i The current character position in the line
+ * @param &$prevlen Length of previous character (ie. 1)
+ * @param &$thislen Length of current character (ie. 1)
+ */
function advance_1(&$i, &$prevlen, &$thislen) {
- $prevlen = $thislen;\r
- $i += $thislen;\r
- $thislen = 1;\r
- }\r
-\r
- /** \r
- * Executes an SQL script as a series of SQL statements. Returns\r
- * the result of the final step. This is a very complicated lexer\r
- * 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
+ $prevlen = $thislen;
+ $i += $thislen;
+ $thislen = 1;
+ }
+
+ /**
+ * Executes an SQL script as a series of SQL statements. Returns
+ * the result of the final step. This is a very complicated lexer
+ * based on the REL7_4_STABLE src/bin/psql/mainloop.c lexer in
+ * the PostgreSQL source code.
+ * XXX: It does not handle multibyte languages properly.
* @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, $callback = null) {\r
- global $data;\r
-\r
- // This whole function isn't very encapsulated, but hey...\r
- $conn = $data->conn->_connectionID;\r
- if (!is_uploaded_file($_FILES[$name]['tmp_name'])) return false;\r
-\r
- $fd = fopen($_FILES[$name]['tmp_name'], 'r');\r
- if (!$fd) return false;\r
- \r
- // Build up each SQL statement, they can be multiline\r
- $query_buf = null;\r
- $query_start = 0;\r
- $in_quote = 0;\r
- $in_xcomment = 0;\r
- $bslash_count = 0;\r
- $dol_quote = null;\r
- $paren_level = 0;\r
- $len = 0;\r
- $i = 0;\r
- $prevlen = 0;\r
+ its result and line number.
+ * @return True for general success, false on any failure.
+ */
+ function executeScript($name, $callback = null) {
+ global $data;
+
+ // This whole function isn't very encapsulated, but hey...
+ $conn = $data->conn->_connectionID;
+ if (!is_uploaded_file($_FILES[$name]['tmp_name'])) return false;
+
+ $fd = fopen($_FILES[$name]['tmp_name'], 'r');
+ if (!$fd) return false;
+
+ // Build up each SQL statement, they can be multiline
+ $query_buf = null;
+ $query_start = 0;
+ $in_quote = 0;
+ $in_xcomment = 0;
+ $bslash_count = 0;
+ $dol_quote = null;
+ $paren_level = 0;
+ $len = 0;
+ $i = 0;
+ $prevlen = 0;
$thislen = 0;
- $lineno = 0;\r
- \r
- // Loop over each line in the file\r
- while (!feof($fd)) {\r
+ $lineno = 0;
+
+ // Loop over each line in the file
+ while (!feof($fd)) {
$line = fgets($fd, 32768);
- $lineno++;\r
- \r
- // Nothing left on line? Then ignore...\r
- if (trim($line) == '') continue;\r
- \r
- $len = strlen($line);\r
- $query_start = 0;\r
-\r
- /*\r
- * Parse line, looking for command separators.\r
- *\r
- * The current character is at line[i], the prior character at line[i\r
- * - prevlen], the next character at line[i + thislen].\r
- */\r
- $prevlen = 0;\r
- $thislen = ($len > 0) ? 1 : 0;\r
- \r
+ $lineno++;
+
+ // Nothing left on line? Then ignore...
+ if (trim($line) == '') continue;
+
+ $len = strlen($line);
+ $query_start = 0;
+
+ /*
+ * Parse line, looking for command separators.
+ *
+ * The current character is at line[i], the prior character at line[i
+ * - prevlen], the next character at line[i + thislen].
+ */
+ $prevlen = 0;
+ $thislen = ($len > 0) ? 1 : 0;
+
for ($i = 0; $i < $len; $this->advance_1($i, $prevlen, $thislen)) {
- /* was the previous character a backslash? */\r
- if ($i > 0 && substr($line, $i - $prevlen, 1) == '\\')\r
- $bslash_count++;\r
- else\r
- $bslash_count = 0;\r
- \r
- /*\r
- * It is important to place the in_* test routines before the\r
- * in_* detection routines. i.e. we have to test if we are in\r
- * a quote before testing for comments.\r
- */\r
- \r
- /* in quote? */\r
- if ($in_quote != 0)\r
+ /* was the previous character a backslash? */
+ if ($i > 0 && substr($line, $i - $prevlen, 1) == '\\')
+ $bslash_count++;
+ else
+ $bslash_count = 0;
+
+ /*
+ * It is important to place the in_* test routines before the
+ * in_* detection routines. i.e. we have to test if we are in
+ * a quote before testing for comments.
+ */
+
+ /* in quote? */
+ if ($in_quote != 0)
{
- /*\r
- * end of quote if matching non-backslashed character.\r
- * backslashes don't count for double quotes, though.\r
- */\r
- if (substr($line, $i, 1) == $in_quote &&\r
- ($bslash_count % 2 == 0 || $in_quote == '"'))\r
- $in_quote = 0;\r
- }\r
- \r
- /* in or end of $foo$ type quote? */ \r
+ /*
+ * end of quote if matching non-backslashed character.
+ * backslashes don't count for double quotes, though.
+ */
+ if (substr($line, $i, 1) == $in_quote &&
+ ($bslash_count % 2 == 0 || $in_quote == '"'))
+ $in_quote = 0;
+ }
+
+ /* in or end of $foo$ type quote? */
else if ($dol_quote) {
- if (strncmp(substr($line, $i), $dol_quote, strlen($dol_quote)) == 0) {\r
- $this->advance_1($i, $prevlen, $thislen);\r
- while(substr($line, $i, 1) != '$')\r
- $this->advance_1($i, $prevlen, $thislen);\r
- $dol_quote = null;\r
- }\r
- }\r
- \r
- /* start of extended comment? */\r
- else if (substr($line, $i, 2) == '/*')\r
+ if (strncmp(substr($line, $i), $dol_quote, strlen($dol_quote)) == 0) {
+ $this->advance_1($i, $prevlen, $thislen);
+ while(substr($line, $i, 1) != '$')
+ $this->advance_1($i, $prevlen, $thislen);
+ $dol_quote = null;
+ }
+ }
+
+ /* start of extended comment? */
+ else if (substr($line, $i, 2) == '/*')
{
- $in_xcomment++;\r
- if ($in_xcomment == 1)\r
- $this->advance_1($i, $prevlen, $thislen);\r
- }\r
- \r
- /* in or end of extended comment? */\r
- else if ($in_xcomment)\r
+ $in_xcomment++;
+ if ($in_xcomment == 1)
+ $this->advance_1($i, $prevlen, $thislen);
+ }
+
+ /* in or end of extended comment? */
+ else if ($in_xcomment)
{
- if (substr($line, $i, 2) == '*/' && !--$in_xcomment)\r
- $this->advance_1($i, $prevlen, $thislen);\r
- }\r
- \r
- /* start of quote? */\r
+ if (substr($line, $i, 2) == '*/' && !--$in_xcomment)
+ $this->advance_1($i, $prevlen, $thislen);
+ }
+
+ /* start of quote? */
else if (substr($line, $i, 1) == '\'' || substr($line, $i, 1) == '"') {
- $in_quote = substr($line, $i, 1);\r
- }\r
-\r
- /* \r
- * start of $foo$ type quote? \r
- */\r
+ $in_quote = substr($line, $i, 1);
+ }
+
+ /*
+ * start of $foo$ type quote?
+ */
else if (!$dol_quote && $this->valid_dolquote(substr($line, $i))) {
- $dol_end = strpos(substr($line, $i + 1), '$');\r
+ $dol_end = strpos(substr($line, $i + 1), '$');
$dol_quote = substr($line, $i, $dol_end + 1);
- $this->advance_1($i, $prevlen, $thislen);\r
+ $this->advance_1($i, $prevlen, $thislen);
while (substr($line, $i, 1) != '$') {
$this->advance_1($i, $prevlen, $thislen);
- }\r
- \r
- }\r
- \r
- /* single-line comment? truncate line */\r
- else if (substr($line, $i, 2) == '--')\r
+ }
+
+ }
+
+ /* single-line comment? truncate line */
+ else if (substr($line, $i, 2) == '--')
{
- $line = substr($line, 0, $i); /* remove comment */\r
- break;\r
- } \r
- \r
- /* count nested parentheses */\r
+ $line = substr($line, 0, $i); /* remove comment */
+ break;
+ }
+
+ /* count nested parentheses */
else if (substr($line, $i, 1) == '(') {
- $paren_level++;\r
- }\r
- \r
+ $paren_level++;
+ }
+
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
+ $paren_level--;
+ }
+
+ /* semicolon? then send query */
+ else if (substr($line, $i, 1) == ';' && !$bslash_count && !$paren_level)
{
- $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
- /*\r
- * insert a cosmetic newline, if this is not the first\r
- * line in the buffer\r
- */\r
- if (strlen($query_buf) > 0)\r
- $query_buf .= "\n";\r
- /* append the line to the query buffer */\r
- $query_buf .= $subline;\r
- $query_buf .= ';';\r
-\r
- // Execute the query (supporting 4.1.x PHP...). PHP cannot execute\r
+ $subline = substr(substr($line, 0, $i), $query_start);
+ /* is there anything else on the line? */
+ if (strspn($subline, " \t\n\r") != strlen($subline))
+ {
+ /*
+ * insert a cosmetic newline, if this is not the first
+ * line in the buffer
+ */
+ if (strlen($query_buf) > 0)
+ $query_buf .= "\n";
+ /* append the line to the query buffer */
+ $query_buf .= $subline;
+ $query_buf .= ';';
+
+ // Execute the query (supporting 4.1.x PHP...). PHP cannot execute
// empty queries, unlike libpq
if (function_exists('pg_query'))
$res = @pg_query($conn, $query_buf);
- else\r
- $res = @pg_exec($conn, $query_buf); \r
+ else
+ $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
+ if ($callback !== null) $callback($query_buf, $res, $lineno);
+ // Check for COPY request
+ if (pg_result_status($res) == 4) { // 4 == PGSQL_COPY_FROM
+ while (!feof($fd)) {
$copy = fgets($fd, 32768);
- $lineno++;\r
- pg_put_line($conn, $copy);\r
- if ($copy == "\\.\n" || $copy == "\\.\r\n") {\r
- pg_end_copy($conn);\r
- break;\r
- }\r
- }\r
- } \r
- }\r
- \r
- $query_buf = null;\r
- $query_start = $i + $thislen;\r
- }\r
- \r
- /*\r
- * keyword or identifier? \r
- * We grab the whole string so that we don't\r
- * mistakenly see $foo$ inside an identifier as the start\r
- * of a dollar quote.\r
- */ \r
- // XXX: multibyte here\r
+ $lineno++;
+ pg_put_line($conn, $copy);
+ if ($copy == "\\.\n" || $copy == "\\.\r\n") {
+ pg_end_copy($conn);
+ break;
+ }
+ }
+ }
+ }
+
+ $query_buf = null;
+ $query_start = $i + $thislen;
+ }
+
+ /*
+ * keyword or identifier?
+ * We grab the whole string so that we don't
+ * mistakenly see $foo$ inside an identifier as the start
+ * of a dollar quote.
+ */
+ // XXX: multibyte here
else if (ereg('^[_[:alpha:]]$', substr($line, $i, 1))) {
$sub = substr($line, $i, $thislen);
while (ereg('^[\$_A-Za-z0-9]$', $sub)) {
- /* keep going while we still have identifier chars */\r
- $this->advance_1($i, $prevlen, $thislen);\r
+ /* keep going while we still have identifier chars */
+ $this->advance_1($i, $prevlen, $thislen);
$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
- /* Put the rest of the line in the query buffer. */\r
- $subline = substr($line, $query_start); \r
- if ($in_quote || $dol_quote || strspn($subline, " \t\n\r") != strlen($subline))\r
+ }
+ } // end for
+
+ /* Put the rest of the line in the query buffer. */
+ $subline = substr($line, $query_start);
+ if ($in_quote || $dol_quote || strspn($subline, " \t\n\r") != strlen($subline))
{
- if (strlen($query_buf) > 0)\r
- $query_buf .= "\n";\r
- $query_buf .= $subline;\r
- }\r
- \r
- $line = null;\r
- \r
- } // end while\r
-\r
- /*\r
- * Process query at the end of file without a semicolon, so long as\r
- * it's non-empty.\r
- */\r
- if (strlen($query_buf) > 0 && strspn($query_buf, " \t\n\r") != strlen($query_buf))\r
- {\r
- // Execute the query (supporting 4.1.x PHP...)\r
- if (function_exists('pg_query'))\r
- $res = @pg_query($conn, $query_buf);\r
- else\r
+ if (strlen($query_buf) > 0)
+ $query_buf .= "\n";
+ $query_buf .= $subline;
+ }
+
+ $line = null;
+
+ } // end while
+
+ /*
+ * Process query at the end of file without a semicolon, so long as
+ * it's non-empty.
+ */
+ if (strlen($query_buf) > 0 && strspn($query_buf, " \t\n\r") != strlen($query_buf))
+ {
+ // Execute the query (supporting 4.1.x PHP...)
+ if (function_exists('pg_query'))
+ $res = @pg_query($conn, $query_buf);
+ else
$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
+ if ($callback !== null) $callback($query_buf, $res, $lineno);
+ // Check for COPY request
+ if (pg_result_status($res) == 4) { // 4 == PGSQL_COPY_FROM
+ while (!feof($fd)) {
$copy = fgets($fd, 32768);
- $lineno++;\r
- pg_put_line($conn, $copy);\r
- if ($copy == "\\.\n" || $copy == "\\.\r\n") {\r
- pg_end_copy($conn);\r
- break;\r
- }\r
- }\r
- } \r
- }\r
- \r
- fclose($fd);\r
- \r
- return true;\r
+ $lineno++;
+ pg_put_line($conn, $copy);
+ if ($copy == "\\.\n" || $copy == "\\.\r\n") {
+ pg_end_copy($conn);
+ break;
+ }
+ }
+ }
+ }
+
+ fclose($fd);
+
+ return true;
}
// Capabilities