mirror of
				https://github.com/brmlab/brmsklad.git
				synced 2025-10-30 15:53:59 +01:00 
			
		
		
		
	Backup of current cakephp version
This commit is contained in:
		
							parent
							
								
									b8f82da6f8
								
							
						
					
					
						commit
						5a580df460
					
				
					 925 changed files with 238041 additions and 1 deletions
				
			
		
							
								
								
									
										907
									
								
								lib/Cake/Model/Datasource/Database/Postgres.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										907
									
								
								lib/Cake/Model/Datasource/Database/Postgres.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,907 @@ | |||
| <?php | ||||
| /** | ||||
|  * PostgreSQL layer for DBO. | ||||
|  * | ||||
|  * PHP 5 | ||||
|  * | ||||
|  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | ||||
|  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) | ||||
|  * | ||||
|  * Licensed under The MIT License | ||||
|  * Redistributions of files must retain the above copyright notice. | ||||
|  * | ||||
|  * @copyright     Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) | ||||
|  * @link          http://cakephp.org CakePHP(tm) Project | ||||
|  * @package       Cake.Model.Datasource.Database | ||||
|  * @since         CakePHP(tm) v 0.9.1.114 | ||||
|  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php) | ||||
|  */ | ||||
| 
 | ||||
| App::uses('DboSource', 'Model/Datasource'); | ||||
| 
 | ||||
| /** | ||||
|  * PostgreSQL layer for DBO. | ||||
|  * | ||||
|  * @package       Cake.Model.Datasource.Database | ||||
|  */ | ||||
| class Postgres extends DboSource { | ||||
| 
 | ||||
| /** | ||||
|  * Driver description | ||||
|  * | ||||
|  * @var string | ||||
|  */ | ||||
| 	public $description = "PostgreSQL DBO Driver"; | ||||
| 
 | ||||
| /** | ||||
|  * Base driver configuration settings.  Merged with user settings. | ||||
|  * | ||||
|  * @var array | ||||
|  */ | ||||
| 	protected $_baseConfig = array( | ||||
| 		'persistent' => true, | ||||
| 		'host' => 'localhost', | ||||
| 		'login' => 'root', | ||||
| 		'password' => '', | ||||
| 		'database' => 'cake', | ||||
| 		'schema' => 'public', | ||||
| 		'port' => 5432, | ||||
| 		'encoding' => '' | ||||
| 	); | ||||
| 
 | ||||
| /** | ||||
|  * Columns | ||||
|  * | ||||
|  * @var array | ||||
|  */ | ||||
| 	public $columns = array( | ||||
| 		'primary_key' => array('name' => 'serial NOT NULL'), | ||||
| 		'string' => array('name' => 'varchar', 'limit' => '255'), | ||||
| 		'text' => array('name' => 'text'), | ||||
| 		'integer' => array('name' => 'integer', 'formatter' => 'intval'), | ||||
| 		'float' => array('name' => 'float', 'formatter' => 'floatval'), | ||||
| 		'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), | ||||
| 		'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), | ||||
| 		'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'), | ||||
| 		'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'), | ||||
| 		'binary' => array('name' => 'bytea'), | ||||
| 		'boolean' => array('name' => 'boolean'), | ||||
| 		'number' => array('name' => 'numeric'), | ||||
| 		'inet' => array('name' => 'inet') | ||||
| 	); | ||||
| 
 | ||||
| /** | ||||
|  * Starting Quote | ||||
|  * | ||||
|  * @var string | ||||
|  */ | ||||
| 	public $startQuote = '"'; | ||||
| 
 | ||||
| /** | ||||
|  * Ending Quote | ||||
|  * | ||||
|  * @var string | ||||
|  */ | ||||
| 	public $endQuote = '"'; | ||||
| 
 | ||||
| /** | ||||
|  * Contains mappings of custom auto-increment sequences, if a table uses a sequence name | ||||
|  * other than what is dictated by convention. | ||||
|  * | ||||
|  * @var array | ||||
|  */ | ||||
| 	protected $_sequenceMap = array(); | ||||
| 
 | ||||
| /** | ||||
|  * Connects to the database using options in the given configuration array. | ||||
|  * | ||||
|  * @return boolean True if successfully connected. | ||||
|  * @throws MissingConnectionException | ||||
|  */ | ||||
| 	public function connect() { | ||||
| 		$config = $this->config; | ||||
| 		$this->connected = false; | ||||
| 		try { | ||||
| 			$flags = array( | ||||
| 				PDO::ATTR_PERSISTENT => $config['persistent'], | ||||
| 				PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION | ||||
| 			); | ||||
| 			$this->_connection = new PDO( | ||||
| 				"pgsql:host={$config['host']};port={$config['port']};dbname={$config['database']}", | ||||
| 				$config['login'], | ||||
| 				$config['password'], | ||||
| 				$flags | ||||
| 			); | ||||
| 
 | ||||
| 			$this->connected = true; | ||||
| 			if (!empty($config['encoding'])) { | ||||
| 				$this->setEncoding($config['encoding']); | ||||
| 			} | ||||
| 			if (!empty($config['schema'])) { | ||||
| 				 $this->_execute('SET search_path TO ' . $config['schema']); | ||||
| 			} | ||||
| 		} catch (PDOException $e) { | ||||
| 			throw new MissingConnectionException(array( | ||||
| 				'class' => get_class($this), | ||||
| 				'message' => $e->getMessage() | ||||
| 			)); | ||||
| 		} | ||||
| 
 | ||||
| 		return $this->connected; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Check if PostgreSQL is enabled/loaded | ||||
|  * | ||||
|  * @return boolean | ||||
|  */ | ||||
| 	public function enabled() { | ||||
| 		return in_array('pgsql', PDO::getAvailableDrivers()); | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits. | ||||
|  * | ||||
|  * @param mixed $data | ||||
|  * @return array Array of table names in the database | ||||
|  */ | ||||
| 	public function listSources($data = null) { | ||||
| 		$cache = parent::listSources(); | ||||
| 
 | ||||
| 		if ($cache != null) { | ||||
| 			return $cache; | ||||
| 		} | ||||
| 
 | ||||
| 		$schema = $this->config['schema']; | ||||
| 		$sql = "SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = ?"; | ||||
| 		$result = $this->_execute($sql, array($schema)); | ||||
| 
 | ||||
| 		if (!$result) { | ||||
| 			return array(); | ||||
| 		} else { | ||||
| 			$tables = array(); | ||||
| 
 | ||||
| 			foreach ($result as $item) { | ||||
| 				$tables[] = $item->name; | ||||
| 			} | ||||
| 
 | ||||
| 			$result->closeCursor(); | ||||
| 			parent::listSources($tables); | ||||
| 			return $tables; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Returns an array of the fields in given table name. | ||||
|  * | ||||
|  * @param Model|string $model Name of database table to inspect | ||||
|  * @return array Fields in table. Keys are name and type | ||||
|  */ | ||||
| 	public function describe($model) { | ||||
| 		$table = $this->fullTableName($model, false, false); | ||||
| 		$fields = parent::describe($table); | ||||
| 		$this->_sequenceMap[$table] = array(); | ||||
| 		$cols = null; | ||||
| 
 | ||||
| 		if ($fields === null) { | ||||
| 			$cols = $this->_execute( | ||||
| 				"SELECT DISTINCT table_schema AS schema, column_name AS name, data_type AS type, is_nullable AS null,
 | ||||
| 					column_default AS default, ordinal_position AS position, character_maximum_length AS char_length, | ||||
| 					character_octet_length AS oct_length FROM information_schema.columns | ||||
| 				WHERE table_name = ? AND table_schema = ?  ORDER BY position",
 | ||||
| 				array($table, $this->config['schema']) | ||||
| 			); | ||||
| 
 | ||||
| 			// @codingStandardsIgnoreStart
 | ||||
| 			// Postgres columns don't match the coding standards.
 | ||||
| 			foreach ($cols as $c) { | ||||
| 				$type = $c->type; | ||||
| 				if (!empty($c->oct_length) && $c->char_length === null) { | ||||
| 					if ($c->type == 'character varying') { | ||||
| 						$length = null; | ||||
| 						$type = 'text'; | ||||
| 					} elseif ($c->type == 'uuid') { | ||||
| 						$length = 36; | ||||
| 					} else { | ||||
| 						$length = intval($c->oct_length); | ||||
| 					} | ||||
| 				} elseif (!empty($c->char_length)) { | ||||
| 					$length = intval($c->char_length); | ||||
| 				} else { | ||||
| 					$length = $this->length($c->type); | ||||
| 				} | ||||
| 				if (empty($length)) { | ||||
| 					$length = null; | ||||
| 				} | ||||
| 				$fields[$c->name] = array( | ||||
| 					'type' => $this->column($type), | ||||
| 					'null' => ($c->null == 'NO' ? false : true), | ||||
| 					'default' => preg_replace( | ||||
| 						"/^'(.*)'$/", | ||||
| 						"$1", | ||||
| 						preg_replace('/::.*/', '', $c->default) | ||||
| 					), | ||||
| 					'length' => $length | ||||
| 				); | ||||
| 				if ($model instanceof Model) { | ||||
| 					if ($c->name == $model->primaryKey) { | ||||
| 						$fields[$c->name]['key'] = 'primary'; | ||||
| 						if ($fields[$c->name]['type'] !== 'string') { | ||||
| 							$fields[$c->name]['length'] = 11; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				if ( | ||||
| 					$fields[$c->name]['default'] == 'NULL' || | ||||
| 					preg_match('/nextval\([\'"]?([\w.]+)/', $c->default, $seq) | ||||
| 				) { | ||||
| 					$fields[$c->name]['default'] = null; | ||||
| 					if (!empty($seq) && isset($seq[1])) { | ||||
| 						if (strpos($seq[1], '.') === false) { | ||||
| 							$sequenceName = $c->schema . '.' . $seq[1]; | ||||
| 						} else { | ||||
| 							$sequenceName = $seq[1]; | ||||
| 						} | ||||
| 						$this->_sequenceMap[$table][$c->name] = $sequenceName; | ||||
| 					} | ||||
| 				} | ||||
| 				if ($fields[$c->name]['type'] == 'boolean' && !empty($fields[$c->name]['default'])) { | ||||
| 					$fields[$c->name]['default'] = constant($fields[$c->name]['default']); | ||||
| 				} | ||||
| 			} | ||||
| 			$this->_cacheDescription($table, $fields); | ||||
| 		} | ||||
| 		// @codingStandardsIgnoreEnd
 | ||||
| 
 | ||||
| 		if (isset($model->sequence)) { | ||||
| 			$this->_sequenceMap[$table][$model->primaryKey] = $model->sequence; | ||||
| 		} | ||||
| 
 | ||||
| 		if ($cols) { | ||||
| 			$cols->closeCursor(); | ||||
| 		} | ||||
| 		return $fields; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Returns the ID generated from the previous INSERT operation. | ||||
|  * | ||||
|  * @param string $source Name of the database table | ||||
|  * @param string $field Name of the ID database field. Defaults to "id" | ||||
|  * @return integer | ||||
|  */ | ||||
| 	public function lastInsertId($source = null, $field = 'id') { | ||||
| 		$seq = $this->getSequence($source, $field); | ||||
| 		return $this->_connection->lastInsertId($seq); | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Gets the associated sequence for the given table/field | ||||
|  * | ||||
|  * @param string|Model $table Either a full table name (with prefix) as a string, or a model object | ||||
|  * @param string $field Name of the ID database field. Defaults to "id" | ||||
|  * @return string The associated sequence name from the sequence map, defaults to "{$table}_{$field}_seq" | ||||
|  */ | ||||
| 	public function getSequence($table, $field = 'id') { | ||||
| 		if (is_object($table)) { | ||||
| 			$table = $this->fullTableName($table, false, false); | ||||
| 		} | ||||
| 		if (isset($this->_sequenceMap[$table]) && isset($this->_sequenceMap[$table][$field])) { | ||||
| 			return $this->_sequenceMap[$table][$field]; | ||||
| 		} else { | ||||
| 			return "{$table}_{$field}_seq"; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Deletes all the records in a table and drops all associated auto-increment sequences | ||||
|  * | ||||
|  * @param string|Model $table A string or model class representing the table to be truncated | ||||
|  * @param boolean $reset true for resetting the sequence, false to leave it as is. | ||||
|  *    and if 1, sequences are not modified | ||||
|  * @return boolean	SQL TRUNCATE TABLE statement, false if not applicable. | ||||
|  */ | ||||
| 	public function truncate($table, $reset = false) { | ||||
| 		$table = $this->fullTableName($table, false, false); | ||||
| 		if (!isset($this->_sequenceMap[$table])) { | ||||
| 			$cache = $this->cacheSources; | ||||
| 			$this->cacheSources = false; | ||||
| 			$this->describe($table); | ||||
| 			$this->cacheSources = $cache; | ||||
| 		} | ||||
| 		if ($this->execute('DELETE FROM ' . $this->fullTableName($table))) { | ||||
| 			$schema = $this->config['schema']; | ||||
| 			if (isset($this->_sequenceMap[$table]) && $reset != true) { | ||||
| 				foreach ($this->_sequenceMap[$table] as $field => $sequence) { | ||||
| 					list($schema, $sequence) = explode('.', $sequence); | ||||
| 					$this->_execute("ALTER SEQUENCE \"{$schema}\".\"{$sequence}\" RESTART WITH 1"); | ||||
| 				} | ||||
| 			} | ||||
| 			return true; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Prepares field names to be quoted by parent | ||||
|  * | ||||
|  * @param string $data | ||||
|  * @return string SQL field | ||||
|  */ | ||||
| 	public function name($data) { | ||||
| 		if (is_string($data)) { | ||||
| 			$data = str_replace('"__"', '__', $data); | ||||
| 		} | ||||
| 		return parent::name($data); | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Generates the fields list of an SQL query. | ||||
|  * | ||||
|  * @param Model $model | ||||
|  * @param string $alias Alias table name | ||||
|  * @param mixed $fields | ||||
|  * @param boolean $quote | ||||
|  * @return array | ||||
|  */ | ||||
| 	public function fields(Model $model, $alias = null, $fields = array(), $quote = true) { | ||||
| 		if (empty($alias)) { | ||||
| 			$alias = $model->alias; | ||||
| 		} | ||||
| 		$fields = parent::fields($model, $alias, $fields, false); | ||||
| 
 | ||||
| 		if (!$quote) { | ||||
| 			return $fields; | ||||
| 		} | ||||
| 		$count = count($fields); | ||||
| 
 | ||||
| 		if ($count >= 1 && !preg_match('/^\s*COUNT\(\*/', $fields[0])) { | ||||
| 			$result = array(); | ||||
| 			for ($i = 0; $i < $count; $i++) { | ||||
| 				if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) { | ||||
| 					if (substr($fields[$i], -1) == '*') { | ||||
| 						if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') { | ||||
| 							$build = explode('.', $fields[$i]); | ||||
| 							$AssociatedModel = $model->{$build[0]}; | ||||
| 						} else { | ||||
| 							$AssociatedModel = $model; | ||||
| 						} | ||||
| 
 | ||||
| 						$_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema())); | ||||
| 						$result = array_merge($result, $_fields); | ||||
| 						continue; | ||||
| 					} | ||||
| 
 | ||||
| 					$prepend = ''; | ||||
| 					if (strpos($fields[$i], 'DISTINCT') !== false) { | ||||
| 						$prepend = 'DISTINCT '; | ||||
| 						$fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i])); | ||||
| 					} | ||||
| 
 | ||||
| 					if (strrpos($fields[$i], '.') === false) { | ||||
| 						$fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '__' . $fields[$i]); | ||||
| 					} else { | ||||
| 						$build = explode('.', $fields[$i]); | ||||
| 						$fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '__' . $build[1]); | ||||
| 					} | ||||
| 				} else { | ||||
| 					$fields[$i] = preg_replace_callback('/\(([\s\.\w]+)\)/',  array(&$this, '_quoteFunctionField'), $fields[$i]); | ||||
| 				} | ||||
| 				$result[] = $fields[$i]; | ||||
| 			} | ||||
| 			return $result; | ||||
| 		} | ||||
| 		return $fields; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Auxiliary function to quote matched `(Model.fields)` from a preg_replace_callback call | ||||
|  * Quotes the fields in a function call. | ||||
|  * | ||||
|  * @param string $match matched string | ||||
|  * @return string quoted string | ||||
|  */ | ||||
| 	protected function _quoteFunctionField($match) { | ||||
| 		$prepend = ''; | ||||
| 		if (strpos($match[1], 'DISTINCT') !== false) { | ||||
| 			$prepend = 'DISTINCT '; | ||||
| 			$match[1] = trim(str_replace('DISTINCT', '', $match[1])); | ||||
| 		} | ||||
| 		$constant = preg_match('/^\d+|NULL|FALSE|TRUE$/i', $match[1]); | ||||
| 
 | ||||
| 		if (!$constant && strpos($match[1], '.') === false) { | ||||
| 			$match[1] = $this->name($match[1]); | ||||
| 		} elseif (!$constant) { | ||||
| 			$parts = explode('.', $match[1]); | ||||
| 			if (!Hash::numeric($parts)) { | ||||
| 				$match[1] = $this->name($match[1]); | ||||
| 			} | ||||
| 		} | ||||
| 		return '(' . $prepend . $match[1] . ')'; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Returns an array of the indexes in given datasource name. | ||||
|  * | ||||
|  * @param string $model Name of model to inspect | ||||
|  * @return array Fields in table. Keys are column and unique | ||||
|  */ | ||||
| 	public function index($model) { | ||||
| 		$index = array(); | ||||
| 		$table = $this->fullTableName($model, false, false); | ||||
| 		if ($table) { | ||||
| 			$indexes = $this->query("SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, i.indisvalid, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) as statement, c2.reltablespace
 | ||||
| 			FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i | ||||
| 			WHERE c.oid  = ( | ||||
| 				SELECT c.oid | ||||
| 				FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace | ||||
| 				WHERE c.relname ~ '^(" . $table . ")$' | ||||
| 					AND pg_catalog.pg_table_is_visible(c.oid) | ||||
| 					AND n.nspname ~ '^(" . $this->config['schema'] . ")$' | ||||
| 			) | ||||
| 			AND c.oid = i.indrelid AND i.indexrelid = c2.oid | ||||
| 			ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname", false);
 | ||||
| 			foreach ($indexes as $info) { | ||||
| 				$key = array_pop($info); | ||||
| 				if ($key['indisprimary']) { | ||||
| 					$key['relname'] = 'PRIMARY'; | ||||
| 				} | ||||
| 				preg_match('/\(([^\)]+)\)/', $key['statement'], $indexColumns); | ||||
| 				$parsedColumn = $indexColumns[1]; | ||||
| 				if (strpos($indexColumns[1], ',') !== false) { | ||||
| 					$parsedColumn = explode(', ', $indexColumns[1]); | ||||
| 				} | ||||
| 				$index[$key['relname']]['unique'] = $key['indisunique']; | ||||
| 				$index[$key['relname']]['column'] = $parsedColumn; | ||||
| 			} | ||||
| 		} | ||||
| 		return $index; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Alter the Schema of a table. | ||||
|  * | ||||
|  * @param array $compare Results of CakeSchema::compare() | ||||
|  * @param string $table name of the table | ||||
|  * @return array | ||||
|  */ | ||||
| 	public function alterSchema($compare, $table = null) { | ||||
| 		if (!is_array($compare)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		$out = ''; | ||||
| 		$colList = array(); | ||||
| 		foreach ($compare as $curTable => $types) { | ||||
| 			$indexes = $colList = array(); | ||||
| 			if (!$table || $table == $curTable) { | ||||
| 				$out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n"; | ||||
| 				foreach ($types as $type => $column) { | ||||
| 					if (isset($column['indexes'])) { | ||||
| 						$indexes[$type] = $column['indexes']; | ||||
| 						unset($column['indexes']); | ||||
| 					} | ||||
| 					switch ($type) { | ||||
| 						case 'add': | ||||
| 							foreach ($column as $field => $col) { | ||||
| 								$col['name'] = $field; | ||||
| 								$colList[] = 'ADD COLUMN ' . $this->buildColumn($col); | ||||
| 							} | ||||
| 						break; | ||||
| 						case 'drop': | ||||
| 							foreach ($column as $field => $col) { | ||||
| 								$col['name'] = $field; | ||||
| 								$colList[] = 'DROP COLUMN ' . $this->name($field); | ||||
| 							} | ||||
| 						break; | ||||
| 						case 'change': | ||||
| 							foreach ($column as $field => $col) { | ||||
| 								if (!isset($col['name'])) { | ||||
| 									$col['name'] = $field; | ||||
| 								} | ||||
| 								$fieldName = $this->name($field); | ||||
| 
 | ||||
| 								$default = isset($col['default']) ? $col['default'] : null; | ||||
| 								$nullable = isset($col['null']) ? $col['null'] : null; | ||||
| 								unset($col['default'], $col['null']); | ||||
| 								$colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col)); | ||||
| 								if (isset($nullable)) { | ||||
| 									$nullable = ($nullable) ? 'DROP NOT NULL' : 'SET NOT NULL'; | ||||
| 									$colList[] = 'ALTER COLUMN ' . $fieldName . '  ' . $nullable; | ||||
| 								} | ||||
| 
 | ||||
| 								if (isset($default)) { | ||||
| 									$colList[] = 'ALTER COLUMN ' . $fieldName . '  SET DEFAULT ' . $this->value($default, $col['type']); | ||||
| 								} else { | ||||
| 									$colList[] = 'ALTER COLUMN ' . $fieldName . '  DROP DEFAULT'; | ||||
| 								} | ||||
| 
 | ||||
| 							} | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				if (isset($indexes['drop']['PRIMARY'])) { | ||||
| 					$colList[] = 'DROP CONSTRAINT ' . $curTable . '_pkey'; | ||||
| 				} | ||||
| 				if (isset($indexes['add']['PRIMARY'])) { | ||||
| 					$cols = $indexes['add']['PRIMARY']['column']; | ||||
| 					if (is_array($cols)) { | ||||
| 						$cols = implode(', ', $cols); | ||||
| 					} | ||||
| 					$colList[] = 'ADD PRIMARY KEY (' . $cols . ')'; | ||||
| 				} | ||||
| 
 | ||||
| 				if (!empty($colList)) { | ||||
| 					$out .= "\t" . implode(",\n\t", $colList) . ";\n\n"; | ||||
| 				} else { | ||||
| 					$out = ''; | ||||
| 				} | ||||
| 				$out .= implode(";\n\t", $this->_alterIndexes($curTable, $indexes)); | ||||
| 			} | ||||
| 		} | ||||
| 		return $out; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Generate PostgreSQL index alteration statements for a table. | ||||
|  * | ||||
|  * @param string $table Table to alter indexes for | ||||
|  * @param array $indexes Indexes to add and drop | ||||
|  * @return array Index alteration statements | ||||
|  */ | ||||
| 	protected function _alterIndexes($table, $indexes) { | ||||
| 		$alter = array(); | ||||
| 		if (isset($indexes['drop'])) { | ||||
| 			foreach ($indexes['drop'] as $name => $value) { | ||||
| 				$out = 'DROP '; | ||||
| 				if ($name == 'PRIMARY') { | ||||
| 					continue; | ||||
| 				} else { | ||||
| 					$out .= 'INDEX ' . $name; | ||||
| 				} | ||||
| 				$alter[] = $out; | ||||
| 			} | ||||
| 		} | ||||
| 		if (isset($indexes['add'])) { | ||||
| 			foreach ($indexes['add'] as $name => $value) { | ||||
| 				$out = 'CREATE '; | ||||
| 				if ($name == 'PRIMARY') { | ||||
| 					continue; | ||||
| 				} else { | ||||
| 					if (!empty($value['unique'])) { | ||||
| 						$out .= 'UNIQUE '; | ||||
| 					} | ||||
| 					$out .= 'INDEX '; | ||||
| 				} | ||||
| 				if (is_array($value['column'])) { | ||||
| 					$out .= $name . ' ON ' . $table . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')'; | ||||
| 				} else { | ||||
| 					$out .= $name . ' ON ' . $table . ' (' . $this->name($value['column']) . ')'; | ||||
| 				} | ||||
| 				$alter[] = $out; | ||||
| 			} | ||||
| 		} | ||||
| 		return $alter; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Returns a limit statement in the correct format for the particular database. | ||||
|  * | ||||
|  * @param integer $limit Limit of results returned | ||||
|  * @param integer $offset Offset from which to start results | ||||
|  * @return string SQL limit/offset statement | ||||
|  */ | ||||
| 	public function limit($limit, $offset = null) { | ||||
| 		if ($limit) { | ||||
| 			$rt = ''; | ||||
| 			if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) { | ||||
| 				$rt = ' LIMIT'; | ||||
| 			} | ||||
| 
 | ||||
| 			$rt .= ' ' . $limit; | ||||
| 			if ($offset) { | ||||
| 				$rt .= ' OFFSET ' . $offset; | ||||
| 			} | ||||
| 
 | ||||
| 			return $rt; | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Converts database-layer column types to basic types | ||||
|  * | ||||
|  * @param string $real Real database-layer column type (i.e. "varchar(255)") | ||||
|  * @return string Abstract column type (i.e. "string") | ||||
|  */ | ||||
| 	public function column($real) { | ||||
| 		if (is_array($real)) { | ||||
| 			$col = $real['name']; | ||||
| 			if (isset($real['limit'])) { | ||||
| 				$col .= '(' . $real['limit'] . ')'; | ||||
| 			} | ||||
| 			return $col; | ||||
| 		} | ||||
| 
 | ||||
| 		$col = str_replace(')', '', $real); | ||||
| 		$limit = null; | ||||
| 
 | ||||
| 		if (strpos($col, '(') !== false) { | ||||
| 			list($col, $limit) = explode('(', $col); | ||||
| 		} | ||||
| 
 | ||||
| 		$floats = array( | ||||
| 			'float', 'float4', 'float8', 'double', 'double precision', 'decimal', 'real', 'numeric' | ||||
| 		); | ||||
| 
 | ||||
| 		switch (true) { | ||||
| 			case (in_array($col, array('date', 'time', 'inet', 'boolean'))): | ||||
| 				return $col; | ||||
| 			case (strpos($col, 'timestamp') !== false): | ||||
| 				return 'datetime'; | ||||
| 			case (strpos($col, 'time') === 0): | ||||
| 				return 'time'; | ||||
| 			case (strpos($col, 'int') !== false && $col != 'interval'): | ||||
| 				return 'integer'; | ||||
| 			case (strpos($col, 'char') !== false || $col == 'uuid'): | ||||
| 				return 'string'; | ||||
| 			case (strpos($col, 'text') !== false): | ||||
| 				return 'text'; | ||||
| 			case (strpos($col, 'bytea') !== false): | ||||
| 				return 'binary'; | ||||
| 			case (in_array($col, $floats)): | ||||
| 				return 'float'; | ||||
| 			default: | ||||
| 				return 'text'; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Gets the length of a database-native column description, or null if no length | ||||
|  * | ||||
|  * @param string $real Real database-layer column type (i.e. "varchar(255)") | ||||
|  * @return integer An integer representing the length of the column | ||||
|  */ | ||||
| 	public function length($real) { | ||||
| 		$col = str_replace(array(')', 'unsigned'), '', $real); | ||||
| 		$limit = null; | ||||
| 
 | ||||
| 		if (strpos($col, '(') !== false) { | ||||
| 			list($col, $limit) = explode('(', $col); | ||||
| 		} | ||||
| 		if ($col == 'uuid') { | ||||
| 			return 36; | ||||
| 		} | ||||
| 		if ($limit != null) { | ||||
| 			return intval($limit); | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * resultSet method | ||||
|  * | ||||
|  * @param array $results | ||||
|  * @return void | ||||
|  */ | ||||
| 	public function resultSet(&$results) { | ||||
| 		$this->map = array(); | ||||
| 		$numFields = $results->columnCount(); | ||||
| 		$index = 0; | ||||
| 		$j = 0; | ||||
| 
 | ||||
| 		while ($j < $numFields) { | ||||
| 			$column = $results->getColumnMeta($j); | ||||
| 			if (strpos($column['name'], '__')) { | ||||
| 				list($table, $name) = explode('__', $column['name']); | ||||
| 				$this->map[$index++] = array($table, $name, $column['native_type']); | ||||
| 			} else { | ||||
| 				$this->map[$index++] = array(0, $column['name'], $column['native_type']); | ||||
| 			} | ||||
| 			$j++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Fetches the next row from the current result set | ||||
|  * | ||||
|  * @return array | ||||
|  */ | ||||
| 	public function fetchResult() { | ||||
| 		if ($row = $this->_result->fetch(PDO::FETCH_NUM)) { | ||||
| 			$resultRow = array(); | ||||
| 
 | ||||
| 			foreach ($this->map as $index => $meta) { | ||||
| 				list($table, $column, $type) = $meta; | ||||
| 
 | ||||
| 				switch ($type) { | ||||
| 					case 'bool': | ||||
| 						$resultRow[$table][$column] = is_null($row[$index]) ? null : $this->boolean($row[$index]); | ||||
| 					break; | ||||
| 					case 'binary': | ||||
| 					case 'bytea': | ||||
| 						$resultRow[$table][$column] = is_null($row[$index]) ? null : stream_get_contents($row[$index]); | ||||
| 					break; | ||||
| 					default: | ||||
| 						$resultRow[$table][$column] = $row[$index]; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			return $resultRow; | ||||
| 		} else { | ||||
| 			$this->_result->closeCursor(); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Translates between PHP boolean values and PostgreSQL boolean values | ||||
|  * | ||||
|  * @param mixed $data Value to be translated | ||||
|  * @param boolean $quote true to quote a boolean to be used in a query, false to return the boolean value | ||||
|  * @return boolean Converted boolean value | ||||
|  */ | ||||
| 	public function boolean($data, $quote = false) { | ||||
| 		switch (true) { | ||||
| 			case ($data === true || $data === false): | ||||
| 				$result = $data; | ||||
| 				break; | ||||
| 			case ($data === 't' || $data === 'f'): | ||||
| 				$result = ($data === 't'); | ||||
| 				break; | ||||
| 			case ($data === 'true' || $data === 'false'): | ||||
| 				$result = ($data === 'true'); | ||||
| 				break; | ||||
| 			case ($data === 'TRUE' || $data === 'FALSE'): | ||||
| 				$result = ($data === 'TRUE'); | ||||
| 				break; | ||||
| 			default: | ||||
| 				$result = (bool)$data; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if ($quote) { | ||||
| 			return ($result) ? 'TRUE' : 'FALSE'; | ||||
| 		} | ||||
| 		return (bool)$result; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Sets the database encoding | ||||
|  * | ||||
|  * @param mixed $enc Database encoding | ||||
|  * @return boolean True on success, false on failure | ||||
|  */ | ||||
| 	public function setEncoding($enc) { | ||||
| 		return $this->_execute('SET NAMES ' . $this->value($enc)) !== false; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Gets the database encoding | ||||
|  * | ||||
|  * @return string The database encoding | ||||
|  */ | ||||
| 	public function getEncoding() { | ||||
| 		$result = $this->_execute('SHOW client_encoding')->fetch(); | ||||
| 		if ($result === false) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		return (isset($result['client_encoding'])) ? $result['client_encoding'] : false; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Generate a Postgres-native column schema string | ||||
|  * | ||||
|  * @param array $column An array structured like the following: | ||||
|  *                      array('name'=>'value', 'type'=>'value'[, options]), | ||||
|  *                      where options can be 'default', 'length', or 'key'. | ||||
|  * @return string | ||||
|  */ | ||||
| 	public function buildColumn($column) { | ||||
| 		$col = $this->columns[$column['type']]; | ||||
| 		if (!isset($col['length']) && !isset($col['limit'])) { | ||||
| 			unset($column['length']); | ||||
| 		} | ||||
| 		$out = preg_replace('/integer\([0-9]+\)/', 'integer', parent::buildColumn($column)); | ||||
| 		$out = str_replace('integer serial', 'serial', $out); | ||||
| 		if (strpos($out, 'timestamp DEFAULT')) { | ||||
| 			if (isset($column['null']) && $column['null']) { | ||||
| 				$out = str_replace('DEFAULT NULL', '', $out); | ||||
| 			} else { | ||||
| 				$out = str_replace('DEFAULT NOT NULL', '', $out); | ||||
| 			} | ||||
| 		} | ||||
| 		if (strpos($out, 'DEFAULT DEFAULT')) { | ||||
| 			if (isset($column['null']) && $column['null']) { | ||||
| 				$out = str_replace('DEFAULT DEFAULT', 'DEFAULT NULL', $out); | ||||
| 			} elseif (in_array($column['type'], array('integer', 'float'))) { | ||||
| 				$out = str_replace('DEFAULT DEFAULT', 'DEFAULT 0', $out); | ||||
| 			} elseif ($column['type'] == 'boolean') { | ||||
| 				$out = str_replace('DEFAULT DEFAULT', 'DEFAULT FALSE', $out); | ||||
| 			} | ||||
| 		} | ||||
| 		return $out; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Format indexes for create table | ||||
|  * | ||||
|  * @param array $indexes | ||||
|  * @param string $table | ||||
|  * @return string | ||||
|  */ | ||||
| 	public function buildIndex($indexes, $table = null) { | ||||
| 		$join = array(); | ||||
| 		if (!is_array($indexes)) { | ||||
| 			return array(); | ||||
| 		} | ||||
| 		foreach ($indexes as $name => $value) { | ||||
| 			if ($name == 'PRIMARY') { | ||||
| 				$out = 'PRIMARY KEY  (' . $this->name($value['column']) . ')'; | ||||
| 			} else { | ||||
| 				$out = 'CREATE '; | ||||
| 				if (!empty($value['unique'])) { | ||||
| 					$out .= 'UNIQUE '; | ||||
| 				} | ||||
| 				if (is_array($value['column'])) { | ||||
| 					$value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column'])); | ||||
| 				} else { | ||||
| 					$value['column'] = $this->name($value['column']); | ||||
| 				} | ||||
| 				$out .= "INDEX {$name} ON {$table}({$value['column']});"; | ||||
| 			} | ||||
| 			$join[] = $out; | ||||
| 		} | ||||
| 		return $join; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Overrides DboSource::renderStatement to handle schema generation with Postgres-style indexes | ||||
|  * | ||||
|  * @param string $type | ||||
|  * @param array $data | ||||
|  * @return string | ||||
|  */ | ||||
| 	public function renderStatement($type, $data) { | ||||
| 		switch (strtolower($type)) { | ||||
| 			case 'schema': | ||||
| 				extract($data); | ||||
| 
 | ||||
| 				foreach ($indexes as $i => $index) { | ||||
| 					if (preg_match('/PRIMARY KEY/', $index)) { | ||||
| 						unset($indexes[$i]); | ||||
| 						$columns[] = $index; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				$join = array('columns' => ",\n\t", 'indexes' => "\n"); | ||||
| 
 | ||||
| 				foreach (array('columns', 'indexes') as $var) { | ||||
| 					if (is_array(${$var})) { | ||||
| 						${$var} = implode($join[$var], array_filter(${$var})); | ||||
| 					} | ||||
| 				} | ||||
| 				return "CREATE TABLE {$table} (\n\t{$columns}\n);\n{$indexes}"; | ||||
| 			default: | ||||
| 				return parent::renderStatement($type, $data); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Gets the schema name | ||||
|  * | ||||
|  * @return string The schema name | ||||
|  */ | ||||
| 	public function getSchemaName() { | ||||
| 		return $this->config['schema']; | ||||
| 	} | ||||
| 
 | ||||
| /** | ||||
|  * Check if the server support nested transactions | ||||
|  * | ||||
|  * @return boolean | ||||
|  */ | ||||
| 	public function nestedTransactionSupported() { | ||||
| 		return $this->useNestedTransactions && version_compare($this->getVersion(), '8.0', '>='); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brm Ko
						Brm Ko