From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doctrine/dbal/src/Platforms/OraclePlatform.php | 784 +++++++++++++++++++++ 1 file changed, 784 insertions(+) create mode 100644 vendor/doctrine/dbal/src/Platforms/OraclePlatform.php (limited to 'vendor/doctrine/dbal/src/Platforms/OraclePlatform.php') diff --git a/vendor/doctrine/dbal/src/Platforms/OraclePlatform.php b/vendor/doctrine/dbal/src/Platforms/OraclePlatform.php new file mode 100644 index 0000000..314f6ee --- /dev/null +++ b/vendor/doctrine/dbal/src/Platforms/OraclePlatform.php @@ -0,0 +1,784 @@ +multiplyInterval($interval, 3); + break; + + case DateIntervalUnit::YEAR: + $interval = $this->multiplyInterval($interval, 12); + break; + } + + return 'ADD_MONTHS(' . $date . ', ' . $operator . $interval . ')'; + + default: + $calculationClause = ''; + + switch ($unit) { + case DateIntervalUnit::SECOND: + $calculationClause = '/24/60/60'; + break; + + case DateIntervalUnit::MINUTE: + $calculationClause = '/24/60'; + break; + + case DateIntervalUnit::HOUR: + $calculationClause = '/24'; + break; + + case DateIntervalUnit::WEEK: + $calculationClause = '*7'; + break; + } + + return '(' . $date . $operator . $interval . $calculationClause . ')'; + } + } + + public function getDateDiffExpression(string $date1, string $date2): string + { + return sprintf('TRUNC(%s) - TRUNC(%s)', $date1, $date2); + } + + public function getBitAndComparisonExpression(string $value1, string $value2): string + { + return 'BITAND(' . $value1 . ', ' . $value2 . ')'; + } + + public function getCurrentDatabaseExpression(): string + { + return "SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')"; + } + + public function getBitOrComparisonExpression(string $value1, string $value2): string + { + return '(' . $value1 . '-' . + $this->getBitAndComparisonExpression($value1, $value2) + . '+' . $value2 . ')'; + } + + public function getCreatePrimaryKeySQL(Index $index, string $table): string + { + return 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $index->getQuotedName($this) + . ' PRIMARY KEY (' . implode(', ', $index->getQuotedColumns($this)) . ')'; + } + + /** + * {@inheritDoc} + * + * Need to specifiy minvalue, since start with is hidden in the system and MINVALUE <= START WITH. + * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection + * in {@see listSequences()} + */ + public function getCreateSequenceSQL(Sequence $sequence): string + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' START WITH ' . $sequence->getInitialValue() . + ' MINVALUE ' . $sequence->getInitialValue() . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + $this->getSequenceCacheSQL($sequence); + } + + public function getAlterSequenceSQL(Sequence $sequence): string + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() + . $this->getSequenceCacheSQL($sequence); + } + + /** + * Cache definition for sequences + */ + private function getSequenceCacheSQL(Sequence $sequence): string + { + if ($sequence->getCache() === 0) { + return ' NOCACHE'; + } + + if ($sequence->getCache() === 1) { + return ' NOCACHE'; + } + + if ($sequence->getCache() > 1) { + return ' CACHE ' . $sequence->getCache(); + } + + return ''; + } + + public function getSequenceNextValSQL(string $sequence): string + { + return 'SELECT ' . $sequence . '.nextval FROM DUAL'; + } + + public function getSetTransactionIsolationSQL(TransactionIsolationLevel $level): string + { + return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + protected function _getTransactionIsolationLevelSQL(TransactionIsolationLevel $level): string + { + return match ($level) { + TransactionIsolationLevel::READ_UNCOMMITTED => 'READ UNCOMMITTED', + TransactionIsolationLevel::READ_COMMITTED => 'READ COMMITTED', + TransactionIsolationLevel::REPEATABLE_READ, + TransactionIsolationLevel::SERIALIZABLE => 'SERIALIZABLE', + }; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column): string + { + return 'NUMBER(1)'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column): string + { + return 'NUMBER(10)'; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column): string + { + return 'NUMBER(20)'; + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column): string + { + return 'NUMBER(5)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column): string + { + return 'TIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $column): string + { + return 'TIMESTAMP(0) WITH TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column): string + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column): string + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column): string + { + return ''; + } + + protected function getVarcharTypeDeclarationSQLSnippet(?int $length): string + { + if ($length === null) { + throw ColumnLengthRequired::new($this, 'VARCHAR2'); + } + + return sprintf('VARCHAR2(%d)', $length); + } + + protected function getBinaryTypeDeclarationSQLSnippet(?int $length): string + { + if ($length === null) { + throw ColumnLengthRequired::new($this, 'RAW'); + } + + return sprintf('RAW(%d)', $length); + } + + protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length): string + { + return $this->getBinaryTypeDeclarationSQLSnippet($length); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column): string + { + return 'CLOB'; + } + + /** @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy. */ + public function getListDatabasesSQL(): string + { + return 'SELECT username FROM all_users'; + } + + /** @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy. */ + public function getListSequencesSQL(string $database): string + { + return 'SELECT SEQUENCE_NAME, MIN_VALUE, INCREMENT_BY FROM SYS.ALL_SEQUENCES WHERE SEQUENCE_OWNER = ' + . $this->quoteStringLiteral( + $this->normalizeIdentifier($database)->getName(), + ); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL(string $name, array $columns, array $options = []): array + { + $indexes = $options['indexes'] ?? []; + $options['indexes'] = []; + $sql = parent::_getCreateTableSQL($name, $columns, $options); + + foreach ($columns as $column) { + if (isset($column['sequence'])) { + $sql[] = $this->getCreateSequenceSQL($column['sequence']); + } + + if ( + empty($column['autoincrement']) + ) { + continue; + } + + $sql = array_merge($sql, $this->getCreateAutoincrementSql($column['name'], $name)); + } + + foreach ($indexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $name); + } + + return $sql; + } + + /** @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy. */ + public function getListViewsSQL(string $database): string + { + return 'SELECT view_name, text FROM sys.user_views'; + } + + /** @return array */ + protected function getCreateAutoincrementSql(string $name, string $table, int $start = 1): array + { + $tableIdentifier = $this->normalizeIdentifier($table); + $quotedTableName = $tableIdentifier->getQuotedName($this); + $unquotedTableName = $tableIdentifier->getName(); + + $nameIdentifier = $this->normalizeIdentifier($name); + $quotedName = $nameIdentifier->getQuotedName($this); + $unquotedName = $nameIdentifier->getName(); + + $sql = []; + + $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($tableIdentifier); + + $idx = new Index($autoincrementIdentifierName, [$quotedName], true, true); + + $sql[] = "DECLARE + constraints_Count NUMBER; +BEGIN + SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count + FROM USER_CONSTRAINTS + WHERE TABLE_NAME = '" . $unquotedTableName . "' + AND CONSTRAINT_TYPE = 'P'; + IF constraints_Count = 0 OR constraints_Count = '' THEN + EXECUTE IMMEDIATE '" . $this->getCreateIndexSQL($idx, $quotedTableName) . "'; + END IF; +END;"; + + $sequenceName = $this->getIdentitySequenceName( + $tableIdentifier->isQuoted() ? $quotedTableName : $unquotedTableName, + ); + $sequence = new Sequence($sequenceName, $start); + $sql[] = $this->getCreateSequenceSQL($sequence); + + $sql[] = 'CREATE TRIGGER ' . $autoincrementIdentifierName . ' + BEFORE INSERT + ON ' . $quotedTableName . ' + FOR EACH ROW +DECLARE + last_Sequence NUMBER; + last_InsertID NUMBER; +BEGIN + IF (:NEW.' . $quotedName . ' IS NULL OR :NEW.' . $quotedName . ' = 0) THEN + SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL; + ELSE + SELECT NVL(Last_Number, 0) INTO last_Sequence + FROM User_Sequences + WHERE Sequence_Name = \'' . $sequence->getName() . '\'; + SELECT :NEW.' . $quotedName . ' INTO last_InsertID FROM DUAL; + WHILE (last_InsertID > last_Sequence) LOOP + SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL; + END LOOP; + SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL; + END IF; +END;'; + + return $sql; + } + + /** + * @internal The method should be only used from within the OracleSchemaManager class hierarchy. + * + * Returns the SQL statements to drop the autoincrement for the given table name. + * + * @param string $table The table name to drop the autoincrement for. + * + * @return string[] + */ + public function getDropAutoincrementSql(string $table): array + { + $table = $this->normalizeIdentifier($table); + $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($table); + $identitySequenceName = $this->getIdentitySequenceName( + $table->isQuoted() ? $table->getQuotedName($this) : $table->getName(), + ); + + return [ + 'DROP TRIGGER ' . $autoincrementIdentifierName, + $this->getDropSequenceSQL($identitySequenceName), + $this->getDropConstraintSQL($autoincrementIdentifierName, $table->getQuotedName($this)), + ]; + } + + /** + * Normalizes the given identifier. + * + * Uppercases the given identifier if it is not quoted by intention + * to reflect Oracle's internal auto uppercasing strategy of unquoted identifiers. + * + * @param string $name The identifier to normalize. + */ + private function normalizeIdentifier(string $name): Identifier + { + $identifier = new Identifier($name); + + return $identifier->isQuoted() ? $identifier : new Identifier(strtoupper($name)); + } + + /** + * Adds suffix to identifier, + * + * if the new string exceeds max identifier length, + * keeps $suffix, cuts from $identifier as much as the part exceeding. + */ + private function addSuffix(string $identifier, string $suffix): string + { + $maxPossibleLengthWithoutSuffix = $this->getMaxIdentifierLength() - strlen($suffix); + if (strlen($identifier) > $maxPossibleLengthWithoutSuffix) { + $identifier = substr($identifier, 0, $maxPossibleLengthWithoutSuffix); + } + + return $identifier . $suffix; + } + + /** + * Returns the autoincrement primary key identifier name for the given table identifier. + * + * Quotes the autoincrement primary key identifier name + * if the given table name is quoted by intention. + */ + private function getAutoincrementIdentifierName(Identifier $table): string + { + $identifierName = $this->addSuffix($table->getName(), '_AI_PK'); + + return $table->isQuoted() + ? $this->quoteSingleIdentifier($identifierName) + : $identifierName; + } + + public function getDropForeignKeySQL(string $foreignKey, string $table): string + { + return $this->getDropConstraintSQL($foreignKey, $table); + } + + /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey): string + { + $referentialAction = ''; + + if ($foreignKey->hasOption('onDelete')) { + $referentialAction = $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete')); + } + + if ($referentialAction !== '') { + return ' ON DELETE ' . $referentialAction; + } + + return ''; + } + + /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */ + public function getForeignKeyReferentialActionSQL(string $action): string + { + $action = strtoupper($action); + + return match ($action) { + 'RESTRICT', + 'NO ACTION' => '', + 'CASCADE', + 'SET NULL' => $action, + default => throw new InvalidArgumentException(sprintf('Invalid foreign key action "%s".', $action)), + }; + } + + public function getCreateDatabaseSQL(string $name): string + { + return 'CREATE USER ' . $name; + } + + public function getDropDatabaseSQL(string $name): string + { + return 'DROP USER ' . $name . ' CASCADE'; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff): array + { + $sql = []; + $commentsSQL = []; + $columnSql = []; + + $addColumnSQL = []; + + $tableNameSQL = $diff->getOldTable()->getQuotedName($this); + + foreach ($diff->getAddedColumns() as $column) { + $addColumnSQL[] = $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + $comment = $column->getComment(); + + if ($comment === '') { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $tableNameSQL, + $column->getQuotedName($this), + $comment, + ); + } + + if (count($addColumnSQL) > 0) { + $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ADD (' . implode(', ', $addColumnSQL) . ')'; + } + + $modifyColumnSQL = []; + foreach ($diff->getModifiedColumns() as $columnDiff) { + $newColumn = $columnDiff->getNewColumn(); + $oldColumn = $columnDiff->getOldColumn(); + + $newColumnProperties = $newColumn->toArray(); + $oldColumnProperties = $oldColumn->toArray(); + + $oldSQL = $this->getColumnDeclarationSQL('', $oldColumnProperties); + $newSQL = $this->getColumnDeclarationSQL('', $newColumnProperties); + + if ($newSQL !== $oldSQL) { + if (! $columnDiff->hasNotNullChanged()) { + unset($newColumnProperties['notnull']); + $newSQL = $this->getColumnDeclarationSQL('', $newColumnProperties); + } + + $modifyColumnSQL[] = $newColumn->getQuotedName($this) . $newSQL; + } + + if (! $columnDiff->hasCommentChanged()) { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $tableNameSQL, + $newColumn->getQuotedName($this), + $newColumn->getComment(), + ); + } + + if (count($modifyColumnSQL) > 0) { + $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' MODIFY (' . implode(', ', $modifyColumnSQL) . ')'; + } + + foreach ($diff->getRenamedColumns() as $oldColumnName => $column) { + $oldColumnName = new Identifier($oldColumnName); + + $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) + . ' TO ' . $column->getQuotedName($this); + } + + $dropColumnSQL = []; + foreach ($diff->getDroppedColumns() as $column) { + $dropColumnSQL[] = $column->getQuotedName($this); + } + + if (count($dropColumnSQL) > 0) { + $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' DROP (' . implode(', ', $dropColumnSQL) . ')'; + } + + return array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $commentsSQL, + $this->getPostAlterTableIndexForeignKeySQL($diff), + $columnSql, + ); + } + + /** + * {@inheritDoc} + * + * @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. + */ + public function getColumnDeclarationSQL(string $name, array $column): string + { + if (isset($column['columnDefinition'])) { + $declaration = $column['columnDefinition']; + } else { + $default = $this->getDefaultValueDeclarationSQL($column); + + $notnull = ''; + + if (isset($column['notnull'])) { + $notnull = $column['notnull'] ? ' NOT NULL' : ' NULL'; + } + + $typeDecl = $column['type']->getSQLDeclaration($column, $this); + $declaration = $typeDecl . $default . $notnull; + } + + return $name . ' ' . $declaration; + } + + /** + * {@inheritDoc} + */ + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName): array + { + if (str_contains($tableName, '.')) { + [$schema] = explode('.', $tableName); + $oldIndexName = $schema . '.' . $oldIndexName; + } + + return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)]; + } + + protected function getIdentitySequenceName(string $tableName): string + { + $table = new Identifier($tableName); + + // No usage of column name to preserve BC compatibility with <2.5 + $identitySequenceName = $this->addSuffix($table->getName(), '_SEQ'); + + if ($table->isQuoted()) { + $identitySequenceName = '"' . $identitySequenceName . '"'; + } + + $identitySequenceIdentifier = $this->normalizeIdentifier($identitySequenceName); + + return $identitySequenceIdentifier->getQuotedName($this); + } + + /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */ + public function supportsCommentOnStatement(): bool + { + return true; + } + + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset): string + { + if ($offset > 0) { + $query .= sprintf(' OFFSET %d ROWS', $offset); + } + + if ($limit !== null) { + $query .= sprintf(' FETCH NEXT %d ROWS ONLY', $limit); + } + + return $query; + } + + public function getCreateTemporaryTableSnippetSQL(): string + { + return 'CREATE GLOBAL TEMPORARY TABLE'; + } + + public function getDateTimeTzFormatString(): string + { + return 'Y-m-d H:i:sP'; + } + + public function getDateFormatString(): string + { + return 'Y-m-d 00:00:00'; + } + + public function getTimeFormatString(): string + { + return '1900-01-01 H:i:s'; + } + + public function getMaxIdentifierLength(): int + { + return 128; + } + + public function supportsSequences(): bool + { + return true; + } + + public function supportsReleaseSavepoints(): bool + { + return false; + } + + public function getTruncateTableSQL(string $tableName, bool $cascade = false): string + { + $tableIdentifier = new Identifier($tableName); + + return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); + } + + public function getDummySelectSQL(string $expression = '1'): string + { + return sprintf('SELECT %s FROM DUAL', $expression); + } + + protected function initializeDoctrineTypeMappings(): void + { + $this->doctrineTypeMapping = [ + 'binary_double' => Types::FLOAT, + 'binary_float' => Types::FLOAT, + 'binary_integer' => Types::BOOLEAN, + 'blob' => Types::BLOB, + 'char' => Types::STRING, + 'clob' => Types::TEXT, + 'date' => Types::DATE_MUTABLE, + 'float' => Types::FLOAT, + 'integer' => Types::INTEGER, + 'long' => Types::STRING, + 'long raw' => Types::BLOB, + 'nchar' => Types::STRING, + 'nclob' => Types::TEXT, + 'number' => Types::INTEGER, + 'nvarchar2' => Types::STRING, + 'pls_integer' => Types::BOOLEAN, + 'raw' => Types::BINARY, + 'rowid' => Types::STRING, + 'timestamp' => Types::DATETIME_MUTABLE, + 'timestamptz' => Types::DATETIMETZ_MUTABLE, + 'urowid' => Types::STRING, + 'varchar' => Types::STRING, + 'varchar2' => Types::STRING, + ]; + } + + public function releaseSavePoint(string $savepoint): string + { + return ''; + } + + protected function createReservedKeywordsList(): KeywordList + { + return new OracleKeywords(); + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column): string + { + return 'BLOB'; + } + + public function createSchemaManager(Connection $connection): OracleSchemaManager + { + return new OracleSchemaManager($connection, $this); + } +} -- cgit v1.2.3