diff --git a/.travis.yml b/.travis.yml index e948614..7a14863 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,5 +17,5 @@ before_script: - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss - cd ~/builds/ss -script: - - phpunit framework/tests +script: + - vendor/bin/phpunit framework/tests diff --git a/.upgrade.yml b/.upgrade.yml new file mode 100644 index 0000000..1208f25 --- /dev/null +++ b/.upgrade.yml @@ -0,0 +1,7 @@ +mappings: + PostgreSQLConnector: SilverStripe\PostgreSQL\PostgreSQLConnector + PostgreSQLDatabase: SilverStripe\PostgreSQL\PostgreSQLDatabase + PostgreSQLDatabaseConfigurationHelper: SilverStripe\PostgreSQL\PostgreSQLDatabaseConfigurationHelper + PostgreSQLQuery: SilverStripe\PostgreSQL\PostgreSQLQuery + PostgreSQLQueryBuilder: SilverStripe\PostgreSQL\PostgreSQLQueryBuilder + PostgreSQLSchemaManager: SilverStripe\PostgreSQL\PostgreSQLSchemaManager diff --git a/_config.php b/_config.php deleted file mode 100644 index b3d9bbc..0000000 --- a/_config.php +++ /dev/null @@ -1 +0,0 @@ - 'PostgrePDODatabase', 'title' => 'PostgreSQL 8.3+ (using PDO)', 'helperPath' => dirname(__FILE__).'/code/PostgreSQLDatabaseConfigurationHelper.php', @@ -15,6 +16,7 @@ DatabaseAdapterRegistry::register(array( // PDO Postgre database DatabaseAdapterRegistry::register(array( + /** @skipUpgrade */ 'class' => 'PostgreSQLDatabase', 'title' => 'PostgreSQL 8.3+ (using pg_connect)', 'helperPath' => dirname(__FILE__).'/code/PostgreSQLDatabaseConfigurationHelper.php', diff --git a/code/PostgreSQLConnector.php b/code/PostgreSQLConnector.php index 3dd945d..5619f93 100644 --- a/code/PostgreSQLConnector.php +++ b/code/PostgreSQLConnector.php @@ -1,12 +1,17 @@ dbConn) { pg_close($this->dbConn); } - + // Connect $this->dbConn = @pg_connect(implode(' ', $arguments)); if ($this->dbConn === false) { @@ -143,13 +148,13 @@ class PostgreSQLConnector extends DBConnector /** * Determines if the SQL fragment either breaks into or out of a string literal * by counting single quotes - * + * * Handles double-quote escaped quotes as well as slash escaped quotes - * + * * @todo Test this! - * + * * @see http://www.postgresql.org/docs/8.3/interactive/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS - * + * * @param string $input The SQL fragment * @return boolean True if the string breaks into or out of a string literal */ @@ -167,9 +172,9 @@ class PostgreSQLConnector extends DBConnector /** * Iteratively replaces all question marks with numerical placeholders * E.g. "Title = ? AND Name = ?" becomes "Title = $1 AND Name = $2" - * + * * @todo Better consider question marks in string literals - * + * * @param string $sql Paramaterised query using question mark placeholders * @return string Paramaterised query using numeric placeholders */ @@ -216,18 +221,20 @@ class PostgreSQLConnector extends DBConnector } // Execute query + // Unfortunately error-suppression is required in order to handle sql errors elegantly. + // Please use PDO if you can help it if (!empty($parameters)) { - $result = pg_query_params($this->dbConn, $sql, $parameters); + $result = @pg_query_params($this->dbConn, $sql, $parameters); } else { - $result = pg_query($this->dbConn, $sql); + $result = @pg_query($this->dbConn, $sql); } - + // Handle error - if ($result === false) { + if (!$result) { $this->databaseError($this->getLastError(), $errorLevel, $sql, $parameters); return null; } - + // Save and return results $this->lastQuery = $result; $this->lastRows = pg_affected_rows($result); @@ -253,16 +260,6 @@ class PostgreSQLConnector extends DBConnector return pg_escape_string($this->dbConn, $value); } - public function escapeIdentifier($value, $separator = '.') - { - if (empty($separator) && function_exists('pg_escape_identifier')) { - return pg_escape_identifier($this->dbConn, $value); - } - - // Let parent function handle recursive calls - return parent::escapeIdentifier($value, $separator); - } - public function selectDatabase($name) { if ($name !== $this->databaseName) { diff --git a/code/PostgreSQLDatabase.php b/code/PostgreSQLDatabase.php index 00a7cbe..5e43424 100644 --- a/code/PostgreSQLDatabase.php +++ b/code/PostgreSQLDatabase.php @@ -1,51 +1,123 @@ get('PostgreSQLDatabase', 'default_fts_cluster_method'); + return static::config()->default_fts_cluster_method; } /** * Full text search method. - * + * * @return string */ public static function default_fts_search_method() { - return Config::inst()->get('PostgreSQLDatabase', 'default_fts_search_method'); + return static::config()->default_fts_search_method; } /** @@ -55,13 +127,15 @@ class PostgreSQLDatabase extends SS_Database * Some locked down systems prevent access to the 'postgres' table in * which case you need to set this to false. * - * If allow_query_master_postgres is false, and model_schema_as_database is also false, + * If allow_query_master_postgres is false, and model_schema_as_database is also false, * then attempts to create or check databases beyond the initial connection will * result in a runtime error. + * + * @return bool */ public static function allow_query_master_postgres() { - return Config::inst()->get('PostgreSQLDatabase', 'allow_query_master_postgres'); + return static::config()->allow_query_master_postgres; } /** @@ -70,13 +144,15 @@ class PostgreSQLDatabase extends SS_Database * instead of using databases. This may be useful if the database user does not * have cross-database permissions, and in cases where multiple databases are used * (such as in running test cases). - * + * * If this is true then the database will only be set during the initial connection, * and attempts to change to this database will use the 'public' schema instead + * + * @return bool */ public static function model_schema_as_database() { - return Config::inst()->get('PostgreSQLDatabase', 'model_schema_as_database'); + return static::config()->model_schema_as_database; } /** @@ -84,16 +160,16 @@ class PostgreSQLDatabase extends SS_Database * could be any of the supported languages that can be found in the * pg_catalog.pg_ts_config table. * - * @var string + * @return string */ public static function search_language() { - return Config::inst()->get('PostgreSQLDatabase', 'search_language'); + return static::config()->search_language; } /** * The database name specified at initial connection - * + * * @var string */ protected $databaseOriginal = ''; @@ -183,7 +259,7 @@ class PostgreSQLDatabase extends SS_Database /** * Sets the system timezone for the database connection - * + * * @param string $timezone */ public function selectTimezone($timezone) @@ -211,7 +287,7 @@ class PostgreSQLDatabase extends SS_Database /** * Returns the name of the current schema in use - * + * * @return string Name of current schema */ public function currentSchema() @@ -222,8 +298,8 @@ class PostgreSQLDatabase extends SS_Database /** * Utility method to manually set the schema to an alternative * Check existance & sets search path to the supplied schema name - * - * @param string $name Name of the schema + * + * @param string $schema Name of the schema * @param boolean $create Flag indicating whether the schema should be created * if it doesn't exist. If $create is false and the schema doesn't exist * then an error will be raised @@ -256,14 +332,12 @@ class PostgreSQLDatabase extends SS_Database * the search path is provided as an advanced PostgreSQL feature for raw * SQL queries. Sapphire cannot search for datamodel tables in alternate * schemas, so be wary of using alternate schemas within the ORM environment. - * - * @param string $arg1 First schema to use - * @param string $arg2 Second schema to use - * @param string $argN Nth schema to use + * + * @param string ...$arg Schema name to use. Add additional schema names as extra arguments. */ - public function setSchemaSearchPath() + public function setSchemaSearchPath($arg = null) { - if (func_num_args() == 0) { + if (!$arg) { user_error('At least one Schema must be supplied to set a search path.', E_USER_ERROR); } $schemas = array_values(func_get_args()); @@ -274,8 +348,17 @@ class PostgreSQLDatabase extends SS_Database * The core search engine configuration. * @todo Properly extract the search functions out of the core. * + * @param array $classesToSearch * @param string $keywords Keywords as a space separated string - * @return object DataObjectSet of result pages + * @param int $start + * @param int $pageLength + * @param string $sortBy + * @param string $extraFilter + * @param bool $booleanSearch + * @param string $alternativeFileFilter + * @param bool $invertedMatch + * @return PaginatedList List of result pages + * @throws Exception */ public function searchEngine($classesToSearch, $keywords, $start, $pageLength, $sortBy = "ts_rank DESC", $extraFilter = "", $booleanSearch = false, $alternativeFileFilter = "", $invertedMatch = false) { @@ -580,7 +663,7 @@ class PostgreSQLDatabase extends SS_Database * Determines the name of the current database to be reported externally * by substituting the schema name for the database name. * Should only be used when model_schema_as_database is true - * + * * @param string $schema Name of the schema * @return string Name of the database to report */ @@ -595,7 +678,7 @@ class PostgreSQLDatabase extends SS_Database /** * Translates a requested database name to a schema name to substitute internally. * Should only be used when model_schema_as_database is true - * + * * @param string $database Name of the database * @return string Name of the schema to use for this database internally */ @@ -613,7 +696,7 @@ class PostgreSQLDatabase extends SS_Database // Check current schema is valid $oldSchema = $this->schema; if (empty($oldSchema)) { - return true; + return; } // Nothing selected to drop // Select another schema @@ -667,6 +750,7 @@ class PostgreSQLDatabase extends SS_Database // New connection made here, treating the new database name as the new original $this->databaseOriginal = $name; $this->connectDefault(); + return true; } /** diff --git a/code/PostgreSQLDatabaseConfigurationHelper.php b/code/PostgreSQLDatabaseConfigurationHelper.php index cf7ba7c..6e5ec9b 100644 --- a/code/PostgreSQLDatabaseConfigurationHelper.php +++ b/code/PostgreSQLDatabaseConfigurationHelper.php @@ -1,17 +1,25 @@ true, 'error' => 'details of error') */ @@ -119,28 +127,10 @@ class PostgreSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelp 'error' => $error ); } - - /** - * Helper function to quote a string value - * - * @param mixed $conn Connection object/resource - * @param string $value Value to quote - * @return string Quoted strieng - */ - protected function quote($conn, $value) - { - if ($conn instanceof PDO) { - return $conn->quote($value); - } elseif (is_resource($conn)) { - return "'".pg_escape_string($conn, $value)."'"; - } else { - user_error('Invalid database connection', E_USER_ERROR); - } - } - + /** * Helper function to execute a query - * + * * @param mixed $conn Connection object/resource * @param string $sql SQL string to execute * @return array List of first value from each resulting row @@ -178,7 +168,7 @@ class PostgreSQLDatabaseConfigurationHelper implements DatabaseConfigurationHelp $success = in_array($databaseConfig['username'], $allowedUsers); } } - + return array( 'success' => $success, 'alreadyExists' => $alreadyExists diff --git a/code/PostgreSQLQuery.php b/code/PostgreSQLQuery.php index 7b1fc7e..811c610 100644 --- a/code/PostgreSQLQuery.php +++ b/code/PostgreSQLQuery.php @@ -1,8 +1,12 @@ database->databaseToSchemaName($name); - return $this->dropSchema($schemaName); + $this->dropSchema($schemaName); + return; } $this->dropPostgresDatabase($name); } /** * Returns true if the schema exists in the current database - * + * * @param string $name * @return boolean */ @@ -143,7 +150,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Creates a schema in the current database - * + * * @param string $name */ public function createSchema($name) @@ -154,7 +161,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Drops a schema from the database. Use carefully! - * + * * @param string $name */ public function dropSchema($name) @@ -165,7 +172,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Returns the list of all available schemas on the current database - * + * * @return array */ public function schemaList() @@ -232,11 +239,11 @@ class PostgreSQLSchemaManager extends DBSchemaManager $tableSpace = ''; } - $this->query("CREATE TABLE \"$table\" ( - $fieldSchemas - $fulltexts - primary key (\"ID\") - )$tableSpace; $indexSchemas $addOptions"); + $this->query("CREATE TABLE \"$table\" ( + $fieldSchemas + $fulltexts + primary key (\"ID\") + )$tableSpace; $indexSchemas $addOptions"); if ($triggers!='') { $this->query($triggers); @@ -257,9 +264,9 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Builds the internal Postgres index name given the silverstripe table and index name - * + * * @param string $tableName - * @param string $indexName + * @param string $indexName * @param string $prefix The optional prefix for the index. Defaults to "ix" for indexes. * @return string The postgres name of the index */ @@ -281,7 +288,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Builds the internal Postgres trigger name given the silverstripe table and trigger name - * + * * @param string $tableName * @param string $triggerName * @return string The postgres name of the trigger @@ -400,7 +407,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager if ($alteredOptions && isset($this->class) && isset($alteredOptions[$this->class])) { $this->query(sprintf("ALTER TABLE \"%s\" %s", $table, $alteredOptions[$this->class])); - Database::alteration_message( + DB::alteration_message( sprintf("Table %s options changed: %s", $table, $alteredOptions[$this->class]), "changed" ); @@ -563,7 +570,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Change the database type of the given field. - * + * * @param string $tableName The name of the tbale the field is in. * @param string $fieldName The name of the field to change. * @param string $fieldSpec The new field specification @@ -697,7 +704,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * Create an index on a table. - * + * * @param string $tableName The name of the table. * @param string $indexName The name of the index. * @param string $indexSpec The specification of the index, see Database::requireIndex() for more details. @@ -710,37 +717,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager } } - /* - * @todo - factor out? Is DBSchemaManager::convertIndexSpec sufficient? - public function convertIndexSpec($indexSpec, $asDbValue=false, $table=''){ - - if(!$asDbValue){ - if(is_array($indexSpec)){ - //Here we create a db-specific version of whatever index we need to create. - switch($indexSpec['type']){ - case 'fulltext': - $indexSpec='fulltext (' . $indexSpec['value'] . ')'; - break; - case 'unique': - $indexSpec='unique (' . $indexSpec['value'] . ')'; - break; - case 'hash': - $indexSpec='using hash (' . $indexSpec['value'] . ')'; - break; - case 'index': - //The default index is 'btree', which we'll use by default (below): - default: - $indexSpec='using btree (' . $indexSpec['value'] . ')'; - break; - } - } - } else { - $indexSpec = $this->buildPostgresIndexName($table, $indexSpec); - } - return $indexSpec; - }*/ - - protected function getIndexSqlDefinition($tableName, $indexName, $indexSpec, $asDbValue=false) + protected function getIndexSqlDefinition($tableName, $indexName, $indexSpec) { //TODO: create table partition support @@ -750,12 +727,6 @@ class PostgreSQLSchemaManager extends DBSchemaManager //Therefore, we now check for the existance of indexes before we create them. //This is techically a bug, since new tables will not be indexed. - // If requesting the definition rather than the DDL - if ($asDbValue) { - $indexName=trim($indexName, '()'); - return $indexName; - } - // Determine index name $tableCol = $this->buildPostgresIndexName($tableName, $indexName); @@ -773,7 +744,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager //create a type-specific index // NOTE: hash should be removed. This is only here to demonstrate how other indexes can be made - // NOTE: Quote the index name to preserve case sensitivity + // NOTE: Quote the index name to preserve case sensitivity switch ($indexSpec['type']) { case 'fulltext': // @see fulltext() for the definition of the trigger that ts_$IndexName uses for fulltext searching @@ -808,6 +779,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager if ($indexSpec[0] != '(') { list($indexType, $indexFields) = explode(' ', $indexSpec, 2); } else { + $indexType = null; $indexFields = $indexSpec; } @@ -961,7 +933,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /** * A function to return the field names and datatypes for the particular table - * + * * @param string $tableName * @return array List of columns an an associative array with the keys Column and DataType */ @@ -1045,28 +1017,12 @@ class PostgreSQLSchemaManager extends DBSchemaManager * Return a boolean type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function boolean($values, $asDbValue=false) + public function boolean($values) { - //Annoyingly, we need to do a good ol' fashioned switch here: $default = $values['default'] ? '1' : '0'; - - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - if ($asDbValue) { - return array('data_type'=>'smallint'); - } - - if ($values['arrayValue'] != '') { - $default = ''; - } else { - $default = ' default ' . (int)$values['default']; - } - return "smallint{$values['arrayValue']}" . $default; + return "smallint default {$default}"; } /** @@ -1077,26 +1033,17 @@ class PostgreSQLSchemaManager extends DBSchemaManager */ public function date($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - return "date{$values['arrayValue']}"; + return "date"; } /** * Return a decimal type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function decimal($values, $asDbValue=false) + public function decimal($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - // Avoid empty strings being put in the db if ($values['precision'] == '') { $precision = 1; @@ -1109,11 +1056,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager $defaultValue = ' default ' . floatval($values['default']); } - if ($asDbValue) { - return array('data_type' => 'numeric', 'precision' => $precision); - } else { - return "decimal($precision){$values['arrayValue']}$defaultValue"; - } + return "decimal($precision)$defaultValue"; } /** @@ -1124,103 +1067,52 @@ class PostgreSQLSchemaManager extends DBSchemaManager */ public function enum($values) { - //Enums are a bit different. We'll be creating a varchar(255) with a constraint of all the usual enum options. - //NOTE: In this one instance, we are including the table name in the values array - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - if ($values['arrayValue']!='') { - $default = ''; - } else { - $default = " default '{$values['default']}'"; - } - - return "varchar(255){$values['arrayValue']}" . $default . " check (\"" . $values['name'] . "\" in ('" . implode('\', \'', $values['enums']) . "'))"; + $default = " default '{$values['default']}'"; + return "varchar(255)" . $default . " check (\"" . $values['name'] . "\" in ('" . implode('\', \'', $values['enums']) . "'))"; } /** * Return a float type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function float($values, $asDbValue = false) + public function float($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - if ($asDbValue) { - return array('data_type' => 'double precision'); - } else { - return "float{$values['arrayValue']}"; - } + return "float"; } /** * Return a float type-formatted string cause double is not supported * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function double($values, $asDbValue=false) + public function double($values) { - return $this->float($values, $asDbValue); + return $this->float($values); } /** * Return a int type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function int($values, $asDbValue = false) + public function int($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - if ($asDbValue) { - return array('data_type'=>'integer', 'precision'=>'32'); - } - - if ($values['arrayValue']!='') { - $default=''; - } else { - $default=' default ' . (int)$values['default']; - } - - return "integer{$values['arrayValue']}" . $default; + return "integer default " . (int)$values['default']; } /** * Return a bigint type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function bigint($values, $asDbValue = false) + public function bigint($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - if ($asDbValue) { - return array('data_type'=>'bigint', 'precision'=>'64'); - } - - if ($values['arrayValue']!='') { - $default=''; - } else { - $default=' default ' . (int)$values['default']; - } - - return "bigint{$values['arrayValue']}" . $default; + return "bigint default" . (int)$values['default']; } /** @@ -1228,40 +1120,22 @@ class PostgreSQLSchemaManager extends DBSchemaManager * For PostgreSQL, we simply return the word 'timestamp', no other parameters are necessary * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function SS_Datetime($values, $asDbValue = false) + public function datetime($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue']=''; - } - - if ($asDbValue) { - return array('data_type'=>'timestamp without time zone'); - } else { - return "timestamp{$values['arrayValue']}"; - } + return "timestamp"; } /** * Return a text type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function text($values, $asDbValue = false) + public function text($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue'] = ''; - } - - if ($asDbValue) { - return array('data_type'=>'text'); - } else { - return "text{$values['arrayValue']}"; - } + return "text"; } /** @@ -1272,57 +1146,34 @@ class PostgreSQLSchemaManager extends DBSchemaManager */ public function time($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue'] = ''; - } - - return "time{$values['arrayValue']}"; + return "time"; } /** * Return a varchar type-formatted string * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function varchar($values, $asDbValue=false) + public function varchar($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue'] = ''; - } - if (!isset($values['precision'])) { $values['precision'] = 255; } - if ($asDbValue) { - return array('data_type'=>'varchar', 'precision'=>$values['precision']); - } else { - return "varchar({$values['precision']}){$values['arrayValue']}"; - } + return "varchar({$values['precision']})"; } /* * Return a 4 digit numeric type. MySQL has a proprietary 'Year' type. * For Postgres, we'll use a 4 digit numeric - * + * * @param array $values Contains a tokenised list of info about this data type - * @param boolean $asDbValue * @return string */ - public function year($values, $asDbValue = false) + public function year($values) { - if (!isset($values['arrayValue'])) { - $values['arrayValue'] = ''; - } - - //TODO: the DbValue result does not include the numeric_scale option (ie, the ,0 value in 4,0) - if ($asDbValue) { - return array('data_type'=>'decimal', 'precision'=>'4'); - } else { - return "decimal(4,0){$values['arrayValue']}"; - } + return "decimal(4,0)"; } /** @@ -1334,7 +1185,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager * @param array $this_index Index specification for the fulltext index * @param string $tableName * @param string $name - * @param array $spec + * @return array */ protected function fulltext($this_index, $tableName, $name) { @@ -1431,7 +1282,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /* * Given a tablespace and and location, either create a new one * or update the existing one - * + * * @param string $name * @param string $location */ @@ -1456,13 +1307,13 @@ class PostgreSQLSchemaManager extends DBSchemaManager } /** - * + * * @param string $tableName * @param array $partitions * @param array $indexes * @param array $extensions */ - public function createOrReplacePartition($tableName, $partitions, $indexes, $extensions) + public function createOrReplacePartition($tableName, $partitions, $indexes = [], $extensions = []) { //We need the plpgsql language to be installed for this to work: @@ -1550,7 +1401,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager /* * This will create a language if it doesn't already exist. * This is used by the createOrReplacePartition function, which needs plpgsql - * + * * @param string $language Language name */ public function createLanguage($language) diff --git a/composer.json b/composer.json index ca49087..67a19f2 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,9 @@ "require": { "silverstripe/framework": "~4.0" }, + "require-dev": { + "phpunit/PHPUnit": "~4.8" + }, "extra": { "branch-alias": { "dev-master": "2.0.x-dev" diff --git a/tests/PostgreSQLConnectorTest.php b/tests/PostgreSQLConnectorTest.php index 6dba478..82653e5 100644 --- a/tests/PostgreSQLConnectorTest.php +++ b/tests/PostgreSQLConnectorTest.php @@ -1,5 +1,7 @@