Initial commit
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Really simple RecordSet to allow printTable of arrays.
|
||||
*
|
||||
* $Id: ArrayRecordSet.php,v 1.3 2007/01/10 01:46:28 soranzo Exp $
|
||||
*/
|
||||
class ArrayRecordSet {
|
||||
|
||||
var $_array;
|
||||
var $_count;
|
||||
var $EOF = false;
|
||||
var $fields;
|
||||
|
||||
function ArrayRecordSet($data) {
|
||||
$this->_array = $data;
|
||||
$this->_count = count($this->_array);
|
||||
$this->fields = reset($this->_array);
|
||||
if ($this->fields === false) $this->EOF = true;
|
||||
}
|
||||
|
||||
function recordCount() {
|
||||
return $this->_count;
|
||||
}
|
||||
|
||||
function moveNext() {
|
||||
$this->fields = next($this->_array);
|
||||
if ($this->fields === false) $this->EOF = true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to handle basic HTML GUI functions
|
||||
*
|
||||
* $Id: Gui.php,v 1.2 2004/06/07 20:03:22 soranzo Exp $
|
||||
*/
|
||||
class GUI {
|
||||
|
||||
/**
|
||||
*Constructor
|
||||
*/
|
||||
function GUI () {}
|
||||
|
||||
/**
|
||||
* Finds a particular report
|
||||
* @param $arrOptions associative array storing options and values of combo should be Option => Value
|
||||
* @param $szName string to specify the name of the form element
|
||||
* @param (optional) $bBlankEntry bool to specify whether or not we want a blank selection
|
||||
* @param (optional) $szDefault string to specify the default VALUE selected
|
||||
* @param (optional) $bMultiple bool to specify whether or not we want a multi select combo box
|
||||
* @param (optional) $iSize int to specify the size IF a multi select combo
|
||||
* @return string with the generated HTML select box
|
||||
*/
|
||||
function printCombo(&$arrOptions, $szName, $bBlankEntry = true, $szDefault = '', $bMultiple = false, $iSize = 10) {
|
||||
$htmlOut = '';
|
||||
if ($bMultiple) // If multiple select combo
|
||||
$htmlOut .= "<select name=\"$szName\" id=\"$szName\" multiple=\"multiple\" size=\"$iSize\">\n";
|
||||
else
|
||||
$htmlOut .= "<select name=\"$szName\" id=\"$szName\">\n";
|
||||
if ($bBlankEntry)
|
||||
$htmlOut .= "<option value=\"\"></option>\n";
|
||||
|
||||
foreach ($arrOptions AS $curKey => $curVal) {
|
||||
$curVal = htmlspecialchars($curVal);
|
||||
$curKey = htmlspecialchars($curKey);
|
||||
if ($curVal == $szDefault) {
|
||||
$htmlOut .= "<option value=\"$curVal\" selected=\"selected\">$curKey</option>\n";
|
||||
}
|
||||
else {
|
||||
$htmlOut .= "<option value=\"$curVal\">$curKey</option>\n";
|
||||
}
|
||||
}
|
||||
$htmlOut .= "</select>\n";
|
||||
|
||||
return $htmlOut;
|
||||
}
|
||||
}
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to manage reports. Note how this class is designed to use
|
||||
* the functions provided by the database driver exclusively, and hence
|
||||
* will work with any database without modification.
|
||||
*
|
||||
* $Id: Reports.php,v 1.18 2007/04/16 11:02:35 mr-russ Exp $
|
||||
*/
|
||||
|
||||
class Reports {
|
||||
|
||||
// A database driver
|
||||
var $driver;
|
||||
var $reports_db = 'phppgadmin';
|
||||
var $reports_schema = 'public';
|
||||
var $reports_table = 'ppa_reports';
|
||||
|
||||
/* Constructor */
|
||||
function Reports(&$status) {
|
||||
global $conf, $misc, $data;
|
||||
|
||||
// Get data from config if it's been defined
|
||||
if (isset($conf['reports_db'])) {
|
||||
$this->reports_db = $conf['reports_db'];
|
||||
}
|
||||
if (isset($conf['reports_schema'])) {
|
||||
$this->reports_schema = $conf['reports_schema'];
|
||||
}
|
||||
if (isset($conf['reports_table'])) {
|
||||
$this->reports_table = $conf['reports_table'];
|
||||
}
|
||||
|
||||
// Check to see if the reports database exists
|
||||
$rs = $data->getDatabase($this->reports_db);
|
||||
if ($rs->recordCount() != 1) $status = -1;
|
||||
else {
|
||||
// Create a new database access object.
|
||||
$this->driver = $misc->getDatabaseAccessor($this->reports_db);
|
||||
// Reports database should have been created in public schema
|
||||
$this->driver->setSchema($this->reports_schema);
|
||||
$status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all reports
|
||||
* @return A recordset
|
||||
*/
|
||||
function getReports() {
|
||||
global $conf, $misc;
|
||||
// Filter for owned reports if necessary
|
||||
if ($conf['owned_reports_only']) {
|
||||
$server_info = $misc->getServerInfo();
|
||||
$filter['created_by'] = $server_info['username'];
|
||||
$ops = array('created_by' => '=');
|
||||
}
|
||||
else $filter = $ops = array();
|
||||
|
||||
$sql = $this->driver->getSelectSQL($this->reports_table,
|
||||
array('report_id', 'report_name', 'db_name', 'date_created', 'created_by', 'descr', 'report_sql', 'paginate'),
|
||||
$filter, $ops, array('db_name' => 'asc', 'report_name' => 'asc'));
|
||||
|
||||
return $this->driver->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a particular report
|
||||
* @param $report_id The ID of the report to find
|
||||
* @return A recordset
|
||||
*/
|
||||
function getReport($report_id) {
|
||||
$sql = $this->driver->getSelectSQL($this->reports_table,
|
||||
array('report_id', 'report_name', 'db_name', 'date_created', 'created_by', 'descr', 'report_sql', 'paginate'),
|
||||
array('report_id' => $report_id), array('report_id' => '='), array());
|
||||
|
||||
return $this->driver->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a report
|
||||
* @param $report_name The name of the report
|
||||
* @param $db_name The name of the database
|
||||
* @param $descr The comment on the report
|
||||
* @param $report_sql The SQL for the report
|
||||
* @param $paginate The report should be paginated
|
||||
* @return 0 success
|
||||
*/
|
||||
function createReport($report_name, $db_name, $descr, $report_sql, $paginate) {
|
||||
global $misc;
|
||||
$server_info = $misc->getServerInfo();
|
||||
$temp = array(
|
||||
'report_name' => $report_name,
|
||||
'db_name' => $db_name,
|
||||
'created_by' => $server_info['username'],
|
||||
'report_sql' => $report_sql,
|
||||
'paginate' => $paginate ? 'true' : 'false',
|
||||
);
|
||||
if ($descr != '') $temp['descr'] = $descr;
|
||||
|
||||
return $this->driver->insert($this->reports_table, $temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters a report
|
||||
* @param $report_id The ID of the report
|
||||
* @param $report_name The name of the report
|
||||
* @param $db_name The name of the database
|
||||
* @param $descr The comment on the report
|
||||
* @param $report_sql The SQL for the report
|
||||
* @param $paginate The report should be paginated
|
||||
* @return 0 success
|
||||
*/
|
||||
function alterReport($report_id, $report_name, $db_name, $descr, $report_sql, $paginate) {
|
||||
global $misc;
|
||||
$server_info = $misc->getServerInfo();
|
||||
$temp = array(
|
||||
'report_name' => $report_name,
|
||||
'db_name' => $db_name,
|
||||
'created_by' => $server_info['username'],
|
||||
'report_sql' => $report_sql,
|
||||
'paginate' => $paginate ? 'true' : 'false',
|
||||
'descr' => $descr
|
||||
);
|
||||
|
||||
return $this->driver->update($this->reports_table, $temp,
|
||||
array('report_id' => $report_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a report
|
||||
* @param $report_id The ID of the report to drop
|
||||
* @return 0 success
|
||||
*/
|
||||
function dropReport($report_id) {
|
||||
return $this->driver->delete($this->reports_table, array('report_id' => $report_id));
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* XHtmlSimpleElement
|
||||
*
|
||||
* Used to generate Xhtml-Code for simple xhtml elements
|
||||
* (i.e. elements, that can't contain child elements)
|
||||
*
|
||||
*
|
||||
* @author Felix Meinhold
|
||||
*
|
||||
*/
|
||||
class XHtmlSimpleElement {
|
||||
var $_element;
|
||||
var $_siblings = array();
|
||||
var $_htmlcode;
|
||||
var $_attributes = array();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string The element's name. Defaults to name of the
|
||||
* derived class
|
||||
*
|
||||
*/
|
||||
function XHtmlSimpleElement($element = null) {
|
||||
|
||||
$this->_element = $this->is_element();
|
||||
|
||||
}
|
||||
|
||||
function set_style($style) {
|
||||
$this->set_attribute('style', $style);
|
||||
}
|
||||
|
||||
function set_class($class) {
|
||||
$this->set_attribute('class', $class);
|
||||
}
|
||||
|
||||
|
||||
function is_element() {
|
||||
return
|
||||
str_replace('xhtml_', '', strtolower(get_class($this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Private function generates xhtml
|
||||
* @access private
|
||||
*/
|
||||
function _html() {
|
||||
$this->_htmlcode = "<";
|
||||
foreach ($this->_attributeCollection as $attribute => $value) {
|
||||
if (!empty($value)) $this->_htmlcode .= " {$attribute}=\"{$value}\"";
|
||||
}
|
||||
$this->_htmlcode .= "/>";
|
||||
|
||||
return $this->_htmlcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns xhtml code
|
||||
*
|
||||
*/
|
||||
function fetch() {
|
||||
return $this->_html();
|
||||
}
|
||||
/**
|
||||
* Echoes xhtml
|
||||
*
|
||||
*/
|
||||
function show() {
|
||||
echo $this->fetch();
|
||||
}
|
||||
|
||||
function set_attribute($attr, $value) {
|
||||
$this->_attributes[$attr] = $value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* XHtmlElement
|
||||
*
|
||||
* Used to generate Xhtml-Code for xhtml elements
|
||||
* that can contain child elements
|
||||
*
|
||||
*
|
||||
*/
|
||||
class XHtmlElement extends XHtmlSimpleElement {
|
||||
var $_text = null;
|
||||
var $_htmlcode = "";
|
||||
var $_siblings = array();
|
||||
|
||||
function XHtmlElement($text = null) {
|
||||
XHtmlSimpleElement::XHtmlSimpleElement();
|
||||
|
||||
if ($text) $this->set_text($text);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an xhtml child to element
|
||||
*
|
||||
* @param XHtmlElement The element to become a child of element
|
||||
*/
|
||||
function add(&$object) {
|
||||
array_push($this->_siblings, $object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The CDATA section of Element
|
||||
*
|
||||
* @param string Text
|
||||
*/
|
||||
function set_text($text) {
|
||||
if ($text) $this->_text = htmlspecialchars($text);
|
||||
}
|
||||
|
||||
function fetch() {
|
||||
return $this->_html();
|
||||
}
|
||||
|
||||
|
||||
function _html() {
|
||||
|
||||
$this->_htmlcode = "<{$this->_element}";
|
||||
foreach ($this->_attributes as $attribute =>$value) {
|
||||
if (!empty($value)) $this->_htmlcode .= " {$attribute} =\"{$value}\"";
|
||||
}
|
||||
$this->_htmlcode .= ">";
|
||||
|
||||
|
||||
if ($this->_text) {
|
||||
$this->_htmlcode .= $this->_text;
|
||||
}
|
||||
|
||||
foreach ($this->_siblings as $obj) {
|
||||
$this->_htmlcode .= $obj->fetch();
|
||||
}
|
||||
|
||||
$this->_htmlcode .= "</{$this->_element}>";
|
||||
|
||||
return $this->_htmlcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns siblings of Element
|
||||
*
|
||||
*/
|
||||
function get_siblings() {
|
||||
return $this->_siblings;
|
||||
}
|
||||
|
||||
function has_siblings() {
|
||||
return (count($this->_siblings) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
class XHTML_Button extends XHtmlElement {
|
||||
function XHTML_Button ($name, $text = null) {
|
||||
parent::XHtmlElement();
|
||||
|
||||
$this->set_attribute("name", $name);
|
||||
|
||||
if ($text) $this->set_text($text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class XHTML_Option extends XHtmlElement {
|
||||
function XHTML_Option($text, $value = null) {
|
||||
XHtmlElement::XHtmlElement(null);
|
||||
$this->set_text($text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class XHTML_Select extends XHTMLElement {
|
||||
var $_data;
|
||||
|
||||
function XHTML_Select ($name, $multiple = false, $size = null) {
|
||||
XHtmlElement::XHtmlElement();
|
||||
|
||||
$this->set_attribute("name", $name);
|
||||
if ($multiple) $this->set_attribute("multiple","multiple");
|
||||
if ($size) $this->set_attribute("size",$size);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function set_data(&$data, $delim = ",") {
|
||||
switch (gettype($data)) {
|
||||
case "string":
|
||||
$this->_data = explode($delim, $data);
|
||||
break;
|
||||
case "array":
|
||||
$this->_data = $data;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function fetch() {
|
||||
if (isset($this->_data) && $this->_data) {
|
||||
foreach ($this->_data as $value) { $this->add(new XHTML_Option($value)); }
|
||||
}
|
||||
return parent::fetch();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Parent class of all ADODB objects.
|
||||
*
|
||||
* $Id: ADODB_base.php,v 1.24 2008/02/20 20:43:10 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./libraries/errorhandler.inc.php');
|
||||
include_once('./libraries/adodb/adodb.inc.php');
|
||||
|
||||
class ADODB_base {
|
||||
|
||||
var $conn;
|
||||
|
||||
// The backend platform. Set to UNKNOWN by default.
|
||||
var $platform = 'UNKNOWN';
|
||||
|
||||
/**
|
||||
* Base constructor
|
||||
* @param &$conn The connection object
|
||||
*/
|
||||
function ADODB_base(&$conn) {
|
||||
$this->conn = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on or off query debugging
|
||||
* @param $debug True to turn on debugging, false otherwise
|
||||
*/
|
||||
function setDebug($debug) {
|
||||
$this->conn->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans (escapes) a string
|
||||
* @param $str The string to clean, by reference
|
||||
* @return The cleaned string
|
||||
*/
|
||||
function clean(&$str) {
|
||||
$str = addslashes($str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans (escapes) an object name (eg. table, field)
|
||||
* @param $str The string to clean, by reference
|
||||
* @return The cleaned string
|
||||
*/
|
||||
function fieldClean(&$str) {
|
||||
$str = str_replace('"', '""', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans (escapes) an array
|
||||
* @param $arr The array to clean, by reference
|
||||
* @return The cleaned array
|
||||
*/
|
||||
function arrayClean(&$arr) {
|
||||
reset($arr);
|
||||
while(list($k, $v) = each($arr))
|
||||
$arr[$k] = addslashes($v);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query on the underlying connection
|
||||
* @param $sql The SQL query to execute
|
||||
* @return A recordset
|
||||
*/
|
||||
function execute($sql) {
|
||||
// Execute the statement
|
||||
$rs = $this->conn->Execute($sql);
|
||||
|
||||
// If failure, return error value
|
||||
return $this->conn->ErrorNo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection the database class
|
||||
* relies on.
|
||||
*/
|
||||
function close() {
|
||||
$this->conn->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a ResultSet from a query
|
||||
* @param $sql The SQL statement to be executed
|
||||
* @return A recordset
|
||||
*/
|
||||
function selectSet($sql) {
|
||||
// Execute the statement
|
||||
$rs = $this->conn->Execute($sql);
|
||||
|
||||
if (!$rs) return $this->conn->ErrorNo();
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a single value from a query
|
||||
*
|
||||
* @@ assumes that the query will return only one row - returns field value in the first row
|
||||
*
|
||||
* @param $sql The SQL statement to be executed
|
||||
* @param $field The field name to be returned
|
||||
* @return A single field value
|
||||
* @return -1 No rows were found
|
||||
*/
|
||||
function selectField($sql, $field) {
|
||||
// Execute the statement
|
||||
$rs = $this->conn->Execute($sql);
|
||||
|
||||
// If failure, or no rows returned, return error value
|
||||
if (!$rs) return $this->conn->ErrorNo();
|
||||
elseif ($rs->RecordCount() == 0) return -1;
|
||||
|
||||
return $rs->fields[$field];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the database
|
||||
* @param $table The name of the table
|
||||
* @param $conditions (array) A map of field names to conditions
|
||||
* @param $schema (optional) The table's schema
|
||||
* @return 0 success
|
||||
* @return -1 on referential integrity violation
|
||||
* @return -2 on no rows deleted
|
||||
*/
|
||||
function delete($table, $conditions, $schema = '') {
|
||||
$this->fieldClean($table);
|
||||
|
||||
reset($conditions);
|
||||
|
||||
if (!empty($schema)) {
|
||||
$this->fieldClean($schema);
|
||||
$schema = "\"{$schema}\".";
|
||||
}
|
||||
|
||||
// Build clause
|
||||
$sql = '';
|
||||
while(list($key, $value) = each($conditions)) {
|
||||
$this->clean($key);
|
||||
$this->clean($value);
|
||||
if ($sql) $sql .= " AND \"{$key}\"='{$value}'";
|
||||
else $sql = "DELETE FROM {$schema}\"{$table}\" WHERE \"{$key}\"='{$value}'";
|
||||
}
|
||||
|
||||
// Check for failures
|
||||
if (!$this->conn->Execute($sql)) {
|
||||
// Check for referential integrity failure
|
||||
if (stristr($this->conn->ErrorMsg(), 'referential'))
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check for no rows modified
|
||||
if ($this->conn->Affected_Rows() == 0) return -2;
|
||||
|
||||
return $this->conn->ErrorNo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a set of values into the database
|
||||
* @param $table The table to insert into
|
||||
* @param $vars (array) A mapping of the field names to the values to be inserted
|
||||
* @return 0 success
|
||||
* @return -1 if a unique constraint is violated
|
||||
* @return -2 if a referential constraint is violated
|
||||
*/
|
||||
function insert($table, $vars) {
|
||||
$this->fieldClean($table);
|
||||
|
||||
// Build clause
|
||||
if (sizeof($vars) > 0) {
|
||||
$fields = '';
|
||||
$values = '';
|
||||
foreach($vars as $key => $value) {
|
||||
$this->clean($key);
|
||||
$this->clean($value);
|
||||
|
||||
if ($fields) $fields .= ", \"{$key}\"";
|
||||
else $fields = "INSERT INTO \"{$table}\" (\"{$key}\"";
|
||||
|
||||
if ($values) $values .= ", '{$value}'";
|
||||
else $values = ") VALUES ('{$value}'";
|
||||
}
|
||||
$sql = $fields . $values . ')';
|
||||
}
|
||||
|
||||
// Check for failures
|
||||
if (!$this->conn->Execute($sql)) {
|
||||
// Check for unique constraint failure
|
||||
if (stristr($this->conn->ErrorMsg(), 'unique'))
|
||||
return -1;
|
||||
// Check for referential integrity failure
|
||||
elseif (stristr($this->conn->ErrorMsg(), 'referential'))
|
||||
return -2;
|
||||
}
|
||||
|
||||
return $this->conn->ErrorNo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a row in the database
|
||||
* @param $table The table that is to be updated
|
||||
* @param $vars (array) A mapping of the field names to the values to be updated
|
||||
* @param $where (array) A mapping of field names to values for the where clause
|
||||
* @param $nulls (array, optional) An array of fields to be set null
|
||||
* @return 0 success
|
||||
* @return -1 if a unique constraint is violated
|
||||
* @return -2 if a referential constraint is violated
|
||||
* @return -3 on no rows deleted
|
||||
*/
|
||||
function update($table, $vars, $where, $nulls = array()) {
|
||||
$this->fieldClean($table);
|
||||
|
||||
$setClause = '';
|
||||
$whereClause = '';
|
||||
|
||||
// Populate the syntax arrays
|
||||
reset($vars);
|
||||
while(list($key, $value) = each($vars)) {
|
||||
$this->fieldClean($key);
|
||||
$this->clean($value);
|
||||
if ($setClause) $setClause .= ", \"{$key}\"='{$value}'";
|
||||
else $setClause = "UPDATE \"{$table}\" SET \"{$key}\"='{$value}'";
|
||||
}
|
||||
|
||||
reset($nulls);
|
||||
while(list(, $value) = each($nulls)) {
|
||||
$this->fieldClean($value);
|
||||
if ($setClause) $setClause .= ", \"{$value}\"=NULL";
|
||||
else $setClause = "UPDATE \"{$table}\" SET \"{$value}\"=NULL";
|
||||
}
|
||||
|
||||
reset($where);
|
||||
while(list($key, $value) = each($where)) {
|
||||
$this->fieldClean($key);
|
||||
$this->clean($value);
|
||||
if ($whereClause) $whereClause .= " AND \"{$key}\"='{$value}'";
|
||||
else $whereClause = " WHERE \"{$key}\"='{$value}'";
|
||||
}
|
||||
|
||||
// Check for failures
|
||||
if (!$this->conn->Execute($setClause . $whereClause)) {
|
||||
// Check for unique constraint failure
|
||||
if (stristr($this->conn->ErrorMsg(), 'unique'))
|
||||
return -1;
|
||||
// Check for referential integrity failure
|
||||
elseif (stristr($this->conn->ErrorMsg(), 'referential'))
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Check for no rows modified
|
||||
if ($this->conn->Affected_Rows() == 0) return -3;
|
||||
|
||||
return $this->conn->ErrorNo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a transaction
|
||||
* @return 0 success
|
||||
*/
|
||||
function beginTransaction() {
|
||||
return !$this->conn->BeginTrans();
|
||||
}
|
||||
|
||||
/**
|
||||
* End a transaction
|
||||
* @return 0 success
|
||||
*/
|
||||
function endTransaction() {
|
||||
return !$this->conn->CommitTrans();
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back a transaction
|
||||
* @return 0 success
|
||||
*/
|
||||
function rollbackTransaction() {
|
||||
return !$this->conn->RollbackTrans();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the backend platform
|
||||
* @return The backend platform
|
||||
*/
|
||||
function getPlatform() {
|
||||
//return $this->conn->platform;
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
// Type conversion routines
|
||||
|
||||
/**
|
||||
* Change the value of a parameter to database representation depending on whether it evaluates to true or false
|
||||
* @param $parameter the parameter
|
||||
*/
|
||||
function dbBool(&$parameter) {
|
||||
return $parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a parameter from database representation to a boolean, (others evaluate to false)
|
||||
* @param $parameter the parameter
|
||||
*/
|
||||
function phpBool($parameter) {
|
||||
return $parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a db array into a PHP array
|
||||
* @param $arr String representing the DB array
|
||||
* @return A PHP array
|
||||
*/
|
||||
function phpArray($dbarr) {
|
||||
// Take off the first and last characters (the braces)
|
||||
$arr = substr($dbarr, 1, strlen($dbarr) - 2);
|
||||
|
||||
// Pick out array entries by carefully parsing. This is necessary in order
|
||||
// to cope with double quotes and commas, etc.
|
||||
$elements = array();
|
||||
$i = $j = 0;
|
||||
$in_quotes = false;
|
||||
while ($i < strlen($arr)) {
|
||||
// If current char is a double quote and it's not escaped, then
|
||||
// enter quoted bit
|
||||
$char = substr($arr, $i, 1);
|
||||
if ($char == '"' && ($i == 0 || substr($arr, $i - 1, 1) != '\\'))
|
||||
$in_quotes = !$in_quotes;
|
||||
elseif ($char == ',' && !$in_quotes) {
|
||||
// Add text so far to the array
|
||||
$elements[] = substr($arr, $j, $i - $j);
|
||||
$j = $i + 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
// Add final text to the array
|
||||
$elements[] = substr($arr, $j);
|
||||
|
||||
// Do one further loop over the elements array to remote double quoting
|
||||
// and escaping of double quotes and backslashes
|
||||
for ($i = 0; $i < sizeof($elements); $i++) {
|
||||
$v = $elements[$i];
|
||||
if (strpos($v, '"') === 0) {
|
||||
$v = substr($v, 1, strlen($v) - 2);
|
||||
$v = str_replace('\\"', '"', $v);
|
||||
$v = str_replace('\\\\', '\\', $v);
|
||||
$elements[$i] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class to represent a database connection
|
||||
*
|
||||
* $Id: Connection.php,v 1.15 2008/02/18 21:42:47 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/ADODB_base.php');
|
||||
|
||||
class Connection {
|
||||
|
||||
var $conn;
|
||||
|
||||
// The backend platform. Set to UNKNOWN by default.
|
||||
var $platform = 'UNKNOWN';
|
||||
|
||||
/**
|
||||
* Creates a new connection. Will actually make a database connection.
|
||||
* @param $fetchMode Defaults to associative. Override for different behaviour
|
||||
*/
|
||||
function Connection($host, $port, $sslmode, $user, $password, $database, $fetchMode = ADODB_FETCH_ASSOC) {
|
||||
$this->conn = &ADONewConnection('postgres7');
|
||||
$this->conn->setFetchMode($fetchMode);
|
||||
|
||||
// Ignore host if null
|
||||
if ($host === null || $host == '')
|
||||
if ($port !== null && $port != '')
|
||||
$pghost = ':'.$port;
|
||||
else
|
||||
$pghost = '';
|
||||
else
|
||||
$pghost = "{$host}:{$port}";
|
||||
|
||||
// Add sslmode to $pghost as needed
|
||||
if (($sslmode == 'disable') || ($sslmode == 'allow') || ($sslmode == 'prefer') || ($sslmode == 'require')) {
|
||||
$pghost .= ':'.$sslmode;
|
||||
} elseif ($sslmode == 'legacy') {
|
||||
$pghost .= ' requiressl=1';
|
||||
}
|
||||
|
||||
$this->conn->connect($pghost, $user, $password, $database);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the correct database driver to use. As a side effect,
|
||||
* sets the platform.
|
||||
* @param (return-by-ref) $description A description of the database and version
|
||||
* @return The class name of the driver eg. Postgres84
|
||||
* @return null if version is < 7.4
|
||||
* @return -3 Database-specific failure
|
||||
*/
|
||||
function getDriver(&$description) {
|
||||
// If we're on a recent enough PHP 5, and against PostgreSQL 7.4 or
|
||||
// higher, we don't need to query for the version. This gives a great
|
||||
// speed up.
|
||||
if (function_exists('pg_version')) {
|
||||
$v = pg_version($this->conn->_connectionID);
|
||||
if (isset($v['server'])) $version = $v['server'];
|
||||
}
|
||||
|
||||
// If we didn't manage to get the version without a query, query...
|
||||
if (!isset($version)) {
|
||||
$adodb = new ADODB_base($this->conn);
|
||||
|
||||
$sql = "SELECT VERSION() AS version";
|
||||
$field = $adodb->selectField($sql, 'version');
|
||||
|
||||
// Check the platform, if it's mingw, set it
|
||||
if (preg_match('/ mingw /i', $field))
|
||||
$this->platform = 'MINGW';
|
||||
|
||||
$params = explode(' ', $field);
|
||||
if (!isset($params[1])) return -3;
|
||||
|
||||
$version = $params[1]; // eg. 8.4.4
|
||||
}
|
||||
|
||||
$description = "PostgreSQL {$version}";
|
||||
|
||||
// Detect version and choose appropriate database driver
|
||||
switch (substr($version,0,3)) {
|
||||
case '8.4': return 'Postgres'; break;
|
||||
case '8.3': return 'Postgres83'; break;
|
||||
case '8.2': return 'Postgres82'; break;
|
||||
case '8.1': return 'Postgres81'; break;
|
||||
case '8.0':
|
||||
case '7.5': return 'Postgres80'; break;
|
||||
case '7.4': return 'Postgres74'; break;
|
||||
}
|
||||
|
||||
/* All <7.4 versions are not supported */
|
||||
// if major version is 7 or less and wasn't catch in the
|
||||
// switch/case block, we have an unsupported version.
|
||||
if ((int)substr($version, 0, 1) < 8)
|
||||
return null;
|
||||
|
||||
// If unknown version, then default to latest driver
|
||||
return 'Postgres';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error in the connection
|
||||
* @return Error string
|
||||
*/
|
||||
function getLastError() {
|
||||
if (function_exists('pg_errormessage'))
|
||||
return pg_errormessage($this->conn->_connectionID);
|
||||
else
|
||||
return pg_last_error($this->conn->_connectionID);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,627 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A class that implements the DB interface for Postgres
|
||||
* Note: This class uses ADODB and returns RecordSets.
|
||||
*
|
||||
* $Id: Postgres74.php,v 1.72 2008/02/20 21:06:18 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/Postgres80.php');
|
||||
|
||||
class Postgres74 extends Postgres80 {
|
||||
|
||||
var $major_version = 7.4;
|
||||
// List of all legal privileges that can be applied to different types
|
||||
// of objects.
|
||||
var $privlist = array(
|
||||
'table' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'view' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'sequence' => array('SELECT', 'UPDATE', 'ALL PRIVILEGES'),
|
||||
'database' => array('CREATE', 'TEMPORARY', 'ALL PRIVILEGES'),
|
||||
'function' => array('EXECUTE', 'ALL PRIVILEGES'),
|
||||
'language' => array('USAGE', 'ALL PRIVILEGES'),
|
||||
'schema' => array('CREATE', 'USAGE', 'ALL PRIVILEGES')
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $conn The database connection
|
||||
*/
|
||||
function Postgres74($conn) {
|
||||
$this->Postgres80($conn);
|
||||
}
|
||||
|
||||
// Help functions
|
||||
|
||||
function getHelpPages() {
|
||||
include_once('./help/PostgresDoc74.php');
|
||||
return $this->help_page;
|
||||
}
|
||||
|
||||
// Database functions
|
||||
|
||||
/**
|
||||
* Alters a database
|
||||
* the multiple return vals are for postgres 8+ which support more functionality in alter database
|
||||
* @param $dbName The name of the database
|
||||
* @param $newName new name for the database
|
||||
* @param $newOwner The new owner for the database
|
||||
* @return 0 success
|
||||
* @return -1 transaction error
|
||||
* @return -2 owner error
|
||||
* @return -3 rename error
|
||||
*/
|
||||
function alterDatabase($dbName, $newName, $newOwner = '', $comment = '') {
|
||||
//ignore $newowner, not supported pre 8.0
|
||||
//ignore $comment, not supported pre 8.2
|
||||
$this->clean($dbName);
|
||||
$this->clean($newName);
|
||||
|
||||
$status = $this->alterDatabaseRename($dbName, $newName);
|
||||
if ($status != 0) return -3;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all database available on the server
|
||||
* @return A list of databases, sorted alphabetically
|
||||
*/
|
||||
function getDatabases($currentdatabase = NULL) {
|
||||
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);
|
||||
$clause = " AND pu.usename='{$username}'";
|
||||
}
|
||||
else $clause = '';
|
||||
|
||||
if ($currentdatabase != NULL) {
|
||||
$this->clean($currentdatabase);
|
||||
$orderby = "ORDER BY pdb.datname = '{$currentdatabase}' DESC, pdb.datname";
|
||||
}
|
||||
else
|
||||
$orderby = "ORDER BY pdb.datname";
|
||||
|
||||
if (!$conf['show_system'])
|
||||
$where = ' AND NOT pdb.datistemplate';
|
||||
else
|
||||
$where = ' AND pdb.datallowconn';
|
||||
|
||||
$sql = "SELECT pdb.datname AS 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}
|
||||
{$clause}
|
||||
{$orderby}";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches all system catalogs to find objects that match a certain name.
|
||||
* @param $term The search term
|
||||
* @param $filter The object type to restrict to ('' means no restriction)
|
||||
* @return A recordset
|
||||
*/
|
||||
function findObject($term, $filter) {
|
||||
global $conf;
|
||||
|
||||
/*about escaping:
|
||||
* SET standard_conforming_string is not available before 8.2
|
||||
* So we must use PostgreSQL specific notation :/
|
||||
* E'' notation is not available before 8.1
|
||||
* $$ is available since 8.0
|
||||
* Nothing specific from 7.4
|
||||
**/
|
||||
|
||||
// Escape search term for ILIKE match
|
||||
$term = str_replace('_', '\\_', $term);
|
||||
$term = str_replace('%', '\\%', $term);
|
||||
$this->clean($term);
|
||||
$this->clean($filter);
|
||||
|
||||
// Exclude system relations if necessary
|
||||
if (!$conf['show_system']) {
|
||||
// XXX: The mention of information_schema here is in the wrong place, but
|
||||
// it's the quickest fix to exclude the info schema from 7.4
|
||||
$where = " AND pn.nspname NOT LIKE 'pg\\\\_%' AND pn.nspname != 'information_schema'";
|
||||
$lan_where = "AND pl.lanispl";
|
||||
}
|
||||
else {
|
||||
$where = '';
|
||||
$lan_where = '';
|
||||
}
|
||||
|
||||
// Apply outer filter
|
||||
$sql = '';
|
||||
if ($filter != '') {
|
||||
$sql = "SELECT * FROM (";
|
||||
}
|
||||
|
||||
$sql .= "
|
||||
SELECT 'SCHEMA' AS type, oid, NULL AS schemaname, NULL AS relname, nspname AS name
|
||||
FROM pg_catalog.pg_namespace pn WHERE nspname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT CASE WHEN relkind='r' THEN 'TABLE' WHEN relkind='v' THEN 'VIEW' WHEN relkind='S' THEN 'SEQUENCE' END, pc.oid,
|
||||
pn.nspname, NULL, pc.relname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn
|
||||
WHERE pc.relnamespace=pn.oid AND relkind IN ('r', 'v', 'S') AND relname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT CASE WHEN pc.relkind='r' THEN 'COLUMNTABLE' ELSE 'COLUMNVIEW' END, NULL, pn.nspname, pc.relname, pa.attname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_attribute pa WHERE pc.relnamespace=pn.oid AND pc.oid=pa.attrelid
|
||||
AND pa.attname ILIKE '%{$term}%' AND pa.attnum > 0 AND NOT pa.attisdropped AND pc.relkind IN ('r', 'v') {$where}
|
||||
UNION ALL
|
||||
SELECT 'FUNCTION', pp.oid, pn.nspname, NULL, pp.proname || '(' || pg_catalog.oidvectortypes(pp.proargtypes) || ')' FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pn
|
||||
WHERE pp.pronamespace=pn.oid AND NOT pp.proisagg AND pp.proname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'INDEX', NULL, pn.nspname, pc.relname, pc2.relname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_index pi, pg_catalog.pg_class pc2 WHERE pc.relnamespace=pn.oid AND pc.oid=pi.indrelid
|
||||
AND pi.indexrelid=pc2.oid
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = pc2.tableoid AND d.objid = pc2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
|
||||
)
|
||||
AND pc2.relname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'CONSTRAINTTABLE', NULL, pn.nspname, pc.relname, pc2.conname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_constraint pc2 WHERE pc.relnamespace=pn.oid AND pc.oid=pc2.conrelid AND pc2.conrelid != 0
|
||||
AND CASE WHEN pc2.contype IN ('f', 'c') THEN TRUE ELSE NOT EXISTS (
|
||||
SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = pc2.tableoid AND d.objid = pc2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
|
||||
) END
|
||||
AND pc2.conname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'CONSTRAINTDOMAIN', pt.oid, pn.nspname, pt.typname, pc.conname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_constraint pc WHERE pt.typnamespace=pn.oid AND pt.oid=pc.contypid AND pc.contypid != 0
|
||||
AND pc.conname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'TRIGGER', NULL, pn.nspname, pc.relname, pt.tgname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_trigger pt WHERE pc.relnamespace=pn.oid AND pc.oid=pt.tgrelid
|
||||
AND ( pt.tgisconstraint = 'f' OR NOT EXISTS
|
||||
(SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = pt.tableoid AND d.objid = pt.oid AND d.deptype = 'i' AND c.contype = 'f'))
|
||||
AND pt.tgname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'RULETABLE', NULL, pn.nspname AS schemaname, c.relname AS tablename, r.rulename FROM pg_catalog.pg_rewrite r
|
||||
JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
|
||||
LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = c.relnamespace
|
||||
WHERE c.relkind='r' AND r.rulename != '_RETURN' AND r.rulename ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'RULEVIEW', NULL, pn.nspname AS schemaname, c.relname AS tablename, r.rulename FROM pg_catalog.pg_rewrite r
|
||||
JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
|
||||
LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = c.relnamespace
|
||||
WHERE c.relkind='v' AND r.rulename != '_RETURN' AND r.rulename ILIKE '%{$term}%' {$where}
|
||||
";
|
||||
|
||||
// Add advanced objects if show_advanced is set
|
||||
if ($conf['show_advanced']) {
|
||||
$sql .= "
|
||||
UNION ALL
|
||||
SELECT CASE WHEN pt.typtype='d' THEN 'DOMAIN' ELSE 'TYPE' END, pt.oid, pn.nspname, NULL,
|
||||
pt.typname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn
|
||||
WHERE pt.typnamespace=pn.oid AND typname ILIKE '%{$term}%'
|
||||
AND (pt.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = pt.typrelid))
|
||||
{$where}
|
||||
UNION ALL
|
||||
SELECT 'OPERATOR', po.oid, pn.nspname, NULL, po.oprname FROM pg_catalog.pg_operator po, pg_catalog.pg_namespace pn
|
||||
WHERE po.oprnamespace=pn.oid AND oprname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'CONVERSION', pc.oid, pn.nspname, NULL, pc.conname FROM pg_catalog.pg_conversion pc,
|
||||
pg_catalog.pg_namespace pn WHERE pc.connamespace=pn.oid AND conname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT 'LANGUAGE', pl.oid, NULL, NULL, pl.lanname FROM pg_catalog.pg_language pl
|
||||
WHERE lanname ILIKE '%{$term}%' {$lan_where}
|
||||
UNION ALL
|
||||
SELECT DISTINCT ON (p.proname) 'AGGREGATE', p.oid, pn.nspname, NULL, p.proname FROM pg_catalog.pg_proc p
|
||||
LEFT JOIN pg_catalog.pg_namespace pn ON p.pronamespace=pn.oid
|
||||
WHERE p.proisagg AND p.proname ILIKE '%{$term}%' {$where}
|
||||
UNION ALL
|
||||
SELECT DISTINCT ON (po.opcname) 'OPCLASS', po.oid, pn.nspname, NULL, po.opcname FROM pg_catalog.pg_opclass po,
|
||||
pg_catalog.pg_namespace pn WHERE po.opcnamespace=pn.oid
|
||||
AND po.opcname ILIKE '%{$term}%' {$where}
|
||||
";
|
||||
}
|
||||
// Otherwise just add domains
|
||||
else {
|
||||
$sql .= "
|
||||
UNION ALL
|
||||
SELECT 'DOMAIN', pt.oid, pn.nspname, NULL,
|
||||
pt.typname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn
|
||||
WHERE pt.typnamespace=pn.oid AND pt.typtype='d' AND typname ILIKE '%{$term}%'
|
||||
AND (pt.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = pt.typrelid))
|
||||
{$where}
|
||||
";
|
||||
}
|
||||
|
||||
if ($filter != '') {
|
||||
// We use like to make RULE, CONSTRAINT and COLUMN searches work
|
||||
$sql .= ") AS sub WHERE type LIKE '{$filter}%' ";
|
||||
}
|
||||
|
||||
$sql .= "ORDER BY type, schemaname, relname, name";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Database functions
|
||||
|
||||
/**
|
||||
* Returns table locks information in the current database
|
||||
* @return A recordset
|
||||
*/
|
||||
function getLocks() {
|
||||
global $conf;
|
||||
|
||||
if (!$conf['show_system'])
|
||||
$where = "AND pn.nspname NOT LIKE 'pg\\\\_%'";
|
||||
else
|
||||
$where = "AND nspname !~ '^pg_t(emp_[0-9]+|oast)$'";
|
||||
|
||||
$sql = "SELECT pn.nspname, pc.relname AS tablename, pl.transaction, pl.pid, pl.mode, pl.granted
|
||||
FROM pg_catalog.pg_locks pl, pg_catalog.pg_class pc, pg_catalog.pg_namespace pn
|
||||
WHERE pl.relation = pc.oid AND pc.relnamespace=pn.oid {$where}
|
||||
ORDER BY nspname,tablename";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Table functions
|
||||
|
||||
/**
|
||||
* Protected method which alter a table
|
||||
* SHOULDN'T BE CALLED OUTSIDE OF A TRANSACTION
|
||||
* @param $tblrs The table recordSet returned by getTable()
|
||||
* @param $name The new name for the table
|
||||
* @param $owner The new owner for the table
|
||||
* @param $schema The new schema 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
|
||||
* @return -3 rename error
|
||||
* @return -4 comment error
|
||||
* @return -5 owner error
|
||||
*/
|
||||
protected
|
||||
function _alterTable($tblrs, $name, $owner, $schema, $comment, $tablespace) {
|
||||
|
||||
/* $schema and tablespace not supported in pg74- */
|
||||
$this->fieldArrayClean($tblrs->fields);
|
||||
|
||||
// Comment
|
||||
$status = $this->setComment('TABLE', '', $tblrs->fields['relname'], $comment);
|
||||
if ($status != 0) return -4;
|
||||
|
||||
// Owner
|
||||
$this->fieldClean($owner);
|
||||
$status = $this->alterTableOwner($tblrs, $owner);
|
||||
if ($status != 0) return -5;
|
||||
|
||||
// Rename
|
||||
$this->fieldClean($name);
|
||||
$status = $this->alterTableName($tblrs, $name);
|
||||
if ($status != 0) return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters a column in a table OR view
|
||||
* @param $table The table in which the column resides
|
||||
* @param $column The column to alter
|
||||
* @param $name The new name for the column
|
||||
* @param $notnull (boolean) True if not null, false otherwise
|
||||
* @param $oldnotnull (boolean) True if column is already not null, false otherwise
|
||||
* @param $default The new default for the column
|
||||
* @param $olddefault The old default for the column
|
||||
* @param $type The new type for the column
|
||||
* @param $array True if array type, false otherwise
|
||||
* @param $length The optional size of the column (ie. 30 for varchar(30))
|
||||
* @param $oldtype The old type for the column
|
||||
* @param $comment Comment for the column
|
||||
* @return 0 success
|
||||
* @return -2 set not null error
|
||||
* @return -3 set default error
|
||||
* @return -4 rename column error
|
||||
* @return -5 comment error
|
||||
* @return -6 transaction error
|
||||
*/
|
||||
function alterColumn($table, $column, $name, $notnull, $oldnotnull, $default, $olddefault,
|
||||
$type, $length, $array, $oldtype, $comment)
|
||||
{
|
||||
$status = $this->beginTransaction();
|
||||
if ($status != 0) return -1;
|
||||
|
||||
// @@ NEED TO HANDLE "NESTED" TRANSACTION HERE
|
||||
if ($notnull != $oldnotnull) {
|
||||
$status = $this->setColumnNull($table, $column, !$notnull);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
// Set default, if it has changed
|
||||
if ($default != $olddefault) {
|
||||
if ($default == '')
|
||||
$status = $this->dropColumnDefault($table, $column);
|
||||
else
|
||||
$status = $this->setColumnDefault($table, $column, $default);
|
||||
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
// Rename the column, if it has been changed
|
||||
if ($column != $name) {
|
||||
$status = $this->renameColumn($table, $column, $name);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
|
||||
// The $name and $table 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);
|
||||
$status = $this->setComment('COLUMN', $name, $table, $comment);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -5;
|
||||
}
|
||||
|
||||
return $this->endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns table information
|
||||
* @param $table The name of the table
|
||||
* @return A recordset
|
||||
*/
|
||||
function getTable($table) {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($table);
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
c.relname, n.nspname, u.usename AS relowner,
|
||||
pg_catalog.obj_description(c.oid, 'pg_class') AS relcomment
|
||||
FROM pg_catalog.pg_class c
|
||||
LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
|
||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'r'
|
||||
AND n.nspname = '{$c_schema}'
|
||||
AND c.relname = '{$table}'";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all tables in current database (and schema)
|
||||
* @param $all True to fetch all tables, false for just in current schema
|
||||
* @return All tables, sorted alphabetically
|
||||
*/
|
||||
function getTables($all = false) {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
if ($all) {
|
||||
// Exclude pg_catalog and information_schema tables
|
||||
$sql = "SELECT schemaname AS nspname, tablename AS relname, tableowner AS relowner
|
||||
FROM pg_catalog.pg_tables
|
||||
WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
||||
ORDER BY schemaname, tablename";
|
||||
} else {
|
||||
$sql = "SELECT c.relname, pg_catalog.pg_get_userbyid(c.relowner) AS relowner,
|
||||
pg_catalog.obj_description(c.oid, 'pg_class') AS relcomment,
|
||||
reltuples::bigint
|
||||
FROM pg_catalog.pg_class c
|
||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'r'
|
||||
AND nspname='{$c_schema}'
|
||||
ORDER BY c.relname";
|
||||
}
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current default_with_oids setting
|
||||
* @return default_with_oids setting
|
||||
*/
|
||||
function getDefaultWithOid() {
|
||||
// 8.0 is the first release to have this setting
|
||||
// Prior releases don't have this setting... oids always activated
|
||||
return 'on';
|
||||
}
|
||||
|
||||
// Constraint functions
|
||||
|
||||
/**
|
||||
* Returns a list of all constraints on a table,
|
||||
* including constraint name, definition, related col and referenced namespace,
|
||||
* table and col if needed
|
||||
* @param $table the table where we are looking for fk
|
||||
* @return a recordset
|
||||
*/
|
||||
function getConstraintsWithFields($table) {
|
||||
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($table);
|
||||
|
||||
// get the max number of col used in a constraint for the table
|
||||
$sql = "SELECT DISTINCT
|
||||
max(SUBSTRING(array_dims(c.conkey) FROM '^\\\\[.*:(.*)\\\\]$')) as nb
|
||||
FROM pg_catalog.pg_constraint AS c
|
||||
JOIN pg_catalog.pg_class AS r ON (c.conrelid=r.oid)
|
||||
JOIN pg_catalog.pg_namespace AS ns ON (r.relnamespace=ns.oid)
|
||||
WHERE
|
||||
r.relname = '{$table}' AND ns.nspname='{$c_schema}'";
|
||||
|
||||
$rs = $this->selectSet($sql);
|
||||
|
||||
if ($rs->EOF) $max_col = 0;
|
||||
else $max_col = $rs->fields['nb'];
|
||||
|
||||
$sql = '
|
||||
SELECT
|
||||
c.oid AS conid, c.contype, c.conname, pg_catalog.pg_get_constraintdef(c.oid, true) AS consrc,
|
||||
ns1.nspname as p_schema, r1.relname as p_table, ns2.nspname as f_schema,
|
||||
r2.relname as f_table, f1.attname as p_field, f1.attnum AS p_attnum, f2.attname as f_field,
|
||||
f2.attnum AS f_attnum, pg_catalog.obj_description(c.oid, \'pg_constraint\') AS constcomment,
|
||||
c.conrelid, c.confrelid
|
||||
FROM
|
||||
pg_catalog.pg_constraint AS c
|
||||
JOIN pg_catalog.pg_class AS r1 ON (c.conrelid=r1.oid)
|
||||
JOIN pg_catalog.pg_attribute AS f1 ON (f1.attrelid=r1.oid AND (f1.attnum=c.conkey[1]';
|
||||
for ($i = 2; $i <= $rs->fields['nb']; $i++) {
|
||||
$sql.= " OR f1.attnum=c.conkey[$i]";
|
||||
}
|
||||
$sql.= '))
|
||||
JOIN pg_catalog.pg_namespace AS ns1 ON r1.relnamespace=ns1.oid
|
||||
LEFT JOIN (
|
||||
pg_catalog.pg_class AS r2 JOIN pg_catalog.pg_namespace AS ns2 ON (r2.relnamespace=ns2.oid)
|
||||
) ON (c.confrelid=r2.oid)
|
||||
LEFT JOIN pg_catalog.pg_attribute AS f2 ON
|
||||
(f2.attrelid=r2.oid AND ((c.confkey[1]=f2.attnum AND c.conkey[1]=f1.attnum)';
|
||||
for ($i = 2; $i <= $rs->fields['nb']; $i++)
|
||||
$sql.= " OR (c.confkey[$i]=f2.attnum AND c.conkey[$i]=f1.attnum)";
|
||||
|
||||
$sql .= sprintf("))
|
||||
WHERE
|
||||
r1.relname = '%s' AND ns1.nspname='%s'
|
||||
ORDER BY 1", $table, $c_schema);
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Sequence functions
|
||||
|
||||
/**
|
||||
* Returns all sequences in the current database
|
||||
* @return A recordset
|
||||
*/
|
||||
function getSequences($all = false) {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
if ($all) {
|
||||
// Exclude pg_catalog and information_schema tables
|
||||
$sql = "SELECT n.nspname, c.relname AS seqname, u.usename AS seqowner
|
||||
FROM pg_catalog.pg_class c, pg_catalog.pg_user u, pg_catalog.pg_namespace n
|
||||
WHERE c.relowner=u.usesysid AND c.relnamespace=n.oid
|
||||
AND c.relkind = 'S'
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
||||
ORDER BY nspname, seqname";
|
||||
} else {
|
||||
$sql = "SELECT c.relname AS seqname, u.usename AS seqowner, pg_catalog.obj_description(c.oid, 'pg_class') AS seqcomment
|
||||
FROM pg_catalog.pg_class c, pg_catalog.pg_user u, pg_catalog.pg_namespace n
|
||||
WHERE c.relowner=u.usesysid AND c.relnamespace=n.oid
|
||||
AND c.relkind = 'S' AND n.nspname='{$c_schema}' ORDER BY seqname";
|
||||
}
|
||||
|
||||
return $this->selectSet( $sql );
|
||||
}
|
||||
|
||||
// Function functions
|
||||
|
||||
/**
|
||||
* Returns all details for a particular function
|
||||
* @param $func The name of the function to retrieve
|
||||
* @return Function info
|
||||
*/
|
||||
function getFunction($function_oid) {
|
||||
$this->clean($function_oid);
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
pc.oid AS prooid,
|
||||
proname,
|
||||
pg_catalog.pg_get_userbyid(proowner) AS proowner,
|
||||
nspname as proschema,
|
||||
lanname as prolanguage,
|
||||
pg_catalog.format_type(prorettype, NULL) as proresult,
|
||||
prosrc,
|
||||
probin,
|
||||
proretset,
|
||||
proisstrict,
|
||||
provolatile,
|
||||
prosecdef,
|
||||
pg_catalog.oidvectortypes(pc.proargtypes) AS proarguments,
|
||||
pg_catalog.obj_description(pc.oid, 'pg_proc') AS procomment
|
||||
FROM
|
||||
pg_catalog.pg_proc pc, pg_catalog.pg_language pl, pg_catalog.pg_namespace n
|
||||
WHERE
|
||||
pc.oid = '$function_oid'::oid
|
||||
AND pc.prolang = pl.oid
|
||||
AND n.oid = pc.pronamespace
|
||||
";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all casts in the database
|
||||
* @return All casts
|
||||
*/
|
||||
function getCasts() {
|
||||
global $conf;
|
||||
|
||||
if ($conf['show_system'])
|
||||
$where = '';
|
||||
else
|
||||
$where = "
|
||||
AND n1.nspname NOT LIKE 'pg\\\\_%'
|
||||
AND n2.nspname NOT LIKE 'pg\\\\_%'
|
||||
AND n3.nspname NOT LIKE 'pg\\\\_%'
|
||||
";
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
c.castsource::pg_catalog.regtype AS castsource,
|
||||
c.casttarget::pg_catalog.regtype AS casttarget,
|
||||
CASE WHEN c.castfunc=0 THEN NULL
|
||||
ELSE c.castfunc::pg_catalog.regprocedure END AS castfunc,
|
||||
c.castcontext,
|
||||
obj_description(c.oid, 'pg_cast') as castcomment
|
||||
FROM
|
||||
(pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p ON c.castfunc=p.oid JOIN pg_catalog.pg_namespace n3 ON p.pronamespace=n3.oid),
|
||||
pg_catalog.pg_type t1,
|
||||
pg_catalog.pg_type t2,
|
||||
pg_catalog.pg_namespace n1,
|
||||
pg_catalog.pg_namespace n2
|
||||
WHERE
|
||||
c.castsource=t1.oid
|
||||
AND c.casttarget=t2.oid
|
||||
AND t1.typnamespace=n1.oid
|
||||
AND t2.typnamespace=n2.oid
|
||||
{$where}
|
||||
ORDER BY 1, 2
|
||||
";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
|
||||
function hasAlterColumnType() { return false; }
|
||||
function hasCreateFieldWithConstraints() { return false; }
|
||||
function hasAlterDatabaseOwner() { return false; }
|
||||
function hasAlterSchemaOwner() { return false; }
|
||||
function hasFunctionAlterOwner() { return false; }
|
||||
function hasNamedParams() { return false; }
|
||||
function hasQueryCancel() { return false; }
|
||||
function hasTablespaces() { return false; }
|
||||
function hasMagicTypes() { return false; }
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PostgreSQL 8.0 support
|
||||
*
|
||||
* $Id: Postgres80.php,v 1.28 2007/12/12 04:11:10 xzilla Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/Postgres81.php');
|
||||
|
||||
class Postgres80 extends Postgres81 {
|
||||
|
||||
var $major_version = 8.0;
|
||||
// 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.
|
||||
var $codemap = array(
|
||||
'ALT' => 'CP866',
|
||||
'EUC_CN' => 'GB2312',
|
||||
'EUC_JP' => 'EUC-JP',
|
||||
'EUC_KR' => 'EUC-KR',
|
||||
'EUC_TW' => 'EUC-TW',
|
||||
'ISO_8859_5' => 'ISO-8859-5',
|
||||
'ISO_8859_6' => 'ISO-8859-6',
|
||||
'ISO_8859_7' => 'ISO-8859-7',
|
||||
'ISO_8859_8' => 'ISO-8859-8',
|
||||
'JOHAB' => 'CP1361',
|
||||
'KOI8' => 'KOI8-R',
|
||||
'LATIN1' => 'ISO-8859-1',
|
||||
'LATIN2' => 'ISO-8859-2',
|
||||
'LATIN3' => 'ISO-8859-3',
|
||||
'LATIN4' => 'ISO-8859-4',
|
||||
// The following encoding map is a known error in PostgreSQL < 7.2
|
||||
// See the constructor for Postgres72.
|
||||
'LATIN5' => 'ISO-8859-5',
|
||||
'LATIN6' => 'ISO-8859-10',
|
||||
'LATIN7' => 'ISO-8859-13',
|
||||
'LATIN8' => 'ISO-8859-14',
|
||||
'LATIN9' => 'ISO-8859-15',
|
||||
'LATIN10' => 'ISO-8859-16',
|
||||
'SQL_ASCII' => 'US-ASCII',
|
||||
'TCVN' => 'CP1258',
|
||||
'UNICODE' => 'UTF-8',
|
||||
'WIN' => 'CP1251',
|
||||
'WIN874' => 'CP874',
|
||||
'WIN1256' => 'CP1256'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $conn The database connection
|
||||
*/
|
||||
function Postgres80($conn) {
|
||||
$this->Postgres81($conn);
|
||||
}
|
||||
|
||||
// Help functions
|
||||
|
||||
function getHelpPages() {
|
||||
include_once('./help/PostgresDoc80.php');
|
||||
return $this->help_page;
|
||||
}
|
||||
|
||||
// Database functions
|
||||
|
||||
/**
|
||||
* Return all database available on the server
|
||||
* @return A list of databases, sorted alphabetically
|
||||
*/
|
||||
function getDatabases($currentdatabase = NULL) {
|
||||
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);
|
||||
$clause = " AND pu.usename='{$username}'";
|
||||
}
|
||||
else $clause = '';
|
||||
|
||||
if ($currentdatabase != NULL) {
|
||||
$this->clean($currentdatabase);
|
||||
$orderby = "ORDER BY pdb.datname = '{$currentdatabase}' DESC, pdb.datname";
|
||||
}
|
||||
else
|
||||
$orderby = "ORDER BY pdb.datname";
|
||||
|
||||
if (!$conf['show_system'])
|
||||
$where = ' AND NOT pdb.datistemplate';
|
||||
else
|
||||
$where = ' AND pdb.datallowconn';
|
||||
|
||||
$sql = "SELECT pdb.datname AS 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,
|
||||
(SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=pdb.dattablespace) AS tablespace
|
||||
FROM pg_database pdb, pg_user pu
|
||||
WHERE pdb.datdba = pu.usesysid
|
||||
{$where}
|
||||
{$clause}
|
||||
{$orderby}";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Schema functions
|
||||
|
||||
/**
|
||||
* Return all schemas in the current database.
|
||||
* @return All schemas, sorted alphabetically
|
||||
*/
|
||||
function getSchemas() {
|
||||
global $conf, $slony;
|
||||
|
||||
if (!$conf['show_system']) {
|
||||
$where = "WHERE nspname NOT LIKE 'pg@_%' ESCAPE '@' AND nspname != 'information_schema'";
|
||||
if (isset($slony) && $slony->isEnabled()) {
|
||||
$temp = $slony->slony_schema;
|
||||
$this->clean($temp);
|
||||
$where .= " AND nspname != '{$temp}'";
|
||||
}
|
||||
|
||||
}
|
||||
else $where = "WHERE nspname !~ '^pg_t(emp_[0-9]+|oast)$'";
|
||||
$sql = "
|
||||
SELECT pn.nspname, pu.usename AS nspowner,
|
||||
pg_catalog.obj_description(pn.oid, 'pg_namespace') AS nspcomment
|
||||
FROM pg_catalog.pg_namespace pn
|
||||
LEFT JOIN pg_catalog.pg_user pu ON (pn.nspowner = pu.usesysid)
|
||||
{$where}
|
||||
ORDER BY nspname";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all information relating to a schema
|
||||
* @param $schema The name of the schema
|
||||
* @return Schema information
|
||||
*/
|
||||
function getSchemaByName($schema) {
|
||||
$this->clean($schema);
|
||||
$sql = "
|
||||
SELECT nspname, nspowner, u.usename AS ownername, nspacl,
|
||||
pg_catalog.obj_description(pn.oid, 'pg_namespace') as nspcomment
|
||||
FROM pg_catalog.pg_namespace pn
|
||||
LEFT JOIN pg_shadow as u ON pn.nspowner = u.usesysid
|
||||
WHERE nspname='{$schema}'";
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Table functions
|
||||
|
||||
/**
|
||||
* Protected method which alter a table
|
||||
* SHOULDN'T BE CALLED OUTSIDE OF A TRANSACTION
|
||||
* @param $tblrs The table recordSet returned by getTable()
|
||||
* @param $name The new name for the table
|
||||
* @param $owner The new owner for the table
|
||||
* @param $schema The new schema 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
|
||||
* @return -3 rename error
|
||||
* @return -4 comment error
|
||||
* @return -5 owner error
|
||||
* @return -6 tablespace error
|
||||
*/
|
||||
protected
|
||||
function _alterTable($tblrs, $name, $owner, $schema, $comment, $tablespace) {
|
||||
|
||||
/* $schema not supported in pg80- */
|
||||
|
||||
// Comment
|
||||
$status = $this->setComment('TABLE', '', $tblrs->fields['relname'], $comment);
|
||||
if ($status != 0) return -4;
|
||||
|
||||
// Owner
|
||||
$this->fieldClean($owner);
|
||||
$status = $this->alterTableOwner($tblrs, $owner);
|
||||
if ($status != 0) return -5;
|
||||
|
||||
// Tablespace
|
||||
$this->fieldClean($tablespace);
|
||||
$status = $this->alterTableTablespace($tblrs, $tablespace);
|
||||
if ($status != 0) return -6;
|
||||
|
||||
// Rename
|
||||
$this->fieldClean($name);
|
||||
$status = $this->alterTableName($tblrs, $name);
|
||||
if ($status != 0) return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// View functions
|
||||
|
||||
/**
|
||||
* Protected method which alter a view
|
||||
* SHOULDN'T BE CALLED OUTSIDE OF A TRANSACTION
|
||||
* @param $vwrs The view recordSet returned by getView()
|
||||
* @param $name The new name for the view
|
||||
* @param $owner The new owner for the view
|
||||
* @param $comment The comment on the view
|
||||
* @return 0 success
|
||||
* @return -3 rename error
|
||||
* @return -4 comment error
|
||||
* @return -5 owner error
|
||||
*/
|
||||
protected
|
||||
function _alterView($vwrs, $name, $owner, $schema, $comment) {
|
||||
|
||||
/* $schema not supported in pg80- */
|
||||
$this->fieldArrayClean($vwrs->fields);
|
||||
|
||||
// Comment
|
||||
if ($this->setComment('VIEW', $vwrs->fields['relname'], '', $comment) != 0)
|
||||
return -4;
|
||||
|
||||
// Owner
|
||||
$this->fieldClean($owner);
|
||||
$status = $this->alterViewOwner($vwrs, $owner);
|
||||
if ($status != 0) return -5;
|
||||
|
||||
// Rename
|
||||
$this->fieldClean($name);
|
||||
$status = $this->alterViewName($vwrs, $name);
|
||||
if ($status != 0) return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sequence functions
|
||||
|
||||
/**
|
||||
* 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 $schema The new schema for the sequence
|
||||
* @param $increment The increment
|
||||
* @param $minvalue The min value
|
||||
* @param $maxvalue The max value
|
||||
* @param $restartvalue The starting value
|
||||
* @param $cachevalue The cache value
|
||||
* @param $cycledvalue True if cycled, false otherwise
|
||||
* @param $startvalue The sequence start value when issueing a restart
|
||||
* @return 0 success
|
||||
* @return -3 rename error
|
||||
* @return -4 comment error
|
||||
* @return -5 owner error
|
||||
* @return -6 get sequence props error
|
||||
* @return -7 schema error
|
||||
*/
|
||||
protected
|
||||
function _alterSequence($seqrs, $name, $comment, $owner, $schema, $increment,
|
||||
$minvalue, $maxvalue, $restartvalue, $cachevalue, $cycledvalue, $startvalue) {
|
||||
|
||||
/* $schema not supported in pg80- */
|
||||
$this->fieldArrayClean($seqrs->fields);
|
||||
|
||||
// Comment
|
||||
$status = $this->setComment('SEQUENCE', $seqrs->fields['seqname'], '', $comment);
|
||||
if ($status != 0)
|
||||
return -4;
|
||||
|
||||
// Owner
|
||||
$this->fieldClean($owner);
|
||||
$status = $this->alterSequenceOwner($seqrs, $owner);
|
||||
if ($status != 0)
|
||||
return -5;
|
||||
|
||||
// Props
|
||||
$this->clean($increment);
|
||||
$this->clean($minvalue);
|
||||
$this->clean($maxvalue);
|
||||
$this->clean($restartvalue);
|
||||
$this->clean($cachevalue);
|
||||
$this->clean($cycledvalue);
|
||||
$this->clean($startvalue);
|
||||
$status = $this->alterSequenceProps($seqrs, $increment, $minvalue,
|
||||
$maxvalue, $restartvalue, $cachevalue, $cycledvalue, null);
|
||||
if ($status != 0)
|
||||
return -6;
|
||||
|
||||
// Rename
|
||||
$this->fieldClean($name);
|
||||
$status = $this->alterSequenceName($seqrs, $name);
|
||||
if ($status != 0)
|
||||
return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Role, User/group functions
|
||||
|
||||
/**
|
||||
* Changes a user's password
|
||||
* @param $username The username
|
||||
* @param $password The new password
|
||||
* @return 0 success
|
||||
*/
|
||||
function changePassword($username, $password) {
|
||||
$enc = $this->_encryptPassword($username, $password);
|
||||
$this->fieldClean($username);
|
||||
$this->clean($enc);
|
||||
|
||||
$sql = "ALTER USER \"{$username}\" WITH ENCRYPTED PASSWORD '{$enc}'";
|
||||
|
||||
return $this->execute($sql);
|
||||
}
|
||||
|
||||
// Aggregate functions
|
||||
|
||||
/**
|
||||
* Gets all information for an aggregate
|
||||
* @param $name The name of the aggregate
|
||||
* @param $basetype The input data type of the aggregate
|
||||
* @return A recordset
|
||||
*/
|
||||
function getAggregate($name, $basetype) {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($name);
|
||||
$this->clean($basetype);
|
||||
|
||||
$sql = "
|
||||
SELECT p.proname,
|
||||
CASE p.proargtypes[0]
|
||||
WHEN 'pg_catalog.\"any\"'::pg_catalog.regtype THEN NULL
|
||||
ELSE pg_catalog.format_type(p.proargtypes[0], NULL)
|
||||
END AS proargtypes, a.aggtransfn, format_type(a.aggtranstype, NULL) AS aggstype,
|
||||
a.aggfinalfn, a.agginitval, u.usename, pg_catalog.obj_description(p.oid, 'pg_proc') AS aggrcomment
|
||||
FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n, pg_catalog.pg_user u, pg_catalog.pg_aggregate a
|
||||
WHERE n.oid = p.pronamespace AND p.proowner=u.usesysid AND p.oid=a.aggfnoid
|
||||
AND p.proisagg AND n.nspname='{$c_schema}'
|
||||
AND p.proname='{$name}'
|
||||
AND CASE p.proargtypes[0]
|
||||
WHEN 'pg_catalog.\"any\"'::pg_catalog.regtype THEN ''
|
||||
ELSE pg_catalog.format_type(p.proargtypes[0], NULL)
|
||||
END ='{$basetype}'";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
|
||||
function hasAggregateSortOp() { return false; }
|
||||
function hasAlterTableSchema() { return false; }
|
||||
function hasAutovacuum() { return false; }
|
||||
function hasDisableTriggers() { return false; }
|
||||
function hasFunctionAlterSchema() { return false; }
|
||||
function hasPreparedXacts() { return false; }
|
||||
function hasRoles() { return false; }
|
||||
function hasAlterSequenceSchema() { return false; }
|
||||
function hasServerAdminFuncs() { return false; }
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PostgreSQL 8.1 support
|
||||
*
|
||||
* $Id: Postgres81.php,v 1.21 2008/01/19 13:46:15 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/Postgres82.php');
|
||||
|
||||
class Postgres81 extends Postgres82 {
|
||||
|
||||
var $major_version = 8.1;
|
||||
// List of all legal privileges that can be applied to different types
|
||||
// of objects.
|
||||
var $privlist = array(
|
||||
'table' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'view' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'sequence' => array('SELECT', 'UPDATE', 'ALL PRIVILEGES'),
|
||||
'database' => array('CREATE', 'TEMPORARY', 'ALL PRIVILEGES'),
|
||||
'function' => array('EXECUTE', 'ALL PRIVILEGES'),
|
||||
'language' => array('USAGE', 'ALL PRIVILEGES'),
|
||||
'schema' => array('CREATE', 'USAGE', 'ALL PRIVILEGES'),
|
||||
'tablespace' => array('CREATE', 'ALL PRIVILEGES')
|
||||
);
|
||||
// List of characters in acl lists and the privileges they
|
||||
// refer to.
|
||||
var $privmap = array(
|
||||
'r' => 'SELECT',
|
||||
'w' => 'UPDATE',
|
||||
'a' => 'INSERT',
|
||||
'd' => 'DELETE',
|
||||
'R' => 'RULE',
|
||||
'x' => 'REFERENCES',
|
||||
't' => 'TRIGGER',
|
||||
'X' => 'EXECUTE',
|
||||
'U' => 'USAGE',
|
||||
'C' => 'CREATE',
|
||||
'T' => 'TEMPORARY'
|
||||
);
|
||||
// Array of allowed index types
|
||||
var $typIndexes = array('BTREE', 'RTREE', 'GIST', 'HASH');
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $conn The database connection
|
||||
*/
|
||||
function Postgres81($conn) {
|
||||
$this->Postgres82($conn);
|
||||
}
|
||||
|
||||
// Help functions
|
||||
|
||||
function getHelpPages() {
|
||||
include_once('./help/PostgresDoc81.php');
|
||||
return $this->help_page;
|
||||
}
|
||||
|
||||
// Database functions
|
||||
|
||||
/**
|
||||
* Returns all databases available on the server
|
||||
* @return A list of databases, sorted alphabetically
|
||||
*/
|
||||
function getDatabases($currentdatabase = NULL) {
|
||||
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);
|
||||
$clause = " AND pr.rolname='{$username}'";
|
||||
}
|
||||
else $clause = '';
|
||||
|
||||
if ($currentdatabase != NULL) {
|
||||
$this->clean($currentdatabase);
|
||||
$orderby = "ORDER BY pdb.datname = '{$currentdatabase}' DESC, pdb.datname";
|
||||
}
|
||||
else
|
||||
$orderby = "ORDER BY pdb.datname";
|
||||
|
||||
if (!$conf['show_system'])
|
||||
$where = ' AND NOT pdb.datistemplate';
|
||||
else
|
||||
$where = ' AND pdb.datallowconn';
|
||||
|
||||
$sql = "SELECT pdb.datname AS datname, pr.rolname AS datowner, pg_encoding_to_char(encoding) AS datencoding,
|
||||
(SELECT description FROM pg_catalog.pg_description pd WHERE pdb.oid=pd.objoid) AS datcomment,
|
||||
(SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=pdb.dattablespace) AS tablespace,
|
||||
pg_catalog.pg_database_size(pdb.oid) as dbsize
|
||||
FROM pg_catalog.pg_database pdb LEFT JOIN pg_catalog.pg_roles pr ON (pdb.datdba = pr.oid)
|
||||
WHERE true
|
||||
{$where}
|
||||
{$clause}
|
||||
{$orderby}";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters a database
|
||||
* the multiple return vals are for postgres 8+ which support more functionality in alter database
|
||||
* @param $dbName The name of the database
|
||||
* @param $newName new name for the database
|
||||
* @param $newOwner The new owner for the database
|
||||
* @return 0 success
|
||||
* @return -1 transaction error
|
||||
* @return -2 owner error
|
||||
* @return -3 rename error
|
||||
*/
|
||||
function alterDatabase($dbName, $newName, $newOwner = '', $comment = '') {
|
||||
$this->clean($dbName);
|
||||
$this->clean($newName);
|
||||
$this->clean($newOwner);
|
||||
//ignore $comment, not supported pre 8.2
|
||||
|
||||
$status = $this->beginTransaction();
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($dbName != $newName) {
|
||||
$status = $this->alterDatabaseRename($dbName, $newName);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
$status = $this->alterDatabaseOwner($newName, $newOwner);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -2;
|
||||
}
|
||||
return $this->endTransaction();
|
||||
}
|
||||
|
||||
// Tablespace functions
|
||||
|
||||
/**
|
||||
* Retrieves a tablespace's information
|
||||
* @return A recordset
|
||||
*/
|
||||
function getTablespace($spcname) {
|
||||
$this->clean($spcname);
|
||||
|
||||
$sql = "SELECT spcname, pg_catalog.pg_get_userbyid(spcowner) AS spcowner, spclocation
|
||||
FROM pg_catalog.pg_tablespace WHERE spcname='{$spcname}'";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information for all tablespaces
|
||||
* @param $all Include all tablespaces (necessary when moving objects back to the default space)
|
||||
* @return A recordset
|
||||
*/
|
||||
function getTablespaces($all = false) {
|
||||
global $conf;
|
||||
|
||||
$sql = "SELECT spcname, pg_catalog.pg_get_userbyid(spcowner) AS spcowner, spclocation
|
||||
FROM pg_catalog.pg_tablespace";
|
||||
|
||||
if (!$conf['show_system'] && !$all) {
|
||||
$sql .= ' WHERE spcname NOT LIKE $$pg\_%$$';
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY spcname";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
|
||||
function hasCreateTableLikeWithConstraints() {return false;}
|
||||
function hasSharedComments() {return false;}
|
||||
function hasConcurrentIndexBuild() {return false;}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PostgreSQL 8.2 support
|
||||
*
|
||||
* $Id: Postgres82.php,v 1.10 2007/12/28 16:21:25 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/Postgres83.php');
|
||||
|
||||
class Postgres82 extends Postgres83 {
|
||||
|
||||
var $major_version = 8.2;
|
||||
|
||||
// Select operators
|
||||
var $selectOps = array('=' => 'i', '!=' => 'i', '<' => 'i', '>' => 'i', '<=' => 'i', '>=' => 'i', '<<' => 'i', '>>' => 'i', '<<=' => 'i', '>>=' => 'i',
|
||||
'LIKE' => 'i', 'NOT LIKE' => 'i', 'ILIKE' => 'i', 'NOT ILIKE' => 'i', 'SIMILAR TO' => 'i',
|
||||
'NOT SIMILAR TO' => 'i', '~' => 'i', '!~' => 'i', '~*' => 'i', '!~*' => 'i',
|
||||
'IS NULL' => 'p', 'IS NOT NULL' => 'p', 'IN' => 'x', 'NOT IN' => 'x');
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $conn The database connection
|
||||
*/
|
||||
function Postgres82($conn) {
|
||||
$this->Postgres($conn);
|
||||
}
|
||||
|
||||
// Help functions
|
||||
|
||||
function getHelpPages() {
|
||||
include_once('./help/PostgresDoc82.php');
|
||||
return $this->help_page;
|
||||
}
|
||||
|
||||
// Database functions
|
||||
|
||||
/**
|
||||
* Returns table locks information in the current database
|
||||
* @return A recordset
|
||||
*/
|
||||
function getLocks() {
|
||||
global $conf;
|
||||
|
||||
if (!$conf['show_system'])
|
||||
$where = 'AND pn.nspname NOT LIKE $$pg\_%$$';
|
||||
else
|
||||
$where = "AND nspname !~ '^pg_t(emp_[0-9]+|oast)$'";
|
||||
|
||||
$sql = "SELECT pn.nspname, pc.relname AS tablename, pl.transaction, pl.pid, pl.mode, pl.granted
|
||||
FROM pg_catalog.pg_locks pl, pg_catalog.pg_class pc, pg_catalog.pg_namespace pn
|
||||
WHERE pl.relation = pc.oid AND pc.relnamespace=pn.oid {$where}
|
||||
ORDER BY nspname,tablename";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Sequence functions
|
||||
|
||||
/**
|
||||
* Rename a sequence
|
||||
* @param $seqrs The sequence RecordSet returned by getSequence()
|
||||
* @param $name The new name for the sequence
|
||||
* @return 0 success
|
||||
*/
|
||||
function alterSequenceName($seqrs, $name) {
|
||||
/* vars are cleaned in _alterSequence */
|
||||
if (!empty($name) && ($seqrs->fields['seqname'] != $name)) {
|
||||
$f_schema = $this->_schema;
|
||||
$this->fieldClean($f_schema);
|
||||
$sql = "ALTER TABLE \"{$f_schema}\".\"{$seqrs->fields['seqname']}\" RENAME TO \"{$name}\"";
|
||||
$status = $this->execute($sql);
|
||||
if ($status == 0)
|
||||
$seqrs->fields['seqname'] = $name;
|
||||
else
|
||||
return $status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// View functions
|
||||
|
||||
/**
|
||||
* Rename a view
|
||||
* @param $vwrs The view recordSet returned by getView()
|
||||
* @param $name The new view's name
|
||||
* @return -1 Failed
|
||||
* @return 0 success
|
||||
*/
|
||||
function alterViewName($vwrs, $name) {
|
||||
// Rename (only if name has changed)
|
||||
/* $vwrs and $name are cleaned in _alterView */
|
||||
if (!empty($name) && ($name != $vwrs->fields['relname'])) {
|
||||
$f_schema = $this->_schema;
|
||||
$this->fieldClean($f_schema);
|
||||
$sql = "ALTER TABLE \"{$f_schema}\".\"{$vwrs->fields['relname']}\" RENAME TO \"{$name}\"";
|
||||
$status = $this->execute($sql);
|
||||
if ($status == 0)
|
||||
$vwrs->fields['relname'] = $name;
|
||||
else
|
||||
return $status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Trigger functions
|
||||
|
||||
/**
|
||||
* Grabs a list of triggers on a table
|
||||
* @param $table The name of a table whose triggers to retrieve
|
||||
* @return A recordset
|
||||
*/
|
||||
function getTriggers($table = '') {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($table);
|
||||
|
||||
$sql = "SELECT
|
||||
t.tgname, pg_catalog.pg_get_triggerdef(t.oid) AS tgdef, t.tgenabled, p.oid AS prooid,
|
||||
p.proname || ' (' || pg_catalog.oidvectortypes(p.proargtypes) || ')' AS proproto,
|
||||
ns.nspname AS pronamespace
|
||||
FROM pg_catalog.pg_trigger t, pg_catalog.pg_proc p, pg_catalog.pg_namespace ns
|
||||
WHERE t.tgrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
|
||||
AND relnamespace=(SELECT oid FROM pg_catalog.pg_namespace WHERE nspname='{$c_schema}'))
|
||||
AND (NOT tgisconstraint OR NOT EXISTS
|
||||
(SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))
|
||||
AND p.oid=t.tgfoid
|
||||
AND p.pronamespace = ns.oid";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Function functions
|
||||
|
||||
/**
|
||||
* Returns all details for a particular function
|
||||
* @param $func The name of the function to retrieve
|
||||
* @return Function info
|
||||
*/
|
||||
function getFunction($function_oid) {
|
||||
$this->clean($function_oid);
|
||||
|
||||
$sql = "SELECT
|
||||
pc.oid AS prooid,
|
||||
proname,
|
||||
pg_catalog.pg_get_userbyid(proowner) AS proowner,
|
||||
nspname as proschema,
|
||||
lanname as prolanguage,
|
||||
pg_catalog.format_type(prorettype, NULL) as proresult,
|
||||
prosrc,
|
||||
probin,
|
||||
proretset,
|
||||
proisstrict,
|
||||
provolatile,
|
||||
prosecdef,
|
||||
pg_catalog.oidvectortypes(pc.proargtypes) AS proarguments,
|
||||
proargnames AS proargnames,
|
||||
pg_catalog.obj_description(pc.oid, 'pg_proc') AS procomment
|
||||
FROM
|
||||
pg_catalog.pg_proc pc, pg_catalog.pg_language pl, pg_catalog.pg_namespace pn
|
||||
WHERE
|
||||
pc.oid = '{$function_oid}'::oid
|
||||
AND pc.prolang = pl.oid
|
||||
AND pc.pronamespace = pn.oid
|
||||
";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new function.
|
||||
* @param $funcname The name of the function to create
|
||||
* @param $args A comma separated string of types
|
||||
* @param $returns The return type
|
||||
* @param $definition The definition for the new function
|
||||
* @param $language The language the function is written for
|
||||
* @param $flags An array of optional flags
|
||||
* @param $setof True if it returns a set, false otherwise
|
||||
* @param $rows number of rows planner should estimate will be returned
|
||||
* @param $cost cost the planner should use in the function execution step
|
||||
* @param $comment The comment on the function
|
||||
* @param $replace (optional) True if OR REPLACE, false for normal
|
||||
* @return 0 success
|
||||
* @return -1 create function failed
|
||||
* @return -4 set comment failed
|
||||
*/
|
||||
function createFunction($funcname, $args, $returns, $definition, $language, $flags, $setof, $cost, $rows, $comment, $replace = false) {
|
||||
|
||||
// Begin a transaction
|
||||
$status = $this->beginTransaction();
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -1;
|
||||
}
|
||||
|
||||
$f_schema = $this->_schema;
|
||||
$this->fieldClean($f_schema);
|
||||
$this->fieldClean($funcname);
|
||||
$this->clean($args);
|
||||
$this->fieldClean($language);
|
||||
$this->arrayClean($flags);
|
||||
|
||||
$sql = "CREATE";
|
||||
if ($replace) $sql .= " OR REPLACE";
|
||||
$sql .= " FUNCTION \"{$f_schema}\".\"{$funcname}\" (";
|
||||
|
||||
if ($args != '')
|
||||
$sql .= $args;
|
||||
|
||||
// For some reason, the returns field cannot have quotes...
|
||||
$sql .= ") RETURNS ";
|
||||
if ($setof) $sql .= "SETOF ";
|
||||
$sql .= "{$returns} AS ";
|
||||
|
||||
if (is_array($definition)) {
|
||||
$this->arrayClean($definition);
|
||||
$sql .= "'" . $definition[0] . "'";
|
||||
if ($definition[1]) {
|
||||
$sql .= ",'" . $definition[1] . "'";
|
||||
}
|
||||
} else {
|
||||
$this->clean($definition);
|
||||
$sql .= "'" . $definition . "'";
|
||||
}
|
||||
|
||||
$sql .= " LANGUAGE \"{$language}\"";
|
||||
|
||||
// Add flags
|
||||
foreach ($flags as $v) {
|
||||
// Skip default flags
|
||||
if ($v == '') continue;
|
||||
else $sql .= "\n{$v}";
|
||||
}
|
||||
|
||||
$status = $this->execute($sql);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* set the comment */
|
||||
$status = $this->setComment('FUNCTION', "\"{$funcname}\"({$args})", null, $comment);
|
||||
if ($status != 0) {
|
||||
$this->rollbackTransaction();
|
||||
return -4;
|
||||
}
|
||||
|
||||
return $this->endTransaction();
|
||||
}
|
||||
|
||||
// Index functions
|
||||
|
||||
/**
|
||||
* Clusters an index
|
||||
* @param $index The name of the index
|
||||
* @param $table The table the index is on
|
||||
* @return 0 success
|
||||
*/
|
||||
function clusterIndex($table='', $index='') {
|
||||
|
||||
$sql = 'CLUSTER';
|
||||
|
||||
// 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
|
||||
|
||||
if (!empty($table)) {
|
||||
$f_schema = $this->_schema;
|
||||
$this->fieldClean($f_schema);
|
||||
$this->fieldClean($table);
|
||||
|
||||
if (!empty($index)) {
|
||||
$this->fieldClean($index);
|
||||
$sql .= " \"{$index}\" ON \"{$f_schema}\".\"{$table}\"";
|
||||
}
|
||||
else {
|
||||
$sql .= " \"{$f_schema}\".\"{$table}\"";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->execute($sql);
|
||||
}
|
||||
|
||||
// Operator functions
|
||||
|
||||
/**
|
||||
* Returns all details for a particular operator
|
||||
* @param $operator_oid The oid of the operator
|
||||
* @return Function info
|
||||
*/
|
||||
function getOperator($operator_oid) {
|
||||
$this->clean($operator_oid);
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
po.oid, po.oprname,
|
||||
oprleft::pg_catalog.regtype AS oprleftname,
|
||||
oprright::pg_catalog.regtype AS oprrightname,
|
||||
oprresult::pg_catalog.regtype AS resultname,
|
||||
po.oprcanhash,
|
||||
oprcom::pg_catalog.regoperator AS oprcom,
|
||||
oprnegate::pg_catalog.regoperator AS oprnegate,
|
||||
oprlsortop::pg_catalog.regoperator AS oprlsortop,
|
||||
oprrsortop::pg_catalog.regoperator AS oprrsortop,
|
||||
oprltcmpop::pg_catalog.regoperator AS oprltcmpop,
|
||||
oprgtcmpop::pg_catalog.regoperator AS oprgtcmpop,
|
||||
po.oprcode::pg_catalog.regproc AS oprcode,
|
||||
po.oprrest::pg_catalog.regproc AS oprrest,
|
||||
po.oprjoin::pg_catalog.regproc AS oprjoin
|
||||
FROM
|
||||
pg_catalog.pg_operator po
|
||||
WHERE
|
||||
po.oid='{$operator_oid}'
|
||||
";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Operator Class functions
|
||||
|
||||
/**
|
||||
* Gets all opclasses
|
||||
* @return A recordset
|
||||
*/
|
||||
function getOpClasses() {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$sql = "
|
||||
SELECT
|
||||
pa.amname,
|
||||
po.opcname,
|
||||
po.opcintype::pg_catalog.regtype AS opcintype,
|
||||
po.opcdefault,
|
||||
pg_catalog.obj_description(po.oid, 'pg_opclass') AS opccomment
|
||||
FROM
|
||||
pg_catalog.pg_opclass po, pg_catalog.pg_am pa, pg_catalog.pg_namespace pn
|
||||
WHERE
|
||||
po.opcamid=pa.oid
|
||||
AND po.opcnamespace=pn.oid
|
||||
AND pn.nspname='{$c_schema}'
|
||||
ORDER BY 1,2
|
||||
";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
|
||||
function hasCreateTableLikeWithIndexes() {return false;}
|
||||
function hasEnumTypes() {return false;}
|
||||
function hasFTS() {return false;}
|
||||
function hasFunctionCosting() {return false;}
|
||||
function hasFunctionGUC() {return false;}
|
||||
function hasVirtualTransactionId() {return false;}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PostgreSQL 8.3 support
|
||||
*
|
||||
* $Id: Postgres82.php,v 1.10 2007/12/28 16:21:25 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/Postgres84.php');
|
||||
|
||||
class Postgres83 extends Postgres84 {
|
||||
|
||||
var $major_version = 8.3;
|
||||
|
||||
// List of all legal privileges that can be applied to different types
|
||||
// of objects.
|
||||
var $privlist = array(
|
||||
'table' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'view' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'sequence' => array('SELECT', 'UPDATE', 'ALL PRIVILEGES'),
|
||||
'database' => array('CREATE', 'TEMPORARY', 'CONNECT', 'ALL PRIVILEGES'),
|
||||
'function' => array('EXECUTE', 'ALL PRIVILEGES'),
|
||||
'language' => array('USAGE', 'ALL PRIVILEGES'),
|
||||
'schema' => array('CREATE', 'USAGE', 'ALL PRIVILEGES'),
|
||||
'tablespace' => array('CREATE', 'ALL PRIVILEGES')
|
||||
);
|
||||
// List of characters in acl lists and the privileges they
|
||||
// refer to.
|
||||
var $privmap = array(
|
||||
'r' => 'SELECT',
|
||||
'w' => 'UPDATE',
|
||||
'a' => 'INSERT',
|
||||
'd' => 'DELETE',
|
||||
'R' => 'RULE',
|
||||
'x' => 'REFERENCES',
|
||||
't' => 'TRIGGER',
|
||||
'X' => 'EXECUTE',
|
||||
'U' => 'USAGE',
|
||||
'C' => 'CREATE',
|
||||
'T' => 'TEMPORARY',
|
||||
'c' => 'CONNECT'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $conn The database connection
|
||||
*/
|
||||
function Postgres83($conn) {
|
||||
$this->Postgres($conn);
|
||||
}
|
||||
|
||||
// Help functions
|
||||
|
||||
function getHelpPages() {
|
||||
include_once('./help/PostgresDoc83.php');
|
||||
return $this->help_page;
|
||||
}
|
||||
|
||||
// Databse functions
|
||||
|
||||
/**
|
||||
* Return all database available on the server
|
||||
* @param $currentdatabase database name that should be on top of the resultset
|
||||
*
|
||||
* @return A list of databases, sorted alphabetically
|
||||
*/
|
||||
function getDatabases($currentdatabase = NULL) {
|
||||
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);
|
||||
$clause = " AND pr.rolname='{$username}'";
|
||||
}
|
||||
else $clause = '';
|
||||
|
||||
if ($currentdatabase != NULL) {
|
||||
$this->clean($currentdatabase);
|
||||
$orderby = "ORDER BY pdb.datname = '{$currentdatabase}' DESC, pdb.datname";
|
||||
}
|
||||
else
|
||||
$orderby = "ORDER BY pdb.datname";
|
||||
|
||||
if (!$conf['show_system'])
|
||||
$where = ' AND NOT pdb.datistemplate';
|
||||
else
|
||||
$where = ' AND pdb.datallowconn';
|
||||
|
||||
$sql = "
|
||||
SELECT pdb.datname AS datname, pr.rolname AS datowner, pg_encoding_to_char(encoding) AS datencoding,
|
||||
(SELECT description FROM pg_catalog.pg_shdescription pd WHERE pdb.oid=pd.objoid) AS datcomment,
|
||||
(SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=pdb.dattablespace) AS tablespace,
|
||||
pg_catalog.pg_database_size(pdb.oid) as dbsize
|
||||
FROM pg_catalog.pg_database pdb LEFT JOIN pg_catalog.pg_roles pr ON (pdb.datdba = pr.oid)
|
||||
WHERE true
|
||||
{$where}
|
||||
{$clause}
|
||||
{$orderby}";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
// Administration functions
|
||||
|
||||
/**
|
||||
* Returns all available autovacuum per table information.
|
||||
* @return A recordset
|
||||
*/
|
||||
function getTableAutovacuum($table='') {
|
||||
$sql = '';
|
||||
|
||||
if ($table !== '') {
|
||||
$this->clean($table);
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
|
||||
$sql = "
|
||||
SELECT vacrelid, nspname, relname,
|
||||
CASE enabled
|
||||
WHEN 't' THEN 'on'
|
||||
ELSE 'off'
|
||||
END AS autovacuum_enabled, vac_base_thresh AS autovacuum_vacuum_threshold,
|
||||
vac_scale_factor AS autovacuum_vacuum_scale_factor, anl_base_thresh AS autovacuum_analyze_threshold,
|
||||
anl_scale_factor AS autovacuum_analyze_scale_factor, vac_cost_delay AS autovacuum_vacuum_cost_delay,
|
||||
vac_cost_limit AS autovacuum_vacuum_cost_limit
|
||||
FROM pg_autovacuum AS a
|
||||
join pg_class AS c on (c.oid=a.vacrelid)
|
||||
join pg_namespace AS n on (n.oid=c.relnamespace)
|
||||
WHERE c.relname = '{$table}' AND n.nspname = '{$c_schema}'
|
||||
ORDER BY nspname, relname
|
||||
";
|
||||
}
|
||||
else {
|
||||
$sql = "
|
||||
SELECT vacrelid, nspname, relname,
|
||||
CASE enabled
|
||||
WHEN 't' THEN 'on'
|
||||
ELSE 'off'
|
||||
END AS autovacuum_enabled, vac_base_thresh AS autovacuum_vacuum_threshold,
|
||||
vac_scale_factor AS autovacuum_vacuum_scale_factor, anl_base_thresh AS autovacuum_analyze_threshold,
|
||||
anl_scale_factor AS autovacuum_analyze_scale_factor, vac_cost_delay AS autovacuum_vacuum_cost_delay,
|
||||
vac_cost_limit AS autovacuum_vacuum_cost_limit
|
||||
FROM pg_autovacuum AS a
|
||||
join pg_class AS c on (c.oid=a.vacrelid)
|
||||
join pg_namespace AS n on (n.oid=c.relnamespace)
|
||||
ORDER BY nspname, relname
|
||||
";
|
||||
}
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
function saveAutovacuum($table, $vacenabled, $vacthreshold, $vacscalefactor, $anathresold,
|
||||
$anascalefactor, $vaccostdelay, $vaccostlimit)
|
||||
{
|
||||
$defaults = $this->getAutovacuum();
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($table);
|
||||
|
||||
$rs = $this->selectSet("
|
||||
SELECT c.oid
|
||||
FROM pg_catalog.pg_class AS c
|
||||
LEFT JOIN pg_catalog.pg_namespace AS n ON (n.oid=c.relnamespace)
|
||||
WHERE
|
||||
c.relname = '{$table}' AND n.nspname = '{$c_schema}'
|
||||
");
|
||||
|
||||
if ($rs->EOF)
|
||||
return -1;
|
||||
|
||||
$toid = $rs->fields('oid');
|
||||
unset ($rs);
|
||||
|
||||
if (empty($_POST['autovacuum_vacuum_threshold']))
|
||||
$_POST['autovacuum_vacuum_threshold'] = $defaults['autovacuum_vacuum_threshold'];
|
||||
|
||||
if (empty($_POST['autovacuum_vacuum_scale_factor']))
|
||||
$_POST['autovacuum_vacuum_scale_factor'] = $defaults['autovacuum_vacuum_scale_factor'];
|
||||
|
||||
if (empty($_POST['autovacuum_analyze_threshold']))
|
||||
$_POST['autovacuum_analyze_threshold'] = $defaults['autovacuum_analyze_threshold'];
|
||||
|
||||
if (empty($_POST['autovacuum_analyze_scale_factor']))
|
||||
$_POST['autovacuum_analyze_scale_factor'] = $defaults['autovacuum_analyze_scale_factor'];
|
||||
|
||||
if (empty($_POST['autovacuum_vacuum_cost_delay']))
|
||||
$_POST['autovacuum_vacuum_cost_delay'] = $defaults['autovacuum_vacuum_cost_delay'];
|
||||
|
||||
if (empty($_POST['autovacuum_vacuum_cost_limit']))
|
||||
$_POST['autovacuum_vacuum_cost_limit'] = $defaults['autovacuum_vacuum_cost_limit'];
|
||||
|
||||
if (empty($_POST['vacuum_freeze_min_age']))
|
||||
$_POST['vacuum_freeze_min_age'] = $defaults['vacuum_freeze_min_age'];
|
||||
|
||||
if (empty($_POST['autovacuum_freeze_max_age']))
|
||||
$_POST['autovacuum_freeze_max_age'] = $defaults['autovacuum_freeze_max_age'];
|
||||
|
||||
|
||||
$rs = $this->selectSet("SELECT vacrelid
|
||||
FROM \"pg_catalog\".\"pg_autovacuum\"
|
||||
WHERE vacrelid = {$toid};");
|
||||
|
||||
$status = -1; // ini
|
||||
if (isset($rs->fields['vacrelid']) and ($rs->fields['vacrelid'] == $toid)) {
|
||||
// table exists in pg_autovacuum, UPDATE
|
||||
$sql = sprintf("UPDATE \"pg_catalog\".\"pg_autovacuum\" SET
|
||||
enabled = '%s',
|
||||
vac_base_thresh = %s,
|
||||
vac_scale_factor = %s,
|
||||
anl_base_thresh = %s,
|
||||
anl_scale_factor = %s,
|
||||
vac_cost_delay = %s,
|
||||
vac_cost_limit = %s,
|
||||
freeze_min_age = %s,
|
||||
freeze_max_age = %s
|
||||
WHERE vacrelid = {$toid};
|
||||
",
|
||||
($_POST['autovacuum_enabled'] == 'on')? 't':'f',
|
||||
$_POST['autovacuum_vacuum_threshold'],
|
||||
$_POST['autovacuum_vacuum_scale_factor'],
|
||||
$_POST['autovacuum_analyze_threshold'],
|
||||
$_POST['autovacuum_analyze_scale_factor'],
|
||||
$_POST['autovacuum_vacuum_cost_delay'],
|
||||
$_POST['autovacuum_vacuum_cost_limit'],
|
||||
$_POST['vacuum_freeze_min_age'],
|
||||
$_POST['autovacuum_freeze_max_age']
|
||||
);
|
||||
$status = $this->execute($sql);
|
||||
}
|
||||
else {
|
||||
// table doesn't exists in pg_autovacuum, INSERT
|
||||
$sql = sprintf("INSERT INTO \"pg_catalog\".\"pg_autovacuum\"
|
||||
VALUES (%s, '%s', %s, %s, %s, %s, %s, %s, %s, %s )
|
||||
WHERE
|
||||
c.relname = '{$table}' AND n.nspname = '{$c_schema}';",
|
||||
$toid,
|
||||
($_POST['autovacuum_enabled'] == 'on')? 't':'f',
|
||||
$_POST['autovacuum_vacuum_threshold'],
|
||||
$_POST['autovacuum_vacuum_scale_factor'],
|
||||
$_POST['autovacuum_analyze_threshold'],
|
||||
$_POST['autovacuum_analyze_scale_factor'],
|
||||
$_POST['autovacuum_vacuum_cost_delay'],
|
||||
$_POST['autovacuum_vacuum_cost_limit'],
|
||||
$_POST['vacuum_freeze_min_age'],
|
||||
$_POST['autovacuum_freeze_max_age']
|
||||
);
|
||||
$status = $this->execute($sql);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
function dropAutovacuum($table) {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($table);
|
||||
|
||||
$rs = $this->selectSet("
|
||||
SELECT c.oid
|
||||
FROM pg_catalog.pg_class AS c
|
||||
LEFT JOIN pg_catalog.pg_namespace AS n ON (n.oid=c.relnamespace)
|
||||
WHERE
|
||||
c.relname = '{$table}' AND n.nspname = '{$c_schema}'
|
||||
");
|
||||
|
||||
return $this->deleteRow('pg_autovacuum', array('vacrelid' => $rs->fields['oid']), 'pg_catalog');
|
||||
}
|
||||
|
||||
// Sequence functions
|
||||
|
||||
/**
|
||||
* Alter a sequence's properties
|
||||
* @param $seqrs The sequence RecordSet returned by getSequence()
|
||||
* @param $increment The sequence incremental value
|
||||
* @param $minvalue The sequence minimum value
|
||||
* @param $maxvalue The sequence maximum value
|
||||
* @param $restartvalue The sequence current value
|
||||
* @param $cachevalue The sequence cache value
|
||||
* @param $cycledvalue Sequence can cycle ?
|
||||
* @param $startvalue The sequence start value when issueing a restart (ignored)
|
||||
* @return 0 success
|
||||
*/
|
||||
function alterSequenceProps($seqrs, $increment, $minvalue, $maxvalue,
|
||||
$restartvalue, $cachevalue, $cycledvalue, $startvalue) {
|
||||
|
||||
$sql = '';
|
||||
/* vars are cleaned in _alterSequence */
|
||||
if (!empty($increment) && ($increment != $seqrs->fields['increment_by'])) $sql .= " INCREMENT {$increment}";
|
||||
if (!empty($minvalue) && ($minvalue != $seqrs->fields['min_value'])) $sql .= " MINVALUE {$minvalue}";
|
||||
if (!empty($maxvalue) && ($maxvalue != $seqrs->fields['max_value'])) $sql .= " MAXVALUE {$maxvalue}";
|
||||
if (!empty($restartvalue) && ($restartvalue != $seqrs->fields['last_value'])) $sql .= " RESTART {$restartvalue}";
|
||||
if (!empty($cachevalue) && ($cachevalue != $seqrs->fields['cache_value'])) $sql .= " CACHE {$cachevalue}";
|
||||
// toggle cycle yes/no
|
||||
if (!is_null($cycledvalue)) $sql .= (!$cycledvalue ? ' NO ' : '') . " CYCLE";
|
||||
if ($sql != '') {
|
||||
$f_schema = $this->_schema;
|
||||
$this->fieldClean($f_schema);
|
||||
$sql = "ALTER SEQUENCE \"{$f_schema}\".\"{$seqrs->fields['seqname']}\" {$sql}";
|
||||
return $this->execute($sql);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a sequence's owner
|
||||
* @param $seqrs The sequence RecordSet returned by getSequence()
|
||||
* @param $name The new owner for the sequence
|
||||
* @return 0 success
|
||||
*/
|
||||
function alterSequenceOwner($seqrs, $owner) {
|
||||
// If owner has been changed, then do the alteration. We are
|
||||
// careful to avoid this generally as changing owner is a
|
||||
// superuser only function.
|
||||
/* vars are cleaned in _alterSequence */
|
||||
if (!empty($owner) && ($seqrs->fields['seqowner'] != $owner)) {
|
||||
$f_schema = $this->_schema;
|
||||
$this->fieldClean($f_schema);
|
||||
$sql = "ALTER TABLE \"{$f_schema}\".\"{$seqrs->fields['seqname']}\" OWNER TO \"{$owner}\"";
|
||||
return $this->execute($sql);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function hasQueryKill() { return false; }
|
||||
function hasDatabaseCollation() { return false; }
|
||||
function hasAlterSequenceStart() { return false; }
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PostgreSQL 8.4 support
|
||||
*
|
||||
* $Id: Postgres82.php,v 1.10 2007/12/28 16:21:25 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/database/Postgres.php');
|
||||
|
||||
class Postgres84 extends Postgres {
|
||||
|
||||
var $major_version = 8.4;
|
||||
|
||||
// List of all legal privileges that can be applied to different types
|
||||
// of objects.
|
||||
var $privlist = array(
|
||||
'table' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'view' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
||||
'sequence' => array('SELECT', 'UPDATE', 'ALL PRIVILEGES'),
|
||||
'database' => array('CREATE', 'TEMPORARY', 'CONNECT', 'ALL PRIVILEGES'),
|
||||
'function' => array('EXECUTE', 'ALL PRIVILEGES'),
|
||||
'language' => array('USAGE', 'ALL PRIVILEGES'),
|
||||
'schema' => array('CREATE', 'USAGE', 'ALL PRIVILEGES'),
|
||||
'tablespace' => array('CREATE', 'ALL PRIVILEGES'),
|
||||
'column' => array('SELECT', 'INSERT', 'UPDATE', 'REFERENCES','ALL PRIVILEGES')
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $conn The database connection
|
||||
*/
|
||||
function Postgres84($conn) {
|
||||
$this->Postgres($conn);
|
||||
}
|
||||
|
||||
// Help functions
|
||||
|
||||
function getHelpPages() {
|
||||
include_once('./help/PostgresDoc84.php');
|
||||
return $this->help_page;
|
||||
}
|
||||
|
||||
// Database functions
|
||||
|
||||
/**
|
||||
* Grabs a list of triggers on a table
|
||||
* @param $table The name of a table whose triggers to retrieve
|
||||
* @return A recordset
|
||||
*/
|
||||
function getTriggers($table = '') {
|
||||
$c_schema = $this->_schema;
|
||||
$this->clean($c_schema);
|
||||
$this->clean($table);
|
||||
|
||||
$sql = "SELECT
|
||||
t.tgname, pg_catalog.pg_get_triggerdef(t.oid) AS tgdef,
|
||||
CASE WHEN t.tgenabled = 'D' THEN FALSE ELSE TRUE END AS tgenabled, p.oid AS prooid,
|
||||
p.proname || ' (' || pg_catalog.oidvectortypes(p.proargtypes) || ')' AS proproto,
|
||||
ns.nspname AS pronamespace
|
||||
FROM pg_catalog.pg_trigger t, pg_catalog.pg_proc p, pg_catalog.pg_namespace ns
|
||||
WHERE t.tgrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
|
||||
AND relnamespace=(SELECT oid FROM pg_catalog.pg_namespace WHERE nspname='{$c_schema}'))
|
||||
AND (NOT tgisconstraint OR NOT EXISTS
|
||||
(SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))
|
||||
AND p.oid=t.tgfoid
|
||||
AND p.pronamespace = ns.oid";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches all system catalogs to find objects that match a certain name.
|
||||
* @param $term The search term
|
||||
* @param $filter The object type to restrict to ('' means no restriction)
|
||||
* @return A recordset
|
||||
*/
|
||||
function findObject($term, $filter) {
|
||||
global $conf;
|
||||
|
||||
/*about escaping:
|
||||
* SET standard_conforming_string is not available before 8.2
|
||||
* So we must use PostgreSQL specific notation :/
|
||||
* E'' notation is not available before 8.1
|
||||
* $$ is available since 8.0
|
||||
* Nothing specific from 7.4
|
||||
**/
|
||||
|
||||
// Escape search term for ILIKE match
|
||||
$this->clean($term);
|
||||
$this->clean($filter);
|
||||
$term = str_replace('_', '\_', $term);
|
||||
$term = str_replace('%', '\%', $term);
|
||||
|
||||
// Exclude system relations if necessary
|
||||
if (!$conf['show_system']) {
|
||||
// XXX: The mention of information_schema here is in the wrong place, but
|
||||
// it's the quickest fix to exclude the info schema from 7.4
|
||||
$where = " AND pn.nspname NOT LIKE \$_PATERN_\$pg\_%\$_PATERN_\$ AND pn.nspname != 'information_schema'";
|
||||
$lan_where = "AND pl.lanispl";
|
||||
}
|
||||
else {
|
||||
$where = '';
|
||||
$lan_where = '';
|
||||
}
|
||||
|
||||
// Apply outer filter
|
||||
$sql = '';
|
||||
if ($filter != '') {
|
||||
$sql = "SELECT * FROM (";
|
||||
}
|
||||
|
||||
$term = "\$_PATERN_\$%{$term}%\$_PATERN_\$";
|
||||
|
||||
$sql .= "
|
||||
SELECT 'SCHEMA' AS type, oid, NULL AS schemaname, NULL AS relname, nspname AS name
|
||||
FROM pg_catalog.pg_namespace pn WHERE nspname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT CASE WHEN relkind='r' THEN 'TABLE' WHEN relkind='v' THEN 'VIEW' WHEN relkind='S' THEN 'SEQUENCE' END, pc.oid,
|
||||
pn.nspname, NULL, pc.relname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn
|
||||
WHERE pc.relnamespace=pn.oid AND relkind IN ('r', 'v', 'S') AND relname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT CASE WHEN pc.relkind='r' THEN 'COLUMNTABLE' ELSE 'COLUMNVIEW' END, NULL, pn.nspname, pc.relname, pa.attname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_attribute pa WHERE pc.relnamespace=pn.oid AND pc.oid=pa.attrelid
|
||||
AND pa.attname ILIKE {$term} AND pa.attnum > 0 AND NOT pa.attisdropped AND pc.relkind IN ('r', 'v') {$where}
|
||||
UNION ALL
|
||||
SELECT 'FUNCTION', pp.oid, pn.nspname, NULL, pp.proname || '(' || pg_catalog.oidvectortypes(pp.proargtypes) || ')' FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pn
|
||||
WHERE pp.pronamespace=pn.oid AND NOT pp.proisagg AND pp.proname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'INDEX', NULL, pn.nspname, pc.relname, pc2.relname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_index pi, pg_catalog.pg_class pc2 WHERE pc.relnamespace=pn.oid AND pc.oid=pi.indrelid
|
||||
AND pi.indexrelid=pc2.oid
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = pc2.tableoid AND d.objid = pc2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
|
||||
)
|
||||
AND pc2.relname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'CONSTRAINTTABLE', NULL, pn.nspname, pc.relname, pc2.conname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_constraint pc2 WHERE pc.relnamespace=pn.oid AND pc.oid=pc2.conrelid AND pc2.conrelid != 0
|
||||
AND CASE WHEN pc2.contype IN ('f', 'c') THEN TRUE ELSE NOT EXISTS (
|
||||
SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = pc2.tableoid AND d.objid = pc2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
|
||||
) END
|
||||
AND pc2.conname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'CONSTRAINTDOMAIN', pt.oid, pn.nspname, pt.typname, pc.conname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_constraint pc WHERE pt.typnamespace=pn.oid AND pt.oid=pc.contypid AND pc.contypid != 0
|
||||
AND pc.conname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'TRIGGER', NULL, pn.nspname, pc.relname, pt.tgname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_trigger pt WHERE pc.relnamespace=pn.oid AND pc.oid=pt.tgrelid
|
||||
AND ( NOT pt.tgisconstraint OR NOT EXISTS
|
||||
(SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
|
||||
ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
|
||||
WHERE d.classid = pt.tableoid AND d.objid = pt.oid AND d.deptype = 'i' AND c.contype = 'f'))
|
||||
AND pt.tgname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'RULETABLE', NULL, pn.nspname AS schemaname, c.relname AS tablename, r.rulename FROM pg_catalog.pg_rewrite r
|
||||
JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
|
||||
LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = c.relnamespace
|
||||
WHERE c.relkind='r' AND r.rulename != '_RETURN' AND r.rulename ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'RULEVIEW', NULL, pn.nspname AS schemaname, c.relname AS tablename, r.rulename FROM pg_catalog.pg_rewrite r
|
||||
JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
|
||||
LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = c.relnamespace
|
||||
WHERE c.relkind='v' AND r.rulename != '_RETURN' AND r.rulename ILIKE {$term} {$where}
|
||||
";
|
||||
|
||||
// Add advanced objects if show_advanced is set
|
||||
if ($conf['show_advanced']) {
|
||||
$sql .= "
|
||||
UNION ALL
|
||||
SELECT CASE WHEN pt.typtype='d' THEN 'DOMAIN' ELSE 'TYPE' END, pt.oid, pn.nspname, NULL,
|
||||
pt.typname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn
|
||||
WHERE pt.typnamespace=pn.oid AND typname ILIKE {$term}
|
||||
AND (pt.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = pt.typrelid))
|
||||
{$where}
|
||||
UNION ALL
|
||||
SELECT 'OPERATOR', po.oid, pn.nspname, NULL, po.oprname FROM pg_catalog.pg_operator po, pg_catalog.pg_namespace pn
|
||||
WHERE po.oprnamespace=pn.oid AND oprname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'CONVERSION', pc.oid, pn.nspname, NULL, pc.conname FROM pg_catalog.pg_conversion pc,
|
||||
pg_catalog.pg_namespace pn WHERE pc.connamespace=pn.oid AND conname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT 'LANGUAGE', pl.oid, NULL, NULL, pl.lanname FROM pg_catalog.pg_language pl
|
||||
WHERE lanname ILIKE {$term} {$lan_where}
|
||||
UNION ALL
|
||||
SELECT DISTINCT ON (p.proname) 'AGGREGATE', p.oid, pn.nspname, NULL, p.proname FROM pg_catalog.pg_proc p
|
||||
LEFT JOIN pg_catalog.pg_namespace pn ON p.pronamespace=pn.oid
|
||||
WHERE p.proisagg AND p.proname ILIKE {$term} {$where}
|
||||
UNION ALL
|
||||
SELECT DISTINCT ON (po.opcname) 'OPCLASS', po.oid, pn.nspname, NULL, po.opcname FROM pg_catalog.pg_opclass po,
|
||||
pg_catalog.pg_namespace pn WHERE po.opcnamespace=pn.oid
|
||||
AND po.opcname ILIKE {$term} {$where}
|
||||
";
|
||||
}
|
||||
// Otherwise just add domains
|
||||
else {
|
||||
$sql .= "
|
||||
UNION ALL
|
||||
SELECT 'DOMAIN', pt.oid, pn.nspname, NULL,
|
||||
pt.typname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn
|
||||
WHERE pt.typnamespace=pn.oid AND pt.typtype='d' AND typname ILIKE {$term}
|
||||
AND (pt.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = pt.typrelid))
|
||||
{$where}
|
||||
";
|
||||
}
|
||||
|
||||
if ($filter != '') {
|
||||
// We use like to make RULE, CONSTRAINT and COLUMN searches work
|
||||
$sql .= ") AS sub WHERE type LIKE '{$filter}%' ";
|
||||
}
|
||||
|
||||
$sql .= "ORDER BY type, schemaname, relname, name";
|
||||
|
||||
return $this->selectSet($sql);
|
||||
}
|
||||
|
||||
|
||||
// Capabilities
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A class that implements the plugin system
|
||||
*
|
||||
* $Id: Plugin.php,v 1.2 2005/06/16 14:40:12 chriskl Exp $
|
||||
*/
|
||||
|
||||
class Plugin {
|
||||
|
||||
var $tabname = null;
|
||||
var $config = null;
|
||||
var $name = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function Plugin($name) {
|
||||
$this->name = $name;
|
||||
|
||||
// Read in configuration
|
||||
if ($this->config !== null) {
|
||||
global $conf;
|
||||
include('./conf/' . $name . '.inc.php');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,910 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A class that implements the Slony 1.0.x support plugin
|
||||
*
|
||||
* $Id: Slony.php,v 1.15 2007/10/02 21:36:35 ioguix Exp $
|
||||
*/
|
||||
|
||||
include_once('./classes/plugins/Plugin.php');
|
||||
|
||||
class Slony extends Plugin {
|
||||
|
||||
var $slony_version;
|
||||
var $slony_schema;
|
||||
var $slony_cluster;
|
||||
var $slony_owner;
|
||||
var $slony_comment;
|
||||
var $enabled = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function Slony() {
|
||||
$this->Plugin('slony');
|
||||
$this->isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not Slony is installed in the current
|
||||
* database.
|
||||
* @post Will populate version and schema fields, etc.
|
||||
* @return True if Slony is installed, false otherwise.
|
||||
*/
|
||||
function isEnabled() {
|
||||
// Access cache
|
||||
if ($this->enabled !== null) return $this->enabled;
|
||||
else $this->enabled = false;
|
||||
|
||||
global $data;
|
||||
|
||||
// Check for the slonyversion() function and find the schema
|
||||
// it's in. We put an order by and limit 1 in here to guarantee
|
||||
// only finding the first one, even if there are somehow two
|
||||
// Slony schemas.
|
||||
$sql = "SELECT pn.nspname AS schema, pu.usename AS owner,
|
||||
SUBSTRING(pn.nspname FROM 2) AS cluster,
|
||||
pg_catalog.obj_description(pn.oid, 'pg_namespace') AS
|
||||
nspcomment
|
||||
FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pn,
|
||||
pg_catalog.pg_user pu
|
||||
WHERE pp.pronamespace=pn.oid
|
||||
AND pn.nspowner = pu.usesysid
|
||||
AND pp.proname='slonyversion'
|
||||
AND pn.nspname LIKE '@_%' ESCAPE '@'
|
||||
ORDER BY pn.nspname LIMIT 1";
|
||||
$rs = $data->selectSet($sql);
|
||||
if ($rs->recordCount() == 1) {
|
||||
$schema = $rs->fields['schema'];
|
||||
$this->slony_schema = $schema;
|
||||
$this->slony_owner = $rs->fields['owner'];
|
||||
$this->slony_comment = $rs->fields['nspcomment'];
|
||||
// Cluster name is schema minus "_" prefix.
|
||||
$this->slony_cluster = $rs->fields['cluster'];
|
||||
$data->fieldClean($schema);
|
||||
$sql = "SELECT \"{$schema}\".slonyversion() AS version";
|
||||
$version = $data->selectField($sql, 'version');
|
||||
if ($version === -1) return false;
|
||||
else {
|
||||
$this->slony_version = $version;
|
||||
$this->enabled = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
// CLUSTERS
|
||||
|
||||
/**
|
||||
* Gets the clusters in this database
|
||||
*/
|
||||
function getClusters() {
|
||||
include_once('./classes/ArrayRecordSet.php');
|
||||
|
||||
if ($this->isEnabled()) {
|
||||
$clusters = array(array('cluster' => $this->slony_cluster, 'comment' => $this->slony_comment));
|
||||
}
|
||||
else
|
||||
$clusters = array();
|
||||
|
||||
return new ArrayRecordSet($clusters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single cluster
|
||||
*/
|
||||
function getCluster() {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
|
||||
$sql = "SELECT no_id, no_comment, \"{$schema}\".slonyversion() AS version
|
||||
FROM \"{$schema}\".sl_local_node_id, \"{$schema}\".sl_node
|
||||
WHERE no_id=last_value";
|
||||
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops an entire cluster.
|
||||
*/
|
||||
function dropCluster() {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".uninstallnode(); DROP SCHEMA \"{$schema}\" CASCADE";
|
||||
|
||||
$status = $data->execute($sql);
|
||||
if ($status == 0) {
|
||||
$this->enabled = null;
|
||||
$enabled = $this->isEnabled();
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get a file into a string and replace
|
||||
* variables.
|
||||
* @return The file contents, or FALSE on error.
|
||||
*/
|
||||
function _getFile($file, $cluster) {
|
||||
global $data,$misc;
|
||||
$schema = '_' . $cluster;
|
||||
$data->fieldClean($cluster);
|
||||
|
||||
$server_info = $misc->getServerInfo();
|
||||
$path = $server_info['slony_sql'] . '/' . $file;
|
||||
|
||||
// Check that we can access the file
|
||||
if (!file_exists($path) || !is_readable($path)) return false;
|
||||
|
||||
$buffer = null;
|
||||
$handle = fopen($path, 'r');
|
||||
if ($handle === false) return false;
|
||||
while (!feof($handle)) {
|
||||
$temp = fgets($handle, 4096);
|
||||
$temp = str_replace('@CLUSTERNAME@', $cluster, $temp);
|
||||
|
||||
$temp = str_replace('@NAMESPACE@', $schema, $temp);
|
||||
$buffer .= $temp;
|
||||
}
|
||||
fclose($handle);
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new cluster
|
||||
*/
|
||||
function initCluster($name, $no_id, $no_comment) {
|
||||
global $data, $misc;
|
||||
|
||||
// Prevent timeouts since cluster initialization can be slow
|
||||
if (!ini_get('safe_mode')) set_time_limit(0);
|
||||
|
||||
$server_info = $misc->getServerInfo();
|
||||
|
||||
if (!$data->isSuperUser($server_info['username'])) {
|
||||
return -10;
|
||||
}
|
||||
|
||||
// Determine Slony compatibility version.
|
||||
if ($data->major_version == 7.3)
|
||||
$ver = '73';
|
||||
elseif ($data->major_version >= 7.4)
|
||||
$ver = '74';
|
||||
else {
|
||||
return -11;
|
||||
}
|
||||
|
||||
$status = $data->beginTransaction();
|
||||
if ($status != 0) return -1;
|
||||
|
||||
// Create the schema
|
||||
$status = $data->createSchema('_' . $name);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -2;
|
||||
}
|
||||
|
||||
$sql = $this->_getFile("xxid.v{$ver}.sql", $name);
|
||||
if ($sql === false) {
|
||||
$data->rollbackTransaction();
|
||||
return -6;
|
||||
}
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
|
||||
$sql = $this->_getFile('slony1_base.sql', $name);
|
||||
if ($sql === false) {
|
||||
$data->rollbackTransaction();
|
||||
return -6;
|
||||
}
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
/* THIS FILE IS EMPTY AND JUST CAUSES ERRORS
|
||||
$sql = $this->_getFile('slony1_base.v74.sql', $name);
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
*/
|
||||
$sql = $this->_getFile('slony1_funcs.sql', $name);
|
||||
if ($sql === false) {
|
||||
$data->rollbackTransaction();
|
||||
return -6;
|
||||
}
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
|
||||
$sql = $this->_getFile("slony1_funcs.v{$ver}.sql", $name);
|
||||
if ($sql === false) {
|
||||
$data->rollbackTransaction();
|
||||
return -6;
|
||||
}
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
|
||||
$this->enabled = null;
|
||||
$enabled = $this->isEnabled();
|
||||
if (!$enabled) {
|
||||
$data->rollbackTransaction();
|
||||
return -4;
|
||||
}
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($no_comment);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".initializelocalnode('{$no_id}', '{$no_comment}'); SELECT \"{$schema}\".enablenode('{$no_id}')";
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -5;
|
||||
}
|
||||
|
||||
return $data->endTransaction();
|
||||
}
|
||||
|
||||
// NODES
|
||||
|
||||
/**
|
||||
* Gets the nodes in this database
|
||||
*/
|
||||
function getNodes() {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
|
||||
// We use 10 seconds as the default check time since that is the
|
||||
// the default in Slony, and it gives no mechanism to look it up
|
||||
$sql = "SELECT no_id, no_active, no_comment, no_spool, ".
|
||||
"CASE WHEN st_lag_time > '10 seconds'::interval ".
|
||||
"THEN 'outofsync' ELSE 'insync' END AS no_status ".
|
||||
"FROM \"{$schema}\".sl_node ".
|
||||
"LEFT JOIN \"{$schema}\".sl_status ON (no_id =st_received) ".
|
||||
"ORDER BY no_comment";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single node
|
||||
*/
|
||||
function getNode($no_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
|
||||
$sql = "SELECT * FROM \"{$schema}\".sl_node WHERE no_id='{$no_id}'";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a node
|
||||
*/
|
||||
function createNode($no_id, $no_comment) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_comment);
|
||||
$data->clean($no_id);
|
||||
|
||||
if ($no_id != '')
|
||||
$sql = "SELECT \"{$schema}\".storenode('{$no_id}', '{$no_comment}')";
|
||||
else
|
||||
$sql = "SELECT \"{$schema}\".storenode((SELECT COALESCE(MAX(no_id), 0) + 1 FROM \"{$schema}\".sl_node), '{$no_comment}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a node
|
||||
*/
|
||||
function dropNode($no_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".dropnode('{$no_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
// REPLICATION SETS
|
||||
|
||||
/**
|
||||
* Gets the replication sets in this database
|
||||
*/
|
||||
function getReplicationSets() {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
|
||||
$sql = "SELECT *, set_locked IS NOT NULL AS is_locked FROM \"{$schema}\".sl_set ORDER BY set_id";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a particular replication set
|
||||
*/
|
||||
function getReplicationSet($set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
|
||||
$sql = "SELECT *, (SELECT COUNT(*) FROM \"{$schema}\".sl_subscribe ssub WHERE ssub.sub_set=ss.set_id) AS subscriptions,
|
||||
set_locked IS NOT NULL AS is_locked
|
||||
FROM \"{$schema}\".sl_set ss, \"{$schema}\".sl_node sn
|
||||
WHERE ss.set_origin=sn.no_id
|
||||
AND set_id='{$set_id}'";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set
|
||||
*/
|
||||
function createReplicationSet($set_id, $set_comment) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_comment);
|
||||
$data->clean($set_id);
|
||||
|
||||
if ($set_id != '')
|
||||
$sql = "SELECT \"{$schema}\".storeset('{$set_id}', '{$set_comment}')";
|
||||
else
|
||||
$sql = "SELECT \"{$schema}\".storeset((SELECT COALESCE(MAX(set_id), 0) + 1 FROM \"{$schema}\".sl_set), '{$set_comment}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a set
|
||||
*/
|
||||
function dropReplicationSet($set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".dropset('{$set_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks or unlocks a set
|
||||
* @param boolean $lock True to lock, false to unlock
|
||||
*/
|
||||
function lockReplicationSet($set_id, $lock) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
|
||||
if ($lock)
|
||||
$sql = "SELECT \"{$schema}\".lockset('{$set_id}')";
|
||||
else
|
||||
$sql = "SELECT \"{$schema}\".unlockset('{$set_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two sets
|
||||
*/
|
||||
function mergeReplicationSet($set_id, $target) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
$data->clean($target);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".mergeset('{$target}', '{$set_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a set to a new origin
|
||||
*/
|
||||
function moveReplicationSet($set_id, $new_origin) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
$data->clean($new_origin);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".moveset('{$set_id}', '{$new_origin}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes schema changing DDL set on nodes
|
||||
*/
|
||||
function executeReplicationSet($set_id, $script) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
$data->clean($script);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".ddlscript('{$set_id}', '{$script}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
// TABLES
|
||||
|
||||
/**
|
||||
* Return all tables in a replication set
|
||||
* @param $set_id The ID of the replication set
|
||||
* @return Tables in the replication set, sorted alphabetically
|
||||
*/
|
||||
function getTables($set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
|
||||
$sql = "SELECT st.tab_id, c.relname, n.nspname, n.nspname||'.'||c.relname AS qualname,
|
||||
pg_catalog.pg_get_userbyid(c.relowner) AS relowner,
|
||||
reltuples::bigint";
|
||||
// Tablespace
|
||||
if ($data->hasTablespaces()) {
|
||||
$sql .= ", (SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=c.reltablespace) AS tablespace";
|
||||
}
|
||||
$sql .= " FROM pg_catalog.pg_class c, \"{$schema}\".sl_table st, pg_catalog.pg_namespace n
|
||||
WHERE c.oid=st.tab_reloid
|
||||
AND c.relnamespace=n.oid
|
||||
AND st.tab_set='{$set_id}'
|
||||
ORDER BY n.nspname, c.relname";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table to a replication set
|
||||
*/
|
||||
function addTable($set_id, $tab_id, $nspname, $relname, $idxname, $comment, $storedtriggers) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
$data->clean($tab_id);
|
||||
$fqname = $nspname . '.' . $relname;
|
||||
$data->clean($fqname);
|
||||
$data->clean($nspname);
|
||||
$data->clean($relname);
|
||||
$data->clean($idxname);
|
||||
$data->clean($comment);
|
||||
|
||||
$hastriggers = (sizeof($storedtriggers) > 0);
|
||||
if ($hastriggers) {
|
||||
// Begin a transaction
|
||||
$status = $data->beginTransaction();
|
||||
if ($status != 0) return -1;
|
||||
}
|
||||
|
||||
if ($tab_id != '')
|
||||
$sql = "SELECT \"{$schema}\".setaddtable('{$set_id}', '{$tab_id}', '{$fqname}', '{$idxname}', '{$comment}')";
|
||||
else {
|
||||
$sql = "SELECT \"{$schema}\".setaddtable('{$set_id}', (SELECT COALESCE(MAX(tab_id), 0) + 1 FROM \"{$schema}\".sl_table), '{$fqname}', '{$idxname}', '{$comment}')";
|
||||
}
|
||||
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
if ($hastriggers) $data->rollbackTransaction();
|
||||
return -3;
|
||||
}
|
||||
|
||||
// If we are storing triggers, we need to know the tab_id that was assigned to the table
|
||||
if ($tab_id == '' && $hastriggers) {
|
||||
$sql = "SELECT tab_id
|
||||
FROM \"{$schema}\".sl_table
|
||||
WHERE tab_set='{$set_id}'
|
||||
AND tab_reloid=(SELECT pc.oid FROM pg_catalog.pg_class pc, pg_namespace pn
|
||||
WHERE pc.relnamespace=pn.oid AND pc.relname='{$relname}'
|
||||
AND pn.nspname='{$nspname}')";
|
||||
$tab_id = $data->selectField($sql, 'tab_id');
|
||||
if ($tab_id === -1) {
|
||||
$data->rollbackTransaction();
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
|
||||
// Store requested triggers
|
||||
if ($hastriggers) {
|
||||
foreach ($storedtriggers as $tgname) {
|
||||
$data->clean($tgname);
|
||||
$sql = "SELECT \"{$schema}\".storetrigger('{$tab_id}', '{$tgname}')";
|
||||
$status = $data->execute($sql);
|
||||
if ($status != 0) {
|
||||
$data->rollbackTransaction();
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($hastriggers)
|
||||
return $data->endTransaction();
|
||||
else
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a table from a replication set
|
||||
*/
|
||||
function dropTable($tab_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($tab_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".setdroptable('{$tab_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a table to another replication set
|
||||
*/
|
||||
function moveTable($tab_id, $new_set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($tab_id);
|
||||
$data->clean($new_set_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".setmovetable('{$tab_id}', '{$new_set_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all tables we are not current in a replication set
|
||||
*/
|
||||
function getNonRepTables()
|
||||
{
|
||||
global $data;
|
||||
/*
|
||||
* we cannot just query pg_tables as we want the OID of the table
|
||||
* for the subquery against the slony table. We could match on
|
||||
* on schema name and table name, but the slony info isn't updated
|
||||
* if the user renames a table which is in a replication set
|
||||
*/
|
||||
$sql = "SELECT c.relname, n.nspname, n.nspname||'.'||c.relname AS qualname,
|
||||
pg_get_userbyid(c.relowner) AS relowner
|
||||
FROM pg_class c
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'r' AND n.nspname NOT IN ('pg_catalog',
|
||||
'information_schema', 'pg_toast') AND
|
||||
NOT(n.nspname = '_{$this->slony_cluster}' AND
|
||||
relname LIKE 'sl_%') AND
|
||||
NOT EXISTS(SELECT 1 FROM _{$this->slony_cluster}.sl_table s
|
||||
WHERE s.tab_reloid = c.oid)
|
||||
ORDER BY n.nspname, c.relname";
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
// SEQUENCES
|
||||
|
||||
/**
|
||||
* Return all sequences in a replication set
|
||||
* @param $set_id The ID of the replication set
|
||||
* @return Sequences in the replication set, sorted alphabetically
|
||||
*/
|
||||
function getSequences($set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
|
||||
$sql = "SELECT ss.seq_id, c.relname AS seqname, n.nspname, n.nspname||'.'||c.relname AS qualname,
|
||||
pg_catalog.obj_description(c.oid, 'pg_class') AS seqcomment,
|
||||
pg_catalog.pg_get_userbyid(c.relowner) AS seqowner
|
||||
FROM pg_catalog.pg_class c, \"{$schema}\".sl_sequence ss, pg_catalog.pg_namespace n
|
||||
WHERE c.oid=ss.seq_reloid
|
||||
AND c.relnamespace=n.oid
|
||||
AND ss.seq_set='{$set_id}'
|
||||
ORDER BY n.nspname, c.relname";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sequence to a replication set
|
||||
*/
|
||||
function addSequence($set_id, $seq_id, $fqname, $comment) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
$data->clean($seq_id);
|
||||
$data->clean($fqname);
|
||||
$data->clean($comment);
|
||||
|
||||
if ($seq_id != '')
|
||||
$sql = "SELECT \"{$schema}\".setaddsequence('{$set_id}', '{$seq_id}', '{$fqname}', '{$comment}')";
|
||||
else
|
||||
$sql = "SELECT \"{$schema}\".setaddsequence('{$set_id}', (SELECT COALESCE(MAX(seq_id), 0) + 1 FROM \"{$schema}\".sl_sequence), '{$fqname}', '{$comment}')";
|
||||
|
||||
return $data->execute($sql); }
|
||||
|
||||
/**
|
||||
* Drops a sequence from a replication set
|
||||
*/
|
||||
function dropSequence($seq_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($seq_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".setdropsequence('{$seq_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a sequence to another replication set
|
||||
*/
|
||||
function moveSequence($seq_id, $new_set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($seq_id);
|
||||
$data->clean($new_set_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".setmovesequence('{$seq_id}', '{$new_set_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
// SUBSCRIPTIONS
|
||||
|
||||
/**
|
||||
* Gets all nodes subscribing to a set
|
||||
* @param $set_id The ID of the replication set
|
||||
* @return Nodes subscribing to this set
|
||||
*/
|
||||
function getSubscribedNodes($set_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
|
||||
$sql = "SELECT sn.*, ss.sub_set
|
||||
FROM \"{$schema}\".sl_subscribe ss, \"{$schema}\".sl_node sn
|
||||
WHERE ss.sub_set='{$set_id}'
|
||||
AND ss.sub_receiver = sn.no_id
|
||||
ORDER BY sn.no_comment";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all nodes subscribing to a set
|
||||
* @param $set_id The ID of the replication set
|
||||
* @return Nodes subscribing to this set
|
||||
*/
|
||||
function getSubscription($set_id, $no_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($set_id);
|
||||
$data->clean($no_id);
|
||||
|
||||
$sql = "SELECT ss.*, sn.no_comment AS receiver, sn2.no_comment AS provider
|
||||
FROM \"{$schema}\".sl_subscribe ss, \"{$schema}\".sl_node sn, \"{$schema}\".sl_node sn2
|
||||
WHERE ss.sub_set='{$set_id}'
|
||||
AND ss.sub_receiver = sn.no_id
|
||||
AND ss.sub_provider = sn2.no_id
|
||||
AND sn.no_id='{$no_id}'";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
// NODES
|
||||
|
||||
/**
|
||||
* Gets node paths
|
||||
*/
|
||||
function getPaths($no_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
|
||||
$sql = "SELECT * FROM \"{$schema}\".sl_path sp, \"{$schema}\".sl_node sn
|
||||
WHERE sp.pa_server=sn.no_id
|
||||
AND sp.pa_client='{$no_id}'
|
||||
ORDER BY sn.no_comment";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets node path details
|
||||
*/
|
||||
function getPath($no_id, $path_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($path_id);
|
||||
|
||||
$sql = "SELECT * FROM \"{$schema}\".sl_path sp, \"{$schema}\".sl_node sn
|
||||
WHERE sp.pa_server=sn.no_id
|
||||
AND sp.pa_client='{$no_id}'
|
||||
AND sn.no_id='{$path_id}'";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path
|
||||
*/
|
||||
function createPath($no_id, $server, $conn, $retry) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($server);
|
||||
$data->clean($conn);
|
||||
$data->clean($retry);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".storepath('{$server}', '{$no_id}', '{$conn}', '{$retry}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a path
|
||||
*/
|
||||
function dropPath($no_id, $path_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($path_id);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".droppath('{$path_id}', '{$no_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
// LISTENS
|
||||
|
||||
/**
|
||||
* Gets node listens
|
||||
*/
|
||||
function getListens($no_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
|
||||
$sql = "SELECT * FROM \"{$schema}\".sl_listen sl, \"{$schema}\".sl_node sn
|
||||
WHERE sl.li_provider=sn.no_id
|
||||
AND sl.li_receiver='{$no_id}'
|
||||
ORDER BY sn.no_comment";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets node listen details
|
||||
*/
|
||||
function getListen($no_id, $listen_id) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($listen_id);
|
||||
|
||||
$sql = "SELECT sl.*, sn.*, sn2.no_comment AS origin FROM \"{$schema}\".sl_listen sl, \"{$schema}\".sl_node sn, \"{$schema}\".sl_node sn2
|
||||
WHERE sl.li_provider=sn.no_id
|
||||
AND sl.li_receiver='{$no_id}'
|
||||
AND sn.no_id='{$listen_id}'
|
||||
AND sn2.no_id=sl.li_origin";
|
||||
|
||||
return $data->selectSet($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a listen
|
||||
*/
|
||||
function createListen($no_id, $origin, $provider) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($origin);
|
||||
$data->clean($provider);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".storelisten('{$origin}', '{$provider}', '{$no_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a listen
|
||||
*/
|
||||
function dropListen($no_id, $origin, $provider) {
|
||||
global $data;
|
||||
|
||||
$schema = $this->slony_schema;
|
||||
$data->fieldClean($schema);
|
||||
$data->clean($no_id);
|
||||
$data->clean($origin);
|
||||
$data->clean($provider);
|
||||
|
||||
$sql = "SELECT \"{$schema}\".droplisten('{$origin}', '{$provider}', '{$no_id}')";
|
||||
|
||||
return $data->execute($sql);
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user