Files
DESKTOP-DH6BVPV\chiefsoft 29452e5b6e first commit
2022-11-15 21:53:02 -05:00

304 lines
9.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Database\OCI8;
use CodeIgniter\Database\Forge as BaseForge;
/**
* Forge for OCI8
*/
class Forge extends BaseForge
{
/**
* DROP INDEX statement
*
* @var string
*/
protected $dropIndexStr = 'DROP INDEX %s';
/**
* CREATE DATABASE statement
*
* @var false
*/
protected $createDatabaseStr = false;
/**
* CREATE TABLE IF statement
*
* @var false
*
* @deprecated This is no longer used.
*/
protected $createTableIfStr = false;
/**
* DROP TABLE IF EXISTS statement
*
* @var false
*/
protected $dropTableIfStr = false;
/**
* DROP DATABASE statement
*
* @var false
*/
protected $dropDatabaseStr = false;
/**
* UNSIGNED support
*
* @var array|bool
*/
protected $unsigned = false;
/**
* NULL value representation in CREATE/ALTER TABLE statements
*
* @var string
*/
protected $null = 'NULL';
/**
* RENAME TABLE statement
*
* @var string
*/
protected $renameTableStr = 'ALTER TABLE %s RENAME TO %s';
/**
* DROP CONSTRAINT statement
*
* @var string
*/
protected $dropConstraintStr = 'ALTER TABLE %s DROP CONSTRAINT %s';
/**
* ALTER TABLE
*
* @param string $alterType ALTER type
* @param string $table Table name
* @param array|string $field Column definition
*
* @return string|string[]
*/
protected function _alterTable(string $alterType, string $table, $field)
{
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
if ($alterType === 'DROP') {
$fields = array_map(fn ($field) => $this->db->escapeIdentifiers(trim($field)), is_string($field) ? explode(',', $field) : $field);
return $sql . ' DROP (' . implode(',', $fields) . ') CASCADE CONSTRAINT INVALIDATE';
}
if ($alterType === 'CHANGE') {
$alterType = 'MODIFY';
}
$nullableMap = array_column($this->db->getFieldData($table), 'nullable', 'name');
$sqls = [];
for ($i = 0, $c = count($field); $i < $c; $i++) {
if ($alterType === 'MODIFY') {
// If a null constraint is added to a column with a null constraint,
// ORA-01451 will occur,
// so add null constraint is used only when it is different from the current null constraint.
$isWantToAddNull = strpos($field[$i]['null'], ' NOT') === false;
$currentNullAddable = $nullableMap[$field[$i]['name']];
if ($isWantToAddNull === $currentNullAddable) {
$field[$i]['null'] = '';
}
}
if ($field[$i]['_literal'] !== false) {
$field[$i] = "\n\t" . $field[$i]['_literal'];
} else {
$field[$i]['_literal'] = "\n\t" . $this->_processColumn($field[$i]);
if (! empty($field[$i]['comment'])) {
$sqls[] = 'COMMENT ON COLUMN '
. $this->db->escapeIdentifiers($table) . '.' . $this->db->escapeIdentifiers($field[$i]['name'])
. ' IS ' . $field[$i]['comment'];
}
if ($alterType === 'MODIFY' && ! empty($field[$i]['new_name'])) {
$sqls[] = $sql . ' RENAME COLUMN ' . $this->db->escapeIdentifiers($field[$i]['name'])
. ' TO ' . $this->db->escapeIdentifiers($field[$i]['new_name']);
}
$field[$i] = "\n\t" . $field[$i]['_literal'];
}
}
$sql .= ' ' . $alterType . ' ';
$sql .= count($field) === 1
? $field[0]
: '(' . implode(',', $field) . ')';
// RENAME COLUMN must be executed after MODIFY
array_unshift($sqls, $sql);
return $sqls;
}
/**
* Field attribute AUTO_INCREMENT
*
* @return void
*/
protected function _attributeAutoIncrement(array &$attributes, array &$field)
{
if (! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === true
&& stripos($field['type'], 'NUMBER') !== false
&& version_compare($this->db->getVersion(), '12.1', '>=')
) {
$field['auto_increment'] = ' GENERATED BY DEFAULT AS IDENTITY';
}
}
/**
* Process column
*/
protected function _processColumn(array $field): string
{
$constraint = '';
// @todo: cant cover multi pattern when set type.
if ($field['type'] === 'VARCHAR2' && strpos($field['length'], "('") === 0) {
$constraint = ' CHECK(' . $this->db->escapeIdentifiers($field['name'])
. ' IN ' . $field['length'] . ')';
$field['length'] = '(' . max(array_map('mb_strlen', explode("','", mb_substr($field['length'], 2, -2)))) . ')' . $constraint;
} elseif (count($this->primaryKeys) === 1 && $field['name'] === $this->primaryKeys[0]) {
$field['unique'] = '';
}
return $this->db->escapeIdentifiers($field['name'])
. ' ' . $field['type'] . $field['length']
. $field['unsigned']
. $field['default']
. $field['auto_increment']
. $field['null']
. $field['unique'];
}
/**
* Performs a data type mapping between different databases.
*
* @return void
*/
protected function _attributeType(array &$attributes)
{
// Reset field lengths for data types that don't support it
// Usually overridden by drivers
switch (strtoupper($attributes['TYPE'])) {
case 'TINYINT':
$attributes['CONSTRAINT'] ??= 3;
// no break
case 'SMALLINT':
$attributes['CONSTRAINT'] ??= 5;
// no break
case 'MEDIUMINT':
$attributes['CONSTRAINT'] ??= 7;
// no break
case 'INT':
case 'INTEGER':
$attributes['CONSTRAINT'] ??= 11;
// no break
case 'BIGINT':
$attributes['CONSTRAINT'] ??= 19;
// no break
case 'NUMERIC':
$attributes['TYPE'] = 'NUMBER';
return;
case 'BOOLEAN':
$attributes['TYPE'] = 'NUMBER';
$attributes['CONSTRAINT'] = 1;
$attributes['UNSIGNED'] = true;
$attributes['NULL'] = false;
return;
case 'DOUBLE':
$attributes['TYPE'] = 'FLOAT';
$attributes['CONSTRAINT'] ??= 126;
return;
case 'DATETIME':
case 'TIME':
$attributes['TYPE'] = 'DATE';
return;
case 'SET':
case 'ENUM':
case 'VARCHAR':
$attributes['CONSTRAINT'] ??= 255;
// no break
case 'TEXT':
case 'MEDIUMTEXT':
$attributes['CONSTRAINT'] ??= 4000;
$attributes['TYPE'] = 'VARCHAR2';
}
}
/**
* Generates a platform-specific DROP TABLE string
*
* @return bool|string
*/
protected function _dropTable(string $table, bool $ifExists, bool $cascade)
{
$sql = parent::_dropTable($table, $ifExists, $cascade);
if ($sql !== true && $cascade === true) {
$sql .= ' CASCADE CONSTRAINTS PURGE';
} elseif ($sql !== true) {
$sql .= ' PURGE';
}
return $sql;
}
protected function _processForeignKeys(string $table): string
{
$sql = '';
$allowActions = [
'CASCADE',
'SET NULL',
'NO ACTION',
];
foreach ($this->foreignKeys as $fkey) {
$nameIndex = $table . '_' . implode('_', $fkey['field']) . '_fk';
$nameIndexFilled = $this->db->escapeIdentifiers($nameIndex);
$foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field']));
$referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']);
$referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField']));
$formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)";
$sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled);
if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) {
$sql .= ' ON DELETE ' . $fkey['onDelete'];
}
}
return $sql;
}
}