mirror of
https://github.com/silverstripe/silverstripe-postgresql
synced 2024-10-22 17:05:45 +02:00
BUG Fix postgres + PDO not working
BUG Fix empty enums
This commit is contained in:
parent
8c5f95fdaa
commit
685e33cf84
@ -10,8 +10,15 @@ indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.yml,*.json}]
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,js,json,css,scss,feature}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[composer.json]
|
||||
indent_size = 4
|
||||
|
||||
# The indent size used in the package.json file cannot be changed:
|
||||
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
||||
|
@ -1,69 +1,15 @@
|
||||
inherit: true
|
||||
|
||||
build:
|
||||
nodes:
|
||||
analysis:
|
||||
tests:
|
||||
override: [php-scrutinizer-run]
|
||||
|
||||
checks:
|
||||
php:
|
||||
verify_property_names: true
|
||||
verify_argument_usable_as_reference: true
|
||||
verify_access_scope_valid: true
|
||||
useless_calls: true
|
||||
use_statement_alias_conflict: true
|
||||
variable_existence: true
|
||||
unused_variables: true
|
||||
unused_properties: true
|
||||
unused_parameters: true
|
||||
unused_methods: true
|
||||
unreachable_code: true
|
||||
too_many_arguments: true
|
||||
sql_injection_vulnerabilities: true
|
||||
simplify_boolean_return: true
|
||||
side_effects_or_types: true
|
||||
security_vulnerabilities: true
|
||||
return_doc_comments: true
|
||||
return_doc_comment_if_not_inferrable: true
|
||||
require_scope_for_properties: true
|
||||
require_scope_for_methods: true
|
||||
require_php_tag_first: true
|
||||
psr2_switch_declaration: true
|
||||
psr2_class_declaration: true
|
||||
property_assignments: true
|
||||
prefer_while_loop_over_for_loop: true
|
||||
precedence_mistakes: true
|
||||
precedence_in_conditions: true
|
||||
phpunit_assertions: true
|
||||
php5_style_constructor: true
|
||||
parse_doc_comments: true
|
||||
parameter_non_unique: true
|
||||
parameter_doc_comments: true
|
||||
param_doc_comment_if_not_inferrable: true
|
||||
optional_parameters_at_the_end: true
|
||||
one_class_per_file: true
|
||||
no_unnecessary_if: true
|
||||
no_trailing_whitespace: true
|
||||
no_property_on_interface: true
|
||||
no_non_implemented_abstract_methods: true
|
||||
no_error_suppression: true
|
||||
no_duplicate_arguments: true
|
||||
no_commented_out_code: true
|
||||
newline_at_end_of_file: true
|
||||
missing_arguments: true
|
||||
method_calls_on_non_object: true
|
||||
instanceof_class_exists: true
|
||||
foreach_traversable: true
|
||||
fix_line_ending: true
|
||||
fix_doc_comments: true
|
||||
duplication: true
|
||||
deprecated_code_usage: true
|
||||
deadlock_detection_in_loops: true
|
||||
code_rating: true
|
||||
closure_use_not_conflicting: true
|
||||
catch_class_exists: true
|
||||
blank_line_after_namespace_declaration: false
|
||||
avoid_multiple_statements_on_same_line: true
|
||||
avoid_duplicate_types: true
|
||||
avoid_conflicting_incrementers: true
|
||||
avoid_closing_tag: true
|
||||
assignment_of_null_return: true
|
||||
argument_type_checks: true
|
||||
duplication: true
|
||||
|
||||
filter:
|
||||
paths: [code/*, tests/*]
|
||||
|
32
.travis.yml
32
.travis.yml
@ -1,8 +1,10 @@
|
||||
language: php
|
||||
|
||||
dist: precise
|
||||
dist: trusty
|
||||
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
php:
|
||||
- 5.6
|
||||
@ -10,23 +12,33 @@ php:
|
||||
env:
|
||||
global:
|
||||
- DB="PGSQL"
|
||||
- CORE_RELEASE="4"
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: 5.6
|
||||
env:
|
||||
- PHPUNIT_TEST=framework
|
||||
- php: 5.6
|
||||
env:
|
||||
- PHPUNIT_TEST=postgresql
|
||||
- PHPCS_TEST=1
|
||||
|
||||
before_script:
|
||||
# Init PHP
|
||||
- printf "\n" | pecl install imagick
|
||||
- phpenv rehash
|
||||
- phpenv config-rm xdebug.ini
|
||||
- export PATH=~/.composer/vendor/bin:$PATH
|
||||
- echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
|
||||
# Temporarily update to 1.5.x-dev of composer
|
||||
- composer self-update --snapshot
|
||||
|
||||
# Install composer dependencies
|
||||
- composer validate
|
||||
- composer install --prefer-dist
|
||||
- composer require --prefer-dist --no-update symfony/config:^3.2 silverstripe/framework:4.0.x-dev silverstripe/cms:4.0.x-dev silverstripe/siteconfig:4.0.x-dev silverstripe/config:1.0.x-dev silverstripe/admin:1.0.x-dev silverstripe/assets:1.0.x-dev silverstripe/versioned:1.0.x-dev
|
||||
- composer require --prefer-dist --no-update silverstripe/recipe-cms:1.0.x-dev
|
||||
- composer update
|
||||
- if [[ $PHPCS_TEST ]]; then composer global require squizlabs/php_codesniffer:^3 --prefer-dist --no-interaction --no-progress --no-suggest -o; fi
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit ./tests
|
||||
- vendor/bin/phpunit ./framework/tests
|
||||
- if [[ $PHPUNIT_TEST == postgresql ]]; then vendor/bin/phpunit ./tests; fi
|
||||
- if [[ $PHPUNIT_TEST == framework ]]; then vendor/bin/phpunit ./vendor/silverstripe/framework/tests/php; fi
|
||||
- if [[ $PHPCS_TEST ]]; then composer run-script lint; fi
|
||||
|
@ -282,7 +282,7 @@ class PostgreSQLDatabase extends Database
|
||||
|
||||
public function getDatabaseServer()
|
||||
{
|
||||
return "postgresql";
|
||||
return "pgsql";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,14 +374,15 @@ class PostgreSQLDatabase extends Database
|
||||
|
||||
// Get tables
|
||||
$tablesToSearch = [];
|
||||
foreach($classesToSearch as $class) {
|
||||
foreach ($classesToSearch as $class) {
|
||||
$tablesToSearch[$class] = DataObject::getSchema()->baseDataTable($class);
|
||||
}
|
||||
|
||||
//We can get a list of all the tsvector columns though this query:
|
||||
//We know what tables to search in based on the $classesToSearch variable:
|
||||
$classesPlaceholders = DB::placeholders($classesToSearch);
|
||||
$searchableColumns = $this->preparedQuery("
|
||||
$searchableColumns = $this->preparedQuery(
|
||||
"
|
||||
SELECT table_name, column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE data_type='tsvector' AND table_name in ($classesPlaceholders);",
|
||||
@ -500,7 +501,7 @@ class PostgreSQLDatabase extends Database
|
||||
/*
|
||||
* This is a quick lookup to discover if the database supports particular extensions
|
||||
*/
|
||||
public function supportsExtensions($extensions=array('partitions', 'tablespaces', 'clustering'))
|
||||
public function supportsExtensions($extensions = array('partitions', 'tablespaces', 'clustering'))
|
||||
{
|
||||
if (isset($extensions['partitions'])) {
|
||||
return true;
|
||||
@ -683,8 +684,10 @@ class PostgreSQLDatabase extends Database
|
||||
public function schemaToDatabaseName($schema)
|
||||
{
|
||||
switch ($schema) {
|
||||
case $this->schemaOriginal: return $this->databaseOriginal;
|
||||
default: return $schema;
|
||||
case $this->schemaOriginal:
|
||||
return $this->databaseOriginal;
|
||||
default:
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
@ -698,8 +701,10 @@ class PostgreSQLDatabase extends Database
|
||||
public function databaseToSchemaName($database)
|
||||
{
|
||||
switch ($database) {
|
||||
case $this->databaseOriginal: return $this->schemaOriginal;
|
||||
default: return $database;
|
||||
case $this->databaseOriginal:
|
||||
return $this->schemaOriginal;
|
||||
default:
|
||||
return $database;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
}
|
||||
return $this->postgresDatabaseList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a postgres database, ignoring model_schema_as_database
|
||||
*
|
||||
@ -177,8 +178,8 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
*/
|
||||
public function schemaList()
|
||||
{
|
||||
return $this->query("
|
||||
SELECT nspname
|
||||
return $this->query(
|
||||
"SELECT nspname
|
||||
FROM pg_catalog.pg_namespace
|
||||
WHERE nspname <> 'information_schema' AND nspname !~ E'^pg_'"
|
||||
)->column();
|
||||
@ -186,7 +187,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
|
||||
public function createTable($table, $fields = null, $indexes = null, $options = null, $advancedOptions = null)
|
||||
{
|
||||
$fieldSchemas = $indexSchemas = "";
|
||||
$fieldSchemas = "";
|
||||
if ($fields) {
|
||||
foreach ($fields as $k => $v) {
|
||||
$fieldSchemas .= "\"$k\" $v,\n";
|
||||
@ -194,9 +195,6 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
}
|
||||
if (!empty($options[self::ID])) {
|
||||
$addOptions = $options[self::ID];
|
||||
} elseif (!empty($options[get_class($this)])) {
|
||||
Deprecation::notice('3.2', 'Use PostgreSQLSchemaManager::ID for referencing postgres-specific table creation options');
|
||||
$addOptions = $options[get_class($this)];
|
||||
} else {
|
||||
$addOptions = null;
|
||||
}
|
||||
@ -211,20 +209,21 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
//If we have a fulltext search request, then we need to create a special column
|
||||
//for GiST searches
|
||||
$fulltexts = '';
|
||||
$triggers = '';
|
||||
$triggers = [];
|
||||
if ($indexes) {
|
||||
foreach ($indexes as $name => $this_index) {
|
||||
if (is_array($this_index) && $this_index['type'] == 'fulltext') {
|
||||
$ts_details = $this->fulltext($this_index, $table, $name);
|
||||
$fulltexts .= $ts_details['fulltexts'] . ', ';
|
||||
$triggers .= $ts_details['triggers'];
|
||||
$triggers[] = $ts_details['triggers'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$indexQueries = [];
|
||||
if ($indexes) {
|
||||
foreach ($indexes as $k => $v) {
|
||||
$indexSchemas .= $this->getIndexSqlDefinition($table, $k, $v) . "\n";
|
||||
$indexQueries[] = $this->getIndexSqlDefinition($table, $k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,14 +238,19 @@ 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 $addOptions"
|
||||
);
|
||||
foreach ($indexQueries as $indexQuery) {
|
||||
$this->query($indexQuery);
|
||||
}
|
||||
|
||||
if ($triggers!='') {
|
||||
$this->query($triggers);
|
||||
foreach ($triggers as $trigger) {
|
||||
$this->query($trigger);
|
||||
}
|
||||
|
||||
//If we have a partitioning requirement, we do that here:
|
||||
@ -256,7 +260,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
|
||||
//Lastly, clustering goes here:
|
||||
if ($advancedOptions && isset($advancedOptions['cluster'])) {
|
||||
$this->query("CLUSTER \"$table\" USING \"{$advancedOptions['cluster']}\";");
|
||||
$this->query("CLUSTER \"$table\" USING \"{$advancedOptions['cluster']}\"");
|
||||
}
|
||||
|
||||
return $table;
|
||||
@ -299,9 +303,16 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
return $this->buildPostgresIndexName($tableName, $triggerName, 'ts');
|
||||
}
|
||||
|
||||
public function alterTable($table, $newFields = null, $newIndexes = null, $alteredFields = null, $alteredIndexes = null, $alteredOptions = null, $advancedOptions = null)
|
||||
{
|
||||
$alterList = array();
|
||||
public function alterTable(
|
||||
$table,
|
||||
$newFields = null,
|
||||
$newIndexes = null,
|
||||
$alteredFields = null,
|
||||
$alteredIndexes = null,
|
||||
$alteredOptions = null,
|
||||
$advancedOptions = null
|
||||
) {
|
||||
$alterList = [];
|
||||
if ($newFields) {
|
||||
foreach ($newFields as $fieldName => $fieldSpec) {
|
||||
$alterList[] = "ADD \"$fieldName\" $fieldSpec";
|
||||
@ -319,46 +330,49 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
|
||||
//Do we need to do anything with the tablespaces?
|
||||
if ($alteredOptions && isset($advancedOptions['tablespace'])) {
|
||||
$this->createOrReplaceTablespace($advancedOptions['tablespace']['name'], $advancedOptions['tablespace']['location']);
|
||||
$this->createOrReplaceTablespace(
|
||||
$advancedOptions['tablespace']['name'],
|
||||
$advancedOptions['tablespace']['location']
|
||||
);
|
||||
$this->query("ALTER TABLE \"$table\" SET TABLESPACE {$advancedOptions['tablespace']['name']};");
|
||||
}
|
||||
|
||||
//DB ABSTRACTION: we need to change the constraints to be a separate 'add' command,
|
||||
//see http://www.postgresql.org/docs/8.1/static/sql-altertable.html
|
||||
$alterIndexList = array();
|
||||
$alterIndexList = [];
|
||||
//Pick up the altered indexes here:
|
||||
$fieldList = $this->fieldList($table);
|
||||
$fulltexts = false;
|
||||
$drop_triggers = false;
|
||||
$triggers = false;
|
||||
$fulltexts = [];
|
||||
$dropTriggers = [];
|
||||
$triggers = [];
|
||||
if ($alteredIndexes) {
|
||||
foreach ($alteredIndexes as $indexName=>$indexSpec) {
|
||||
foreach ($alteredIndexes as $indexName => $indexSpec) {
|
||||
$indexNamePG = $this->buildPostgresIndexName($table, $indexName);
|
||||
|
||||
if ($indexSpec['type']=='fulltext') {
|
||||
if ($indexSpec['type'] == 'fulltext') {
|
||||
//For full text indexes, we need to drop the trigger, drop the index, AND drop the column
|
||||
|
||||
//Go and get the tsearch details:
|
||||
$ts_details = $this->fulltext($indexSpec, $table, $indexName);
|
||||
//Go and get the tsearch details:
|
||||
$ts_details = $this->fulltext($indexSpec, $table, $indexName);
|
||||
|
||||
//Drop this column if it already exists:
|
||||
//Drop this column if it already exists:
|
||||
|
||||
//No IF EXISTS option is available for Postgres <9.0
|
||||
if (array_key_exists($ts_details['ts_name'], $fieldList)) {
|
||||
$fulltexts.="ALTER TABLE \"{$table}\" DROP COLUMN \"{$ts_details['ts_name']}\";";
|
||||
//No IF EXISTS option is available for Postgres <9.0
|
||||
if (array_key_exists($ts_details['ts_name'], $fieldList)) {
|
||||
$fulltexts[] = "ALTER TABLE \"{$table}\" DROP COLUMN \"{$ts_details['ts_name']}\";";
|
||||
}
|
||||
|
||||
// We'll execute these later:
|
||||
$triggerNamePG = $this->buildPostgresTriggerName($table, $indexName);
|
||||
$dropTriggers[] = "DROP TRIGGER IF EXISTS \"$triggerNamePG\" ON \"$table\";";
|
||||
$fulltexts[] = "ALTER TABLE \"{$table}\" ADD COLUMN {$ts_details['fulltexts']};";
|
||||
$triggers[] = $ts_details['triggers'];
|
||||
}
|
||||
|
||||
// We'll execute these later:
|
||||
$triggerNamePG = $this->buildPostgresTriggerName($table, $indexName);
|
||||
$drop_triggers.= "DROP TRIGGER IF EXISTS \"$triggerNamePG\" ON \"$table\";";
|
||||
$fulltexts .= "ALTER TABLE \"{$table}\" ADD COLUMN {$ts_details['fulltexts']};";
|
||||
$triggers .= $ts_details['triggers'];
|
||||
}
|
||||
|
||||
// Create index action (including fulltext)
|
||||
$alterIndexList[] = "DROP INDEX IF EXISTS \"$indexNamePG\";";
|
||||
// Create index action (including fulltext)
|
||||
$alterIndexList[] = "DROP INDEX IF EXISTS \"$indexNamePG\";";
|
||||
$createIndex = $this->getIndexSqlDefinition($table, $indexName, $indexSpec);
|
||||
if ($createIndex!==false) {
|
||||
if ($createIndex) {
|
||||
$alterIndexList[] = $createIndex;
|
||||
}
|
||||
}
|
||||
@ -368,25 +382,25 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
if ($newIndexes) {
|
||||
foreach ($newIndexes as $indexName => $indexSpec) {
|
||||
$indexNamePG = $this->buildPostgresIndexName($table, $indexName);
|
||||
//If we have a fulltext search request, then we need to create a special column
|
||||
//for GiST searches
|
||||
//Pick up the new indexes here:
|
||||
if ($indexSpec['type']=='fulltext') {
|
||||
$ts_details=$this->fulltext($indexSpec, $table, $indexName);
|
||||
if (!isset($fieldList[$ts_details['ts_name']])) {
|
||||
$fulltexts.="ALTER TABLE \"{$table}\" ADD COLUMN {$ts_details['fulltexts']};";
|
||||
$triggers.=$ts_details['triggers'];
|
||||
//If we have a fulltext search request, then we need to create a special column
|
||||
//for GiST searches
|
||||
//Pick up the new indexes here:
|
||||
if ($indexSpec['type'] == 'fulltext') {
|
||||
$ts_details = $this->fulltext($indexSpec, $table, $indexName);
|
||||
if (!isset($fieldList[$ts_details['ts_name']])) {
|
||||
$fulltexts[] = "ALTER TABLE \"{$table}\" ADD COLUMN {$ts_details['fulltexts']};";
|
||||
$triggers[] = $ts_details['triggers'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check that this index doesn't already exist:
|
||||
$indexes=$this->indexList($table);
|
||||
//Check that this index doesn't already exist:
|
||||
$indexes = $this->indexList($table);
|
||||
if (isset($indexes[$indexName])) {
|
||||
$alterIndexList[] = "DROP INDEX IF EXISTS \"$indexNamePG\";";
|
||||
}
|
||||
|
||||
$createIndex=$this->getIndexSqlDefinition($table, $indexName, $indexSpec);
|
||||
if ($createIndex!==false) {
|
||||
$createIndex = $this->getIndexSqlDefinition($table, $indexName, $indexSpec);
|
||||
if ($createIndex) {
|
||||
$alterIndexList[] = $createIndex;
|
||||
}
|
||||
}
|
||||
@ -399,7 +413,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
|
||||
//Do we need to create a tablespace for this item?
|
||||
if ($advancedOptions && isset($advancedOptions['extensions']['tablespace'])) {
|
||||
$extensions=$advancedOptions['extensions'];
|
||||
$extensions = $advancedOptions['extensions'];
|
||||
$this->createOrReplaceTablespace($extensions['tablespace']['name'], $extensions['tablespace']['location']);
|
||||
}
|
||||
|
||||
@ -412,24 +426,19 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
}
|
||||
|
||||
//Create any fulltext columns and triggers here:
|
||||
if ($fulltexts) {
|
||||
$this->query($fulltexts);
|
||||
foreach ($fulltexts as $fulltext) {
|
||||
$this->query($fulltext);
|
||||
}
|
||||
if ($drop_triggers) {
|
||||
$this->query($drop_triggers);
|
||||
foreach ($dropTriggers as $dropTrigger) {
|
||||
$this->query($dropTrigger);
|
||||
}
|
||||
|
||||
if ($triggers) {
|
||||
$this->query($triggers);
|
||||
|
||||
$triggerbits=explode(';', $triggers);
|
||||
foreach ($triggerbits as $trigger) {
|
||||
$trigger_fields=$this->triggerFieldsFromTrigger($trigger);
|
||||
|
||||
if ($trigger_fields) {
|
||||
//We need to run a simple query to force the database to update the triggered columns
|
||||
$this->query("UPDATE \"{$table}\" SET \"{$trigger_fields[0]}\"=\"$trigger_fields[0]\";");
|
||||
}
|
||||
foreach ($triggers as $trigger) {
|
||||
$this->query($trigger);
|
||||
$triggerFields = $this->triggerFieldsFromTrigger($trigger);
|
||||
if ($triggerFields) {
|
||||
//We need to run a simple query to force the database to update the triggered columns
|
||||
$this->query("UPDATE \"{$table}\" SET \"{$triggerFields[0]}\"=\"$triggerFields[0]\";");
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,11 +463,12 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
"SELECT relid FROM pg_stat_user_tables WHERE relname = ?;",
|
||||
array($table)
|
||||
)->first();
|
||||
$oid=$stats['relid'];
|
||||
$oid = $stats['relid'];
|
||||
|
||||
//Now we can run a long query to get the clustered status:
|
||||
//If anyone knows a better way to get the clustered status, then feel free to replace this!
|
||||
$clustered = $this->preparedQuery("
|
||||
$clustered = $this->preparedQuery(
|
||||
"
|
||||
SELECT c2.relname, i.indisclustered
|
||||
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
|
||||
WHERE c.oid = ? AND c.oid = i.indrelid AND i.indexrelid = c2.oid AND indisclustered='t';",
|
||||
@ -488,11 +498,11 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$pattern = '/^([\w(\,)]+)\s?((?:not\s)?null)?\s?(default\s[\w\.\']+)?\s?(check\s[\w()\'",\s]+)?$/i';
|
||||
preg_match($pattern, $colSpec, $matches);
|
||||
|
||||
if (sizeof($matches)==0) {
|
||||
if (sizeof($matches) == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($matches[1]=='serial8') {
|
||||
if ($matches[1] == 'serial8') {
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -515,20 +525,20 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$constraintExists = $this->constraintExists($constraintName, false);
|
||||
if (isset($matches[4])) {
|
||||
//Take this new constraint and see what's outstanding from the target table:
|
||||
$constraint_bits=explode('(', $matches[4]);
|
||||
$constraint_values=trim($constraint_bits[2], ')');
|
||||
$constraint_values_bits=explode(',', $constraint_values);
|
||||
$default=trim($constraint_values_bits[0], " '");
|
||||
$constraint_bits = explode('(', $matches[4]);
|
||||
$constraint_values = trim($constraint_bits[2], ')');
|
||||
$constraint_values_bits = explode(',', $constraint_values);
|
||||
$default = trim($constraint_values_bits[0], " '");
|
||||
|
||||
//Now go and convert anything that's not in this list to 'Page'
|
||||
//We have to run this as a query, not as part of the alteration queries due to the way they are constructed.
|
||||
$updateConstraint='';
|
||||
$updateConstraint.="UPDATE \"{$tableName}\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
$updateConstraint = '';
|
||||
$updateConstraint .= "UPDATE \"{$tableName}\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
if ($this->hasTable("{$tableName}_Live")) {
|
||||
$updateConstraint.="UPDATE \"{$tableName}_Live\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
$updateConstraint .= "UPDATE \"{$tableName}_Live\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
}
|
||||
if ($this->hasTable("{$tableName}_versions")) {
|
||||
$updateConstraint.="UPDATE \"{$tableName}_versions\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
$updateConstraint .= "UPDATE \"{$tableName}_versions\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
}
|
||||
|
||||
$this->query($updateConstraint);
|
||||
@ -595,13 +605,14 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
//This gets us more information than we need, but I've included it all for the moment....
|
||||
|
||||
//if(!isset(self::$cached_fieldlists[$table])){
|
||||
$fields = $this->preparedQuery("
|
||||
$fields = $this->preparedQuery(
|
||||
"
|
||||
SELECT ordinal_position, column_name, data_type, column_default,
|
||||
is_nullable, character_maximum_length, numeric_precision, numeric_scale
|
||||
FROM information_schema.columns WHERE table_name = ? and table_schema = ?
|
||||
ORDER BY ordinal_position;",
|
||||
array($table, $this->database->currentSchema())
|
||||
);
|
||||
array($table, $this->database->currentSchema())
|
||||
);
|
||||
|
||||
$output = array();
|
||||
if ($fields) {
|
||||
@ -618,62 +629,70 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
//CHECK ("ClassName"::text = 'PageComment'::text)
|
||||
|
||||
//TODO: replace all this with a regular expression!
|
||||
$value=$constraint['pg_get_constraintdef'];
|
||||
$value=substr($value, strpos($value, '='));
|
||||
$value=str_replace("''", "'", $value);
|
||||
$value = $constraint['pg_get_constraintdef'];
|
||||
$value = substr($value, strpos($value, '='));
|
||||
$value = str_replace("''", "'", $value);
|
||||
|
||||
$in_value=false;
|
||||
$constraints=array();
|
||||
$current_value='';
|
||||
for ($i=0; $i<strlen($value); $i++) {
|
||||
$char=substr($value, $i, 1);
|
||||
$in_value = false;
|
||||
$constraints = array();
|
||||
$current_value = '';
|
||||
for ($i = 0; $i < strlen($value); $i++) {
|
||||
$char = substr($value, $i, 1);
|
||||
if ($in_value) {
|
||||
$current_value.=$char;
|
||||
$current_value .= $char;
|
||||
}
|
||||
|
||||
if ($char=="'") {
|
||||
if ($char == "'") {
|
||||
if (!$in_value) {
|
||||
$in_value=true;
|
||||
$in_value = true;
|
||||
} else {
|
||||
$in_value=false;
|
||||
$constraints[]=substr($current_value, 0, -1);
|
||||
$current_value='';
|
||||
$in_value = false;
|
||||
$constraints[] = substr($current_value, 0, -1);
|
||||
$current_value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sizeof($constraints)>0) {
|
||||
if (sizeof($constraints) > 0) {
|
||||
//Get the default:
|
||||
$default=trim(substr($field['column_default'], 0, strpos($field['column_default'], '::')), "'");
|
||||
$output[$field['column_name']]=$this->enum(array('default'=>$default, 'name'=>$field['column_name'], 'enums'=>$constraints));
|
||||
$default = trim(substr(
|
||||
$field['column_default'],
|
||||
0,
|
||||
strpos($field['column_default'], '::')
|
||||
), "'");
|
||||
$output[$field['column_name']] = $this->enum(array(
|
||||
'default' => $default,
|
||||
'name' => $field['column_name'],
|
||||
'enums' => $constraints
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$output[$field['column_name']]='varchar(' . $field['character_maximum_length'] . ')';
|
||||
$output[$field['column_name']] = 'varchar(' . $field['character_maximum_length'] . ')';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'numeric':
|
||||
$output[$field['column_name']]='decimal(' . $field['numeric_precision'] . ',' . $field['numeric_scale'] . ') default ' . floatval($field['column_default']);
|
||||
$output[$field['column_name']] = 'decimal(' . $field['numeric_precision'] . ',' . $field['numeric_scale'] . ') default ' . floatval($field['column_default']);
|
||||
break;
|
||||
|
||||
case 'integer':
|
||||
$output[$field['column_name']]='integer default ' . (int)$field['column_default'];
|
||||
$output[$field['column_name']] = 'integer default ' . (int)$field['column_default'];
|
||||
break;
|
||||
|
||||
case 'timestamp without time zone':
|
||||
$output[$field['column_name']]='timestamp';
|
||||
$output[$field['column_name']] = 'timestamp';
|
||||
break;
|
||||
|
||||
case 'smallint':
|
||||
$output[$field['column_name']]='smallint default ' . (int)$field['column_default'];
|
||||
$output[$field['column_name']] = 'smallint default ' . (int)$field['column_default'];
|
||||
break;
|
||||
|
||||
case 'time without time zone':
|
||||
$output[$field['column_name']]='time';
|
||||
$output[$field['column_name']] = 'time';
|
||||
break;
|
||||
|
||||
case 'double precision':
|
||||
$output[$field['column_name']]='float';
|
||||
$output[$field['column_name']] = 'float';
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -690,12 +709,12 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function clearCachedFieldlist($tableName=false)
|
||||
public function clearCachedFieldlist($tableName = false)
|
||||
{
|
||||
if ($tableName) {
|
||||
unset(self::$cached_fieldlists[$tableName]);
|
||||
} else {
|
||||
self::$cached_fieldlists=array();
|
||||
self::$cached_fieldlists = array();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -761,7 +780,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
break;
|
||||
|
||||
case 'index':
|
||||
//'index' is the same as default, just a normal index with the default type decided by the database.
|
||||
//'index' is the same as default, just a normal index with the default type decided by the database.
|
||||
default:
|
||||
$spec = "create index \"$tableCol\" ON \"$tableName\" (" . $this->implodeColumnList($indexSpec['columns']) . ") $fillfactor $where";
|
||||
}
|
||||
@ -790,22 +809,36 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
* Given a trigger name attempt to determine the columns upon which it acts
|
||||
*
|
||||
* @param string $triggerName Postgres trigger name
|
||||
* @param string $table
|
||||
* @return array List of columns
|
||||
*/
|
||||
protected function extractTriggerColumns($triggerName)
|
||||
protected function extractTriggerColumns($triggerName, $table)
|
||||
{
|
||||
$trigger = $this->preparedQuery(
|
||||
"SELECT tgargs FROM pg_catalog.pg_trigger WHERE tgname = ?",
|
||||
array($triggerName)
|
||||
"SELECT t.tgargs
|
||||
FROM pg_catalog.pg_trigger t
|
||||
INNER JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid
|
||||
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relname = ?
|
||||
AND n.nspname = ?
|
||||
AND t.tgname = ?",
|
||||
[
|
||||
$table,
|
||||
$this->database->currentSchema(),
|
||||
$triggerName
|
||||
]
|
||||
)->first();
|
||||
|
||||
// Option 1: output as a string
|
||||
if (strpos($trigger['tgargs'], '\000') !== false) {
|
||||
$argList = explode('\000', $trigger['tgargs']);
|
||||
array_pop($argList);
|
||||
// Convert stream to string
|
||||
if (is_resource($trigger['tgargs'])) {
|
||||
$trigger['tgargs'] = stream_get_contents($trigger['tgargs']);
|
||||
}
|
||||
|
||||
// Option 2: hex-encoded (not sure why this happens, depends on PGSQL config)
|
||||
if (strpos($trigger['tgargs'], "\000") !== false) {
|
||||
// Option 1: output as a string (PDO)
|
||||
$argList = array_filter(explode("\000", $trigger['tgargs']));
|
||||
} else {
|
||||
// Option 2: hex-encoded (pg_sql non-pdo)
|
||||
$bytes = str_split($trigger['tgargs'], 2);
|
||||
$argList = array();
|
||||
$nextArg = "";
|
||||
@ -826,7 +859,8 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
public function indexList($table)
|
||||
{
|
||||
//Retrieve a list of indexes for the specified table
|
||||
$indexes = $this->preparedQuery("
|
||||
$indexes = $this->preparedQuery(
|
||||
"
|
||||
SELECT tablename, indexname, indexdef
|
||||
FROM pg_catalog.pg_indexes
|
||||
WHERE tablename = ? AND schemaname = ?;",
|
||||
@ -843,12 +877,12 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$type = '';
|
||||
|
||||
//Check for uniques:
|
||||
if (substr($index['indexdef'], 0, 13)=='CREATE UNIQUE') {
|
||||
if (substr($index['indexdef'], 0, 13) == 'CREATE UNIQUE') {
|
||||
$type = 'unique';
|
||||
}
|
||||
|
||||
//check for hashes, btrees etc:
|
||||
if (strpos(strtolower($index['indexdef']), 'using hash ')!==false) {
|
||||
if (strpos(strtolower($index['indexdef']), 'using hash ') !== false) {
|
||||
$type = 'hash';
|
||||
}
|
||||
|
||||
@ -856,7 +890,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
//if(strpos(strtolower($index['indexdef']), 'using btree ')!==false)
|
||||
// $prefix='using btree ';
|
||||
|
||||
if (strpos(strtolower($index['indexdef']), 'using rtree ')!==false) {
|
||||
if (strpos(strtolower($index['indexdef']), 'using rtree ') !== false) {
|
||||
$type = 'rtree';
|
||||
}
|
||||
|
||||
@ -865,7 +899,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$type = 'fulltext';
|
||||
// Extract trigger information from postgres
|
||||
$triggerName = preg_replace('/^ix_/', 'ts_', $index['indexname']);
|
||||
$columns = $this->extractTriggerColumns($triggerName);
|
||||
$columns = $this->extractTriggerColumns($triggerName, $table);
|
||||
$columnString = $this->implodeColumnList($columns);
|
||||
} else {
|
||||
$columnString = $this->quoteColumnSpecString($index['indexdef']);
|
||||
@ -908,7 +942,8 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
protected function constraintExists($constraint, $cache = true)
|
||||
{
|
||||
if (!$cache || !isset(self::$cached_constraints[$constraint])) {
|
||||
$value = $this->preparedQuery("
|
||||
$value = $this->preparedQuery(
|
||||
"
|
||||
SELECT conname,pg_catalog.pg_get_constraintdef(r.oid, true)
|
||||
FROM pg_catalog.pg_constraint r
|
||||
INNER JOIN pg_catalog.pg_namespace n
|
||||
@ -968,7 +1003,8 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
*/
|
||||
protected function dropTrigger($triggerName, $tableName)
|
||||
{
|
||||
$exists = $this->preparedQuery("
|
||||
$exists = $this->preparedQuery(
|
||||
"
|
||||
SELECT trigger_name
|
||||
FROM information_schema.triggers
|
||||
WHERE trigger_name = ? AND trigger_schema = ?;",
|
||||
@ -988,18 +1024,18 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
protected function triggerFieldsFromTrigger($trigger)
|
||||
{
|
||||
if ($trigger) {
|
||||
$tsvector='tsvector_update_trigger';
|
||||
$ts_pos=strpos($trigger, $tsvector);
|
||||
$details=trim(substr($trigger, $ts_pos+strlen($tsvector)), '();');
|
||||
$tsvector = 'tsvector_update_trigger';
|
||||
$ts_pos = strpos($trigger, $tsvector);
|
||||
$details = trim(substr($trigger, $ts_pos + strlen($tsvector)), '();');
|
||||
//Now split this into bits:
|
||||
$bits=explode(',', $details);
|
||||
$bits = explode(',', $details);
|
||||
|
||||
$fields=$bits[2];
|
||||
$fields = $bits[2];
|
||||
|
||||
$field_bits=explode(',', str_replace('"', '', $fields));
|
||||
$result=array();
|
||||
$field_bits = explode(',', str_replace('"', '', $fields));
|
||||
$result = array();
|
||||
foreach ($field_bits as $field_bit) {
|
||||
$result[]=trim($field_bit);
|
||||
$result[] = trim($field_bit);
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -1063,7 +1099,10 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
public function enum($values)
|
||||
{
|
||||
$default = " default '{$values['default']}'";
|
||||
return "varchar(255)" . $default . " check (\"" . $values['name'] . "\" in ('" . implode('\', \'', $values['enums']) . "'))";
|
||||
return "varchar(255)" . $default . " check (\"" . $values['name'] . "\" in ('" . implode(
|
||||
'\', \'',
|
||||
$values['enums']
|
||||
) . "', null))";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1250,7 +1289,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
*/
|
||||
protected function enumValuesFromConstraint($constraint)
|
||||
{
|
||||
$constraint = substr($constraint, strpos($constraint, 'ANY (ARRAY[')+11);
|
||||
$constraint = substr($constraint, strpos($constraint, 'ANY (ARRAY[') + 11);
|
||||
$constraint = substr($constraint, 0, -11);
|
||||
$constraints = array();
|
||||
$segments = explode(',', $constraint);
|
||||
@ -1314,21 +1353,25 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
//We need the plpgsql language to be installed for this to work:
|
||||
$this->createLanguage('plpgsql');
|
||||
|
||||
$trigger='CREATE OR REPLACE FUNCTION ' . $tableName . '_insert_trigger() RETURNS TRIGGER AS $$ BEGIN ';
|
||||
$first=true;
|
||||
$trigger = 'CREATE OR REPLACE FUNCTION ' . $tableName . '_insert_trigger() RETURNS TRIGGER AS $$ BEGIN ';
|
||||
$first = true;
|
||||
|
||||
//Do we need to create a tablespace for this item?
|
||||
if ($extensions && isset($extensions['tablespace'])) {
|
||||
$this->createOrReplaceTablespace($extensions['tablespace']['name'], $extensions['tablespace']['location']);
|
||||
$tableSpace=' TABLESPACE ' . $extensions['tablespace']['name'];
|
||||
$tableSpace = ' TABLESPACE ' . $extensions['tablespace']['name'];
|
||||
} else {
|
||||
$tableSpace='';
|
||||
$tableSpace = '';
|
||||
}
|
||||
|
||||
foreach ($partitions as $partition_name => $partition_value) {
|
||||
//Check that this child table does not already exist:
|
||||
if (!$this->hasTable($partition_name)) {
|
||||
$this->query("CREATE TABLE \"$partition_name\" (CHECK (" . str_replace('NEW.', '', $partition_value) . ")) INHERITS (\"$tableName\")$tableSpace;");
|
||||
$this->query("CREATE TABLE \"$partition_name\" (CHECK (" . str_replace(
|
||||
'NEW.',
|
||||
'',
|
||||
$partition_value
|
||||
) . ")) INHERITS (\"$tableName\")$tableSpace;");
|
||||
} else {
|
||||
//Drop the constraint, we will recreate in in the next line
|
||||
$constraintName = "{$partition_name}_pkey";
|
||||
@ -1342,10 +1385,10 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$this->query("ALTER TABLE \"$partition_name\" ADD CONSTRAINT \"{$partition_name}_pkey\" PRIMARY KEY (\"ID\");");
|
||||
|
||||
if ($first) {
|
||||
$trigger.='IF';
|
||||
$first=false;
|
||||
$trigger .= 'IF';
|
||||
$first = false;
|
||||
} else {
|
||||
$trigger.='ELSIF';
|
||||
$trigger .= 'ELSIF';
|
||||
}
|
||||
|
||||
$trigger .= " ($partition_value) THEN INSERT INTO \"$partition_name\" VALUES (NEW.*);";
|
||||
@ -1354,7 +1397,7 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
// We need to propogate the indexes through to the child pages.
|
||||
// Some of this code is duplicated, and could be tidied up
|
||||
foreach ($indexes as $name => $this_index) {
|
||||
if ($this_index['type']=='fulltext') {
|
||||
if ($this_index['type'] == 'fulltext') {
|
||||
$fillfactor = $where = '';
|
||||
if (isset($this_index['fillfactor'])) {
|
||||
$fillfactor = 'WITH (FILLFACTOR = ' . $this_index['fillfactor'] . ')';
|
||||
@ -1363,7 +1406,10 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$where = 'WHERE ' . $this_index['where'];
|
||||
}
|
||||
$clusterMethod = PostgreSQLDatabase::default_fts_cluster_method();
|
||||
$this->query("CREATE INDEX \"" . $this->buildPostgresIndexName($partition_name, $this_index['name']) . "\" ON \"" . $partition_name . "\" USING $clusterMethod(\"ts_" . $name . "\") $fillfactor $where");
|
||||
$this->query("CREATE INDEX \"" . $this->buildPostgresIndexName(
|
||||
$partition_name,
|
||||
$this_index['name']
|
||||
) . "\" ON \"" . $partition_name . "\" USING $clusterMethod(\"ts_" . $name . "\") $fillfactor $where");
|
||||
$ts_details = $this->fulltext($this_index, $partition_name, $name);
|
||||
$this->query($ts_details['triggers']);
|
||||
} else {
|
||||
|
@ -1,27 +1,41 @@
|
||||
{
|
||||
"name": "silverstripe/postgresql",
|
||||
"description": "SilverStripe now has tentative support for PostgreSQL ('Postgres')",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"keywords": ["silverstripe", "postgresql", "database"],
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sam Minnée",
|
||||
"email": "sam@silverstripe.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"silverstripe/framework": "^4.0@dev",
|
||||
"silverstripe/vendor-plugin": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
"name": "silverstripe/postgresql",
|
||||
"description": "SilverStripe now has tentative support for PostgreSQL ('Postgres')",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"keywords": [
|
||||
"silverstripe",
|
||||
"postgresql",
|
||||
"database"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sam Minnée",
|
||||
"email": "sam@silverstripe.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"silverstripe/framework": "^4",
|
||||
"silverstripe/vendor-plugin": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SilverStripe\\PostgreSQL\\": "code/",
|
||||
"SilverStripe\\PostgreSQL\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "phpcs code/ tests/",
|
||||
"lint-clean": "phpcbf code/ tests/"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
30
phpcs.xml.dist
Normal file
30
phpcs.xml.dist
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="SilverStripe">
|
||||
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||
|
||||
<!-- base rules are PSR-2 -->
|
||||
<rule ref="PSR2" >
|
||||
<!-- Current exclusions -->
|
||||
<exclude name="PSR1.Methods.CamelCapsMethodName" />
|
||||
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
|
||||
<exclude name="PSR2.Classes.PropertyDeclaration" />
|
||||
<exclude name="PSR2.ControlStructures.SwitchDeclaration" /> <!-- causes php notice while linting -->
|
||||
<exclude name="PSR2.ControlStructures.SwitchDeclaration.WrongOpenercase" />
|
||||
<exclude name="PSR2.ControlStructures.SwitchDeclaration.WrongOpenerdefault" />
|
||||
<exclude name="PSR2.ControlStructures.SwitchDeclaration.TerminatingComment" />
|
||||
<exclude name="PSR2.Methods.MethodDeclaration.Underscore" />
|
||||
<exclude name="Squiz.Scope.MethodScope" />
|
||||
<exclude name="Squiz.Classes.ValidClassName.NotCamelCaps" />
|
||||
<exclude name="Generic.Files.LineLength.TooLong" />
|
||||
<exclude name="PEAR.Functions.ValidDefaultValue.NotAtEnd" />
|
||||
</rule>
|
||||
|
||||
<!-- include php files only -->
|
||||
<arg name="extensions" value="php,lib,inc,php5"/>
|
||||
|
||||
<!-- PHP-PEG generated file not intended for human consumption -->
|
||||
<exclude-pattern>*/SSTemplateParser.php$</exclude-pattern>
|
||||
<exclude-pattern>*/_fakewebroot/*</exclude-pattern>
|
||||
<exclude-pattern>*/fixtures/*</exclude-pattern>
|
||||
</ruleset>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<phpunit bootstrap="cms/tests/bootstrap.php" colors="true">
|
||||
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
|
||||
|
||||
<testsuite name="Default">
|
||||
<directory>tests</directory>
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\PostgreSQL\Tests;
|
||||
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\PostgreSQL\PostgreSQLConnector;
|
||||
|
||||
@ -23,7 +25,7 @@ class PostgreSQLConnectorTest extends SapphireTest
|
||||
|
||||
// Ignoring question mark placeholders within string literals
|
||||
$this->assertEquals(
|
||||
"SELECT * FROM Table WHERE ID = $1 AND Name = $2 AND Content = '<p>What is love?</p>'",
|
||||
"SELECT * FROM Table WHERE ID = $1 AND Name = $2 AND Content = '<p>What is love?</p>'",
|
||||
$connector->replacePlaceholders(
|
||||
"SELECT * FROM Table WHERE ID = ? AND Name = ? AND Content = '<p>What is love?</p>'"
|
||||
)
|
||||
@ -31,7 +33,7 @@ class PostgreSQLConnectorTest extends SapphireTest
|
||||
|
||||
// Ignoring question mark placeholders within string literals with escaped slashes
|
||||
$this->assertEquals(
|
||||
"SELECT * FROM Table WHERE ID = $1 AND Title = '\\'' AND Content = '<p>What is love?</p>' AND Name = $2",
|
||||
"SELECT * FROM Table WHERE ID = $1 AND Title = '\\'' AND Content = '<p>What is love?</p>' AND Name = $2",
|
||||
$connector->replacePlaceholders(
|
||||
"SELECT * FROM Table WHERE ID = ? AND Title = '\\'' AND Content = '<p>What is love?</p>' AND Name = ?"
|
||||
)
|
||||
@ -39,7 +41,7 @@ class PostgreSQLConnectorTest extends SapphireTest
|
||||
|
||||
// same as above, but use double single quote escape syntax
|
||||
$this->assertEquals(
|
||||
"SELECT * FROM Table WHERE ID = $1 AND Title = '''' AND Content = '<p>What is love?</p>' AND Name = $2",
|
||||
"SELECT * FROM Table WHERE ID = $1 AND Title = '''' AND Content = '<p>What is love?</p>' AND Name = $2",
|
||||
$connector->replacePlaceholders(
|
||||
"SELECT * FROM Table WHERE ID = ? AND Title = '''' AND Content = '<p>What is love?</p>' AND Name = ?"
|
||||
)
|
||||
|
@ -1,5 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\PostgreSQL\Tests;
|
||||
|
||||
use Exception;
|
||||
use Page;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
@ -15,19 +19,18 @@ class PostgreSQLDatabaseTest extends SapphireTest
|
||||
|
||||
public function testReadOnlyTransaction()
|
||||
{
|
||||
if (
|
||||
DB::get_conn()->supportsTransactions() == true
|
||||
if (DB::get_conn()->supportsTransactions() == true
|
||||
&& DB::get_conn() instanceof PostgreSQLDatabase
|
||||
) {
|
||||
$page=new Page();
|
||||
$page->Title='Read only success';
|
||||
$page = new Page();
|
||||
$page->Title = 'Read only success';
|
||||
$page->write();
|
||||
|
||||
DB::get_conn()->transactionStart('READ ONLY');
|
||||
|
||||
try {
|
||||
$page=new Page();
|
||||
$page->Title='Read only page failed';
|
||||
$page = new Page();
|
||||
$page->Title = 'Read only page failed';
|
||||
$page->write();
|
||||
} catch (Exception $e) {
|
||||
//could not write this record
|
||||
@ -39,8 +42,8 @@ class PostgreSQLDatabaseTest extends SapphireTest
|
||||
|
||||
DataObject::flush_and_destroy_cache();
|
||||
|
||||
$success=DataObject::get('Page', "\"Title\"='Read only success'");
|
||||
$fail=DataObject::get('Page', "\"Title\"='Read only page failed'");
|
||||
$success = DataObject::get('Page', "\"Title\"='Read only success'");
|
||||
$fail = DataObject::get('Page', "\"Title\"='Read only page failed'");
|
||||
|
||||
//This page should be in the system
|
||||
$this->assertTrue(is_object($success) && $success->exists());
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\PostgreSQL\Tests;
|
||||
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
|
Loading…
Reference in New Issue
Block a user