* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres.php,v 1.307 2007/10/03 17:32:07 ioguix Exp $
+ * $Id: Postgres.php,v 1.308 2007/10/17 15:55:33 ioguix Exp $
*/
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
var $extraTypes = array('SERIAL');
// Array of allowed index types
var $typIndexes = array('BTREE', 'RTREE', 'GIST', 'HASH');
- // Default index type
+ // Default index type
var $typIndexDef = 'BTREE';
- // Array of allowed trigger events
- var $triggerEvents= array('INSERT', 'UPDATE', 'DELETE', 'INSERT OR UPDATE', 'INSERT OR DELETE',
+ // Array of allowed trigger events
+ var $triggerEvents= array('INSERT', 'UPDATE', 'DELETE', 'INSERT OR UPDATE', 'INSERT OR DELETE',
'DELETE OR UPDATE', 'INSERT OR DELETE OR UPDATE');
- // When to execute the trigger
+ // When to execute the trigger
var $triggerExecTimes = array('BEFORE', 'AFTER');
- // How often to execute the trigger
+ // How often to execute the trigger
var $triggerFrequency = array('ROW');
// Foreign key stuff. First element MUST be the default.
var $fkactions = array('NO ACTION', 'RESTRICT', 'CASCADE', 'SET NULL', 'SET DEFAULT');
// Function properties
var $funcprops = array(array('', 'ISCACHABLE'));
var $defaultprops = array('');
-
+
// Last oid assigned to a system object
var $_lastSystemOID = 18539;
var $_maxNameLen = 31;
-
+
// Name of id column
var $id = 'oid';
-
+
// Map of database encoding names to HTTP encoding names. If a
// database encoding does not appear in this list, then its HTTP
// encoding name is the same as its database encoding name.
'EUC_CN' => 'GB2312',
'EUC_JP' => 'EUC-JP',
'EUC_KR' => 'EUC-KR',
- 'EUC_TW' => 'EUC-TW',
+ 'EUC_TW' => 'EUC-TW',
'ISO_8859_5' => 'ISO-8859-5',
'ISO_8859_6' => 'ISO-8859-6',
'ISO_8859_7' => 'ISO-8859-7',
'WIN874' => 'CP874',
'WIN1256' => 'CP1256'
);
-
+
// Map of internal language name to syntax highlighting name
var $langmap = array(
'sql' => 'SQL',
'plruby' => 'Ruby',
'plrubyu' => 'Ruby'
);
-
+
// List of all legal privileges that can be applied to different types
// of objects.
var $privlist = array(
'a' => 'INSERT',
'R' => 'RULE'
);
-
+
// Rule action types
var $rule_events = array('SELECT', 'INSERT', 'UPDATE', 'DELETE');
// Select operators
// Operators of type 'i' are 'infix', eg. a = '1'. Type 'p' means postfix unary, eg. a IS TRUE.
// 'x' is a bracketed subquery form. eg. IN (1,2,3)
- var $selectOps = array('=' => 'i', '!=' => 'i', '<' => 'i', '>' => 'i', '<=' => 'i', '>=' => 'i', '<<' => 'i', '>>' => 'i', '<<=' => 'i', '>>=' => 'i',
- 'LIKE' => 'i', 'NOT LIKE' => 'i', '~' => 'i', '!~' => 'i', '~*' => 'i', '!~*' => 'i',
+ var $selectOps = array('=' => 'i', '!=' => 'i', '<' => 'i', '>' => 'i', '<=' => 'i', '>=' => 'i', '<<' => 'i', '>>' => 'i', '<<=' => 'i', '>>=' => 'i',
+ 'LIKE' => 'i', 'NOT LIKE' => 'i', '~' => 'i', '!~' => 'i', '~*' => 'i', '!~*' => 'i',
'IS NULL' => 'p', 'IS NOT NULL' => 'p', 'IN' => 'x', 'NOT IN' => 'x');
// Supported join operations for use with view wizard
var $joinOps = array('INNER JOIN' => 'INNER JOIN');
-
+
// Default help URL
var $help_base;
// Predefined size types
var $predefined_size_types = array('abstime','aclitem','bigserial','boolean','bytea','cid','cidr','circle','date','float4','float8','gtsvector','inet','int2','int4','int8','macaddr','money','oid','path','polygon','refcursor','regclass','regoper','regoperator','regproc','regprocedure','regtype','reltime','serial','smgr','text','tid','tinterval','tsquery','tsvector','varbit','void','xid');
-
+
/**
* Constructor
* @param $conn The database connection
}
// Help functions
-
+
/**
* Fetch a URL (or array of URLs) for a given help page.
*/
function getHelp($help) {
$this->getHelpPages();
-
+
if (isset($this->help_page[$help])) {
if (is_array($this->help_page[$help])) {
$urls = array();
include_once('./help/PostgresDoc70.php');
return $this->help_page;
}
-
+
// Formatting functions
-
+
/**
* Cleans (escapes) a string
* @param $str The string to clean, by reference
$str = addslashes($str);
return $str;
}
-
+
/**
* Cleans (escapes) an object name (eg. table, field)
* @param $str The string to clean, by reference
}
return $arr;
}
-
+
/**
* Escapes bytea data for display on the screen
* @param $data The bytea data
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
*/
function printField($name, $value, $type, $actions = array(),$szExtra="") {
global $lang;
-
+
// Determine actions string
$action_str = '';
foreach ($actions as $k => $v) {
if ($value !== null && $value == '') $value = null;
elseif ($value == 'true') $value = 't';
elseif ($value == 'false') $value = 'f';
-
+
// If value is null, 't' or 'f'...
if ($value === null || $value == 't' || $value == 'f') {
echo "<select name=\"", htmlspecialchars($name), "\"{$action_str}>\n";
}
else {
echo "<input name=\"", htmlspecialchars($name), "\" value=\"", htmlspecialchars($value), "\" size=\"35\"{$action_str} {$szExtra} />\n";
- }
+ }
break;
case 'bytea':
case 'bytea[]':
default:
echo "<input name=\"", htmlspecialchars($name), "\" value=\"", htmlspecialchars($value), "\" size=\"35\"{$action_str} {$szExtra} />\n";
break;
- }
+ }
}
-
+
/**
* Formats a value or expression for sql purposes
* @param $type The type of the field
return 'NULL';
else
return $value;
- break;
+ break;
default:
// Checking variable fields is difficult as there might be a size
- // attribute...
+ // attribute...
if (strpos($type, 'time') === 0) {
// Assume it's one of the time types...
if ($value == '') return "''";
- elseif (strcasecmp($value, 'CURRENT_TIMESTAMP') == 0
+ elseif (strcasecmp($value, 'CURRENT_TIMESTAMP') == 0
|| strcasecmp($value, 'CURRENT_TIME') == 0
|| strcasecmp($value, 'CURRENT_DATE') == 0
|| strcasecmp($value, 'LOCALTIME') == 0
else {
if ($format == 'VALUE') {
$this->clean($value);
- return "'{$value}'";
+ return "'{$value}'";
}
return $value;
}
function formatType($typname, $typmod) {
// This is a specific constant in the 7.0 source
$varhdrsz = 4;
-
+
// If the first character is an underscore, it's an array type
- $is_array = false;
+ $is_array = false;
if (substr($typname, 0, 1) == '_') {
$is_array = true;
$typname = substr($typname, 1);
- }
-
+ }
+
// Show lengths on bpchar and varchar
if ($typname == 'bpchar') {
$len = $typmod - $varhdrsz;
elseif ($typname == 'varchar') {
$temp = 'character varying';
if ($typmod != -1)
- $temp .= "(" . ($typmod - $varhdrsz) . ")";
+ $temp .= "(" . ($typmod - $varhdrsz) . ")";
}
elseif ($typname == 'numeric') {
$temp = 'numeric';
$precision = ($tmp_typmod >> 16) & 0xffff;
$scale = $tmp_typmod & 0xffff;
$temp .= "({$precision}, {$scale})";
- }
+ }
}
else $temp = $typname;
-
+
// Add array qualifier if it's an array
if ($is_array) $temp .= '[]';
-
+
return $temp;
}
global $conf, $misc;
$server_info = $misc->getServerInfo();
-
+
if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($server_info['username'])) {
$username = $server_info['username'];
$this->clean($username);
else
$where = '';
- $sql = "SELECT pdb.datname, pu.usename AS datowner, pg_encoding_to_char(encoding) AS datencoding,
- (SELECT description FROM pg_description pd WHERE pdb.oid=pd.objoid) AS datcomment
+ $sql = "SELECT pdb.datname, pu.usename AS datowner, pg_encoding_to_char(encoding) AS datencoding,
+ (SELECT description FROM pg_description pd WHERE pdb.oid=pd.objoid) AS datcomment
FROM pg_database pdb, pg_user pu
WHERE pdb.datdba = pu.usesysid
{$where}
$encoding = pg_parameter_status($this->conn->_connectionID, 'server_encoding');
if ($encoding !== false) return $encoding;
}
-
+
$sql = "SELECT getdatabaseencoding() AS encoding";
-
+
return $this->selectField($sql, 'encoding');
}
-
+
/**
* Sets the client encoding
* @param $encoding The encoding to for the client
} else {
$sql = "CREATE DATABASE \"{$database}\" WITH ENCODING='{$encoding}'";
}
-
+
if ($tablespace != '' && $this->hasTablespaces()) $sql .= " TABLESPACE \"{$tablespace}\"";
-
+
$status = $this->execute($sql);
if ($status != 0) return -1;
-
- if ($comment != '' && $this->hasSharedComments()) {
+
+ if ($comment != '' && $this->hasSharedComments()) {
$status = $this->setComment('DATABASE',$database,'',$comment);
if ($status != 0) return -2;
}
$sql = "DROP DATABASE \"{$database}\"";
return $this->execute($sql);
}
-
+
// Schema functions
-
+
/**
* Sets the current working schema. This is a do nothing method for
* < 7.3 and is just here for polymorphism's sake.
function setSchema($schema) {
return 0;
}
-
+
// Inheritance functions
-
+
/**
* Finds the names and schemas of parent tables (in order)
* @param $table The table to find the parents for
*/
function getTableParents($table) {
$this->clean($table);
-
+
$sql = "
- SELECT
+ SELECT
NULL AS nspname, relname
FROM
pg_class pc, pg_inherits pi
ORDER BY
pi.inhseqno
";
-
- return $this->selectSet($sql);
- }
+
+ return $this->selectSet($sql);
+ }
/**
*/
function getTableChildren($table) {
$this->clean($table);
-
+
$sql = "
- SELECT
+ SELECT
NULL AS nspname, relname
FROM
pg_class pc, pg_inherits pi
pc.oid=pi.inhrelid
AND pi.inhparent = (SELECT oid from pg_class WHERE relname='{$table}')
";
-
- return $this->selectSet($sql);
- }
-
+
+ return $this->selectSet($sql);
+ }
+
// Table functions
/**
*/
function getTable($table) {
$this->clean($table);
-
- $sql = "SELECT pc.relname,
- pg_get_userbyid(pc.relowner) AS relowner,
- (SELECT description FROM pg_description pd
- WHERE pc.oid=pd.objoid) AS relcomment
+
+ $sql = "SELECT pc.relname,
+ pg_get_userbyid(pc.relowner) AS relowner,
+ (SELECT description FROM pg_description pd
+ WHERE pc.oid=pd.objoid) AS relcomment
FROM pg_class pc
WHERE pc.relname='{$table}'";
-
+
return $this->selectSet($sql);
}
/**
* Return all tables in current database
* @param $all True to fetch all tables, false for just in current schema
- * @return All tables, sorted alphabetically
+ * @return All tables, sorted alphabetically
*/
function getTables($all = false) {
global $conf;
if (!$conf['show_system'] || $all) $where = "AND c.relname NOT LIKE 'pg@_%' ESCAPE '@' ";
else $where = '';
-
- $sql = "SELECT NULL AS nspname, c.relname,
- (SELECT usename FROM pg_user u WHERE u.usesysid=c.relowner) AS relowner,
+
+ $sql = "SELECT NULL AS nspname, c.relname,
+ (SELECT usename FROM pg_user u WHERE u.usesysid=c.relowner) AS relowner,
(SELECT description FROM pg_description pd WHERE c.oid=pd.objoid) AS relcomment,
reltuples::bigint AS reltuples
- FROM pg_class c
- WHERE c.relkind='r'
+ FROM pg_class c
+ WHERE c.relkind='r'
AND NOT EXISTS (SELECT 1 FROM pg_rewrite r WHERE r.ev_class = c.oid AND r.ev_type = '1')
{$where}
ORDER BY relname";
function getTableAttributes($table, $field = '') {
$this->clean($table);
$this->clean($field);
-
+
if ($field == '') {
$sql = "SELECT
a.attname, t.typname as type, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, -1 AS attstattarget, a.attstorage,
(SELECT adsrc FROM pg_attrdef adef WHERE a.attrelid=adef.adrelid AND a.attnum=adef.adnum) AS adsrc,
- a.attstorage AS typstorage, false AS attisserial,
- (SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
+ a.attstorage AS typstorage, false AS attisserial,
+ (SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
FROM
pg_attribute a,
pg_class c,
}
else {
$sql = "SELECT
- a.attname, t.typname as type, t.typname as base_type,
+ a.attname, t.typname as type, t.typname as base_type,
a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, -1 AS attstattarget, a.attstorage,
(SELECT adsrc FROM pg_attrdef adef WHERE a.attrelid=adef.adrelid AND a.attnum=adef.adnum) AS adsrc,
- a.attstorage AS typstorage,
- (SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
+ a.attstorage AS typstorage,
+ (SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
FROM
pg_attribute a ,
pg_class c,
WHERE
c.relname = '{$table}' AND a.attname='{$field}' AND a.attrelid = c.oid AND a.atttypid = t.oid";
}
-
+
return $this->selectSet($sql);
}
// Prior releases don't have this setting... oids always activated
return 'on';
}
-
+
/**
* Creates a new table in the database
* @param $name The name of the table
* @return 0 success
* @return -1 no fields supplied
*/
- function createTable($name, $fields, $field, $type, $array, $length, $notnull,
+ function createTable($name, $fields, $field, $type, $array, $length, $notnull,
$default, $withoutoids, $colcomment, $tblcomment, $tablespace,
$uniquekey, $primarykey) {
$this->fieldClean($name);
// If not the first column, add a comma
if (!$first) $sql .= ", ";
else $first = false;
-
+
switch ($type[$i]) {
// Have to account for weird placing of length for with/without
// time zone types
$found = true;
}
-
+
if (!$found) return -1;
-
+
// PRIMARY KEY
$primarykeycolumns = array();
for ($i = 0; $i < $fields; $i++) {
if (count($primarykeycolumns) > 0) {
$sql .= ", PRIMARY KEY (" . implode(", ", $primarykeycolumns) . ")";
}
-
+
$sql .= ")";
-
+
// WITHOUT OIDS
if ($this->hasWithoutOIDs() && $withoutoids)
$sql .= ' WITHOUT OIDS';
-
+
// Tablespace
if ($this->hasTablespaces() && $tablespace != '') {
$this->fieldClean($tablespace);
$sql .= " TABLESPACE \"{$tablespace}\"";
}
-
+
$status = $this->execute($sql);
if ($status) {
$this->rollbackTransaction();
}
}
return $this->endTransaction();
-
+
}
/**
* Alters a table
* @param $table The name of the table
* @param $name The new name for the table
- * @param $owner The new owner for the table
+ * @param $owner The new owner for the table
* @param $comment The comment on the table
* @param $tablespace The new tablespace for the table ('' means leave as is)
* @return 0 success
$this->rollbackTransaction();
return -1;
}
-
+
// Comment
$status = $this->setComment('TABLE', '', $table, $comment);
if ($status != 0) {
$this->rollbackTransaction();
return -4;
}
-
+
// Owner
if ($this->hasAlterTableOwner() && $owner != '') {
// Fetch existing owner
$this->rollbackTransaction();
return -5;
}
-
+
// If owner has been changed, then do the alteration. We are
// careful to avoid this generally as changing owner is a
// superuser only function.
if ($data->fields['relowner'] != $owner) {
$sql = "ALTER TABLE \"{$table}\" OWNER TO \"{$owner}\"";
-
+
$status = $this->execute($sql);
if ($status != 0) {
$this->rollbackTransaction();
}
}
}
-
+
// Tablespace
if ($this->hasTablespaces() && $tablespace != '') {
// Fetch existing tablespace
$this->rollbackTransaction();
return -5;
}
-
+
// If tablespace has been changed, then do the alteration. We
// don't want to do this unnecessarily.
if ($data->fields['tablespace'] != $tablespace) {
$sql = "ALTER TABLE \"{$table}\" SET TABLESPACE \"{$tablespace}\"";
-
+
$status = $this->execute($sql);
if ($status != 0) {
$this->rollbackTransaction();
return -6;
}
- }
+ }
}
// Rename (only if name has changed)
return -3;
}
}
-
+
return $this->endTransaction();
}
-
+
/**
* Removes a table from the database
* @param $table The table to drop
function renameTable($table, $newName) {
$this->fieldClean($table);
$this->fieldClean($newName);
-
+
$sql = "ALTER TABLE \"{$table}\" RENAME TO \"{$newName}\"";
return $this->execute($sql);
if ($this->hasSchemas()) {
$sql .= "SET search_path = \"{$this->_schema}\", pg_catalog;\n\n";
}
-
+
// Begin CREATE TABLE definition
$sql .= "-- Definition\n\n";
// DROP TABLE must be fully qualified in case a table with the same name exists
$this->fieldClean($atts->fields['attname']);
$sql .= " \"{$atts->fields['attname']}\"";
// Dump SERIAL and BIGSERIAL columns correctly
- if ($this->phpBool($atts->fields['attisserial']) &&
+ if ($this->phpBool($atts->fields['attisserial']) &&
($atts->fields['type'] == 'integer' || $atts->fields['type'] == 'bigint')) {
if ($atts->fields['type'] == 'integer')
$sql .= " SERIAL";
if ($this->phpBool($atts->fields['attnotnull']))
$sql .= " NOT NULL";
// Add default if necessary
- if ($atts->fields['adsrc'] !== null)
+ if ($atts->fields['adsrc'] !== null)
$sql .= " DEFAULT {$atts->fields['adsrc']}";
}
if ($i < $num) $sql .= ",\n";
else $sql .= "\n";
- // Does this column have a comment?
+ // Does this column have a comment?
if ($atts->fields['comment'] !== null) {
$this->clean($atts->fields['comment']);
$col_comments_sql .= "COMMENT ON COLUMN \"{$t->fields['relname']}\".\"{$atts->fields['attname']}\" IS '{$atts->fields['comment']}';\n";
}
-
+
$atts->moveNext();
$i++;
}
$sql .= "\"{$parents->fields['schemaname']}\".";
}
$sql .= "\"{$parents->fields['relname']}\"";
-
+
$parents->moveNext();
if (!$parents->EOF) $sql .= ', ';
- }
+ }
$sql .= ")";
}
*/
foreach ($privs as $v) {
// Get non-GRANT OPTION privs
$nongrant = array_diff($v[2], $v[4]);
-
+
// Skip empty or owner ACEs
if (sizeof($v[2]) == 0 || ($v[0] == 'user' && $v[1] == $t->fields['relowner'])) continue;
-
+
// Change user if necessary
if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
$grantor = $v[3];
$this->clean($grantor);
$sql .= "SET SESSION AUTHORIZATION '{$grantor}';\n";
- }
-
+ }
+
// Output privileges with no GRANT OPTION
$sql .= "GRANT " . join(', ', $nongrant) . " ON TABLE \"{$t->fields['relname']}\" TO ";
switch ($v[0]) {
// Reset user if necessary
if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
$sql .= "RESET SESSION AUTHORIZATION;\n";
- }
-
+ }
+
// Output privileges with GRANT OPTION
-
+
// Skip empty or owner ACEs
if (!$this->hasGrantOption() || sizeof($v[4]) == 0) continue;
$grantor = $v[3];
$this->clean($grantor);
$sql .= "SET SESSION AUTHORIZATION '{$grantor}';\n";
- }
-
+ }
+
$sql .= "GRANT " . join(', ', $v[4]) . " ON \"{$t->fields['relname']}\" TO ";
switch ($v[0]) {
case 'public':
return null;
}
$sql .= " WITH GRANT OPTION;\n";
-
+
// Reset user if necessary
if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
$sql .= "RESET SESSION AUTHORIZATION;\n";
- }
+ }
}
}
// Nasty hack to support pre-7.4 PostgreSQL
if ($triggers->fields['tgdef'] !== null)
$sql .= $triggers->fields['tgdef'];
- else
- $sql .= $this->getTriggerDef($triggers->fields);
+ else
+ $sql .= $this->getTriggerDef($triggers->fields);
$sql .= ";\n";
$sql = "ALTER TABLE \"{$table}\" ADD COLUMN \"{$column}\" {$type}({$length})";
}
}
-
+
// Add array qualifier, if requested
if ($array) $sql .= '[]';
-
+
// If we have advanced column adding, add the extra qualifiers
if ($this->hasAlterColumnType()) {
// NOT NULL clause
if ($notnull) $sql .= ' NOT NULL';
-
+
// DEFAULT clause
if ($default != '') $sql .= ' DEFAULT ' . $default;
}
function setColumnDefault($table, $column, $default) {
$this->fieldClean($table);
$this->fieldClean($column);
-
+
$sql = "ALTER TABLE \"{$table}\" ALTER COLUMN \"{$column}\" SET DEFAULT {$default}";
return $this->execute($sql);
}
// Otherwise update the table. Note the reverse-sensed $state variable
- $sql = "UPDATE pg_attribute SET attnotnull = " . (($state) ? 'false' : 'true') . "
- WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '{$table}')
+ $sql = "UPDATE pg_attribute SET attnotnull = " . (($state) ? 'false' : 'true') . "
+ WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '{$table}')
AND attname = '{$column}'";
$status = $this->execute($sql);
function dropColumn($table, $column, $cascade) {
return -99;
}
-
+
/**
* Alters a column in a table OR view
* @param $table The table in which the column resides
* @return -3 rename column error
* @return -4 comment error
*/
- function alterColumn($table, $column, $name, $notnull, $oldnotnull, $default, $olddefault,
+ function alterColumn($table, $column, $name, $notnull, $oldnotnull, $default, $olddefault,
$type, $length, $array, $oldtype, $comment) {
$this->beginTransaction();
return -1;
}
}
-
+
// Set default, if it has changed
if ($default != $olddefault) {
if ($default == '')
$status = $this->dropColumnDefault($table, $column);
- else
+ else
$status = $this->setColumnDefault($table, $column, $default);
if ($status != 0) {
return -3;
}
}
-
+
// Parameters must be cleaned for the setComment function. It's ok to do
// that here since this is the last time these variables are used.
$this->fieldClean($name);
$this->fieldClean($table);
- $this->clean($comment);
+ $this->clean($comment);
$status = $this->setComment('COLUMN', $name, $table, $comment);
if ($status != 0) {
$this->rollbackTransaction();
}
return $this->endTransaction();
- }
+ }
// Row functions
-
+
/**
* Delete a row from a table
* @param $table The table from which to delete
$this->rollbackTransaction();
return -1;
}
-
+
$status = $this->delete($table, $key);
if ($status != 0 || $this->conn->Affected_Rows() != 1) {
$this->rollbackTransaction();
return -2;
}
-
+
// End transaction
return $this->endTransaction();
}
}
-
+
/**
* Updates a row in a table
* @param $table The table in which to update
if (sizeof($vars) > 0) {
foreach($vars as $key => $value) {
$this->fieldClean($key);
-
+
// Handle NULL values
if (isset($nulls[$key])) $tmp = 'NULL';
else $tmp = $this->formatValue($types[$key], $format[$key], $value);
-
+
if (isset($sql)) $sql .= ", \"{$key}\"={$tmp}";
else $sql = "UPDATE \"{$table}\" SET \"{$key}\"={$tmp}";
}
$first = false;
}
else $sql .= " AND \"{$k}\"='{$v}'";
- }
+ }
}
// Begin transaction. We do this so that we can ensure only one row is
$this->rollbackTransaction();
return -2;
}
-
+
// End transaction
- return $this->endTransaction();
+ return $this->endTransaction();
}
}
$values = '';
foreach($vars as $key => $value) {
$this->fieldClean($key);
-
+
// Handle NULL values
if (isset($nulls[$key])) $tmp = 'NULL';
else $tmp = $this->formatValue($types[$key], $format[$key], $value);
-
+
if ($fields) $fields .= ", \"{$key}\"";
else $fields = "INSERT INTO \"{$table}\" (\"{$key}\"";
else $values = ") VALUES ({$tmp}";
}
$sql = $fields . $values . ')';
- }
+ }
return $this->execute($sql);
}
}
-
+
/**
* Returns a recordset of all columns in a table
* @param $table The name of a table
function getRowIdentifier($table) {
$oldtable = $table;
$this->clean($table);
-
+
$status = $this->beginTransaction();
if ($status != 0) return -1;
-
+
// Get the first primary or unique index (sorting primary keys first) that
// is NOT a partial index.
- $sql = "SELECT indrelid, indkey FROM pg_index WHERE indisunique AND indrelid=(SELECT oid FROM pg_class
+ $sql = "SELECT indrelid, indkey FROM pg_index WHERE indisunique AND indrelid=(SELECT oid FROM pg_class
WHERE relname='{$table}') AND indpred='' AND indproc=0 ORDER BY indisprimary DESC LIMIT 1";
$rs = $this->selectSet($sql);
// If none, check for an OID column. Even though OIDs can be duplicated, the edit and delete row
// functions check that they're only modiying a single row. Otherwise, return empty array.
- if ($rs->recordCount() == 0) {
+ if ($rs->recordCount() == 0) {
// Check for OID column
$temp = array();
if ($this->hasObjectID($table)) {
$this->endTransaction();
return $attnames;
}
- }
+ }
}
// Sequence functions
-
+
/**
* Returns all sequences in the current database
* @return A recordset
c.relname AS seqname,
u.usename AS seqowner,
(SELECT description FROM pg_description pd WHERE c.oid=pd.objoid) AS seqcomment
- FROM
- pg_class c, pg_user u WHERE c.relowner=u.usesysid AND c.relkind = 'S' ORDER BY seqname";
-
+ FROM
+ pg_class c, pg_user u
+ WHERE c.relowner=u.usesysid AND c.relkind = 'S' ORDER BY seqname";
+
return $this->selectSet( $sql );
}
// Need both field cleaned and literal cleaned versions
$this->fieldClean($sequence);
$this->clean($temp);
-
- $sql = "SELECT sequence_name AS seqname, *,
- (SELECT description FROM pg_description pd WHERE pd.objoid=(SELECT oid FROM pg_class WHERE relname='{$temp}')) AS seqcomment
- FROM \"{$sequence}\" AS s";
-
+
+ $sql = "SELECT '{$sequence}' AS seqname, s.*,
+ (SELECT description FROM pg_description pd WHERE pd.objoid=(SELECT oid FROM pg_class WHERE relname='{$temp}')) AS seqcomment,
+ u.usename AS seqowner
+ FROM \"{$sequence}\" AS s, pg_user u, pg_class c
+ WHERE
+ c.relowner = u.usesysid AND c.relkind = 'S'
+ AND c.relname = '{$sequence}'";
+
return $this->selectSet( $sql );
}
- /**
+ /**
* Drops a given sequence
* @param $sequence Sequence name
* @param $cascade True to cascade drop, false to restrict
*/
function dropSequence($sequence, $cascade) {
$this->fieldClean($sequence);
-
+
$sql = "DROP SEQUENCE \"{$sequence}\"";
if ($cascade) $sql .= " CASCADE";
-
+
return $this->execute($sql);
}
- /**
+ /**
* Resets a given sequence to min value of sequence
* @param $sequence Sequence name
* @return 0 success
/* This double-cleaning is deliberate */
$this->fieldClean($sequence);
$this->clean($sequence);
-
+
$sql = "SELECT SETVAL('\"{$sequence}\"', {$minvalue})";
-
+
return $this->execute($sql);
}
- /**
+ /**
* Execute nextval on a given sequence
* @param $sequence Sequence name
* @return 0 success
$this->clean($sequence);
$sql = "SELECT NEXTVAL('\"{$sequence}\"')";
-
+
return $this->execute($sql);
}
- /**
+ /**
* Execute setval on a given sequence
* @param $sequence Sequence name
* @param $nextvalue The next value
$this->clean($nextvalue);
$sql = "SELECT SETVAL('\"{$sequence}\"', '{$nextvalue}')";
-
+
return $this->execute($sql);
}
* @param $cycledvalue True if cycled, false otherwise
* @return 0 success
*/
- function createSequence($sequence, $increment, $minvalue, $maxvalue,
+ function createSequence($sequence, $increment, $minvalue, $maxvalue,
$startvalue, $cachevalue, $cycledvalue) {
$this->fieldClean($sequence);
$this->clean($increment);
$this->clean($maxvalue);
$this->clean($startvalue);
$this->clean($cachevalue);
-
+
$sql = "CREATE SEQUENCE \"{$sequence}\"";
if ($increment != '') $sql .= " INCREMENT {$increment}";
if ($minvalue != '') $sql .= " MINVALUE {$minvalue}";
if ($startvalue != '') $sql .= " START {$startvalue}";
if ($cachevalue != '') $sql .= " CACHE {$cachevalue}";
if ($cycledvalue) $sql .= " CYCLE";
-
+
+ return $this->execute($sql);
+ }
+
+ /**
+ * Rename a sequence
+ * @param $sequence The sequence name
+ * @param $name The new name for the sequence
+ * @return 0 success
+ */
+ function renameSequence($sequence, $name) {
+ $this->fieldClean($name);
+ $this->fieldClean($sequence);
+
+ $sql = "ALTER TABLE \"{$sequence}\" RENAME TO \"{$name}\"";
return $this->execute($sql);
}
+ /**
+ * Protected method which alter a sequence
+ * SHOULDN'T BE CALLED OUTSIDE OF A TRANSACTION
+ * @param $seqrs The sequence recordSet returned by getSequence()
+ * @param $name The new name for the sequence
+ * @param $comment The comment on the sequence
+ * @param $owner The new owner for the sequence
+ * @param $increment The increment
+ * @param $minvalue The min value
+ * @param $maxvalue The max value
+ * @param $startvalue The starting value
+ * @param $cachevalue The cache value
+ * @param $cycledvalue True if cycled, false otherwise
+ * @return 0 success
+ * @return -3 rename error
+ * @return -4 comment error
+ */
+ /*protected*/
+ function _alterSequence($seqrs, $name, $comment, $owner, $increment,
+ $minvalue, $maxvalue, $startvalue, $cachevalue, $cycledvalue) {
+
+ $sequence = $seqrs->fields['seqname'];
+ $this->fieldClean($name);
+ $this->clean($comment);
+ /* $owner, $increment, $minvalue, $maxvalue,
+ * $startvalue, $cachevalue, $cycledvalue not supported in pg70 */
+
+ // Comment
+ $status = $this->setComment('SEQUENCE', $sequence, '', $comment);
+ if ($status != 0)
+ return -4;
+
+ // Rename (only if name has changed)
+ if ($name != $sequence) {
+ $status = $this->renameSequence($sequence, $name);
+ if ($status != 0)
+ return -3;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Alters a sequence
+ * @param $sequence The name of the sequence
+ * @param $name The new name for the sequence
+ * @param $comment The comment on the sequence
+ * @param $owner The new owner for the sequence
+ * @param $increment The increment
+ * @param $minvalue The min value
+ * @param $maxvalue The max value
+ * @param $startvalue The starting value
+ * @param $cachevalue The cache value
+ * @param $cycledvalue True if cycled, false otherwise
+ * @return 0 success
+ * @return -1 transaction error
+ * @return -2 get existing sequence error
+ * @return $this->_alterSequence error code
+ */
+ function alterSequence($sequence, $name, $comment, $owner=null, $increment=null,
+ $minvalue=null, $maxvalue=null, $startvalue=null, $cachevalue=null, $cycledvalue=null) {
+
+ $this->fieldClean($sequence);
+ $data = $this->getSequence($sequence);
+ if ($data->recordCount() != 1)
+ return -2;
+
+ $status = $this->beginTransaction();
+ if ($status != 0) {
+ $this->rollbackTransaction();
+ return -1;
+ }
+
+ $status = $this->_alterSequence($data, $name, $comment, $owner, $increment,
+ $minvalue, $maxvalue, $startvalue, $cachevalue, $cycledvalue);
+
+ if ($status != 0) {
+ $this->rollbackTransaction();
+ return $status;
+ }
+
+ return $this->endTransaction();
+ }
+
// Constraint functions
/**
NULL::int2vector AS indkey
FROM
pg_relcheck
- WHERE
+ WHERE
rcrelid = (SELECT oid FROM pg_class WHERE relname='{$table}')
UNION ALL
SELECT
return $this->execute($sql);
}
-
+
/**
* Drops a check constraint from a table
* @param $table The table from which to drop the check
function dropCheckConstraint($table, $name) {
$this->clean($table);
$this->clean($name);
-
+
// Begin transaction
$status = $this->beginTransaction();
if ($status != 0) return -2;
$this->rollbackTransaction();
return -4;
}
-
+
// Update the pg_class catalog to reflect the new number of checks
- $sql = "UPDATE pg_class SET relchecks=(SELECT COUNT(*) FROM pg_relcheck WHERE
- rcrelid=(SELECT oid FROM pg_class WHERE relname='{$table}'))
+ $sql = "UPDATE pg_class SET relchecks=(SELECT COUNT(*) FROM pg_relcheck WHERE
+ rcrelid=(SELECT oid FROM pg_class WHERE relname='{$table}'))
WHERE relname='{$table}'";
$status = $this->execute($sql);
if ($status != 0) {
// Otherwise, close the transaction
return $this->endTransaction();
- }
+ }
// Constraint functions
switch ($type) {
case 'c':
- // CHECK constraint
+ // CHECK constraint
return $this->dropCheckConstraint($relation, $constraint);
break;
case 'p':
case 'f':
// FOREIGN KEY constraint
return -99;
- }
+ }
}
/**
$this->fieldClean($table);
$this->fieldArrayClean($fields);
$this->fieldClean($name);
-
+
if ($name != '')
$sql = "CREATE UNIQUE INDEX \"{$name}\" ON \"{$table}\"(\"" . join('","', $fields) . "\")";
else return -99; // Not supported
* @return 0 success
* @return -1 no fields given
*/
- function addForeignKey($table, $targschema, $targtable, $sfields, $tfields, $upd_action, $del_action,
+ function addForeignKey($table, $targschema, $targtable, $sfields, $tfields, $upd_action, $del_action,
$match, $deferrable, $initially, $name = '') {
if (!is_array($sfields) || sizeof($sfields) == 0 ||
!is_array($tfields) || sizeof($tfields) == 0) return -1;
// Target table needs to be fully qualified
if ($this->hasSchemas()) {
$sql .= "\"{$targschema}\".";
- }
+ }
$sql .= "\"{$targtable}\"(\"" . join('","', $tfields) . "\") ";
if ($match != $this->fkmatches[0]) $sql .= " {$match}";
if ($upd_action != $this->fkactions[0]) $sql .= " ON UPDATE {$upd_action}";
return $this->execute($sql);
}
-
+
/**
* Adds a primary key constraint to a table
* @param $table The table to which to add the primery key
$sql = "CREATE";
if ($unique) $sql .= " UNIQUE";
$sql .= " INDEX \"{$name}\" ON \"{$table}\" USING {$type} ";
-
+
if (is_array($columns)) {
$this->arrayClean($columns);
$sql .= "(\"" . implode('","', $columns) . "\")";
}
// Rule functions
-
+
/**
* Returns a list of all rules on a table
* @param $table The table to find rules for
if ($where != '') $sql .= " WHERE {$where}";
$sql .= " DO";
if ($instead) $sql .= " INSTEAD";
- if ($type == 'NOTHING')
+ if ($type == 'NOTHING')
$sql .= " NOTHING";
else $sql .= " ({$action})";
return $this->execute($sql);
}
-
+
/**
* Edits a rule
* @param $name The name of the new rule
$this->rollbackTransaction();
return -4;
}
-
+
$status = $this->endTransaction();
return ($status == 0) ? 0 : -2;
}
// View functions
-
+
/**
* Returns a list of all views in the database
* @return All views
$where = '';
$sql = "SELECT viewname AS relname, viewowner AS relowner, definition AS vwdefinition,
- (SELECT description FROM pg_description pd, pg_class pc
+ (SELECT description FROM pg_description pd, pg_class pc
WHERE pc.oid=pd.objoid AND pc.relname=v.viewname) AS relcomment
FROM pg_views v
{$where}
return $this->selectSet($sql);
}
-
+
/**
* Returns all details for a particular view
* @param $view The name of the view to retrieve
*/
function getView($view) {
$this->clean($view);
-
+
$sql = "SELECT viewname AS relname, viewowner AS relowner, definition AS vwdefinition,
- (SELECT description FROM pg_description pd, pg_class pc
+ (SELECT description FROM pg_description pd, pg_class pc
WHERE pc.oid=pd.objoid AND pc.relname=v.viewname) AS relcomment
FROM pg_views v
WHERE viewname='{$view}'";
-
+
return $this->selectSet($sql);
- }
+ }
/**
* Creates a new view.
$this->clean($comment);
// Note: $definition not cleaned
-
+
$sql = "CREATE ";
- if ($replace) $sql .= "OR REPLACE ";
+ if ($replace) $sql .= "OR REPLACE ";
$sql .= "VIEW \"{$viewname}\" AS {$definition}";
-
+
$status = $this->execute($sql);
if ($status) {
$this->rollbackTransaction();
return $this->endTransaction();
}
-
+
/**
* Drops a view.
* @param $viewname The name of the view to drop
function setView($viewname, $definition, $comment) {
$status = $this->beginTransaction();
if ($status != 0) return -1;
-
+
$status = $this->dropView($viewname, false);
if ($status != 0) {
$this->rollbackTransaction();
return -2;
}
-
+
$status = $this->createView($viewname, $definition, false, $comment);
if ($status != 0) {
$this->rollbackTransaction();
return -3;
}
-
+
$status = $this->endTransaction();
return ($status == 0) ? 0 : -1;
}
$status = $this->execute($sql);
if ($status != 0) {
$this->rollbackTransaction();
- return -3;
- }
+ return -3;
+ }
}
return $this->endTransaction();
if (!$conf['show_system'])
$where = "WHERE po.oid > '{$this->_lastSystemOID}'::oid";
else $where = '';
-
+
$sql = "
SELECT
po.oid,
(SELECT description FROM pg_description pd WHERE po.oid=pd.objoid) AS oprcomment
FROM
pg_operator po
- {$where}
+ {$where}
ORDER BY
po.oprname, oprleftname, oprrightname
";
WHERE
po.oid='{$operator_oid}'
";
-
+
return $this->selectSet($sql);
}
else $sql .= "NONE, ";
if ($opr->fields['oprrightname'] !== null) $sql .= $opr->fields['oprrightname'] . ')';
else $sql .= "NONE)";
-
+
if ($cascade) $sql .= " CASCADE";
-
+
return $this->execute($sql);
- }
+ }
// User functions
-
+
/**
* Changes a user's password
* @param $username The username
function changePassword($username, $password) {
$this->fieldClean($username);
$this->clean($password);
-
+
$sql = "ALTER USER \"{$username}\" WITH PASSWORD '{$password}'";
-
+
return $this->execute($sql);
}
-
+
/**
* Returns all users in the database cluster
* @return All users
$sql = "SELECT usename, usesuper, usecreatedb, valuntil AS useexpires";
if ($this->hasUserSessionDefaults()) $sql .= ", useconfig";
$sql .= " FROM pg_user ORDER BY usename";
-
+
return $this->selectSet($sql);
}
-
+
/**
* Returns information about a single user
* @param $username The username of the user to retrieve
*/
function getUser($username) {
$this->clean($username);
-
+
$sql = "SELECT usename, usesuper, usecreatedb, valuntil AS useexpires";
if ($this->hasUserSessionDefaults()) $sql .= ", useconfig";
$sql .= " FROM pg_user WHERE usename='{$username}'";
-
+
return $this->selectSet($sql);
}
$this->clean($username);
if (function_exists('pg_parameter_status')) {
- $val = pg_parameter_status($this->conn->_connectionID, 'is_superuser');
+ $val = pg_parameter_status($this->conn->_connectionID, 'is_superuser');
if ($val !== false) return $val == 'on';
}
-
+
$sql = "SELECT usesuper FROM pg_user WHERE usename='{$username}'";
-
+
$usesuper = $this->selectField($sql, 'usesuper');
if ($usesuper == -1) return false;
else return $usesuper == 't';
- }
-
+ }
+
/**
* Creates a new user
* @param $username The username of the user to create
$this->fieldClean($username);
$this->clean($password);
$this->clean($expiry);
- $this->fieldArrayClean($groups);
+ $this->fieldArrayClean($groups);
$sql = "CREATE USER \"{$username}\"";
if ($password != '') $sql .= " WITH PASSWORD '{$password}'";
if (is_array($groups) && sizeof($groups) > 0) $sql .= " IN GROUP \"" . join('", "', $groups) . "\"";
if ($expiry != '') $sql .= " VALID UNTIL '{$expiry}'";
else $sql .= " VALID UNTIL 'infinity'";
-
+
return $this->execute($sql);
- }
-
+ }
+
/**
* Adjusts a user's info
* @param $username The username of the user to modify
$this->fieldClean($username);
$this->clean($password);
$this->clean($expiry);
-
+
$sql = "ALTER USER \"{$username}\"";
if ($password != '') $sql .= " WITH PASSWORD '{$password}'";
$sql .= ($createdb) ? ' CREATEDB' : ' NOCREATEDB';
$sql .= ($createuser) ? ' CREATEUSER' : ' NOCREATEUSER';
if ($expiry != '') $sql .= " VALID UNTIL '{$expiry}'";
else $sql .= " VALID UNTIL 'infinity'";
-
+
return $this->execute($sql);
- }
-
+ }
+
/**
* Removes a user
* @param $username The username of the user to drop
*/
function dropUser($username) {
$this->fieldClean($username);
-
+
$sql = "DROP USER \"{$username}\"";
-
+
return $this->execute($sql);
}
-
+
// Group functions
-
+
/**
* Returns all groups in the database cluser
* @return All groups
*/
function getGroups() {
$sql = "SELECT groname FROM pg_group ORDER BY groname";
-
+
return $this->selectSet($sql);
}
$this->clean($groname);
$sql = "SELECT grolist FROM pg_group WHERE groname = '{$groname}'";
-
+
$grodata = $this->selectSet($sql);
if ($grodata->fields['grolist'] !== null && $grodata->fields['grolist'] != '{}') {
$members = $grodata->fields['grolist'];
$this->fieldClean($groname);
$sql = "CREATE GROUP \"{$groname}\"";
-
+
if (is_array($users) && sizeof($users) > 0) {
$this->fieldArrayClean($users);
- $sql .= ' WITH USER "' . join('", "', $users) . '"';
- }
-
+ $sql .= ' WITH USER "' . join('", "', $users) . '"';
+ }
+
return $this->execute($sql);
- }
-
+ }
+
/**
* Removes a group
* @param $groname The name of the group to drop
*/
function dropGroup($groname) {
$this->fieldClean($groname);
-
+
$sql = "DROP GROUP \"{$groname}\"";
-
+
return $this->execute($sql);
}
function addGroupMember($groname, $user) {
$this->fieldClean($groname);
$this->fieldClean($user);
-
+
$sql = "ALTER GROUP \"{$groname}\" ADD USER \"{$user}\"";
return $this->execute($sql);
}
-
+
/**
* Removes a group member
* @param $groname The name of the group
function dropGroupMember($groname, $user) {
$this->fieldClean($groname);
$this->fieldClean($user);
-
+
$sql = "ALTER GROUP \"{$groname}\" DROP USER \"{$user}\"";
return $this->execute($sql);
}
-
+
// Type functions
/**
*/
function getTypes($all = false, $tabletypes = false, $domains = false) {
global $conf;
-
+
if ($all || $conf['show_system']) {
$where = '';
} else {
*/
function getType($typname) {
$this->clean($typname);
-
- $sql = "SELECT typtype, typbyval, typname, typinput AS typin, typoutput AS typout, typlen, typalign
+
+ $sql = "SELECT typtype, typbyval, typname, typinput AS typin, typoutput AS typout, typlen, typalign
FROM pg_type WHERE typname='{$typname}'";
return $this->selectSet($sql);
- }
-
+ }
+
/**
* Creates a new type
* @param ...
if ($typbyval) $sql .= ", PASSEDBYVALUE, ";
if ($typalign != '') $sql .= ", ALIGNMENT = {$typalign}";
if ($typstorage != '') $sql .= ", STORAGE = {$typstorage}";
-
+
$sql .= ")";
return $this->execute($sql);
}
-
+
/**
* Drops a type.
* @param $typname The name of the type to drop
else
$tgdef .= ' UPDATE';
}
-
+
// Table name
$tgdef .= " ON \"{$trigger['relname']}\" ";
-
+
// Deferrability
if ($trigger['tgisconstraint']) {
if ($trigger['tgconstrrelid'] != 0) {
// Execute procedure
$tgdef .= "EXECUTE PROCEDURE \"{$trigger['tgfname']}\"(";
-
+
// Parameters
// Escape null characters
$v = addCSlashes($trigger['tgargs'], "\0");
// Split on escaped null characters
- $params = explode('\\000', $v);
+ $params = explode('\\000', $v);
for ($findx = 0; $findx < $trigger['tgnargs']; $findx++) {
$param = "'" . str_replace('\'', '\\\'', $params[$findx]) . "'";
$tgdef .= $param;
if ($findx < ($trigger['tgnargs'] - 1))
$tgdef .= ', ';
}
-
+
// Finish it off
$tgdef .= ')';
$this->clean($table);
// We include constraint triggers
- $sql = "SELECT t.tgname, t.tgisconstraint, t.tgdeferrable, t.tginitdeferred, t.tgtype,
- t.tgargs, t.tgnargs, t.tgconstrrelid,
+ $sql = "SELECT t.tgname, t.tgisconstraint, t.tgdeferrable, t.tginitdeferred, t.tgtype,
+ t.tgargs, t.tgnargs, t.tgconstrrelid,
(SELECT relname FROM pg_class c2 WHERE c2.oid=t.tgconstrrelid) AS tgconstrrelname,
- (SELECT proname FROM pg_proc p WHERE t.tgfoid=p.oid) AS tgfname,
+ (SELECT proname FROM pg_proc p WHERE t.tgfoid=p.oid) AS tgfname,
c.relname, NULL AS tgdef
FROM pg_trigger t, pg_class c
WHERE t.tgrelid=c.oid
return $this->selectSet($sql);
}
-
+
/**
* Creates a trigger
* @param $tgname The name of the trigger to create
$this->fieldClean($tgname);
$this->fieldClean($table);
$this->fieldClean($tgproc);
-
+
/* No Statement Level Triggers in PostgreSQL (by now) */
- $sql = "CREATE TRIGGER \"{$tgname}\" {$tgtime}
+ $sql = "CREATE TRIGGER \"{$tgname}\" {$tgtime}
{$tgevent} ON \"{$table}\"
FOR EACH {$tgfrequency} EXECUTE PROCEDURE \"{$tgproc}\"({$tgargs})";
-
+
return $this->execute($sql);
}
// Pick out individual ACE's by carefully parsing. This is necessary in order
// to cope with usernames and stuff that contain commas
$aces = array();
- $i = $j = 0;
+ $i = $j = 0;
$in_quotes = false;
while ($i < strlen($acl)) {
// If current char is a double quote and it's not escaped, then
// enter quoted bit
$char = substr($acl, $i, 1);
- if ($char == '"' && ($i == 0 || substr($acl, $i - 1, 1) != '\\'))
+ if ($char == '"' && ($i == 0 || substr($acl, $i - 1, 1) != '\\'))
$in_quotes = !$in_quotes;
elseif ($char == ',' && !$in_quotes) {
// Add text so far to the array
// For each ACE, generate an entry in $temp
foreach ($aces as $v) {
-
+
// If the ACE begins with a double quote, strip them off both ends
// and unescape backslashes and double quotes
$unquote = false;
$v = str_replace('\\"', '"', $v);
$v = str_replace('\\\\', '\\', $v);
}
-
+
// Figure out type of ACE (public, user or group)
if (strpos($v, '=') === 0)
$atype = 'public';
$atype = 'user';
// Break on unquoted equals sign...
- $i = 0;
+ $i = 0;
$in_quotes = false;
$entity = null;
- $chars = null;
+ $chars = null;
while ($i < strlen($v)) {
// If current char is a double quote and it's not escaped, then
// enter quoted bit
$i++;
}
elseif ($char == '=' && !$in_quotes) {
- // Split on current equals sign
+ // Split on current equals sign
$entity = substr($v, 0, $i);
$chars = substr($v, $i + 1);
break;
}
$i++;
}
-
+
// Check for quoting on entity name, and unescape if necessary
if (strpos($entity, '"') === 0) {
$entity = substr($entity, 1, strlen($entity) - 2);
$entity = str_replace('""', '"', $entity);
}
-
+
// New row to be added to $temp
// (type, grantee, privileges, grantor, grant option?
$row = array($atype, $entity, array(), '', array());
$row[2][] = $this->privmap[$char];
}
}
-
+
// Append row to temp
$temp[] = $row;
}
return $temp;
}
-
+
/**
* Grabs an array of users and their privileges for an object,
* given its type.
elseif ($acl == '' || $acl == null) return array();
else return $this->_parseACL($acl);
}
-
+
/**
* Grants a privilege to a user, group or public
* @param $mode 'GRANT' or 'REVOKE';
* @param $object The name of the object
* @param $public True to grant to public, false otherwise
* @param $usernames The array of usernames to grant privs to.
- * @param $groupnames The array of group names to grant privs to.
+ * @param $groupnames The array of group names to grant privs to.
* @param $privileges The array of privileges to grant (eg. ('SELECT', 'ALL PRIVILEGES', etc.) )
* @param $grantoption True if has grant option, false otherwise
* @param $cascade True for cascade revoke, false otherwise
// Input checking
if (!is_array($privileges) || sizeof($privileges) == 0) return -3;
- if (!is_array($usernames) || !is_array($groupnames) ||
+ if (!is_array($usernames) || !is_array($groupnames) ||
(!$public && sizeof($usernames) == 0 && sizeof($groupnames) == 0)) return -4;
if ($mode != 'GRANT' && $mode != 'REVOKE') return -5;
// Grant option
if ($this->hasGrantOption() && $mode == 'REVOKE' && $grantoption) {
$sql .= ' GRANT OPTION FOR';
- }
+ }
if (in_array('ALL PRIVILEGES', $privileges))
$sql .= " ALL PRIVILEGES ON";
default:
return -1;
}
-
+
// Dump PUBLIC
$first = true;
$sql .= ($mode == 'GRANT') ? ' TO ' : ' FROM ';
else {
$sql .= ", \"{$v}\"";
}
- }
+ }
// Dump groups
foreach ($groupnames as $v) {
if ($first) {
else {
$sql .= ", GROUP \"{$v}\"";
}
- }
+ }
// Grant option
if ($this->hasGrantOption() && $mode == 'GRANT' && $grantoption) {
$sql .= ' WITH GRANT OPTION';
}
-
+
// Cascade revoke
if ($this->hasGrantOption() && $mode == 'REVOKE' && $cascade) {
$sql .= ' CASCADE';
return $this->execute($sql);
}
-
+
// Administration functions
/**
*/
function getFunctions($all = false) {
global $conf;
-
+
if ($all || $conf['show_system'])
$where = '';
else
AND pc.prolang = pl.oid
{$where}
UNION
- SELECT
+ SELECT
pc.oid AS prooid,
proname,
proretset,
usename as proowner
FROM
pg_proc pc, pg_user pu, pg_type pt, pg_language pl
- WHERE
+ WHERE
pc.proowner = pu.usesysid
AND pc.prorettype = 0
AND pc.prolang = pl.oid
return $this->selectSet($sql);
}
-
+
/**
* Returns a list of all functions that can be used in triggers
*/
*/
function getFunction($function_oid) {
$this->clean($function_oid);
-
- $sql = "SELECT
+
+ $sql = "SELECT
pc.oid AS prooid,
proname,
lanname AS prolanguage,
(SELECT description FROM pg_description pd WHERE pc.oid=pd.objoid) AS procomment
FROM
pg_proc pc, pg_language pl, pg_type pt
- WHERE
+ WHERE
pc.oid = '$function_oid'::oid
AND pc.prolang = pl.oid
AND pc.prorettype = pt.oid
";
-
+
return $this->selectSet($sql);
}
- /**
+ /**
* Returns an array containing a function's properties
* @param $f The array of data for the function
* @return An array containing the properties
$temp[] = 'ISCACHABLE';
else
$temp[] = '';
-
+
return $temp;
}
-
+
/**
* Updates a function. Postgres 7.1 doesn't have CREATE OR REPLACE function,
* so we do it with a drop and a recreate.
* @return -3 create function error
* @return -4 comment error
*/
- function setFunction($function_oid, $funcname, $newname, $args, $returns, $definition, $language, $flags, $setof, $comment) {
+ function setFunction($function_oid, $funcname, $newname, $args, $returns, $definition, $language, $flags, $setof, $comment) {
$status = $this->beginTransaction();
if ($status != 0) return -1;
-
+
// Drop existing function
$status = $this->dropFunction($function_oid, false);
if ($status != 0) {
$this->rollbackTransaction();
return -2;
}
-
+
// Create function with new name
$status = $this->createFunction($newname, $args, $returns, $definition, $language, $flags, $setof, false);
if ($status != 0) {
$this->rollbackTransaction();
return -3;
}
-
+
// Comment on the function
$this->fieldClean($newname);
$this->clean($comment);
$status = $this->endTransaction();
return ($status == 0) ? 0 : -1;
}
-
+
/**
* Creates a new function.
* @param $funcname The name of the function to create
$sql = "CREATE";
if ($replace) $sql .= " OR REPLACE";
$sql .= " FUNCTION \"{$funcname}\" (";
-
+
if ($args != '')
$sql .= $args;
$sql .= ") RETURNS ";
if ($setof) $sql .= "SETOF ";
$sql .= "{$returns} AS ";
-
+
if (is_array($definition)) {
$this->arrayClean($definition);
$sql .= "'" . $definition[0] . "'";
$this->clean($definition);
$sql .= "'" . $definition . "'";
}
-
+
$sql .= " LANGUAGE '{$language}'";
-
+
// Add flags
$first = true;
foreach ($flags as $v) {
return $this->execute($sql);
}
-
+
/**
* Drops a function.
* @param $function_oid The OID of the function to drop
// Function comes in with $object as function OID
$fn = $this->getFunction($function_oid);
$this->fieldClean($fn->fields['proname']);
-
+
$sql = "DROP FUNCTION \"{$fn->fields['proname']}\"({$fn->fields['proarguments']})";
if ($cascade) $sql .= " CASCADE";
-
+
return $this->execute($sql);
- }
+ }
// Language functions
-
+
/**
* Gets all languages
* @param $all True to get all languages, regardless of show_system
*/
function getLanguages($all = false) {
global $conf;
-
+
if ($conf['show_system'] || $all)
$where = '';
else
ORDER BY
lanname
";
-
+
return $this->selectSet($sql);
}
// Aggregate functions
-
+
/**
* Gets all aggregates
* @return A recordset
*/
function getAggregates() {
global $conf;
-
+
if ($conf['show_system'])
$where = '';
else
ELSE (SELECT typname FROM pg_type t WHERE t.oid=a.aggbasetype)
END AS proargtypes,
(SELECT description FROM pg_description pd WHERE a.oid=pd.objoid) AS aggcomment
- FROM
+ FROM
pg_aggregate a
{$where}
ORDER BY
$this->clean($comment);
$this->beginTransaction();
-
+
$sql = "CREATE AGGREGATE \"{$name}\" (BASETYPE = \"{$basetype}\", SFUNC = \"{$sfunc}\", STYPE = \"{$stype}\"";
if(trim($ffunc) != '') $sql .= ", FINALFUNC = \"{$ffunc}\"";
if(trim($initcond) != '') $sql .= ", INITCOND = \"{$initcond}\"";
}
return $this->endTransaction();
- }
+ }
/**
* Removes an aggregate function from the database
// Operator Class functions
-
+
/**
* Gets all opclasses
* @return A recordset
*/
function getOpClasses() {
global $conf;
-
+
if ($conf['show_system'])
$where = '';
else
$sql = "
SELECT DISTINCT
- pa.amname,
- po.opcname,
+ pa.amname,
+ po.opcname,
(SELECT typname FROM pg_type t WHERE t.oid=opcdeftype) AS opcintype,
TRUE AS opcdefault,
NULL::text AS opccomment
$parameter = ($parameter == 't');
return $parameter;
}
-
+
// Misc functions
/**
case 'TEXT SEARCH PARSER':
$sql .= "\"{$obj_name}\" IS ";
break;
- case 'FUNCTION':
+ case 'FUNCTION':
$sql .= "{$obj_name} IS ";
break;
case 'AGGREGATE':
// Begin serializable transaction (to dump consistent data)
$status = $this->beginTransaction();
if ($status != 0) return -1;
-
+
// Set serializable
$sql = "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE";
$status = $this->execute($sql);
* @param $show An array of columns to show. Empty array means all columns.
* @param $values An array mapping columns to values
* @param $ops An array of the operators to use
- * @param $orderby (optional) An array of column numbers or names (one based)
+ * @param $orderby (optional) An array of column numbers or names (one based)
* mapped to sort direction (asc or desc or '' or null) to order by
* @return The SQL query
*/
$sql = "SELECT \"{$this->id}\", \"";
else
$sql = "SELECT \"";
-
+
$sql .= join('","', $show) . "\" FROM ";
}
-
+
if ($this->hasSchemas() && isset($_REQUEST['schema'])) {
$this->fieldClean($_REQUEST['schema']);
$sql .= "\"{$_REQUEST['schema']}\".";
if (strtoupper($v) == 'DESC') $sql .= " DESC";
}
}
-
+
return $sql;
}
if (!is_object($rs)) {
return -1;
}
-
- return $rs->recordCount();
+
+ return $rs->recordCount();
}
-
+
/**
* Returns a recordset of all columns in a query. Supports paging.
* @param $type Either 'QUERY' if it is an SQL query, or 'TABLE' if it is a table identifier,
// Open a transaction
$status = $this->beginTransaction();
if ($status != 0) return -1;
-
+
// If backend supports read only queries, then specify read only mode
// to avoid side effects from repeating queries that do writes.
if ($this->hasReadOnlyQueries()) {
}
}
-
+
// Count the number of rows
$total = $this->browseQueryCount($query, $count);
if ($total < 0) {
// Calculate max pages
$max_pages = ceil($total / $page_size);
-
+
// Check that page is less than or equal to max pages
if (!is_numeric($page) || $page != (int)$page || $page > $max_pages || $page < 1) {
$this->rollbackTransaction();
$orderby .= ' DESC';
else
$orderby .= ' ASC';
- }
+ }
else $orderby = '';
// Actually retrieve the rows, with offset and limit
$this->rollbackTransaction();
return -1;
}
-
+
return $rs;
}
-
+
/**
* Returns a recordset of all columns in a relation. Used for data export.
* @@ Note: Really needs to use a cursor
*/
function dumpRelation($relation, $oids) {
$this->fieldClean($relation);
-
+
// Actually retrieve the rows
if ($oids) $oid_str = $this->id . ', ';
else $oid_str = '';
// Relations
$case_clause = "CASE WHEN relkind='r' THEN (CASE WHEN EXISTS (SELECT 1 FROM pg_rewrite r WHERE r.ev_class = pc.oid AND r.ev_type = '1') THEN 'VIEW'::VARCHAR ELSE 'TABLE'::VARCHAR END) WHEN relkind='v' THEN 'VIEW'::VARCHAR WHEN relkind='S' THEN 'SEQUENCE'::VARCHAR END";
$sql = "
- SELECT {$case_clause} AS type,
+ SELECT {$case_clause} AS type,
pc.oid, NULL::VARCHAR AS schemaname, NULL::VARCHAR AS relname, pc.relname AS name FROM pg_class pc
WHERE relkind IN ('r', 'v', 'S') AND relname ~* '.*{$term}.*'";
- if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
+ if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
if ($filter == 'TABLE' || $filter == 'VIEW' || $filter == 'SEQUENCE') $sql .= " AND {$case_clause} = '{$filter}'";
elseif ($filter != '') $sql .= " AND FALSE";
// Columns
- $sql .= "
+ $sql .= "
UNION ALL
SELECT CASE WHEN relkind='r' THEN (CASE WHEN EXISTS (SELECT 1 FROM pg_rewrite r WHERE r.ev_class = pc.oid AND r.ev_type = '1') THEN 'COLUMNVIEW'::VARCHAR ELSE 'COLUMNTABLE'::VARCHAR END) WHEN relkind='v' THEN 'COLUMNVIEW'::VARCHAR END,
NULL, NULL, pc.relname, pa.attname FROM pg_class pc,
- pg_attribute pa WHERE pc.oid=pa.attrelid
+ pg_attribute pa WHERE pc.oid=pa.attrelid
AND pa.attname ~* '.*{$term}.*' AND pa.attnum > 0 AND pc.relkind IN ('r', 'v')";
if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
if ($filter != '' && $filter != 'COLUMNTABLE' || $filter != 'COLUMNVIEW') $sql .= " AND FALSE";
WHERE proname ~* '.*{$term}.*'";
if (!$conf['show_system']) $sql .= " AND pp.oid > '{$this->_lastSystemOID}'::oid";
if ($filter != '' && $filter != 'FUNCTION') $sql .= " AND FALSE";
-
+
// Indexes
$sql .= "
UNION ALL
SELECT 'INDEX', NULL, NULL, pc.relname, pc2.relname FROM pg_class pc,
- pg_index pi, pg_class pc2 WHERE pc.oid=pi.indrelid
+ pg_index pi, pg_class pc2 WHERE pc.oid=pi.indrelid
AND pi.indexrelid=pc2.oid
AND pc2.relname ~* '.*{$term}.*' AND NOT pi.indisprimary AND NOT pi.indisunique";
if (!$conf['show_system']) $sql .= " AND pc2.relname NOT LIKE 'pg@_%' ESCAPE '@'";
SELECT 'CONSTRAINTTABLE', NULL, NULL, pc.relname, pr.rcname FROM pg_class pc,
pg_relcheck pr WHERE pc.oid=pr.rcrelid
AND pr.rcname ~* '.*{$term}.*'";
- if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
+ if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
if ($filter != '' && $filter != 'CONSTRAINT') $sql .= " AND FALSE";
-
+
// Unique and Primary Key Constraints
$sql .= "
UNION ALL
SELECT 'CONSTRAINTTABLE', NULL, NULL, pc.relname, pc2.relname FROM pg_class pc,
- pg_index pi, pg_class pc2 WHERE pc.oid=pi.indrelid
+ pg_index pi, pg_class pc2 WHERE pc.oid=pi.indrelid
AND pi.indexrelid=pc2.oid
AND pc2.relname ~* '.*{$term}.*' AND (pi.indisprimary OR pi.indisunique)";
- if (!$conf['show_system']) $sql .= " AND pc2.relname NOT LIKE 'pg@_%' ESCAPE '@'";
- if ($filter != '' && $filter != 'CONSTRAINT') $sql .= " AND FALSE";
+ if (!$conf['show_system']) $sql .= " AND pc2.relname NOT LIKE 'pg@_%' ESCAPE '@'";
+ if ($filter != '' && $filter != 'CONSTRAINT') $sql .= " AND FALSE";
// Triggers
$sql .= "
SELECT 'TRIGGER', NULL, NULL, pc.relname, pt.tgname FROM pg_class pc,
pg_trigger pt WHERE pc.oid=pt.tgrelid
AND pt.tgname ~* '.*{$term}.*'";
- if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
+ if (!$conf['show_system']) $sql .= " AND pc.relname NOT LIKE 'pg@_%' ESCAPE '@'";
if ($filter != '' && $filter != 'TRIGGER') $sql .= " AND FALSE";
// Table Rules
UNION ALL
SELECT 'RULETABLE', NULL, NULL, c.relname AS tablename, r.rulename
FROM pg_rewrite r, pg_class c
- WHERE c.relkind='r' AND NOT EXISTS (SELECT 1 FROM pg_rewrite r WHERE r.ev_class = c.oid AND r.ev_type = '1')
+ WHERE c.relkind='r' AND NOT EXISTS (SELECT 1 FROM pg_rewrite r WHERE r.ev_class = c.oid AND r.ev_type = '1')
AND r.rulename !~ '^_RET' AND c.oid = r.ev_class AND r.rulename ~* '.*{$term}.*'";
- if (!$conf['show_system']) $sql .= " AND c.relname NOT LIKE 'pg@_%' ESCAPE '@'";
+ if (!$conf['show_system']) $sql .= " AND c.relname NOT LIKE 'pg@_%' ESCAPE '@'";
if ($filter != '' && $filter != 'RULE') $sql .= " AND FALSE";
// View Rules
FROM pg_rewrite r, pg_class c
WHERE c.relkind='r' AND EXISTS (SELECT 1 FROM pg_rewrite r WHERE r.ev_class = c.oid AND r.ev_type = '1')
AND r.rulename !~ '^_RET' AND c.oid = r.ev_class AND r.rulename ~* '.*{$term}.*'";
- if (!$conf['show_system']) $sql .= " AND c.relname NOT LIKE 'pg@_%' ESCAPE '@'";
+ if (!$conf['show_system']) $sql .= " AND c.relname NOT LIKE 'pg@_%' ESCAPE '@'";
if ($filter != '' && $filter != 'RULE') $sql .= " AND FALSE";
// Advanced Objects
if ($filter != '' && $filter != 'TYPE') $sql .= " AND FALSE";
// Operators
- $sql .= "
+ $sql .= "
UNION ALL
SELECT 'OPERATOR', po.oid, NULL, NULL, po.oprname FROM pg_operator po
WHERE oprname ~* '.*{$term}.*'";
if ($filter != '' && $filter != 'OPERATOR') $sql .= " AND FALSE";
// Languages
- $sql .= "
+ $sql .= "
UNION ALL
SELECT 'LANGUAGE', pl.oid, NULL, NULL, pl.lanname FROM pg_language pl
WHERE lanname ~* '.*{$term}.*'";
if ($filter != '' && $filter != 'LANGUAGE') $sql .= " AND FALSE";
// Aggregates
- $sql .= "
+ $sql .= "
UNION ALL
- SELECT DISTINCT ON (a.aggname) 'AGGREGATE', a.oid, NULL, NULL, a.aggname FROM pg_aggregate a
+ SELECT DISTINCT ON (a.aggname) 'AGGREGATE', a.oid, NULL, NULL, a.aggname FROM pg_aggregate a
WHERE aggname ~* '.*{$term}.*'";
if (!$conf['show_system']) $sql .= " AND a.oid > '{$this->_lastSystemOID}'::oid";
if ($filter != '' && $filter != 'AGGREGATE') $sql .= " AND FALSE";
// Op Classes
- $sql .= "
+ $sql .= "
UNION ALL
SELECT DISTINCT ON (po.opcname) 'OPCLASS', po.oid, NULL, NULL, po.opcname FROM pg_opclass po
WHERE po.opcname ~* '.*{$term}.*'";
if (!$conf['show_system']) $sql .= " AND po.oid > '{$this->_lastSystemOID}'::oid";
if ($filter != '' && $filter != 'OPCLASS') $sql .= " AND FALSE";
}
-
+
$sql .= " ORDER BY type, schemaname, relname, name";
-
+
return $this->selectSet($sql);
}
- /**
+ /**
* 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
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
* 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)
+ * @param &$thislen Length of current character (ie. 1)
*/
function advance_1(&$i, &$prevlen, &$thislen) {
$prevlen = $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
$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;
$prevlen = 0;
$thislen = 0;
$lineno = 0;
-
+
// Loop over each line in the file
while (!feof($fd)) {
$line = fgets($fd, 32768);
$lineno++;
-
+
// Nothing left on line? Then ignore...
if (trim($line) == '') continue;
-
+
$len = strlen($line);
$query_start = 0;
*/
$prevlen = 0;
$thislen = ($len > 0) ? 1 : 0;
-
+
for ($i = 0; $i < $len; $this->advance_1($i, $prevlen, $thislen)) {
-
+
/* 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)
{
($bslash_count % 2 == 0 || $in_quote == '"'))
$in_quote = 0;
}
-
- /* in or end of $foo$ type quote? */
+
+ /* in or end of $foo$ type quote? */
else if ($dol_quote) {
if (strncmp(substr($line, $i), $dol_quote, strlen($dol_quote)) == 0) {
$this->advance_1($i, $prevlen, $thislen);
$dol_quote = null;
}
}
-
+
/* start of extended comment? */
else if (substr($line, $i, 2) == '/*')
{
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)
$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);
}
- /*
- * start of $foo$ type quote?
+ /*
+ * start of $foo$ type quote?
*/
else if (!$dol_quote && $this->valid_dolquote(substr($line, $i))) {
$dol_end = strpos(substr($line, $i + 1), '$');
while (substr($line, $i, 1) != '$') {
$this->advance_1($i, $prevlen, $thislen);
}
-
+
}
-
+
/* single-line comment? truncate line */
else if (substr($line, $i, 2) == '--')
{
$line = substr($line, 0, $i); /* remove comment */
break;
- }
-
+ }
+
/* count nested parentheses */
else if (substr($line, $i, 1) == '(') {
$paren_level++;
}
-
+
else if (substr($line, $i, 1) == ')' && $paren_level > 0) {
$paren_level--;
}
-
+
/* semicolon? then send query */
else if (substr($line, $i, 1) == ';' && !$bslash_count && !$paren_level)
{
if (function_exists('pg_query'))
$res = @pg_query($conn, $query_buf);
else
- $res = @pg_exec($conn, $query_buf);
+ $res = @pg_exec($conn, $query_buf);
// Call the callback function for display
if ($callback !== null) $callback($query_buf, $res, $lineno);
// Check for COPY request
break;
}
}
- }
+ }
}
-
+
$query_buf = null;
$query_start = $i + $thislen;
}
-
+
/*
- * keyword or identifier?
+ * 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);
} // end for
/* Put the rest of the line in the query buffer. */
- $subline = substr($line, $query_start);
+ $subline = substr($line, $query_start);
if ($in_quote || $dol_quote || strspn($subline, " \t\n\r") != strlen($subline))
{
if (strlen($query_buf) > 0)
$query_buf .= "\n";
$query_buf .= $subline;
}
-
+
$line = null;
-
+
} // end while
/*
break;
}
}
- }
+ }
}
-
+
fclose($fd);
-
+
return true;
}
function hasAlterDatabaseRename() { return false; }
function hasAlterDatabase() { return $this->hasAlterDatabaseRename(); }
function hasSchemas() { return false; }
- function hasConversions() { return false; }
+ function hasConversions() { return false; }
function hasGrantOption() { return false; }
function hasIsClustered() { return false; }
function hasDropBehavior() { return false; }
function hasAlterTrigger() { return false; }
function hasWithoutOIDs() { return false; }
function hasAlterTableOwner() { return false; }
+ function hasAlterSequenceOwner() { return false; }
+ function hasAlterSequenceProps() { return false; }
function hasPartialIndexes() { return false; }
function hasCasts() { return false; }
function hasFullSubqueries() { return false; }
function hasServerAdminFuncs() { return false; }
function hasRoles() { return false; }
function hasAutovacuum() { return false; }
- function hasAlterSequence() { return false; }
function hasLocksView() { return false; }
function hasPreparedXacts() { return false; }
function hasDisableTriggers() { return false; }
/**
* PostgreSQL 8.3 support
*
- * $Id: Postgres83.php,v 1.8 2007/10/03 17:32:07 ioguix Exp $
+ * $Id: Postgres83.php,v 1.9 2007/10/17 15:55:33 ioguix Exp $
*/
include_once('./classes/database/Postgres82.php');
class Postgres83 extends Postgres82 {
var $major_version = 8.3;
-
+
// Last oid assigned to a system object
var $_lastSystemOID = 17231; // need to confirm this once we get to beta!!!
}
// Help functions
-
+
function getHelpPages() {
include_once('./help/PostgresDoc83.php');
return $this->help_page;
* Returns table locks information in the current database
* @return A recordset
*/
-
+
function getLocks() {
global $conf;
else
$where = "AND nspname !~ '^pg_t(emp_[0-9]+|oast)$'";
- $sql = "SELECT
- pn.nspname, pc.relname AS tablename, pl.pid, pl.mode, pl.granted, pl.virtualtransaction,
- (select transactionid from pg_catalog.pg_locks l2 where l2.locktype='transactionid'
+ $sql = "SELECT
+ pn.nspname, pc.relname AS tablename, pl.pid, pl.mode, pl.granted, pl.virtualtransaction,
+ (select transactionid from pg_catalog.pg_locks l2 where l2.locktype='transactionid'
and l2.mode='ExclusiveLock' and l2.virtualtransaction=pl.virtualtransaction) as transaction
- FROM
+ FROM
pg_catalog.pg_locks pl,
- pg_catalog.pg_class pc,
+ pg_catalog.pg_class pc,
pg_catalog.pg_namespace pn
- WHERE
- pl.relation = pc.oid
- AND
- pc.relnamespace=pn.oid
+ WHERE
+ pl.relation = pc.oid
+ AND
+ pc.relnamespace=pn.oid
{$where}
- ORDER BY
+ ORDER BY
pid,nspname,tablename";
return $this->selectSet($sql);
}
// Views functions
-
+
/**
* Alters a view
* @param $view The name of the view
*/
function alterView($view, $name, $owner, $comment) {
$this->fieldClean($view);
-
+
$this->fieldClean($name);
$this->fieldClean($owner);
$this->clean($comment);
-
+
$status = $this->beginTransaction();
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
// Comment
$status = $this->setComment('VIEW', $view, '', $comment);
if ($status != 0) {
$this->rollbackTransaction();
return -4;
}
-
+
// Owner
if ($owner != '') {
// Fetch existing owner
$this->rollbackTransaction();
return -5;
}
-
+
// If owner has been changed, then do the alteration. We are
// careful to avoid this generally as changing owner is a
// superuser only function.
}
}
}
-
+
// Rename (only if name has changed)
if ($name != $view) {
$sql = "ALTER VIEW \"{$view}\" RENAME TO \"{$name}\"";
$status = $this->execute($sql);
if ($status != 0) {
$this->rollbackTransaction();
- return -3;
- }
+ return -3;
+ }
}
-
+
return $this->endTransaction();
}
* @return 0 success
*/
function clusterIndex($index, $table) {
-
- $this->fieldClean($index);
+
+ $this->fieldClean($index);
$this->fieldClean($table);
// We don't bother with a transaction here, as there's no point rolling
- // back an expensive cluster if a cheap analyze fails for whatever reason
+ // back an expensive cluster if a cheap analyze fails for whatever reason
$sql = "CLUSTER \"{$table}\" USING \"{$index}\"";
- return $this->execute($sql);
+ return $this->execute($sql);
+ }
+
+ // Sequence functions
+
+ /**
+ * Rename a sequence
+ * @param $sequence The sequence name
+ * @param $name The new name for the sequence
+ * @return 0 success
+ */
+ function renameSequence($sequence, $name) {
+ $this->fieldClean($name);
+ $this->fieldClean($sequence);
+
+ $sql = "ALTER SEQUENCE \"{$sequence}\" RENAME TO \"{$name}\"";
+ return $this->execute($sql);
}
// Operator Class functions
/**
* Gets all opclasses
- *
+ *
* * @return A recordset
*/
* Creates a new FTS configuration.
* @param string $cfgname The name of the FTS configuration to create
* @param string $parser The parser to be used in new FTS configuration
- * @param string $locale Locale of the FTS configuration
+ * @param string $locale Locale of the FTS configuration
* @param string $template The existing FTS configuration to be used as template for the new one
* @param string $withmap Should we copy whole map of existing FTS configuration to the new one
- * @param string $makeDefault Should this configuration be the default for locale given
+ * @param string $makeDefault Should this configuration be the default for locale given
* @param string $comment If omitted, defaults to nothing
* @return 0 success
*/
$this->fieldClean($template);
$this->fieldClean($parser);
$this->clean($comment);
-
+
$sql = "CREATE TEXT SEARCH CONFIGURATION \"{$cfgname}\"";
if ($parser != '') $sql .= " PARSER \"{$parser}\"";
if ($template != '') {
$sql .= " LIKE \"{$template}\"";
if ($withMap != '') $sql .= " WITH MAP";
- }
-
+ }
+
if ($comment != '') {
$status = $this->beginTransaction();
if ($status != 0) return -1;
}
-
+
// Create the FTS configuration
$status = $this->execute($sql);
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
// Set the comment
if ($comment != '') {
$status = $this->setComment('TEXT SEARCH CONFIGURATION', $cfgname, '', $comment);
$this->rollbackTransaction();
return -1;
}
-
+
return $this->endTransaction();
}
-
+
return 0;
}
-
-
+
+
/**
* Returns all FTS configurations available
*/
function getFtsConfigurations() {
- $sql = "SELECT
+ $sql = "SELECT
n.nspname as schema,
c.cfgname as name,
pg_catalog.obj_description(c.oid, 'pg_ts_config') as comment
- FROM
+ FROM
pg_catalog.pg_ts_config c
- JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace
- WHERE
+ JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace
+ WHERE
pg_catalog.pg_ts_config_is_visible(c.oid)
- ORDER BY
+ ORDER BY
schema, name";
return $this->selectSet($sql);
}
-
+
/**
* Return all information related to a FTS configuration
* @param $ftscfg The name of the FTS configuration
*/
function getFtsConfigurationByName($ftscfg) {
$this->clean($ftscfg);
- $sql = "SELECT
+ $sql = "SELECT
n.nspname as schema,
c.cfgname as name,
p.prsname as parser,
c.cfgparser as parser_id,
pg_catalog.obj_description(c.oid, 'pg_ts_config') as comment
FROM pg_catalog.pg_ts_config c
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace
LEFT JOIN pg_catalog.pg_ts_parser p ON p.oid = c.cfgparser
WHERE pg_catalog.pg_ts_config_is_visible(c.oid)
AND c.cfgname = '{$ftscfg}'";
-
+
return $this->selectSet($sql);
}
-
-
+
+
/**
* Returns the map of FTS configuration given (list of mappings (tokens) and their processing dictionaries)
- *
- * @param string $ftscfg Name of the FTS configuration
+ *
+ * @param string $ftscfg Name of the FTS configuration
*/
function getFtsConfigurationMap($ftscfg) {
$this->fieldClean($ftscfg);
$getOidSql = "SELECT oid FROM pg_catalog.pg_ts_config WHERE cfgname = '{$ftscfg}'";
$oidSet = $this->selectSet($getOidSql);
$oid = $oidSet->fields['oid'];
-
+
$sql = " SELECT
(SELECT t.alias FROM pg_catalog.ts_token_type(c.cfgparser) AS t WHERE t.tokid = m.maptokentype) AS name,
(SELECT t.description FROM pg_catalog.ts_token_type(c.cfgparser) AS t WHERE t.tokid = m.maptokentype) AS description,
,n.nspname ||'.'|| d.dictname as dictionaries
FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m, pg_catalog.pg_ts_dict d, pg_catalog.pg_namespace n
WHERE c.oid = {$oid} AND m.mapcfg = c.oid and m.mapdict = d.oid and d.dictnamespace = n.oid
- ORDER BY name
+ ORDER BY name
";
return $this->selectSet($sql);
}
-
+
/**
* Returns all FTS parsers available
*/
function getFtsParsers() {
- $sql = "SELECT
+ $sql = "SELECT
n.nspname as schema,
p.prsname as name,
pg_catalog.obj_description(p.oid, 'pg_ts_parser') as comment
- FROM pg_catalog.pg_ts_parser p
+ FROM pg_catalog.pg_ts_parser p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace WHERE pg_catalog.pg_ts_parser_is_visible(p.oid)
ORDER BY schema, name";
return $this->selectSet($sql);
}
-
+
/**
* Returns all FTS dictionaries available
*/
function getFtsDictionaries() {
- $sql = "SELECT
+ $sql = "SELECT
n.nspname as schema,
d.dictname as name,
pg_catalog.obj_description(d.oid, 'pg_ts_dict') as comment
FROM pg_catalog.pg_ts_dict d
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace
WHERE pg_catalog.pg_ts_dict_is_visible(d.oid)
ORDER BY schema, name;";
return $this->selectSet($sql);
}
-
+
/**
* Returns all FTS dictionary templates available
*/
function getFtsDictionaryTemplates() {
- $sql = "SELECT
+ $sql = "SELECT
n.nspname as schema,
t.tmplname as name,
- ( SELECT COALESCE(np.nspname, '(null)')::pg_catalog.text || '.' || p.proname FROM
- pg_catalog.pg_proc p
- LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.pronamespace
- WHERE t.tmplinit = p.oid ) AS init,
- ( SELECT COALESCE(np.nspname, '(null)')::pg_catalog.text || '.' || p.proname FROM
- pg_catalog.pg_proc p
- LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.pronamespace
- WHERE t.tmpllexize = p.oid ) AS lexize,
+ ( SELECT COALESCE(np.nspname, '(null)')::pg_catalog.text || '.' || p.proname FROM
+ pg_catalog.pg_proc p
+ LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.pronamespace
+ WHERE t.tmplinit = p.oid ) AS init,
+ ( SELECT COALESCE(np.nspname, '(null)')::pg_catalog.text || '.' || p.proname FROM
+ pg_catalog.pg_proc p
+ LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.pronamespace
+ WHERE t.tmpllexize = p.oid ) AS lexize,
pg_catalog.obj_description(t.oid, 'pg_ts_template') as comment
FROM pg_catalog.pg_ts_template t
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace
WHERE pg_catalog.pg_ts_template_is_visible(t.oid)
ORDER BY schema, name;";
return $this->selectSet($sql);
}
-
+
/**
* Drops FTS coniguration
- */
+ */
function dropFtsConfiguration($ftscfg, $cascade) {
$this->fieldClean($ftscfg);
-
+
$sql = "DROP TEXT SEARCH CONFIGURATION \"{$ftscfg}\"";
if ($cascade) $sql .= " CASCADE";
-
+
return $this->execute($sql);
}
-
+
/**
* Drops FTS dictionary
- *
+ *
* @todo Support of dictionary templates dropping
- */
+ */
function dropFtsDictionary($ftsdict, $cascade = true) {
$this->fieldClean($ftsdict);
-
+
$sql = "DROP TEXT SEARCH DICTIONARY";
$sql .= " \"{$ftsdict}\"";
if ($cascade) $sql .= " CASCADE";
-
+
return $this->execute($sql);
}
-
+
/**
* Alters FTS configuration
*/
$this->fieldClean($cfgname);
$this->fieldClean($name);
$this->clean($comment);
-
+
$status = $this->beginTransaction();
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
$status = $this->setComment('TEXT SEARCH CONFIGURATION', $cfgname, '', $comment);
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
// Only if the name has changed
if ($name != $cfgname) {
$sql = "ALTER TEXT SEARCH CONFIGURATION \"{$cfgname}\" RENAME TO \"{$name}\"";
return -1;
}
}
-
+
// Only if parser is defined
if ($prsname) {
$sql = "ALTER TEXT SEARCH CONFIGURATION \"{$cfgname}\" SET PARSER \"{$prsname}\"";
return -1;
}
}
-
+
return $this->endTransaction();
}
-
+
/**
- * Creates a new FTS dictionary or FTS dictionary template.
+ * Creates a new FTS dictionary or FTS dictionary template.
* @param string $dictname The name of the FTS dictionary to create
* @param boolean $isTemplate Flag whether we create usual dictionary or dictionary template
* @param string $template The existing FTS dictionary to be used as template for the new one
* @param string $lexize The name of the function, which does transformation of input word
- * @param string $init The name of the function, which initializes dictionary
+ * @param string $init The name of the function, which initializes dictionary
* @param string $option Usually, it stores various options required for the dictionary
* @param string $comment If omitted, defaults to nothing
* @return 0 success
$this->fieldClean($init);
$this->fieldClean($option);
$this->clean($comment);
-
+
$sql = "CREATE TEXT SEARCH DICTIONARY";
if ($isTemplate) {
$sql .= " TEMPLATE \"{$dictname}\"";
if ($option != '') $sql .= " OPTION \"{$option}\"";
$whatToComment = 'TEXT SEARCH DICTIONARY';
}
-
+
if ($comment != '') {
$status = $this->beginTransaction();
if ($status != 0) return -1;
}
-
+
// Create the FTS dictionary
$status = $this->execute($sql);
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
// Set the comment
if ($comment != '') {
$status = $this->setComment($whatToComment, $dictname, '', $comment);
return -1;
}
}
-
+
return $this->endTransaction();
}
-
+
/**
* Alters FTS dictionary or dictionary template
*/
$this->fieldClean($dictname);
$this->fieldClean($name);
$this->clean($comment);
-
+
$status = $this->beginTransaction();
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
$status = $this->setComment('TEXT SEARCH DICTIONARY', $dictname, '', $comment);
if ($status != 0) {
$this->rollbackTransaction();
return -1;
}
-
+
// Only if the name has changed
if ($name != $dictname) {
$sql = "ALTER TEXT SEARCH CONFIGURATION \"{$dictname}\" RENAME TO \"{$name}\"";
return -1;
}
}
-
+
return $this->endTransaction();
}
-
+
/**
* Return all information relating to a FTS dictionary
* @param $ftsdict The name of the FTS dictionary
*/
function getFtsDictionaryByName($ftsdict) {
$this->clean($ftsdict);
- $sql = "SELECT
+ $sql = "SELECT
n.nspname as schema,
d.dictname as name,
- ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM
- pg_catalog.pg_ts_template t
- LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace
- WHERE d.dicttemplate = t.oid ) AS template,
- d.dictinitoption as init,
+ ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM
+ pg_catalog.pg_ts_template t
+ LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace
+ WHERE d.dicttemplate = t.oid ) AS template,
+ d.dictinitoption as init,
pg_catalog.obj_description(d.oid, 'pg_ts_dict') as comment
FROM pg_catalog.pg_ts_dict d
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace
WHERE d.dictname = '{$ftsdict}'
AND pg_catalog.pg_ts_dict_is_visible(d.oid)
ORDER BY schema, name";
-
+
return $this->selectSet($sql);
}
-
+
/**
* Creates/updates/deletes FTS mapping.
* @param string $cfgname The name of the FTS configuration to alter
* @param array $mapping Array of tokens' names
* @param string $action What to do with the mapping: add, alter or drop
- * @param string $dictname Dictionary that will process tokens given or null in case of drop action
+ * @param string $dictname Dictionary that will process tokens given or null in case of drop action
* @return 0 success
*/
function changeFtsMapping($ftscfg, $mapping, $action, $dictname = null) {
$this->fieldClean($ftscfg);
$this->fieldClean($dictname);
$this->arrayClean($mapping);
-
+
if (count($mapping) > 0) {
switch ($action) {
case 'alter':
}
$sql = "ALTER TEXT SEARCH CONFIGURATION \"{$ftscfg}\" {$whatToDo} MAPPING FOR ";
$sql .= implode(",", $mapping);
- if ($action != 'drop' && !empty($dictname)) {
+ if ($action != 'drop' && !empty($dictname)) {
$sql .= " WITH {$dictname}";
}
-
+
$status = $this->beginTransaction();
if ($status != 0) {
$this->rollbackTransaction();
$this->rollbackTransaction();
return -1;
}
- return $this->endTransaction();
+ return $this->endTransaction();
} else {
return -1;
}
}
-
+
/**
* Return all information related to a given FTS configuration's mapping
* @param $ftscfg The name of the FTS configuration
- * @param $mapping The name of the mapping
+ * @param $mapping The name of the mapping
* @return FTS configuration information
*/
function getFtsMappingByName($ftscfg, $mapping) {
$this->fieldClean($ftscfg);
$this->fieldClean($mapping);
-
+
$getOidSql = "SELECT oid, cfgparser FROM pg_catalog.pg_ts_config WHERE cfgname = '{$ftscfg}'";
$oidSet = $this->selectSet($getOidSql);
$oid = $oidSet->fields['oid'];
$cfgparser = $oidSet->fields['cfgparser'];
-
+
$getTokenIdSql = "SELECT tokid FROM pg_catalog.ts_token_type({$cfgparser}) WHERE alias = '{$mapping}'";
$tokenIdSet = $this->selectSet($getTokenIdSql);
$tokid = $tokenIdSet->fields['tokid'];
-
- $sql = "SELECT
+
+ $sql = "SELECT
(SELECT t.alias FROM pg_catalog.ts_token_type(c.cfgparser) AS t WHERE t.tokid = m.maptokentype) AS name,
d.dictname as dictionaries
FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m, pg_catalog.pg_ts_dict d
- WHERE c.oid = {$oid} AND m.mapcfg = c.oid AND m.maptokentype = {$tokid} AND m.mapdict = d.oid
+ WHERE c.oid = {$oid} AND m.mapcfg = c.oid AND m.maptokentype = {$tokid} AND m.mapdict = d.oid
LIMIT 1;";
return $this->selectSet($sql);
}
-
+
/**
* Return list of FTS mappings possible for given parser (specified by given configuration since configuration
* can only have 1 parser)
$sql = "SELECT alias AS name, description FROM pg_catalog.ts_token_type({$cfg->fields['parser_id']}) ORDER BY name";
return $this->selectSet($sql);
}
-
+
// Type functions
-
+
/**
* Creates a new enum type in the database
* @param $name The name of the type
}
return $this->endTransaction();
-
+
}
/**