@@ -48,7 +48,7 @@ |
||
| 48 | 48 | public function iLike($x, $y, $type = null) { |
| 49 | 49 | $x = $this->helper->quoteColumnName($x); |
| 50 | 50 | $y = $this->helper->quoteColumnName($y); |
| 51 | - return $this->expressionBuilder->comparison($x, ' COLLATE ' . $this->charset . '_general_ci LIKE', $y); |
|
| 51 | + return $this->expressionBuilder->comparison($x, ' COLLATE '.$this->charset.'_general_ci LIKE', $y); |
|
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | } |
@@ -30,27 +30,27 @@ |
||
| 30 | 30 | |
| 31 | 31 | class MySqlExpressionBuilder extends ExpressionBuilder { |
| 32 | 32 | |
| 33 | - /** @var string */ |
|
| 34 | - protected $charset; |
|
| 35 | - |
|
| 36 | - /** |
|
| 37 | - * @param \OCP\IDBConnection|Connection $connection |
|
| 38 | - * @param IQueryBuilder $queryBuilder |
|
| 39 | - */ |
|
| 40 | - public function __construct(IDBConnection $connection, IQueryBuilder $queryBuilder) { |
|
| 41 | - parent::__construct($connection, $queryBuilder); |
|
| 42 | - |
|
| 43 | - $params = $connection->getParams(); |
|
| 44 | - $this->charset = isset($params['charset']) ? $params['charset'] : 'utf8'; |
|
| 45 | - } |
|
| 46 | - |
|
| 47 | - /** |
|
| 48 | - * @inheritdoc |
|
| 49 | - */ |
|
| 50 | - public function iLike($x, $y, $type = null) { |
|
| 51 | - $x = $this->helper->quoteColumnName($x); |
|
| 52 | - $y = $this->helper->quoteColumnName($y); |
|
| 53 | - return $this->expressionBuilder->comparison($x, ' COLLATE ' . $this->charset . '_general_ci LIKE', $y); |
|
| 54 | - } |
|
| 33 | + /** @var string */ |
|
| 34 | + protected $charset; |
|
| 35 | + |
|
| 36 | + /** |
|
| 37 | + * @param \OCP\IDBConnection|Connection $connection |
|
| 38 | + * @param IQueryBuilder $queryBuilder |
|
| 39 | + */ |
|
| 40 | + public function __construct(IDBConnection $connection, IQueryBuilder $queryBuilder) { |
|
| 41 | + parent::__construct($connection, $queryBuilder); |
|
| 42 | + |
|
| 43 | + $params = $connection->getParams(); |
|
| 44 | + $this->charset = isset($params['charset']) ? $params['charset'] : 'utf8'; |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + /** |
|
| 48 | + * @inheritdoc |
|
| 49 | + */ |
|
| 50 | + public function iLike($x, $y, $type = null) { |
|
| 51 | + $x = $this->helper->quoteColumnName($x); |
|
| 52 | + $y = $this->helper->quoteColumnName($y); |
|
| 53 | + return $this->expressionBuilder->comparison($x, ' COLLATE ' . $this->charset . '_general_ci LIKE', $y); |
|
| 54 | + } |
|
| 55 | 55 | |
| 56 | 56 | } |
@@ -29,29 +29,29 @@ |
||
| 29 | 29 | |
| 30 | 30 | class PgSqlExpressionBuilder extends ExpressionBuilder { |
| 31 | 31 | |
| 32 | - /** |
|
| 33 | - * Returns a IQueryFunction that casts the column to the given type |
|
| 34 | - * |
|
| 35 | - * @param string $column |
|
| 36 | - * @param mixed $type One of IQueryBuilder::PARAM_* |
|
| 37 | - * @return string |
|
| 38 | - */ |
|
| 39 | - public function castColumn($column, $type) { |
|
| 40 | - if ($type === IQueryBuilder::PARAM_INT) { |
|
| 41 | - $column = $this->helper->quoteColumnName($column); |
|
| 42 | - return new QueryFunction('CAST(' . $column . ' AS INT)'); |
|
| 43 | - } |
|
| 44 | - |
|
| 45 | - return parent::castColumn($column, $type); |
|
| 46 | - } |
|
| 47 | - |
|
| 48 | - /** |
|
| 49 | - * @inheritdoc |
|
| 50 | - */ |
|
| 51 | - public function iLike($x, $y, $type = null) { |
|
| 52 | - $x = $this->helper->quoteColumnName($x); |
|
| 53 | - $y = $this->helper->quoteColumnName($y); |
|
| 54 | - return $this->expressionBuilder->comparison($x, 'ILIKE', $y); |
|
| 55 | - } |
|
| 32 | + /** |
|
| 33 | + * Returns a IQueryFunction that casts the column to the given type |
|
| 34 | + * |
|
| 35 | + * @param string $column |
|
| 36 | + * @param mixed $type One of IQueryBuilder::PARAM_* |
|
| 37 | + * @return string |
|
| 38 | + */ |
|
| 39 | + public function castColumn($column, $type) { |
|
| 40 | + if ($type === IQueryBuilder::PARAM_INT) { |
|
| 41 | + $column = $this->helper->quoteColumnName($column); |
|
| 42 | + return new QueryFunction('CAST(' . $column . ' AS INT)'); |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + return parent::castColumn($column, $type); |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | + /** |
|
| 49 | + * @inheritdoc |
|
| 50 | + */ |
|
| 51 | + public function iLike($x, $y, $type = null) { |
|
| 52 | + $x = $this->helper->quoteColumnName($x); |
|
| 53 | + $y = $this->helper->quoteColumnName($y); |
|
| 54 | + return $this->expressionBuilder->comparison($x, 'ILIKE', $y); |
|
| 55 | + } |
|
| 56 | 56 | |
| 57 | 57 | } |
@@ -39,7 +39,7 @@ |
||
| 39 | 39 | public function castColumn($column, $type) { |
| 40 | 40 | if ($type === IQueryBuilder::PARAM_INT) { |
| 41 | 41 | $column = $this->helper->quoteColumnName($column); |
| 42 | - return new QueryFunction('CAST(' . $column . ' AS INT)'); |
|
| 42 | + return new QueryFunction('CAST('.$column.' AS INT)'); |
|
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | return parent::castColumn($column, $type); |
@@ -31,41 +31,41 @@ |
||
| 31 | 31 | */ |
| 32 | 32 | class PgSqlTools { |
| 33 | 33 | |
| 34 | - /** @var \OCP\IConfig */ |
|
| 35 | - private $config; |
|
| 34 | + /** @var \OCP\IConfig */ |
|
| 35 | + private $config; |
|
| 36 | 36 | |
| 37 | - /** |
|
| 38 | - * @param \OCP\IConfig $config |
|
| 39 | - */ |
|
| 40 | - public function __construct(IConfig $config) { |
|
| 41 | - $this->config = $config; |
|
| 42 | - } |
|
| 37 | + /** |
|
| 38 | + * @param \OCP\IConfig $config |
|
| 39 | + */ |
|
| 40 | + public function __construct(IConfig $config) { |
|
| 41 | + $this->config = $config; |
|
| 42 | + } |
|
| 43 | 43 | |
| 44 | - /** |
|
| 45 | - * @brief Resynchronizes all sequences of a database after using INSERTs |
|
| 46 | - * without leaving out the auto-incremented column. |
|
| 47 | - * @param \OC\DB\Connection $conn |
|
| 48 | - * @return null |
|
| 49 | - */ |
|
| 50 | - public function resynchronizeDatabaseSequences(Connection $conn) { |
|
| 51 | - $filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
|
| 52 | - $databaseName = $conn->getDatabase(); |
|
| 53 | - $conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 44 | + /** |
|
| 45 | + * @brief Resynchronizes all sequences of a database after using INSERTs |
|
| 46 | + * without leaving out the auto-incremented column. |
|
| 47 | + * @param \OC\DB\Connection $conn |
|
| 48 | + * @return null |
|
| 49 | + */ |
|
| 50 | + public function resynchronizeDatabaseSequences(Connection $conn) { |
|
| 51 | + $filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
|
| 52 | + $databaseName = $conn->getDatabase(); |
|
| 53 | + $conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 54 | 54 | |
| 55 | - foreach ($conn->getSchemaManager()->listSequences() as $sequence) { |
|
| 56 | - $sequenceName = $sequence->getName(); |
|
| 57 | - $sqlInfo = 'SELECT table_schema, table_name, column_name |
|
| 55 | + foreach ($conn->getSchemaManager()->listSequences() as $sequence) { |
|
| 56 | + $sequenceName = $sequence->getName(); |
|
| 57 | + $sqlInfo = 'SELECT table_schema, table_name, column_name |
|
| 58 | 58 | FROM information_schema.columns |
| 59 | 59 | WHERE column_default = ? AND table_catalog = ?'; |
| 60 | - $sequenceInfo = $conn->fetchAssoc($sqlInfo, array( |
|
| 61 | - "nextval('$sequenceName'::regclass)", |
|
| 62 | - $databaseName |
|
| 63 | - )); |
|
| 64 | - $tableName = $sequenceInfo['table_name']; |
|
| 65 | - $columnName = $sequenceInfo['column_name']; |
|
| 66 | - $sqlMaxId = "SELECT MAX($columnName) FROM $tableName"; |
|
| 67 | - $sqlSetval = "SELECT setval('$sequenceName', ($sqlMaxId))"; |
|
| 68 | - $conn->executeQuery($sqlSetval); |
|
| 69 | - } |
|
| 70 | - } |
|
| 60 | + $sequenceInfo = $conn->fetchAssoc($sqlInfo, array( |
|
| 61 | + "nextval('$sequenceName'::regclass)", |
|
| 62 | + $databaseName |
|
| 63 | + )); |
|
| 64 | + $tableName = $sequenceInfo['table_name']; |
|
| 65 | + $columnName = $sequenceInfo['column_name']; |
|
| 66 | + $sqlMaxId = "SELECT MAX($columnName) FROM $tableName"; |
|
| 67 | + $sqlSetval = "SELECT setval('$sequenceName', ($sqlMaxId))"; |
|
| 68 | + $conn->executeQuery($sqlSetval); |
|
| 69 | + } |
|
| 70 | + } |
|
| 71 | 71 | } |
@@ -48,7 +48,7 @@ |
||
| 48 | 48 | * @return null |
| 49 | 49 | */ |
| 50 | 50 | public function resynchronizeDatabaseSequences(Connection $conn) { |
| 51 | - $filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
|
| 51 | + $filterExpression = '/^'.preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')).'/'; |
|
| 52 | 52 | $databaseName = $conn->getDatabase(); |
| 53 | 53 | $conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
| 54 | 54 | |
@@ -25,32 +25,32 @@ |
||
| 25 | 25 | use Doctrine\DBAL\Schema\Schema; |
| 26 | 26 | |
| 27 | 27 | class PostgreSqlMigrator extends Migrator { |
| 28 | - /** |
|
| 29 | - * @param Schema $targetSchema |
|
| 30 | - * @param \Doctrine\DBAL\Connection $connection |
|
| 31 | - * @return \Doctrine\DBAL\Schema\SchemaDiff |
|
| 32 | - */ |
|
| 33 | - protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { |
|
| 34 | - $schemaDiff = parent::getDiff($targetSchema, $connection); |
|
| 28 | + /** |
|
| 29 | + * @param Schema $targetSchema |
|
| 30 | + * @param \Doctrine\DBAL\Connection $connection |
|
| 31 | + * @return \Doctrine\DBAL\Schema\SchemaDiff |
|
| 32 | + */ |
|
| 33 | + protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { |
|
| 34 | + $schemaDiff = parent::getDiff($targetSchema, $connection); |
|
| 35 | 35 | |
| 36 | - foreach ($schemaDiff->changedTables as $tableDiff) { |
|
| 37 | - // fix default value in brackets - pg 9.4 is returning a negative default value in () |
|
| 38 | - // see https://github.com/doctrine/dbal/issues/2427 |
|
| 39 | - foreach ($tableDiff->changedColumns as $column) { |
|
| 40 | - $column->changedProperties = array_filter($column->changedProperties, function ($changedProperties) use ($column) { |
|
| 41 | - if ($changedProperties !== 'default') { |
|
| 42 | - return true; |
|
| 43 | - } |
|
| 44 | - $fromDefault = $column->fromColumn->getDefault(); |
|
| 45 | - $toDefault = $column->column->getDefault(); |
|
| 46 | - $fromDefault = trim($fromDefault, "()"); |
|
| 36 | + foreach ($schemaDiff->changedTables as $tableDiff) { |
|
| 37 | + // fix default value in brackets - pg 9.4 is returning a negative default value in () |
|
| 38 | + // see https://github.com/doctrine/dbal/issues/2427 |
|
| 39 | + foreach ($tableDiff->changedColumns as $column) { |
|
| 40 | + $column->changedProperties = array_filter($column->changedProperties, function ($changedProperties) use ($column) { |
|
| 41 | + if ($changedProperties !== 'default') { |
|
| 42 | + return true; |
|
| 43 | + } |
|
| 44 | + $fromDefault = $column->fromColumn->getDefault(); |
|
| 45 | + $toDefault = $column->column->getDefault(); |
|
| 46 | + $fromDefault = trim($fromDefault, "()"); |
|
| 47 | 47 | |
| 48 | - // by intention usage of != |
|
| 49 | - return $fromDefault != $toDefault; |
|
| 50 | - }); |
|
| 51 | - } |
|
| 52 | - } |
|
| 48 | + // by intention usage of != |
|
| 49 | + return $fromDefault != $toDefault; |
|
| 50 | + }); |
|
| 51 | + } |
|
| 52 | + } |
|
| 53 | 53 | |
| 54 | - return $schemaDiff; |
|
| 55 | - } |
|
| 54 | + return $schemaDiff; |
|
| 55 | + } |
|
| 56 | 56 | } |
@@ -37,7 +37,7 @@ |
||
| 37 | 37 | // fix default value in brackets - pg 9.4 is returning a negative default value in () |
| 38 | 38 | // see https://github.com/doctrine/dbal/issues/2427 |
| 39 | 39 | foreach ($tableDiff->changedColumns as $column) { |
| 40 | - $column->changedProperties = array_filter($column->changedProperties, function ($changedProperties) use ($column) { |
|
| 40 | + $column->changedProperties = array_filter($column->changedProperties, function($changedProperties) use ($column) { |
|
| 41 | 41 | if ($changedProperties !== 'default') { |
| 42 | 42 | return true; |
| 43 | 43 | } |
@@ -66,7 +66,7 @@ discard block |
||
| 66 | 66 | */ |
| 67 | 67 | public function lockTable($tableName) { |
| 68 | 68 | $this->conn->beginTransaction(); |
| 69 | - $this->conn->executeUpdate('LOCK TABLE `' .$tableName . '` IN EXCLUSIVE MODE'); |
|
| 69 | + $this->conn->executeUpdate('LOCK TABLE `'.$tableName.'` IN EXCLUSIVE MODE'); |
|
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | /** |
@@ -93,14 +93,14 @@ discard block |
||
| 93 | 93 | if (empty($compare)) { |
| 94 | 94 | $compare = array_keys($input); |
| 95 | 95 | } |
| 96 | - $query = 'INSERT INTO `' .$table . '` (`' |
|
| 97 | - . implode('`,`', array_keys($input)) . '`) SELECT ' |
|
| 98 | - . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? |
|
| 99 | - . 'FROM `' . $table . '` WHERE '; |
|
| 96 | + $query = 'INSERT INTO `'.$table.'` (`' |
|
| 97 | + . implode('`,`', array_keys($input)).'`) SELECT ' |
|
| 98 | + . str_repeat('?,', count($input) - 1).'? ' // Is there a prettier alternative? |
|
| 99 | + . 'FROM `'.$table.'` WHERE '; |
|
| 100 | 100 | |
| 101 | 101 | $inserts = array_values($input); |
| 102 | - foreach($compare as $key) { |
|
| 103 | - $query .= '`' . $key . '`'; |
|
| 102 | + foreach ($compare as $key) { |
|
| 103 | + $query .= '`'.$key.'`'; |
|
| 104 | 104 | if (is_null($input[$key])) { |
| 105 | 105 | $query .= ' IS NULL AND '; |
| 106 | 106 | } else { |
@@ -35,95 +35,95 @@ |
||
| 35 | 35 | */ |
| 36 | 36 | class Adapter { |
| 37 | 37 | |
| 38 | - /** |
|
| 39 | - * @var \OC\DB\Connection $conn |
|
| 40 | - */ |
|
| 41 | - protected $conn; |
|
| 38 | + /** |
|
| 39 | + * @var \OC\DB\Connection $conn |
|
| 40 | + */ |
|
| 41 | + protected $conn; |
|
| 42 | 42 | |
| 43 | - public function __construct($conn) { |
|
| 44 | - $this->conn = $conn; |
|
| 45 | - } |
|
| 43 | + public function __construct($conn) { |
|
| 44 | + $this->conn = $conn; |
|
| 45 | + } |
|
| 46 | 46 | |
| 47 | - /** |
|
| 48 | - * @param string $table name |
|
| 49 | - * @return int id of last insert statement |
|
| 50 | - */ |
|
| 51 | - public function lastInsertId($table) { |
|
| 52 | - return $this->conn->realLastInsertId($table); |
|
| 53 | - } |
|
| 47 | + /** |
|
| 48 | + * @param string $table name |
|
| 49 | + * @return int id of last insert statement |
|
| 50 | + */ |
|
| 51 | + public function lastInsertId($table) { |
|
| 52 | + return $this->conn->realLastInsertId($table); |
|
| 53 | + } |
|
| 54 | 54 | |
| 55 | - /** |
|
| 56 | - * @param string $statement that needs to be changed so the db can handle it |
|
| 57 | - * @return string changed statement |
|
| 58 | - */ |
|
| 59 | - public function fixupStatement($statement) { |
|
| 60 | - return $statement; |
|
| 61 | - } |
|
| 55 | + /** |
|
| 56 | + * @param string $statement that needs to be changed so the db can handle it |
|
| 57 | + * @return string changed statement |
|
| 58 | + */ |
|
| 59 | + public function fixupStatement($statement) { |
|
| 60 | + return $statement; |
|
| 61 | + } |
|
| 62 | 62 | |
| 63 | - /** |
|
| 64 | - * Create an exclusive read+write lock on a table |
|
| 65 | - * |
|
| 66 | - * @param string $tableName |
|
| 67 | - * @since 9.1.0 |
|
| 68 | - */ |
|
| 69 | - public function lockTable($tableName) { |
|
| 70 | - $this->conn->beginTransaction(); |
|
| 71 | - $this->conn->executeUpdate('LOCK TABLE `' .$tableName . '` IN EXCLUSIVE MODE'); |
|
| 72 | - } |
|
| 63 | + /** |
|
| 64 | + * Create an exclusive read+write lock on a table |
|
| 65 | + * |
|
| 66 | + * @param string $tableName |
|
| 67 | + * @since 9.1.0 |
|
| 68 | + */ |
|
| 69 | + public function lockTable($tableName) { |
|
| 70 | + $this->conn->beginTransaction(); |
|
| 71 | + $this->conn->executeUpdate('LOCK TABLE `' .$tableName . '` IN EXCLUSIVE MODE'); |
|
| 72 | + } |
|
| 73 | 73 | |
| 74 | - /** |
|
| 75 | - * Release a previous acquired lock again |
|
| 76 | - * |
|
| 77 | - * @since 9.1.0 |
|
| 78 | - */ |
|
| 79 | - public function unlockTable() { |
|
| 80 | - $this->conn->commit(); |
|
| 81 | - } |
|
| 74 | + /** |
|
| 75 | + * Release a previous acquired lock again |
|
| 76 | + * |
|
| 77 | + * @since 9.1.0 |
|
| 78 | + */ |
|
| 79 | + public function unlockTable() { |
|
| 80 | + $this->conn->commit(); |
|
| 81 | + } |
|
| 82 | 82 | |
| 83 | - /** |
|
| 84 | - * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance |
|
| 85 | - * it is needed that there is also a unique constraint on the values. Then this method will |
|
| 86 | - * catch the exception and return 0. |
|
| 87 | - * |
|
| 88 | - * @param string $table The table name (will replace *PREFIX* with the actual prefix) |
|
| 89 | - * @param array $input data that should be inserted into the table (column name => value) |
|
| 90 | - * @param array|null $compare List of values that should be checked for "if not exists" |
|
| 91 | - * If this is null or an empty array, all keys of $input will be compared |
|
| 92 | - * Please note: text fields (clob) must not be used in the compare array |
|
| 93 | - * @return int number of inserted rows |
|
| 94 | - * @throws \Doctrine\DBAL\DBALException |
|
| 95 | - * @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371 |
|
| 96 | - */ |
|
| 97 | - public function insertIfNotExist($table, $input, array $compare = null) { |
|
| 98 | - if (empty($compare)) { |
|
| 99 | - $compare = array_keys($input); |
|
| 100 | - } |
|
| 101 | - $query = 'INSERT INTO `' .$table . '` (`' |
|
| 102 | - . implode('`,`', array_keys($input)) . '`) SELECT ' |
|
| 103 | - . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? |
|
| 104 | - . 'FROM `' . $table . '` WHERE '; |
|
| 83 | + /** |
|
| 84 | + * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance |
|
| 85 | + * it is needed that there is also a unique constraint on the values. Then this method will |
|
| 86 | + * catch the exception and return 0. |
|
| 87 | + * |
|
| 88 | + * @param string $table The table name (will replace *PREFIX* with the actual prefix) |
|
| 89 | + * @param array $input data that should be inserted into the table (column name => value) |
|
| 90 | + * @param array|null $compare List of values that should be checked for "if not exists" |
|
| 91 | + * If this is null or an empty array, all keys of $input will be compared |
|
| 92 | + * Please note: text fields (clob) must not be used in the compare array |
|
| 93 | + * @return int number of inserted rows |
|
| 94 | + * @throws \Doctrine\DBAL\DBALException |
|
| 95 | + * @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371 |
|
| 96 | + */ |
|
| 97 | + public function insertIfNotExist($table, $input, array $compare = null) { |
|
| 98 | + if (empty($compare)) { |
|
| 99 | + $compare = array_keys($input); |
|
| 100 | + } |
|
| 101 | + $query = 'INSERT INTO `' .$table . '` (`' |
|
| 102 | + . implode('`,`', array_keys($input)) . '`) SELECT ' |
|
| 103 | + . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? |
|
| 104 | + . 'FROM `' . $table . '` WHERE '; |
|
| 105 | 105 | |
| 106 | - $inserts = array_values($input); |
|
| 107 | - foreach($compare as $key) { |
|
| 108 | - $query .= '`' . $key . '`'; |
|
| 109 | - if (is_null($input[$key])) { |
|
| 110 | - $query .= ' IS NULL AND '; |
|
| 111 | - } else { |
|
| 112 | - $inserts[] = $input[$key]; |
|
| 113 | - $query .= ' = ? AND '; |
|
| 114 | - } |
|
| 115 | - } |
|
| 116 | - $query = substr($query, 0, -5); |
|
| 117 | - $query .= ' HAVING COUNT(*) = 0'; |
|
| 106 | + $inserts = array_values($input); |
|
| 107 | + foreach($compare as $key) { |
|
| 108 | + $query .= '`' . $key . '`'; |
|
| 109 | + if (is_null($input[$key])) { |
|
| 110 | + $query .= ' IS NULL AND '; |
|
| 111 | + } else { |
|
| 112 | + $inserts[] = $input[$key]; |
|
| 113 | + $query .= ' = ? AND '; |
|
| 114 | + } |
|
| 115 | + } |
|
| 116 | + $query = substr($query, 0, -5); |
|
| 117 | + $query .= ' HAVING COUNT(*) = 0'; |
|
| 118 | 118 | |
| 119 | - try { |
|
| 120 | - return $this->conn->executeUpdate($query, $inserts); |
|
| 121 | - } catch (UniqueConstraintViolationException $e) { |
|
| 122 | - // if this is thrown then a concurrent insert happened between the insert and the sub-select in the insert, that should have avoided it |
|
| 123 | - // it's fine to ignore this then |
|
| 124 | - // |
|
| 125 | - // more discussions about this can be found at https://github.com/nextcloud/server/pull/12315 |
|
| 126 | - return 0; |
|
| 127 | - } |
|
| 128 | - } |
|
| 119 | + try { |
|
| 120 | + return $this->conn->executeUpdate($query, $inserts); |
|
| 121 | + } catch (UniqueConstraintViolationException $e) { |
|
| 122 | + // if this is thrown then a concurrent insert happened between the insert and the sub-select in the insert, that should have avoided it |
|
| 123 | + // it's fine to ignore this then |
|
| 124 | + // |
|
| 125 | + // more discussions about this can be found at https://github.com/nextcloud/server/pull/12315 |
|
| 126 | + return 0; |
|
| 127 | + } |
|
| 128 | + } |
|
| 129 | 129 | } |
@@ -27,31 +27,31 @@ |
||
| 27 | 27 | |
| 28 | 28 | class AdapterMySQL extends Adapter { |
| 29 | 29 | |
| 30 | - /** @var string */ |
|
| 31 | - protected $charset; |
|
| 32 | - |
|
| 33 | - /** |
|
| 34 | - * @param string $tableName |
|
| 35 | - */ |
|
| 36 | - public function lockTable($tableName) { |
|
| 37 | - $this->conn->executeUpdate('LOCK TABLES `' .$tableName . '` WRITE'); |
|
| 38 | - } |
|
| 39 | - |
|
| 40 | - public function unlockTable() { |
|
| 41 | - $this->conn->executeUpdate('UNLOCK TABLES'); |
|
| 42 | - } |
|
| 43 | - |
|
| 44 | - public function fixupStatement($statement) { |
|
| 45 | - $statement = str_replace(' ILIKE ', ' COLLATE ' . $this->getCharset() . '_general_ci LIKE ', $statement); |
|
| 46 | - return $statement; |
|
| 47 | - } |
|
| 48 | - |
|
| 49 | - protected function getCharset() { |
|
| 50 | - if (!$this->charset) { |
|
| 51 | - $params = $this->conn->getParams(); |
|
| 52 | - $this->charset = isset($params['charset']) ? $params['charset'] : 'utf8'; |
|
| 53 | - } |
|
| 54 | - |
|
| 55 | - return $this->charset; |
|
| 56 | - } |
|
| 30 | + /** @var string */ |
|
| 31 | + protected $charset; |
|
| 32 | + |
|
| 33 | + /** |
|
| 34 | + * @param string $tableName |
|
| 35 | + */ |
|
| 36 | + public function lockTable($tableName) { |
|
| 37 | + $this->conn->executeUpdate('LOCK TABLES `' .$tableName . '` WRITE'); |
|
| 38 | + } |
|
| 39 | + |
|
| 40 | + public function unlockTable() { |
|
| 41 | + $this->conn->executeUpdate('UNLOCK TABLES'); |
|
| 42 | + } |
|
| 43 | + |
|
| 44 | + public function fixupStatement($statement) { |
|
| 45 | + $statement = str_replace(' ILIKE ', ' COLLATE ' . $this->getCharset() . '_general_ci LIKE ', $statement); |
|
| 46 | + return $statement; |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + protected function getCharset() { |
|
| 50 | + if (!$this->charset) { |
|
| 51 | + $params = $this->conn->getParams(); |
|
| 52 | + $this->charset = isset($params['charset']) ? $params['charset'] : 'utf8'; |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + return $this->charset; |
|
| 56 | + } |
|
| 57 | 57 | } |
@@ -34,7 +34,7 @@ discard block |
||
| 34 | 34 | * @param string $tableName |
| 35 | 35 | */ |
| 36 | 36 | public function lockTable($tableName) { |
| 37 | - $this->conn->executeUpdate('LOCK TABLES `' .$tableName . '` WRITE'); |
|
| 37 | + $this->conn->executeUpdate('LOCK TABLES `'.$tableName.'` WRITE'); |
|
| 38 | 38 | } |
| 39 | 39 | |
| 40 | 40 | public function unlockTable() { |
@@ -42,7 +42,7 @@ discard block |
||
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | public function fixupStatement($statement) { |
| 45 | - $statement = str_replace(' ILIKE ', ' COLLATE ' . $this->getCharset() . '_general_ci LIKE ', $statement); |
|
| 45 | + $statement = str_replace(' ILIKE ', ' COLLATE '.$this->getCharset().'_general_ci LIKE ', $statement); |
|
| 46 | 46 | return $statement; |
| 47 | 47 | } |
| 48 | 48 | |
@@ -25,17 +25,17 @@ |
||
| 25 | 25 | |
| 26 | 26 | |
| 27 | 27 | class MigrationException extends \Exception { |
| 28 | - private $table; |
|
| 28 | + private $table; |
|
| 29 | 29 | |
| 30 | - public function __construct($table, $message) { |
|
| 31 | - $this->table = $table; |
|
| 32 | - parent::__construct($message); |
|
| 33 | - } |
|
| 30 | + public function __construct($table, $message) { |
|
| 31 | + $this->table = $table; |
|
| 32 | + parent::__construct($message); |
|
| 33 | + } |
|
| 34 | 34 | |
| 35 | - /** |
|
| 36 | - * @return string |
|
| 37 | - */ |
|
| 38 | - public function getTable() { |
|
| 39 | - return $this->table; |
|
| 40 | - } |
|
| 35 | + /** |
|
| 36 | + * @return string |
|
| 37 | + */ |
|
| 38 | + public function getTable() { |
|
| 39 | + return $this->table; |
|
| 40 | + } |
|
| 41 | 41 | } |
@@ -31,153 +31,153 @@ |
||
| 31 | 31 | |
| 32 | 32 | class MDB2SchemaWriter { |
| 33 | 33 | |
| 34 | - /** |
|
| 35 | - * @param string $file |
|
| 36 | - * @param \OC\DB\Connection $conn |
|
| 37 | - * @return bool |
|
| 38 | - */ |
|
| 39 | - static public function saveSchemaToFile($file, \OC\DB\Connection $conn) { |
|
| 40 | - $config = \OC::$server->getConfig(); |
|
| 34 | + /** |
|
| 35 | + * @param string $file |
|
| 36 | + * @param \OC\DB\Connection $conn |
|
| 37 | + * @return bool |
|
| 38 | + */ |
|
| 39 | + static public function saveSchemaToFile($file, \OC\DB\Connection $conn) { |
|
| 40 | + $config = \OC::$server->getConfig(); |
|
| 41 | 41 | |
| 42 | - $xml = new \SimpleXMLElement('<database/>'); |
|
| 43 | - $xml->addChild('name', $config->getSystemValue('dbname', 'owncloud')); |
|
| 44 | - $xml->addChild('create', 'true'); |
|
| 45 | - $xml->addChild('overwrite', 'false'); |
|
| 46 | - if($config->getSystemValue('dbtype', 'sqlite') === 'mysql' && $config->getSystemValue('mysql.utf8mb4', false)) { |
|
| 47 | - $xml->addChild('charset', 'utf8mb4'); |
|
| 48 | - } else { |
|
| 49 | - $xml->addChild('charset', 'utf8'); |
|
| 50 | - } |
|
| 42 | + $xml = new \SimpleXMLElement('<database/>'); |
|
| 43 | + $xml->addChild('name', $config->getSystemValue('dbname', 'owncloud')); |
|
| 44 | + $xml->addChild('create', 'true'); |
|
| 45 | + $xml->addChild('overwrite', 'false'); |
|
| 46 | + if($config->getSystemValue('dbtype', 'sqlite') === 'mysql' && $config->getSystemValue('mysql.utf8mb4', false)) { |
|
| 47 | + $xml->addChild('charset', 'utf8mb4'); |
|
| 48 | + } else { |
|
| 49 | + $xml->addChild('charset', 'utf8'); |
|
| 50 | + } |
|
| 51 | 51 | |
| 52 | - // FIX ME: bloody work around |
|
| 53 | - if ($config->getSystemValue('dbtype', 'sqlite') === 'oci') { |
|
| 54 | - $filterExpression = '/^"' . preg_quote($conn->getPrefix()) . '/'; |
|
| 55 | - } else { |
|
| 56 | - $filterExpression = '/^' . preg_quote($conn->getPrefix()) . '/'; |
|
| 57 | - } |
|
| 58 | - $conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 52 | + // FIX ME: bloody work around |
|
| 53 | + if ($config->getSystemValue('dbtype', 'sqlite') === 'oci') { |
|
| 54 | + $filterExpression = '/^"' . preg_quote($conn->getPrefix()) . '/'; |
|
| 55 | + } else { |
|
| 56 | + $filterExpression = '/^' . preg_quote($conn->getPrefix()) . '/'; |
|
| 57 | + } |
|
| 58 | + $conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 59 | 59 | |
| 60 | - foreach ($conn->getSchemaManager()->listTables() as $table) { |
|
| 61 | - self::saveTable($table, $xml->addChild('table')); |
|
| 62 | - } |
|
| 63 | - file_put_contents($file, $xml->asXML()); |
|
| 64 | - return true; |
|
| 65 | - } |
|
| 60 | + foreach ($conn->getSchemaManager()->listTables() as $table) { |
|
| 61 | + self::saveTable($table, $xml->addChild('table')); |
|
| 62 | + } |
|
| 63 | + file_put_contents($file, $xml->asXML()); |
|
| 64 | + return true; |
|
| 65 | + } |
|
| 66 | 66 | |
| 67 | - /** |
|
| 68 | - * @param \Doctrine\DBAL\Schema\Table $table |
|
| 69 | - * @param \SimpleXMLElement $xml |
|
| 70 | - */ |
|
| 71 | - private static function saveTable($table, $xml) { |
|
| 72 | - $xml->addChild('name', $table->getName()); |
|
| 73 | - $declaration = $xml->addChild('declaration'); |
|
| 74 | - foreach($table->getColumns() as $column) { |
|
| 75 | - self::saveColumn($column, $declaration->addChild('field')); |
|
| 76 | - } |
|
| 77 | - foreach($table->getIndexes() as $index) { |
|
| 78 | - if ($index->getName() == 'PRIMARY') { |
|
| 79 | - $autoincrement = false; |
|
| 80 | - foreach($index->getColumns() as $column) { |
|
| 81 | - if ($table->getColumn($column)->getAutoincrement()) { |
|
| 82 | - $autoincrement = true; |
|
| 83 | - } |
|
| 84 | - } |
|
| 85 | - if ($autoincrement) { |
|
| 86 | - continue; |
|
| 87 | - } |
|
| 88 | - } |
|
| 89 | - self::saveIndex($index, $declaration->addChild('index')); |
|
| 90 | - } |
|
| 91 | - } |
|
| 67 | + /** |
|
| 68 | + * @param \Doctrine\DBAL\Schema\Table $table |
|
| 69 | + * @param \SimpleXMLElement $xml |
|
| 70 | + */ |
|
| 71 | + private static function saveTable($table, $xml) { |
|
| 72 | + $xml->addChild('name', $table->getName()); |
|
| 73 | + $declaration = $xml->addChild('declaration'); |
|
| 74 | + foreach($table->getColumns() as $column) { |
|
| 75 | + self::saveColumn($column, $declaration->addChild('field')); |
|
| 76 | + } |
|
| 77 | + foreach($table->getIndexes() as $index) { |
|
| 78 | + if ($index->getName() == 'PRIMARY') { |
|
| 79 | + $autoincrement = false; |
|
| 80 | + foreach($index->getColumns() as $column) { |
|
| 81 | + if ($table->getColumn($column)->getAutoincrement()) { |
|
| 82 | + $autoincrement = true; |
|
| 83 | + } |
|
| 84 | + } |
|
| 85 | + if ($autoincrement) { |
|
| 86 | + continue; |
|
| 87 | + } |
|
| 88 | + } |
|
| 89 | + self::saveIndex($index, $declaration->addChild('index')); |
|
| 90 | + } |
|
| 91 | + } |
|
| 92 | 92 | |
| 93 | - /** |
|
| 94 | - * @param Column $column |
|
| 95 | - * @param \SimpleXMLElement $xml |
|
| 96 | - */ |
|
| 97 | - private static function saveColumn($column, $xml) { |
|
| 98 | - $xml->addChild('name', $column->getName()); |
|
| 99 | - switch($column->getType()) { |
|
| 100 | - case 'SmallInt': |
|
| 101 | - case 'Integer': |
|
| 102 | - case 'BigInt': |
|
| 103 | - $xml->addChild('type', 'integer'); |
|
| 104 | - $default = $column->getDefault(); |
|
| 105 | - if (is_null($default) && $column->getAutoincrement()) { |
|
| 106 | - $default = '0'; |
|
| 107 | - } |
|
| 108 | - $xml->addChild('default', $default); |
|
| 109 | - $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 110 | - if ($column->getAutoincrement()) { |
|
| 111 | - $xml->addChild('autoincrement', '1'); |
|
| 112 | - } |
|
| 113 | - if ($column->getUnsigned()) { |
|
| 114 | - $xml->addChild('unsigned', 'true'); |
|
| 115 | - } |
|
| 116 | - $length = '4'; |
|
| 117 | - if ($column->getType() == 'SmallInt') { |
|
| 118 | - $length = '2'; |
|
| 119 | - } |
|
| 120 | - elseif ($column->getType() == 'BigInt') { |
|
| 121 | - $length = '8'; |
|
| 122 | - } |
|
| 123 | - $xml->addChild('length', $length); |
|
| 124 | - break; |
|
| 125 | - case 'String': |
|
| 126 | - $xml->addChild('type', 'text'); |
|
| 127 | - $default = trim($column->getDefault()); |
|
| 128 | - if ($default === '') { |
|
| 129 | - $default = false; |
|
| 130 | - } |
|
| 131 | - $xml->addChild('default', $default); |
|
| 132 | - $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 133 | - $xml->addChild('length', $column->getLength()); |
|
| 134 | - break; |
|
| 135 | - case 'Text': |
|
| 136 | - $xml->addChild('type', 'clob'); |
|
| 137 | - $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 138 | - break; |
|
| 139 | - case 'Decimal': |
|
| 140 | - $xml->addChild('type', 'decimal'); |
|
| 141 | - $xml->addChild('default', $column->getDefault()); |
|
| 142 | - $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 143 | - $xml->addChild('length', '15'); |
|
| 144 | - break; |
|
| 145 | - case 'Boolean': |
|
| 146 | - $xml->addChild('type', 'integer'); |
|
| 147 | - $xml->addChild('default', $column->getDefault()); |
|
| 148 | - $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 149 | - $xml->addChild('length', '1'); |
|
| 150 | - break; |
|
| 151 | - case 'DateTime': |
|
| 152 | - $xml->addChild('type', 'timestamp'); |
|
| 153 | - $xml->addChild('default', $column->getDefault()); |
|
| 154 | - $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 155 | - break; |
|
| 93 | + /** |
|
| 94 | + * @param Column $column |
|
| 95 | + * @param \SimpleXMLElement $xml |
|
| 96 | + */ |
|
| 97 | + private static function saveColumn($column, $xml) { |
|
| 98 | + $xml->addChild('name', $column->getName()); |
|
| 99 | + switch($column->getType()) { |
|
| 100 | + case 'SmallInt': |
|
| 101 | + case 'Integer': |
|
| 102 | + case 'BigInt': |
|
| 103 | + $xml->addChild('type', 'integer'); |
|
| 104 | + $default = $column->getDefault(); |
|
| 105 | + if (is_null($default) && $column->getAutoincrement()) { |
|
| 106 | + $default = '0'; |
|
| 107 | + } |
|
| 108 | + $xml->addChild('default', $default); |
|
| 109 | + $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 110 | + if ($column->getAutoincrement()) { |
|
| 111 | + $xml->addChild('autoincrement', '1'); |
|
| 112 | + } |
|
| 113 | + if ($column->getUnsigned()) { |
|
| 114 | + $xml->addChild('unsigned', 'true'); |
|
| 115 | + } |
|
| 116 | + $length = '4'; |
|
| 117 | + if ($column->getType() == 'SmallInt') { |
|
| 118 | + $length = '2'; |
|
| 119 | + } |
|
| 120 | + elseif ($column->getType() == 'BigInt') { |
|
| 121 | + $length = '8'; |
|
| 122 | + } |
|
| 123 | + $xml->addChild('length', $length); |
|
| 124 | + break; |
|
| 125 | + case 'String': |
|
| 126 | + $xml->addChild('type', 'text'); |
|
| 127 | + $default = trim($column->getDefault()); |
|
| 128 | + if ($default === '') { |
|
| 129 | + $default = false; |
|
| 130 | + } |
|
| 131 | + $xml->addChild('default', $default); |
|
| 132 | + $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 133 | + $xml->addChild('length', $column->getLength()); |
|
| 134 | + break; |
|
| 135 | + case 'Text': |
|
| 136 | + $xml->addChild('type', 'clob'); |
|
| 137 | + $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 138 | + break; |
|
| 139 | + case 'Decimal': |
|
| 140 | + $xml->addChild('type', 'decimal'); |
|
| 141 | + $xml->addChild('default', $column->getDefault()); |
|
| 142 | + $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 143 | + $xml->addChild('length', '15'); |
|
| 144 | + break; |
|
| 145 | + case 'Boolean': |
|
| 146 | + $xml->addChild('type', 'integer'); |
|
| 147 | + $xml->addChild('default', $column->getDefault()); |
|
| 148 | + $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 149 | + $xml->addChild('length', '1'); |
|
| 150 | + break; |
|
| 151 | + case 'DateTime': |
|
| 152 | + $xml->addChild('type', 'timestamp'); |
|
| 153 | + $xml->addChild('default', $column->getDefault()); |
|
| 154 | + $xml->addChild('notnull', self::toBool($column->getNotnull())); |
|
| 155 | + break; |
|
| 156 | 156 | |
| 157 | - } |
|
| 158 | - } |
|
| 157 | + } |
|
| 158 | + } |
|
| 159 | 159 | |
| 160 | - /** |
|
| 161 | - * @param Index $index |
|
| 162 | - * @param \SimpleXMLElement $xml |
|
| 163 | - */ |
|
| 164 | - private static function saveIndex($index, $xml) { |
|
| 165 | - $xml->addChild('name', $index->getName()); |
|
| 166 | - if ($index->isPrimary()) { |
|
| 167 | - $xml->addChild('primary', 'true'); |
|
| 168 | - } |
|
| 169 | - elseif ($index->isUnique()) { |
|
| 170 | - $xml->addChild('unique', 'true'); |
|
| 171 | - } |
|
| 172 | - foreach($index->getColumns() as $column) { |
|
| 173 | - $field = $xml->addChild('field'); |
|
| 174 | - $field->addChild('name', $column); |
|
| 175 | - $field->addChild('sorting', 'ascending'); |
|
| 160 | + /** |
|
| 161 | + * @param Index $index |
|
| 162 | + * @param \SimpleXMLElement $xml |
|
| 163 | + */ |
|
| 164 | + private static function saveIndex($index, $xml) { |
|
| 165 | + $xml->addChild('name', $index->getName()); |
|
| 166 | + if ($index->isPrimary()) { |
|
| 167 | + $xml->addChild('primary', 'true'); |
|
| 168 | + } |
|
| 169 | + elseif ($index->isUnique()) { |
|
| 170 | + $xml->addChild('unique', 'true'); |
|
| 171 | + } |
|
| 172 | + foreach($index->getColumns() as $column) { |
|
| 173 | + $field = $xml->addChild('field'); |
|
| 174 | + $field->addChild('name', $column); |
|
| 175 | + $field->addChild('sorting', 'ascending'); |
|
| 176 | 176 | |
| 177 | - } |
|
| 178 | - } |
|
| 177 | + } |
|
| 178 | + } |
|
| 179 | 179 | |
| 180 | - private static function toBool($bool) { |
|
| 181 | - return $bool ? 'true' : 'false'; |
|
| 182 | - } |
|
| 180 | + private static function toBool($bool) { |
|
| 181 | + return $bool ? 'true' : 'false'; |
|
| 182 | + } |
|
| 183 | 183 | } |
@@ -43,7 +43,7 @@ discard block |
||
| 43 | 43 | $xml->addChild('name', $config->getSystemValue('dbname', 'owncloud')); |
| 44 | 44 | $xml->addChild('create', 'true'); |
| 45 | 45 | $xml->addChild('overwrite', 'false'); |
| 46 | - if($config->getSystemValue('dbtype', 'sqlite') === 'mysql' && $config->getSystemValue('mysql.utf8mb4', false)) { |
|
| 46 | + if ($config->getSystemValue('dbtype', 'sqlite') === 'mysql' && $config->getSystemValue('mysql.utf8mb4', false)) { |
|
| 47 | 47 | $xml->addChild('charset', 'utf8mb4'); |
| 48 | 48 | } else { |
| 49 | 49 | $xml->addChild('charset', 'utf8'); |
@@ -51,9 +51,9 @@ discard block |
||
| 51 | 51 | |
| 52 | 52 | // FIX ME: bloody work around |
| 53 | 53 | if ($config->getSystemValue('dbtype', 'sqlite') === 'oci') { |
| 54 | - $filterExpression = '/^"' . preg_quote($conn->getPrefix()) . '/'; |
|
| 54 | + $filterExpression = '/^"'.preg_quote($conn->getPrefix()).'/'; |
|
| 55 | 55 | } else { |
| 56 | - $filterExpression = '/^' . preg_quote($conn->getPrefix()) . '/'; |
|
| 56 | + $filterExpression = '/^'.preg_quote($conn->getPrefix()).'/'; |
|
| 57 | 57 | } |
| 58 | 58 | $conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
| 59 | 59 | |
@@ -71,13 +71,13 @@ discard block |
||
| 71 | 71 | private static function saveTable($table, $xml) { |
| 72 | 72 | $xml->addChild('name', $table->getName()); |
| 73 | 73 | $declaration = $xml->addChild('declaration'); |
| 74 | - foreach($table->getColumns() as $column) { |
|
| 74 | + foreach ($table->getColumns() as $column) { |
|
| 75 | 75 | self::saveColumn($column, $declaration->addChild('field')); |
| 76 | 76 | } |
| 77 | - foreach($table->getIndexes() as $index) { |
|
| 77 | + foreach ($table->getIndexes() as $index) { |
|
| 78 | 78 | if ($index->getName() == 'PRIMARY') { |
| 79 | 79 | $autoincrement = false; |
| 80 | - foreach($index->getColumns() as $column) { |
|
| 80 | + foreach ($index->getColumns() as $column) { |
|
| 81 | 81 | if ($table->getColumn($column)->getAutoincrement()) { |
| 82 | 82 | $autoincrement = true; |
| 83 | 83 | } |
@@ -96,7 +96,7 @@ discard block |
||
| 96 | 96 | */ |
| 97 | 97 | private static function saveColumn($column, $xml) { |
| 98 | 98 | $xml->addChild('name', $column->getName()); |
| 99 | - switch($column->getType()) { |
|
| 99 | + switch ($column->getType()) { |
|
| 100 | 100 | case 'SmallInt': |
| 101 | 101 | case 'Integer': |
| 102 | 102 | case 'BigInt': |
@@ -169,7 +169,7 @@ discard block |
||
| 169 | 169 | elseif ($index->isUnique()) { |
| 170 | 170 | $xml->addChild('unique', 'true'); |
| 171 | 171 | } |
| 172 | - foreach($index->getColumns() as $column) { |
|
| 172 | + foreach ($index->getColumns() as $column) { |
|
| 173 | 173 | $field = $xml->addChild('field'); |
| 174 | 174 | $field->addChild('name', $column); |
| 175 | 175 | $field->addChild('sorting', 'ascending'); |
@@ -116,8 +116,7 @@ discard block |
||
| 116 | 116 | $length = '4'; |
| 117 | 117 | if ($column->getType() == 'SmallInt') { |
| 118 | 118 | $length = '2'; |
| 119 | - } |
|
| 120 | - elseif ($column->getType() == 'BigInt') { |
|
| 119 | + } elseif ($column->getType() == 'BigInt') { |
|
| 121 | 120 | $length = '8'; |
| 122 | 121 | } |
| 123 | 122 | $xml->addChild('length', $length); |
@@ -165,8 +164,7 @@ discard block |
||
| 165 | 164 | $xml->addChild('name', $index->getName()); |
| 166 | 165 | if ($index->isPrimary()) { |
| 167 | 166 | $xml->addChild('primary', 'true'); |
| 168 | - } |
|
| 169 | - elseif ($index->isUnique()) { |
|
| 167 | + } elseif ($index->isUnique()) { |
|
| 170 | 168 | $xml->addChild('unique', 'true'); |
| 171 | 169 | } |
| 172 | 170 | foreach($index->getColumns() as $column) { |
@@ -137,7 +137,7 @@ discard block |
||
| 137 | 137 | * @return string |
| 138 | 138 | */ |
| 139 | 139 | protected function generateTemporaryTableName($name) { |
| 140 | - return $this->config->getSystemValue('dbtableprefix', 'oc_') . $name . '_' . $this->random->generate(13, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); |
|
| 140 | + return $this->config->getSystemValue('dbtableprefix', 'oc_').$name.'_'.$this->random->generate(13, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS); |
|
| 141 | 141 | } |
| 142 | 142 | |
| 143 | 143 | /** |
@@ -188,7 +188,7 @@ discard block |
||
| 188 | 188 | $indexName = $index->getName(); |
| 189 | 189 | } else { |
| 190 | 190 | // avoid conflicts in index names |
| 191 | - $indexName = $this->config->getSystemValue('dbtableprefix', 'oc_') . $this->random->generate(13, ISecureRandom::CHAR_LOWER); |
|
| 191 | + $indexName = $this->config->getSystemValue('dbtableprefix', 'oc_').$this->random->generate(13, ISecureRandom::CHAR_LOWER); |
|
| 192 | 192 | } |
| 193 | 193 | $newIndexes[] = new Index($indexName, $index->getColumns(), $index->isUnique(), $index->isPrimary()); |
| 194 | 194 | } |
@@ -268,15 +268,15 @@ discard block |
||
| 268 | 268 | $quotedSource = $this->connection->quoteIdentifier($sourceName); |
| 269 | 269 | $quotedTarget = $this->connection->quoteIdentifier($targetName); |
| 270 | 270 | |
| 271 | - $this->connection->exec('CREATE TABLE ' . $quotedTarget . ' (LIKE ' . $quotedSource . ')'); |
|
| 272 | - $this->connection->exec('INSERT INTO ' . $quotedTarget . ' SELECT * FROM ' . $quotedSource); |
|
| 271 | + $this->connection->exec('CREATE TABLE '.$quotedTarget.' (LIKE '.$quotedSource.')'); |
|
| 272 | + $this->connection->exec('INSERT INTO '.$quotedTarget.' SELECT * FROM '.$quotedSource); |
|
| 273 | 273 | } |
| 274 | 274 | |
| 275 | 275 | /** |
| 276 | 276 | * @param string $name |
| 277 | 277 | */ |
| 278 | 278 | protected function dropTable($name) { |
| 279 | - $this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($name)); |
|
| 279 | + $this->connection->exec('DROP TABLE '.$this->connection->quoteIdentifier($name)); |
|
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 | /** |
@@ -284,30 +284,30 @@ discard block |
||
| 284 | 284 | * @return string |
| 285 | 285 | */ |
| 286 | 286 | protected function convertStatementToScript($statement) { |
| 287 | - $script = $statement . ';'; |
|
| 287 | + $script = $statement.';'; |
|
| 288 | 288 | $script .= PHP_EOL; |
| 289 | 289 | $script .= PHP_EOL; |
| 290 | 290 | return $script; |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | 293 | protected function getFilterExpression() { |
| 294 | - return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
|
| 294 | + return '/^'.preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')).'/'; |
|
| 295 | 295 | } |
| 296 | 296 | |
| 297 | 297 | protected function emit($sql, $step, $max) { |
| 298 | 298 | if ($this->noEmit) { |
| 299 | 299 | return; |
| 300 | 300 | } |
| 301 | - if(is_null($this->dispatcher)) { |
|
| 301 | + if (is_null($this->dispatcher)) { |
|
| 302 | 302 | return; |
| 303 | 303 | } |
| 304 | - $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max])); |
|
| 304 | + $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step + 1, $max])); |
|
| 305 | 305 | } |
| 306 | 306 | |
| 307 | 307 | private function emitCheckStep($tableName, $step, $max) { |
| 308 | - if(is_null($this->dispatcher)) { |
|
| 308 | + if (is_null($this->dispatcher)) { |
|
| 309 | 309 | return; |
| 310 | 310 | } |
| 311 | - $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max])); |
|
| 311 | + $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step + 1, $max])); |
|
| 312 | 312 | } |
| 313 | 313 | } |
@@ -43,272 +43,272 @@ |
||
| 43 | 43 | |
| 44 | 44 | class Migrator { |
| 45 | 45 | |
| 46 | - /** @var \Doctrine\DBAL\Connection */ |
|
| 47 | - protected $connection; |
|
| 48 | - |
|
| 49 | - /** @var ISecureRandom */ |
|
| 50 | - private $random; |
|
| 51 | - |
|
| 52 | - /** @var IConfig */ |
|
| 53 | - protected $config; |
|
| 54 | - |
|
| 55 | - /** @var EventDispatcher */ |
|
| 56 | - private $dispatcher; |
|
| 57 | - |
|
| 58 | - /** @var bool */ |
|
| 59 | - private $noEmit = false; |
|
| 60 | - |
|
| 61 | - /** |
|
| 62 | - * @param \Doctrine\DBAL\Connection|Connection $connection |
|
| 63 | - * @param ISecureRandom $random |
|
| 64 | - * @param IConfig $config |
|
| 65 | - * @param EventDispatcher $dispatcher |
|
| 66 | - */ |
|
| 67 | - public function __construct(\Doctrine\DBAL\Connection $connection, |
|
| 68 | - ISecureRandom $random, |
|
| 69 | - IConfig $config, |
|
| 70 | - EventDispatcher $dispatcher = null) { |
|
| 71 | - $this->connection = $connection; |
|
| 72 | - $this->random = $random; |
|
| 73 | - $this->config = $config; |
|
| 74 | - $this->dispatcher = $dispatcher; |
|
| 75 | - } |
|
| 76 | - |
|
| 77 | - /** |
|
| 78 | - * @param \Doctrine\DBAL\Schema\Schema $targetSchema |
|
| 79 | - */ |
|
| 80 | - public function migrate(Schema $targetSchema) { |
|
| 81 | - $this->noEmit = true; |
|
| 82 | - $this->applySchema($targetSchema); |
|
| 83 | - } |
|
| 84 | - |
|
| 85 | - /** |
|
| 86 | - * @param \Doctrine\DBAL\Schema\Schema $targetSchema |
|
| 87 | - * @return string |
|
| 88 | - */ |
|
| 89 | - public function generateChangeScript(Schema $targetSchema) { |
|
| 90 | - $schemaDiff = $this->getDiff($targetSchema, $this->connection); |
|
| 91 | - |
|
| 92 | - $script = ''; |
|
| 93 | - $sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform()); |
|
| 94 | - foreach ($sqls as $sql) { |
|
| 95 | - $script .= $this->convertStatementToScript($sql); |
|
| 96 | - } |
|
| 97 | - |
|
| 98 | - return $script; |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - /** |
|
| 102 | - * @param Schema $targetSchema |
|
| 103 | - * @throws \OC\DB\MigrationException |
|
| 104 | - */ |
|
| 105 | - public function checkMigrate(Schema $targetSchema) { |
|
| 106 | - $this->noEmit = true; |
|
| 107 | - /**@var \Doctrine\DBAL\Schema\Table[] $tables */ |
|
| 108 | - $tables = $targetSchema->getTables(); |
|
| 109 | - $filterExpression = $this->getFilterExpression(); |
|
| 110 | - $this->connection->getConfiguration()-> |
|
| 111 | - setFilterSchemaAssetsExpression($filterExpression); |
|
| 112 | - $existingTables = $this->connection->getSchemaManager()->listTableNames(); |
|
| 113 | - |
|
| 114 | - $step = 0; |
|
| 115 | - foreach ($tables as $table) { |
|
| 116 | - if (strpos($table->getName(), '.')) { |
|
| 117 | - list(, $tableName) = explode('.', $table->getName()); |
|
| 118 | - } else { |
|
| 119 | - $tableName = $table->getName(); |
|
| 120 | - } |
|
| 121 | - $this->emitCheckStep($tableName, $step++, count($tables)); |
|
| 122 | - // don't need to check for new tables |
|
| 123 | - if (array_search($tableName, $existingTables) !== false) { |
|
| 124 | - $this->checkTableMigrate($table); |
|
| 125 | - } |
|
| 126 | - } |
|
| 127 | - } |
|
| 128 | - |
|
| 129 | - /** |
|
| 130 | - * Create a unique name for the temporary table |
|
| 131 | - * |
|
| 132 | - * @param string $name |
|
| 133 | - * @return string |
|
| 134 | - */ |
|
| 135 | - protected function generateTemporaryTableName($name) { |
|
| 136 | - return $this->config->getSystemValue('dbtableprefix', 'oc_') . $name . '_' . $this->random->generate(13, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); |
|
| 137 | - } |
|
| 138 | - |
|
| 139 | - /** |
|
| 140 | - * Check the migration of a table on a copy so we can detect errors before messing with the real table |
|
| 141 | - * |
|
| 142 | - * @param \Doctrine\DBAL\Schema\Table $table |
|
| 143 | - * @throws \OC\DB\MigrationException |
|
| 144 | - */ |
|
| 145 | - protected function checkTableMigrate(Table $table) { |
|
| 146 | - $name = $table->getName(); |
|
| 147 | - $tmpName = $this->generateTemporaryTableName($name); |
|
| 148 | - |
|
| 149 | - $this->copyTable($name, $tmpName); |
|
| 150 | - |
|
| 151 | - //create the migration schema for the temporary table |
|
| 152 | - $tmpTable = $this->renameTableSchema($table, $tmpName); |
|
| 153 | - $schemaConfig = new SchemaConfig(); |
|
| 154 | - $schemaConfig->setName($this->connection->getDatabase()); |
|
| 155 | - $schema = new Schema(array($tmpTable), array(), $schemaConfig); |
|
| 156 | - |
|
| 157 | - try { |
|
| 158 | - $this->applySchema($schema); |
|
| 159 | - $this->dropTable($tmpName); |
|
| 160 | - } catch (DBALException $e) { |
|
| 161 | - // pgsql needs to commit it's failed transaction before doing anything else |
|
| 162 | - if ($this->connection->isTransactionActive()) { |
|
| 163 | - $this->connection->commit(); |
|
| 164 | - } |
|
| 165 | - $this->dropTable($tmpName); |
|
| 166 | - throw new MigrationException($table->getName(), $e->getMessage()); |
|
| 167 | - } |
|
| 168 | - } |
|
| 169 | - |
|
| 170 | - /** |
|
| 171 | - * @param \Doctrine\DBAL\Schema\Table $table |
|
| 172 | - * @param string $newName |
|
| 173 | - * @return \Doctrine\DBAL\Schema\Table |
|
| 174 | - */ |
|
| 175 | - protected function renameTableSchema(Table $table, $newName) { |
|
| 176 | - /** |
|
| 177 | - * @var \Doctrine\DBAL\Schema\Index[] $indexes |
|
| 178 | - */ |
|
| 179 | - $indexes = $table->getIndexes(); |
|
| 180 | - $newIndexes = array(); |
|
| 181 | - foreach ($indexes as $index) { |
|
| 182 | - if ($index->isPrimary()) { |
|
| 183 | - // do not rename primary key |
|
| 184 | - $indexName = $index->getName(); |
|
| 185 | - } else { |
|
| 186 | - // avoid conflicts in index names |
|
| 187 | - $indexName = $this->config->getSystemValue('dbtableprefix', 'oc_') . $this->random->generate(13, ISecureRandom::CHAR_LOWER); |
|
| 188 | - } |
|
| 189 | - $newIndexes[] = new Index($indexName, $index->getColumns(), $index->isUnique(), $index->isPrimary()); |
|
| 190 | - } |
|
| 191 | - |
|
| 192 | - // foreign keys are not supported so we just set it to an empty array |
|
| 193 | - return new Table($newName, $table->getColumns(), $newIndexes, array(), 0, $table->getOptions()); |
|
| 194 | - } |
|
| 195 | - |
|
| 196 | - public function createSchema() { |
|
| 197 | - $filterExpression = $this->getFilterExpression(); |
|
| 198 | - $this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 199 | - return $this->connection->getSchemaManager()->createSchema(); |
|
| 200 | - } |
|
| 201 | - |
|
| 202 | - /** |
|
| 203 | - * @param Schema $targetSchema |
|
| 204 | - * @param \Doctrine\DBAL\Connection $connection |
|
| 205 | - * @return \Doctrine\DBAL\Schema\SchemaDiff |
|
| 206 | - * @throws DBALException |
|
| 207 | - */ |
|
| 208 | - protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { |
|
| 209 | - // adjust varchar columns with a length higher then getVarcharMaxLength to clob |
|
| 210 | - foreach ($targetSchema->getTables() as $table) { |
|
| 211 | - foreach ($table->getColumns() as $column) { |
|
| 212 | - if ($column->getType() instanceof StringType) { |
|
| 213 | - if ($column->getLength() > $connection->getDatabasePlatform()->getVarcharMaxLength()) { |
|
| 214 | - $column->setType(Type::getType('text')); |
|
| 215 | - $column->setLength(null); |
|
| 216 | - } |
|
| 217 | - } |
|
| 218 | - } |
|
| 219 | - } |
|
| 220 | - |
|
| 221 | - $filterExpression = $this->getFilterExpression(); |
|
| 222 | - $this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 223 | - $sourceSchema = $connection->getSchemaManager()->createSchema(); |
|
| 224 | - |
|
| 225 | - // remove tables we don't know about |
|
| 226 | - /** @var $table \Doctrine\DBAL\Schema\Table */ |
|
| 227 | - foreach ($sourceSchema->getTables() as $table) { |
|
| 228 | - if (!$targetSchema->hasTable($table->getName())) { |
|
| 229 | - $sourceSchema->dropTable($table->getName()); |
|
| 230 | - } |
|
| 231 | - } |
|
| 232 | - // remove sequences we don't know about |
|
| 233 | - foreach ($sourceSchema->getSequences() as $table) { |
|
| 234 | - if (!$targetSchema->hasSequence($table->getName())) { |
|
| 235 | - $sourceSchema->dropSequence($table->getName()); |
|
| 236 | - } |
|
| 237 | - } |
|
| 238 | - |
|
| 239 | - $comparator = new Comparator(); |
|
| 240 | - return $comparator->compare($sourceSchema, $targetSchema); |
|
| 241 | - } |
|
| 242 | - |
|
| 243 | - /** |
|
| 244 | - * @param \Doctrine\DBAL\Schema\Schema $targetSchema |
|
| 245 | - * @param \Doctrine\DBAL\Connection $connection |
|
| 246 | - */ |
|
| 247 | - protected function applySchema(Schema $targetSchema, \Doctrine\DBAL\Connection $connection = null) { |
|
| 248 | - if (is_null($connection)) { |
|
| 249 | - $connection = $this->connection; |
|
| 250 | - } |
|
| 251 | - |
|
| 252 | - $schemaDiff = $this->getDiff($targetSchema, $connection); |
|
| 253 | - |
|
| 254 | - $connection->beginTransaction(); |
|
| 255 | - $sqls = $schemaDiff->toSql($connection->getDatabasePlatform()); |
|
| 256 | - $step = 0; |
|
| 257 | - foreach ($sqls as $sql) { |
|
| 258 | - $this->emit($sql, $step++, count($sqls)); |
|
| 259 | - $connection->query($sql); |
|
| 260 | - } |
|
| 261 | - $connection->commit(); |
|
| 262 | - } |
|
| 263 | - |
|
| 264 | - /** |
|
| 265 | - * @param string $sourceName |
|
| 266 | - * @param string $targetName |
|
| 267 | - */ |
|
| 268 | - protected function copyTable($sourceName, $targetName) { |
|
| 269 | - $quotedSource = $this->connection->quoteIdentifier($sourceName); |
|
| 270 | - $quotedTarget = $this->connection->quoteIdentifier($targetName); |
|
| 271 | - |
|
| 272 | - $this->connection->exec('CREATE TABLE ' . $quotedTarget . ' (LIKE ' . $quotedSource . ')'); |
|
| 273 | - $this->connection->exec('INSERT INTO ' . $quotedTarget . ' SELECT * FROM ' . $quotedSource); |
|
| 274 | - } |
|
| 275 | - |
|
| 276 | - /** |
|
| 277 | - * @param string $name |
|
| 278 | - */ |
|
| 279 | - protected function dropTable($name) { |
|
| 280 | - $this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($name)); |
|
| 281 | - } |
|
| 282 | - |
|
| 283 | - /** |
|
| 284 | - * @param $statement |
|
| 285 | - * @return string |
|
| 286 | - */ |
|
| 287 | - protected function convertStatementToScript($statement) { |
|
| 288 | - $script = $statement . ';'; |
|
| 289 | - $script .= PHP_EOL; |
|
| 290 | - $script .= PHP_EOL; |
|
| 291 | - return $script; |
|
| 292 | - } |
|
| 293 | - |
|
| 294 | - protected function getFilterExpression() { |
|
| 295 | - return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
|
| 296 | - } |
|
| 297 | - |
|
| 298 | - protected function emit($sql, $step, $max) { |
|
| 299 | - if ($this->noEmit) { |
|
| 300 | - return; |
|
| 301 | - } |
|
| 302 | - if(is_null($this->dispatcher)) { |
|
| 303 | - return; |
|
| 304 | - } |
|
| 305 | - $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max])); |
|
| 306 | - } |
|
| 307 | - |
|
| 308 | - private function emitCheckStep($tableName, $step, $max) { |
|
| 309 | - if(is_null($this->dispatcher)) { |
|
| 310 | - return; |
|
| 311 | - } |
|
| 312 | - $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max])); |
|
| 313 | - } |
|
| 46 | + /** @var \Doctrine\DBAL\Connection */ |
|
| 47 | + protected $connection; |
|
| 48 | + |
|
| 49 | + /** @var ISecureRandom */ |
|
| 50 | + private $random; |
|
| 51 | + |
|
| 52 | + /** @var IConfig */ |
|
| 53 | + protected $config; |
|
| 54 | + |
|
| 55 | + /** @var EventDispatcher */ |
|
| 56 | + private $dispatcher; |
|
| 57 | + |
|
| 58 | + /** @var bool */ |
|
| 59 | + private $noEmit = false; |
|
| 60 | + |
|
| 61 | + /** |
|
| 62 | + * @param \Doctrine\DBAL\Connection|Connection $connection |
|
| 63 | + * @param ISecureRandom $random |
|
| 64 | + * @param IConfig $config |
|
| 65 | + * @param EventDispatcher $dispatcher |
|
| 66 | + */ |
|
| 67 | + public function __construct(\Doctrine\DBAL\Connection $connection, |
|
| 68 | + ISecureRandom $random, |
|
| 69 | + IConfig $config, |
|
| 70 | + EventDispatcher $dispatcher = null) { |
|
| 71 | + $this->connection = $connection; |
|
| 72 | + $this->random = $random; |
|
| 73 | + $this->config = $config; |
|
| 74 | + $this->dispatcher = $dispatcher; |
|
| 75 | + } |
|
| 76 | + |
|
| 77 | + /** |
|
| 78 | + * @param \Doctrine\DBAL\Schema\Schema $targetSchema |
|
| 79 | + */ |
|
| 80 | + public function migrate(Schema $targetSchema) { |
|
| 81 | + $this->noEmit = true; |
|
| 82 | + $this->applySchema($targetSchema); |
|
| 83 | + } |
|
| 84 | + |
|
| 85 | + /** |
|
| 86 | + * @param \Doctrine\DBAL\Schema\Schema $targetSchema |
|
| 87 | + * @return string |
|
| 88 | + */ |
|
| 89 | + public function generateChangeScript(Schema $targetSchema) { |
|
| 90 | + $schemaDiff = $this->getDiff($targetSchema, $this->connection); |
|
| 91 | + |
|
| 92 | + $script = ''; |
|
| 93 | + $sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform()); |
|
| 94 | + foreach ($sqls as $sql) { |
|
| 95 | + $script .= $this->convertStatementToScript($sql); |
|
| 96 | + } |
|
| 97 | + |
|
| 98 | + return $script; |
|
| 99 | + } |
|
| 100 | + |
|
| 101 | + /** |
|
| 102 | + * @param Schema $targetSchema |
|
| 103 | + * @throws \OC\DB\MigrationException |
|
| 104 | + */ |
|
| 105 | + public function checkMigrate(Schema $targetSchema) { |
|
| 106 | + $this->noEmit = true; |
|
| 107 | + /**@var \Doctrine\DBAL\Schema\Table[] $tables */ |
|
| 108 | + $tables = $targetSchema->getTables(); |
|
| 109 | + $filterExpression = $this->getFilterExpression(); |
|
| 110 | + $this->connection->getConfiguration()-> |
|
| 111 | + setFilterSchemaAssetsExpression($filterExpression); |
|
| 112 | + $existingTables = $this->connection->getSchemaManager()->listTableNames(); |
|
| 113 | + |
|
| 114 | + $step = 0; |
|
| 115 | + foreach ($tables as $table) { |
|
| 116 | + if (strpos($table->getName(), '.')) { |
|
| 117 | + list(, $tableName) = explode('.', $table->getName()); |
|
| 118 | + } else { |
|
| 119 | + $tableName = $table->getName(); |
|
| 120 | + } |
|
| 121 | + $this->emitCheckStep($tableName, $step++, count($tables)); |
|
| 122 | + // don't need to check for new tables |
|
| 123 | + if (array_search($tableName, $existingTables) !== false) { |
|
| 124 | + $this->checkTableMigrate($table); |
|
| 125 | + } |
|
| 126 | + } |
|
| 127 | + } |
|
| 128 | + |
|
| 129 | + /** |
|
| 130 | + * Create a unique name for the temporary table |
|
| 131 | + * |
|
| 132 | + * @param string $name |
|
| 133 | + * @return string |
|
| 134 | + */ |
|
| 135 | + protected function generateTemporaryTableName($name) { |
|
| 136 | + return $this->config->getSystemValue('dbtableprefix', 'oc_') . $name . '_' . $this->random->generate(13, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); |
|
| 137 | + } |
|
| 138 | + |
|
| 139 | + /** |
|
| 140 | + * Check the migration of a table on a copy so we can detect errors before messing with the real table |
|
| 141 | + * |
|
| 142 | + * @param \Doctrine\DBAL\Schema\Table $table |
|
| 143 | + * @throws \OC\DB\MigrationException |
|
| 144 | + */ |
|
| 145 | + protected function checkTableMigrate(Table $table) { |
|
| 146 | + $name = $table->getName(); |
|
| 147 | + $tmpName = $this->generateTemporaryTableName($name); |
|
| 148 | + |
|
| 149 | + $this->copyTable($name, $tmpName); |
|
| 150 | + |
|
| 151 | + //create the migration schema for the temporary table |
|
| 152 | + $tmpTable = $this->renameTableSchema($table, $tmpName); |
|
| 153 | + $schemaConfig = new SchemaConfig(); |
|
| 154 | + $schemaConfig->setName($this->connection->getDatabase()); |
|
| 155 | + $schema = new Schema(array($tmpTable), array(), $schemaConfig); |
|
| 156 | + |
|
| 157 | + try { |
|
| 158 | + $this->applySchema($schema); |
|
| 159 | + $this->dropTable($tmpName); |
|
| 160 | + } catch (DBALException $e) { |
|
| 161 | + // pgsql needs to commit it's failed transaction before doing anything else |
|
| 162 | + if ($this->connection->isTransactionActive()) { |
|
| 163 | + $this->connection->commit(); |
|
| 164 | + } |
|
| 165 | + $this->dropTable($tmpName); |
|
| 166 | + throw new MigrationException($table->getName(), $e->getMessage()); |
|
| 167 | + } |
|
| 168 | + } |
|
| 169 | + |
|
| 170 | + /** |
|
| 171 | + * @param \Doctrine\DBAL\Schema\Table $table |
|
| 172 | + * @param string $newName |
|
| 173 | + * @return \Doctrine\DBAL\Schema\Table |
|
| 174 | + */ |
|
| 175 | + protected function renameTableSchema(Table $table, $newName) { |
|
| 176 | + /** |
|
| 177 | + * @var \Doctrine\DBAL\Schema\Index[] $indexes |
|
| 178 | + */ |
|
| 179 | + $indexes = $table->getIndexes(); |
|
| 180 | + $newIndexes = array(); |
|
| 181 | + foreach ($indexes as $index) { |
|
| 182 | + if ($index->isPrimary()) { |
|
| 183 | + // do not rename primary key |
|
| 184 | + $indexName = $index->getName(); |
|
| 185 | + } else { |
|
| 186 | + // avoid conflicts in index names |
|
| 187 | + $indexName = $this->config->getSystemValue('dbtableprefix', 'oc_') . $this->random->generate(13, ISecureRandom::CHAR_LOWER); |
|
| 188 | + } |
|
| 189 | + $newIndexes[] = new Index($indexName, $index->getColumns(), $index->isUnique(), $index->isPrimary()); |
|
| 190 | + } |
|
| 191 | + |
|
| 192 | + // foreign keys are not supported so we just set it to an empty array |
|
| 193 | + return new Table($newName, $table->getColumns(), $newIndexes, array(), 0, $table->getOptions()); |
|
| 194 | + } |
|
| 195 | + |
|
| 196 | + public function createSchema() { |
|
| 197 | + $filterExpression = $this->getFilterExpression(); |
|
| 198 | + $this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 199 | + return $this->connection->getSchemaManager()->createSchema(); |
|
| 200 | + } |
|
| 201 | + |
|
| 202 | + /** |
|
| 203 | + * @param Schema $targetSchema |
|
| 204 | + * @param \Doctrine\DBAL\Connection $connection |
|
| 205 | + * @return \Doctrine\DBAL\Schema\SchemaDiff |
|
| 206 | + * @throws DBALException |
|
| 207 | + */ |
|
| 208 | + protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { |
|
| 209 | + // adjust varchar columns with a length higher then getVarcharMaxLength to clob |
|
| 210 | + foreach ($targetSchema->getTables() as $table) { |
|
| 211 | + foreach ($table->getColumns() as $column) { |
|
| 212 | + if ($column->getType() instanceof StringType) { |
|
| 213 | + if ($column->getLength() > $connection->getDatabasePlatform()->getVarcharMaxLength()) { |
|
| 214 | + $column->setType(Type::getType('text')); |
|
| 215 | + $column->setLength(null); |
|
| 216 | + } |
|
| 217 | + } |
|
| 218 | + } |
|
| 219 | + } |
|
| 220 | + |
|
| 221 | + $filterExpression = $this->getFilterExpression(); |
|
| 222 | + $this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); |
|
| 223 | + $sourceSchema = $connection->getSchemaManager()->createSchema(); |
|
| 224 | + |
|
| 225 | + // remove tables we don't know about |
|
| 226 | + /** @var $table \Doctrine\DBAL\Schema\Table */ |
|
| 227 | + foreach ($sourceSchema->getTables() as $table) { |
|
| 228 | + if (!$targetSchema->hasTable($table->getName())) { |
|
| 229 | + $sourceSchema->dropTable($table->getName()); |
|
| 230 | + } |
|
| 231 | + } |
|
| 232 | + // remove sequences we don't know about |
|
| 233 | + foreach ($sourceSchema->getSequences() as $table) { |
|
| 234 | + if (!$targetSchema->hasSequence($table->getName())) { |
|
| 235 | + $sourceSchema->dropSequence($table->getName()); |
|
| 236 | + } |
|
| 237 | + } |
|
| 238 | + |
|
| 239 | + $comparator = new Comparator(); |
|
| 240 | + return $comparator->compare($sourceSchema, $targetSchema); |
|
| 241 | + } |
|
| 242 | + |
|
| 243 | + /** |
|
| 244 | + * @param \Doctrine\DBAL\Schema\Schema $targetSchema |
|
| 245 | + * @param \Doctrine\DBAL\Connection $connection |
|
| 246 | + */ |
|
| 247 | + protected function applySchema(Schema $targetSchema, \Doctrine\DBAL\Connection $connection = null) { |
|
| 248 | + if (is_null($connection)) { |
|
| 249 | + $connection = $this->connection; |
|
| 250 | + } |
|
| 251 | + |
|
| 252 | + $schemaDiff = $this->getDiff($targetSchema, $connection); |
|
| 253 | + |
|
| 254 | + $connection->beginTransaction(); |
|
| 255 | + $sqls = $schemaDiff->toSql($connection->getDatabasePlatform()); |
|
| 256 | + $step = 0; |
|
| 257 | + foreach ($sqls as $sql) { |
|
| 258 | + $this->emit($sql, $step++, count($sqls)); |
|
| 259 | + $connection->query($sql); |
|
| 260 | + } |
|
| 261 | + $connection->commit(); |
|
| 262 | + } |
|
| 263 | + |
|
| 264 | + /** |
|
| 265 | + * @param string $sourceName |
|
| 266 | + * @param string $targetName |
|
| 267 | + */ |
|
| 268 | + protected function copyTable($sourceName, $targetName) { |
|
| 269 | + $quotedSource = $this->connection->quoteIdentifier($sourceName); |
|
| 270 | + $quotedTarget = $this->connection->quoteIdentifier($targetName); |
|
| 271 | + |
|
| 272 | + $this->connection->exec('CREATE TABLE ' . $quotedTarget . ' (LIKE ' . $quotedSource . ')'); |
|
| 273 | + $this->connection->exec('INSERT INTO ' . $quotedTarget . ' SELECT * FROM ' . $quotedSource); |
|
| 274 | + } |
|
| 275 | + |
|
| 276 | + /** |
|
| 277 | + * @param string $name |
|
| 278 | + */ |
|
| 279 | + protected function dropTable($name) { |
|
| 280 | + $this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($name)); |
|
| 281 | + } |
|
| 282 | + |
|
| 283 | + /** |
|
| 284 | + * @param $statement |
|
| 285 | + * @return string |
|
| 286 | + */ |
|
| 287 | + protected function convertStatementToScript($statement) { |
|
| 288 | + $script = $statement . ';'; |
|
| 289 | + $script .= PHP_EOL; |
|
| 290 | + $script .= PHP_EOL; |
|
| 291 | + return $script; |
|
| 292 | + } |
|
| 293 | + |
|
| 294 | + protected function getFilterExpression() { |
|
| 295 | + return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
|
| 296 | + } |
|
| 297 | + |
|
| 298 | + protected function emit($sql, $step, $max) { |
|
| 299 | + if ($this->noEmit) { |
|
| 300 | + return; |
|
| 301 | + } |
|
| 302 | + if(is_null($this->dispatcher)) { |
|
| 303 | + return; |
|
| 304 | + } |
|
| 305 | + $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max])); |
|
| 306 | + } |
|
| 307 | + |
|
| 308 | + private function emitCheckStep($tableName, $step, $max) { |
|
| 309 | + if(is_null($this->dispatcher)) { |
|
| 310 | + return; |
|
| 311 | + } |
|
| 312 | + $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max])); |
|
| 313 | + } |
|
| 314 | 314 | } |