MINI Sh3ll
<?php
namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ColumnDiff;
use Doctrine\DBAL\Schema\Constraint;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Identifier;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\TransactionIsolationLevel;
use InvalidArgumentException;
use function array_merge;
use function array_unique;
use function array_values;
use function count;
use function explode;
use function func_get_args;
use function get_class;
use function implode;
use function is_string;
use function preg_match;
use function sprintf;
use function strlen;
use function strpos;
use function strtoupper;
use function substr;
/**
* The SQLAnywherePlatform provides the behavior, features and SQL dialect of the
* SAP Sybase SQL Anywhere 10 database platform.
*/
class SQLAnywherePlatform extends AbstractPlatform
{
public const FOREIGN_KEY_MATCH_SIMPLE = 1;
public const FOREIGN_KEY_MATCH_FULL = 2;
public const FOREIGN_KEY_MATCH_SIMPLE_UNIQUE = 129;
public const FOREIGN_KEY_MATCH_FULL_UNIQUE = 130;
/**
* {@inheritdoc}
*/
public function appendLockHint($fromClause, $lockMode)
{
switch (true) {
case $lockMode === LockMode::NONE:
return $fromClause . ' WITH (NOLOCK)';
case $lockMode === LockMode::PESSIMISTIC_READ:
return $fromClause . ' WITH (UPDLOCK)';
case $lockMode === LockMode::PESSIMISTIC_WRITE:
return $fromClause . ' WITH (XLOCK)';
default:
return $fromClause;
}
}
/**
* {@inheritdoc}
*
* SQL Anywhere supports a maximum length of 128 bytes for identifiers.
*/
public function fixSchemaElementName($schemaElementName)
{
$maxIdentifierLength = $this->getMaxIdentifierLength();
if (strlen($schemaElementName) > $maxIdentifierLength) {
return substr($schemaElementName, 0, $maxIdentifierLength);
}
return $schemaElementName;
}
/**
* {@inheritdoc}
*/
public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
{
$query = '';
if ($foreignKey->hasOption('match')) {
$query = ' MATCH ' . $this->getForeignKeyMatchClauseSQL($foreignKey->getOption('match'));
}
$query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
if ($foreignKey->hasOption('check_on_commit') && (bool) $foreignKey->getOption('check_on_commit')) {
$query .= ' CHECK ON COMMIT';
}
if ($foreignKey->hasOption('clustered') && (bool) $foreignKey->getOption('clustered')) {
$query .= ' CLUSTERED';
}
if ($foreignKey->hasOption('for_olap_workload') && (bool) $foreignKey->getOption('for_olap_workload')) {
$query .= ' FOR OLAP WORKLOAD';
}
return $query;
}
/**
* {@inheritdoc}
*/
public function getAlterTableSQL(TableDiff $diff)
{
$sql = [];
$columnSql = [];
$commentsSQL = [];
$tableSql = [];
$alterClauses = [];
foreach ($diff->addedColumns as $column) {
if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
continue;
}
$alterClauses[] = $this->getAlterTableAddColumnClause($column);
$comment = $this->getColumnComment($column);
if ($comment === null || $comment === '') {
continue;
}
$commentsSQL[] = $this->getCommentOnColumnSQL(
$diff->getName($this)->getQuotedName($this),
$column->getQuotedName($this),
$comment
);
}
foreach ($diff->removedColumns as $column) {
if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
continue;
}
$alterClauses[] = $this->getAlterTableRemoveColumnClause($column);
}
foreach ($diff->changedColumns as $columnDiff) {
if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
continue;
}
$alterClause = $this->getAlterTableChangeColumnClause($columnDiff);
if ($alterClause !== null) {
$alterClauses[] = $alterClause;
}
if (! $columnDiff->hasChanged('comment')) {
continue;
}
$column = $columnDiff->column;
$commentsSQL[] = $this->getCommentOnColumnSQL(
$diff->getName($this)->getQuotedName($this),
$column->getQuotedName($this),
$this->getColumnComment($column)
);
}
foreach ($diff->renamedColumns as $oldColumnName => $column) {
if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
continue;
}
$sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' .
$this->getAlterTableRenameColumnClause($oldColumnName, $column);
}
if (! $this->onSchemaAlterTable($diff, $tableSql)) {
if (! empty($alterClauses)) {
$sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . implode(', ', $alterClauses);
}
$sql = array_merge($sql, $commentsSQL);
$newName = $diff->getNewName();
if ($newName !== false) {
$sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' .
$this->getAlterTableRenameTableClause($newName);
}
$sql = array_merge(
$this->getPreAlterTableIndexForeignKeySQL($diff),
$sql,
$this->getPostAlterTableIndexForeignKeySQL($diff)
);
}
return array_merge($sql, $tableSql, $columnSql);
}
/**
* Returns the SQL clause for creating a column in a table alteration.
*
* @param Column $column The column to add.
*
* @return string
*/
protected function getAlterTableAddColumnClause(Column $column)
{
return 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
}
/**
* Returns the SQL clause for altering a table.
*
* @param Identifier $tableName The quoted name of the table to alter.
*
* @return string
*/
protected function getAlterTableClause(Identifier $tableName)
{
return 'ALTER TABLE ' . $tableName->getQuotedName($this);
}
/**
* Returns the SQL clause for dropping a column in a table alteration.
*
* @param Column $column The column to drop.
*
* @return string
*/
protected function getAlterTableRemoveColumnClause(Column $column)
{
return 'DROP ' . $column->getQuotedName($this);
}
/**
* Returns the SQL clause for renaming a column in a table alteration.
*
* @param string $oldColumnName The quoted name of the column to rename.
* @param Column $column The column to rename to.
*
* @return string
*/
protected function getAlterTableRenameColumnClause($oldColumnName, Column $column)
{
$oldColumnName = new Identifier($oldColumnName);
return 'RENAME ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this);
}
/**
* Returns the SQL clause for renaming a table in a table alteration.
*
* @param Identifier $newTableName The quoted name of the table to rename to.
*
* @return string
*/
protected function getAlterTableRenameTableClause(Identifier $newTableName)
{
return 'RENAME ' . $newTableName->getQuotedName($this);
}
/**
* Returns the SQL clause for altering a column in a table alteration.
*
* This method returns null in case that only the column comment has changed.
* Changes in column comments have to be handled differently.
*
* @param ColumnDiff $columnDiff The diff of the column to alter.
*
* @return string|null
*/
protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff)
{
$column = $columnDiff->column;
// Do not return alter clause if only comment has changed.
if (! ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1)) {
$columnAlterationClause = 'ALTER ' .
$this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
if ($columnDiff->hasChanged('default') && $column->getDefault() === null) {
$columnAlterationClause .= ', ALTER ' . $column->getQuotedName($this) . ' DROP DEFAULT';
}
return $columnAlterationClause;
}
return null;
}
/**
* {@inheritdoc}
*/
public function getBigIntTypeDeclarationSQL(array $columnDef)
{
$columnDef['integer_type'] = 'BIGINT';
return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
}
/**
* {@inheritdoc}
*/
public function getBinaryDefaultLength()
{
return 1;
}
/**
* {@inheritdoc}
*/
public function getBinaryMaxLength()
{
return 32767;
}
/**
* {@inheritdoc}
*/
public function getBlobTypeDeclarationSQL(array $field)
{
return 'LONG BINARY';
}
/**
* {@inheritdoc}
*
* BIT type columns require an explicit NULL declaration
* in SQL Anywhere if they shall be nullable.
* Otherwise by just omitting the NOT NULL clause,
* SQL Anywhere will declare them NOT NULL nonetheless.
*/
public function getBooleanTypeDeclarationSQL(array $columnDef)
{
$nullClause = isset($columnDef['notnull']) && (bool) $columnDef['notnull'] === false ? ' NULL' : '';
return 'BIT' . $nullClause;
}
/**
* {@inheritdoc}
*/
public function getClobTypeDeclarationSQL(array $field)
{
return 'TEXT';
}
/**
* {@inheritdoc}
*/
public function getCommentOnColumnSQL($tableName, $columnName, $comment)
{
$tableName = new Identifier($tableName);
$columnName = new Identifier($columnName);
$comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment);
return sprintf(
'COMMENT ON COLUMN %s.%s IS %s',
$tableName->getQuotedName($this),
$columnName->getQuotedName($this),
$comment
);
}
/**
* {@inheritdoc}
*/
public function getConcatExpression()
{
return 'STRING(' . implode(', ', (array) func_get_args()) . ')';
}
/**
* {@inheritdoc}
*/
public function getCreateConstraintSQL(Constraint $constraint, $table)
{
if ($constraint instanceof ForeignKeyConstraint) {
return $this->getCreateForeignKeySQL($constraint, $table);
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
return 'ALTER TABLE ' . $table .
' ADD ' . $this->getTableConstraintDeclarationSQL($constraint, $constraint->getQuotedName($this));
}
/**
* {@inheritdoc}
*/
public function getCreateDatabaseSQL($database)
{
$database = new Identifier($database);
return "CREATE DATABASE '" . $database->getName() . "'";
}
/**
* {@inheritdoc}
*
* Appends SQL Anywhere specific flags if given.
*/
public function getCreateIndexSQL(Index $index, $table)
{
return parent::getCreateIndexSQL($index, $table) . $this->getAdvancedIndexOptionsSQL($index);
}
/**
* {@inheritdoc}
*/
public function getCreatePrimaryKeySQL(Index $index, $table)
{
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
return 'ALTER TABLE ' . $table . ' ADD ' . $this->getPrimaryKeyDeclarationSQL($index);
}
/**
* {@inheritdoc}
*/
public function getCreateTemporaryTableSnippetSQL()
{
return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE';
}
/**
* {@inheritdoc}
*/
public function getCreateViewSQL($name, $sql)
{
return 'CREATE VIEW ' . $name . ' AS ' . $sql;
}
/**
* {@inheritdoc}
*/
public function getCurrentDateSQL()
{
return 'CURRENT DATE';
}
/**
* {@inheritdoc}
*/
public function getCurrentTimeSQL()
{
return 'CURRENT TIME';
}
/**
* {@inheritdoc}
*/
public function getCurrentTimestampSQL()
{
return 'CURRENT TIMESTAMP';
}
/**
* {@inheritdoc}
*/
protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
{
$factorClause = '';
if ($operator === '-') {
$factorClause = '-1 * ';
}
return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')';
}
/**
* {@inheritdoc}
*/
public function getDateDiffExpression($date1, $date2)
{
return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')';
}
/**
* {@inheritdoc}
*/
public function getDateTimeFormatString()
{
return 'Y-m-d H:i:s.u';
}
/**
* {@inheritdoc}
*/
public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
{
return 'DATETIME';
}
/**
* {@inheritdoc}
*/
public function getDateTimeTzFormatString()
{
return $this->getDateTimeFormatString();
}
/**
* {@inheritdoc}
*/
public function getDateTypeDeclarationSQL(array $fieldDeclaration)
{
return 'DATE';
}
/**
* {@inheritdoc}
*/
public function getDefaultTransactionIsolationLevel()
{
return TransactionIsolationLevel::READ_UNCOMMITTED;
}
/**
* {@inheritdoc}
*/
public function getDropDatabaseSQL($database)
{
$database = new Identifier($database);
return "DROP DATABASE '" . $database->getName() . "'";
}
/**
* {@inheritdoc}
*/
public function getDropIndexSQL($index, $table = null)
{
if ($index instanceof Index) {
$index = $index->getQuotedName($this);
}
if (! is_string($index)) {
throw new InvalidArgumentException(
'SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be string or ' . Index::class . '.'
);
}
if (! isset($table)) {
return 'DROP INDEX ' . $index;
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
if (! is_string($table)) {
throw new InvalidArgumentException(
'SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be string or ' . Index::class . '.'
);
}
return 'DROP INDEX ' . $table . '.' . $index;
}
/**
* {@inheritdoc}
*/
public function getDropViewSQL($name)
{
return 'DROP VIEW ' . $name;
}
/**
* {@inheritdoc}
*/
public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
{
$sql = '';
$foreignKeyName = $foreignKey->getName();
$localColumns = $foreignKey->getQuotedLocalColumns($this);
$foreignColumns = $foreignKey->getQuotedForeignColumns($this);
$foreignTableName = $foreignKey->getQuotedForeignTableName($this);
if (! empty($foreignKeyName)) {
$sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
}
if (empty($localColumns)) {
throw new InvalidArgumentException("Incomplete definition. 'local' required.");
}
if (empty($foreignColumns)) {
throw new InvalidArgumentException("Incomplete definition. 'foreign' required.");
}
if (empty($foreignTableName)) {
throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
}
if ($foreignKey->hasOption('notnull') && (bool) $foreignKey->getOption('notnull')) {
$sql .= 'NOT NULL ';
}
return $sql .
'FOREIGN KEY (' . $this->getIndexFieldDeclarationListSQL($localColumns) . ') ' .
'REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) .
' (' . $this->getIndexFieldDeclarationListSQL($foreignColumns) . ')';
}
/**
* Returns foreign key MATCH clause for given type.
*
* @param int $type The foreign key match type
*
* @return string
*
* @throws InvalidArgumentException If unknown match type given.
*/
public function getForeignKeyMatchClauseSQL($type)
{
switch ((int) $type) {
case self::FOREIGN_KEY_MATCH_SIMPLE:
return 'SIMPLE';
case self::FOREIGN_KEY_MATCH_FULL:
return 'FULL';
case self::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE:
return 'UNIQUE SIMPLE';
case self::FOREIGN_KEY_MATCH_FULL_UNIQUE:
return 'UNIQUE FULL';
default:
throw new InvalidArgumentException('Invalid foreign key match type: ' . $type);
}
}
/**
* {@inheritdoc}
*/
public function getForeignKeyReferentialActionSQL($action)
{
// NO ACTION is not supported, therefore falling back to RESTRICT.
if (strtoupper($action) === 'NO ACTION') {
return 'RESTRICT';
}
return parent::getForeignKeyReferentialActionSQL($action);
}
/**
* {@inheritdoc}
*/
public function getForUpdateSQL()
{
return '';
}
/**
* {@inheritdoc}
*
* @deprecated Use application-generated UUIDs instead
*/
public function getGuidExpression()
{
return 'NEWID()';
}
/**
* {@inheritdoc}
*/
public function getGuidTypeDeclarationSQL(array $field)
{
return 'UNIQUEIDENTIFIER';
}
/**
* {@inheritdoc}
*/
public function getIndexDeclarationSQL($name, Index $index)
{
// Index declaration in statements like CREATE TABLE is not supported.
throw DBALException::notSupported(__METHOD__);
}
/**
* {@inheritdoc}
*/
public function getIntegerTypeDeclarationSQL(array $columnDef)
{
$columnDef['integer_type'] = 'INT';
return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
}
/**
* {@inheritdoc}
*/
public function getListDatabasesSQL()
{
return 'SELECT db_name(number) AS name FROM sa_db_list()';
}
/**
* {@inheritdoc}
*/
public function getListTableColumnsSQL($table, $database = null)
{
$user = 'USER_NAME()';
if (strpos($table, '.') !== false) {
[$user, $table] = explode('.', $table);
$user = $this->quoteStringLiteral($user);
}
return sprintf(
<<<'SQL'
SELECT col.column_name,
COALESCE(def.user_type_name, def.domain_name) AS 'type',
def.declared_width AS 'length',
def.scale,
CHARINDEX('unsigned', def.domain_name) AS 'unsigned',
IF col.nulls = 'Y' THEN 0 ELSE 1 ENDIF AS 'notnull',
col."default",
def.is_autoincrement AS 'autoincrement',
rem.remarks AS 'comment'
FROM sa_describe_query('SELECT * FROM "%s"') AS def
JOIN SYS.SYSTABCOL AS col
ON col.table_id = def.base_table_id AND col.column_id = def.base_column_id
LEFT JOIN SYS.SYSREMARK AS rem
ON col.object_id = rem.object_id
WHERE def.base_owner_name = %s
ORDER BY def.base_column_id ASC
SQL
,
$table,
$user
);
}
/**
* {@inheritdoc}
*
* @todo Where is this used? Which information should be retrieved?
*/
public function getListTableConstraintsSQL($table)
{
$user = '';
if (strpos($table, '.') !== false) {
[$user, $table] = explode('.', $table);
$user = $this->quoteStringLiteral($user);
$table = $this->quoteStringLiteral($table);
} else {
$table = $this->quoteStringLiteral($table);
}
return sprintf(
<<<'SQL'
SELECT con.*
FROM SYS.SYSCONSTRAINT AS con
JOIN SYS.SYSTAB AS tab ON con.table_object_id = tab.object_id
WHERE tab.table_name = %s
AND tab.creator = USER_ID(%s)
SQL
,
$table,
$user
);
}
/**
* {@inheritdoc}
*/
public function getListTableForeignKeysSQL($table)
{
$user = '';
if (strpos($table, '.') !== false) {
[$user, $table] = explode('.', $table);
$user = $this->quoteStringLiteral($user);
$table = $this->quoteStringLiteral($table);
} else {
$table = $this->quoteStringLiteral($table);
}
return sprintf(
<<<'SQL'
SELECT fcol.column_name AS local_column,
ptbl.table_name AS foreign_table,
pcol.column_name AS foreign_column,
idx.index_name,
IF fk.nulls = 'N'
THEN 1
ELSE NULL
ENDIF AS notnull,
CASE ut.referential_action
WHEN 'C' THEN 'CASCADE'
WHEN 'D' THEN 'SET DEFAULT'
WHEN 'N' THEN 'SET NULL'
WHEN 'R' THEN 'RESTRICT'
ELSE NULL
END AS on_update,
CASE dt.referential_action
WHEN 'C' THEN 'CASCADE'
WHEN 'D' THEN 'SET DEFAULT'
WHEN 'N' THEN 'SET NULL'
WHEN 'R' THEN 'RESTRICT'
ELSE NULL
END AS on_delete,
IF fk.check_on_commit = 'Y'
THEN 1
ELSE NULL
ENDIF AS check_on_commit, -- check_on_commit flag
IF ftbl.clustered_index_id = idx.index_id
THEN 1
ELSE NULL
ENDIF AS 'clustered', -- clustered flag
IF fk.match_type = 0
THEN NULL
ELSE fk.match_type
ENDIF AS 'match', -- match option
IF pidx.max_key_distance = 1
THEN 1
ELSE NULL
ENDIF AS for_olap_workload -- for_olap_workload flag
FROM SYS.SYSFKEY AS fk
JOIN SYS.SYSIDX AS idx
ON fk.foreign_table_id = idx.table_id
AND fk.foreign_index_id = idx.index_id
JOIN SYS.SYSPHYSIDX pidx
ON idx.table_id = pidx.table_id
AND idx.phys_index_id = pidx.phys_index_id
JOIN SYS.SYSTAB AS ptbl
ON fk.primary_table_id = ptbl.table_id
JOIN SYS.SYSTAB AS ftbl
ON fk.foreign_table_id = ftbl.table_id
JOIN SYS.SYSIDXCOL AS idxcol
ON idx.table_id = idxcol.table_id
AND idx.index_id = idxcol.index_id
JOIN SYS.SYSTABCOL AS pcol
ON ptbl.table_id = pcol.table_id
AND idxcol.primary_column_id = pcol.column_id
JOIN SYS.SYSTABCOL AS fcol
ON ftbl.table_id = fcol.table_id
AND idxcol.column_id = fcol.column_id
LEFT JOIN SYS.SYSTRIGGER ut
ON fk.foreign_table_id = ut.foreign_table_id
AND fk.foreign_index_id = ut.foreign_key_id
AND ut.event = 'C'
LEFT JOIN SYS.SYSTRIGGER dt
ON fk.foreign_table_id = dt.foreign_table_id
AND fk.foreign_index_id = dt.foreign_key_id
AND dt.event = 'D'
WHERE ftbl.table_name = %s
AND ftbl.creator = USER_ID(%s)
ORDER BY fk.foreign_index_id ASC, idxcol.sequence ASC
SQL
,
$table,
$user
);
}
/**
* {@inheritdoc}
*/
public function getListTableIndexesSQL($table, $currentDatabase = null)
{
$user = '';
if (strpos($table, '.') !== false) {
[$user, $table] = explode('.', $table);
$user = $this->quoteStringLiteral($user);
$table = $this->quoteStringLiteral($table);
} else {
$table = $this->quoteStringLiteral($table);
}
return sprintf(
<<<'SQL'
SELECT idx.index_name AS key_name,
IF idx.index_category = 1
THEN 1
ELSE 0
ENDIF AS 'primary',
col.column_name,
IF idx."unique" IN(1, 2, 5)
THEN 0
ELSE 1
ENDIF AS non_unique,
IF tbl.clustered_index_id = idx.index_id
THEN 1
ELSE NULL
ENDIF AS 'clustered', -- clustered flag
IF idx."unique" = 5
THEN 1
ELSE NULL
ENDIF AS with_nulls_not_distinct, -- with_nulls_not_distinct flag
IF pidx.max_key_distance = 1
THEN 1
ELSE NULL
ENDIF AS for_olap_workload -- for_olap_workload flag
FROM SYS.SYSIDX AS idx
JOIN SYS.SYSPHYSIDX pidx
ON idx.table_id = pidx.table_id
AND idx.phys_index_id = pidx.phys_index_id
JOIN SYS.SYSIDXCOL AS idxcol
ON idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id
JOIN SYS.SYSTABCOL AS col
ON idxcol.table_id = col.table_id AND idxcol.column_id = col.column_id
JOIN SYS.SYSTAB AS tbl
ON idx.table_id = tbl.table_id
WHERE tbl.table_name = %s
AND tbl.creator = USER_ID(%s)
AND idx.index_category != 2 -- exclude indexes implicitly created by foreign key constraints
ORDER BY idx.index_id ASC, idxcol.sequence ASC
SQL
,
$table,
$user
);
}
/**
* {@inheritdoc}
*/
public function getListTablesSQL()
{
return "SELECT tbl.table_name
FROM SYS.SYSTAB AS tbl
JOIN SYS.SYSUSER AS usr ON tbl.creator = usr.user_id
JOIN dbo.SYSOBJECTS AS obj ON tbl.object_id = obj.id
WHERE tbl.table_type IN(1, 3) -- 'BASE', 'GBL TEMP'
AND usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
AND obj.type = 'U' -- user created tables only
ORDER BY tbl.table_name ASC";
}
/**
* {@inheritdoc}
*
* @todo Where is this used? Which information should be retrieved?
*/
public function getListUsersSQL()
{
return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC';
}
/**
* {@inheritdoc}
*/
public function getListViewsSQL($database)
{
return "SELECT tbl.table_name, v.view_def
FROM SYS.SYSVIEW v
JOIN SYS.SYSTAB tbl ON v.view_object_id = tbl.object_id
JOIN SYS.SYSUSER usr ON tbl.creator = usr.user_id
JOIN dbo.SYSOBJECTS obj ON tbl.object_id = obj.id
WHERE usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
ORDER BY tbl.table_name ASC";
}
/**
* {@inheritdoc}
*/
public function getLocateExpression($str, $substr, $startPos = false)
{
if ($startPos === false) {
return 'LOCATE(' . $str . ', ' . $substr . ')';
}
return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')';
}
/**
* {@inheritdoc}
*/
public function getMaxIdentifierLength()
{
return 128;
}
/**
* {@inheritdoc}
*/
public function getMd5Expression($column)
{
return 'HASH(' . $column . ", 'MD5')";
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'sqlanywhere';
}
/**
* Obtain DBMS specific SQL code portion needed to set a primary key
* declaration to be used in statements like ALTER TABLE.
*
* @param Index $index Index definition
* @param string $name Name of the primary key
*
* @return string DBMS specific SQL code portion needed to set a primary key
*
* @throws InvalidArgumentException If the given index is not a primary key.
*/
public function getPrimaryKeyDeclarationSQL(Index $index, $name = null)
{
if (! $index->isPrimary()) {
throw new InvalidArgumentException(
'Can only create primary key declarations with getPrimaryKeyDeclarationSQL()'
);
}
return $this->getTableConstraintDeclarationSQL($index, $name);
}
/**
* {@inheritdoc}
*/
public function getSetTransactionIsolationSQL($level)
{
return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level);
}
/**
* {@inheritdoc}
*/
public function getSmallIntTypeDeclarationSQL(array $columnDef)
{
$columnDef['integer_type'] = 'SMALLINT';
return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
}
/**
* Returns the SQL statement for starting an existing database.
*
* In SQL Anywhere you can start and stop databases on a
* database server instance.
* This is a required statement after having created a new database
* as it has to be explicitly started to be usable.
* SQL Anywhere does not automatically start a database after creation!
*
* @param string $database Name of the database to start.
*
* @return string
*/
public function getStartDatabaseSQL($database)
{
$database = new Identifier($database);
return "START DATABASE '" . $database->getName() . "' AUTOSTOP OFF";
}
/**
* Returns the SQL statement for stopping a running database.
*
* In SQL Anywhere you can start and stop databases on a
* database server instance.
* This is a required statement before dropping an existing database
* as it has to be explicitly stopped before it can be dropped.
*
* @param string $database Name of the database to stop.
*
* @return string
*/
public function getStopDatabaseSQL($database)
{
$database = new Identifier($database);
return 'STOP DATABASE "' . $database->getName() . '" UNCONDITIONALLY';
}
/**
* {@inheritdoc}
*/
public function getSubstringExpression($value, $from, $length = null)
{
if ($length === null) {
return 'SUBSTRING(' . $value . ', ' . $from . ')';
}
return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')';
}
/**
* {@inheritdoc}
*/
public function getTemporaryTableSQL()
{
return 'GLOBAL TEMPORARY';
}
/**
* {@inheritdoc}
*/
public function getTimeFormatString()
{
return 'H:i:s.u';
}
/**
* {@inheritdoc}
*/
public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
{
return 'TIME';
}
/**
* {@inheritdoc}
*/
public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false)
{
if (! $char) {
switch ($pos) {
case TrimMode::LEADING:
return $this->getLtrimExpression($str);
case TrimMode::TRAILING:
return $this->getRtrimExpression($str);
default:
return 'TRIM(' . $str . ')';
}
}
$pattern = "'%[^' + " . $char . " + ']%'";
switch ($pos) {
case TrimMode::LEADING:
return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))';
case TrimMode::TRAILING:
return 'REVERSE(SUBSTR(REVERSE(' . $str . '), PATINDEX(' . $pattern . ', REVERSE(' . $str . '))))';
default:
return 'REVERSE(SUBSTR(REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))), ' .
'PATINDEX(' . $pattern . ', REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))))))';
}
}
/**
* {@inheritdoc}
*/
public function getTruncateTableSQL($tableName, $cascade = false)
{
$tableIdentifier = new Identifier($tableName);
return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this);
}
/**
* {@inheritdoc}
*/
public function getUniqueConstraintDeclarationSQL($name, Index $index)
{
if ($index->isPrimary()) {
throw new InvalidArgumentException(
'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().'
);
}
if (! $index->isUnique()) {
throw new InvalidArgumentException(
'Can only create unique constraint declarations, no common index declarations with ' .
'getUniqueConstraintDeclarationSQL().'
);
}
return $this->getTableConstraintDeclarationSQL($index, $name);
}
/**
* {@inheritdoc}
*/
public function getVarcharDefaultLength()
{
return 1;
}
/**
* {@inheritdoc}
*/
public function getVarcharMaxLength()
{
return 32767;
}
/**
* {@inheritdoc}
*/
public function hasNativeGuidType()
{
return true;
}
/**
* {@inheritdoc}
*/
public function prefersIdentityColumns()
{
return true;
}
/**
* {@inheritdoc}
*/
public function supportsCommentOnStatement()
{
return true;
}
/**
* {@inheritdoc}
*/
public function supportsIdentityColumns()
{
return true;
}
/**
* {@inheritdoc}
*/
protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
{
$unsigned = ! empty($columnDef['unsigned']) ? 'UNSIGNED ' : '';
$autoincrement = ! empty($columnDef['autoincrement']) ? ' IDENTITY' : '';
return $unsigned . $columnDef['integer_type'] . $autoincrement;
}
/**
* {@inheritdoc}
*/
protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
{
$columnListSql = $this->getColumnDeclarationListSQL($columns);
$indexSql = [];
if (! empty($options['uniqueConstraints'])) {
foreach ((array) $options['uniqueConstraints'] as $name => $definition) {
$columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
}
}
if (! empty($options['indexes'])) {
/** @var Index $index */
foreach ((array) $options['indexes'] as $index) {
$indexSql[] = $this->getCreateIndexSQL($index, $tableName);
}
}
if (! empty($options['primary'])) {
$flags = '';
if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) {
$flags = ' CLUSTERED ';
}
$columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values((array) $options['primary']))) . ')';
}
if (! empty($options['foreignKeys'])) {
foreach ((array) $options['foreignKeys'] as $definition) {
$columnListSql .= ', ' . $this->getForeignKeyDeclarationSQL($definition);
}
}
$query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
$check = $this->getCheckDeclarationSQL($columns);
if (! empty($check)) {
$query .= ', ' . $check;
}
$query .= ')';
return array_merge([$query], $indexSql);
}
/**
* {@inheritdoc}
*/
protected function _getTransactionIsolationLevelSQL($level)
{
switch ($level) {
case TransactionIsolationLevel::READ_UNCOMMITTED:
return '0';
case TransactionIsolationLevel::READ_COMMITTED:
return '1';
case TransactionIsolationLevel::REPEATABLE_READ:
return '2';
case TransactionIsolationLevel::SERIALIZABLE:
return '3';
default:
throw new InvalidArgumentException('Invalid isolation level:' . $level);
}
}
/**
* {@inheritdoc}
*/
protected function doModifyLimitQuery($query, $limit, $offset)
{
$limitOffsetClause = $this->getTopClauseSQL($limit, $offset);
if ($limitOffsetClause === '') {
return $query;
}
if (! preg_match('/^\s*(SELECT\s+(DISTINCT\s+)?)(.*)/i', $query, $matches)) {
return $query;
}
return $matches[1] . $limitOffsetClause . ' ' . $matches[3];
}
private function getTopClauseSQL(?int $limit, ?int $offset) : string
{
if ($offset > 0) {
return sprintf('TOP %s START AT %d', $limit ?? 'ALL', $offset + 1);
}
return $limit === null ? '' : 'TOP ' . $limit;
}
/**
* Return the INDEX query section dealing with non-standard
* SQL Anywhere options.
*
* @param Index $index Index definition
*
* @return string
*/
protected function getAdvancedIndexOptionsSQL(Index $index)
{
$sql = '';
if (! $index->isPrimary() && $index->hasFlag('for_olap_workload')) {
$sql .= ' FOR OLAP WORKLOAD';
}
return $sql;
}
/**
* {@inheritdoc}
*/
protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
{
return $fixed
? 'BINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')'
: 'VARBINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')';
}
/**
* Returns the SQL snippet for creating a table constraint.
*
* @param Constraint $constraint The table constraint to create the SQL snippet for.
* @param string|null $name The table constraint name to use if any.
*
* @return string
*
* @throws InvalidArgumentException If the given table constraint type is not supported by this method.
*/
protected function getTableConstraintDeclarationSQL(Constraint $constraint, $name = null)
{
if ($constraint instanceof ForeignKeyConstraint) {
return $this->getForeignKeyDeclarationSQL($constraint);
}
if (! $constraint instanceof Index) {
throw new InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint));
}
if (! $constraint->isPrimary() && ! $constraint->isUnique()) {
throw new InvalidArgumentException(
'Can only create primary, unique or foreign key constraint declarations, no common index declarations ' .
'with getTableConstraintDeclarationSQL().'
);
}
$constraintColumns = $constraint->getQuotedColumns($this);
if (empty($constraintColumns)) {
throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
}
$sql = '';
$flags = '';
if (! empty($name)) {
$name = new Identifier($name);
$sql .= 'CONSTRAINT ' . $name->getQuotedName($this) . ' ';
}
if ($constraint->hasFlag('clustered')) {
$flags = 'CLUSTERED ';
}
if ($constraint->isPrimary()) {
return $sql . 'PRIMARY KEY ' . $flags . '(' . $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')';
}
return $sql . 'UNIQUE ' . $flags . '(' . $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')';
}
/**
* {@inheritdoc}
*/
protected function getCreateIndexSQLFlags(Index $index)
{
$type = '';
if ($index->hasFlag('virtual')) {
$type .= 'VIRTUAL ';
}
if ($index->isUnique()) {
$type .= 'UNIQUE ';
}
if ($index->hasFlag('clustered')) {
$type .= 'CLUSTERED ';
}
return $type;
}
/**
* {@inheritdoc}
*/
protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
{
return ['ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)];
}
/**
* {@inheritdoc}
*/
protected function getReservedKeywordsClass()
{
return Keywords\SQLAnywhereKeywords::class;
}
/**
* {@inheritdoc}
*/
protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
{
return $fixed
? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')')
: ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')');
}
/**
* {@inheritdoc}
*/
protected function initializeDoctrineTypeMappings()
{
$this->doctrineTypeMapping = [
'char' => 'string',
'long nvarchar' => 'text',
'long varchar' => 'text',
'nchar' => 'string',
'ntext' => 'text',
'nvarchar' => 'string',
'text' => 'text',
'uniqueidentifierstr' => 'guid',
'varchar' => 'string',
'xml' => 'text',
'bigint' => 'bigint',
'unsigned bigint' => 'bigint',
'bit' => 'boolean',
'decimal' => 'decimal',
'double' => 'float',
'float' => 'float',
'int' => 'integer',
'integer' => 'integer',
'unsigned int' => 'integer',
'numeric' => 'decimal',
'smallint' => 'smallint',
'unsigned smallint' => 'smallint',
'tinyint' => 'smallint',
'unsigned tinyint' => 'smallint',
'money' => 'decimal',
'smallmoney' => 'decimal',
'long varbit' => 'text',
'varbit' => 'string',
'date' => 'date',
'datetime' => 'datetime',
'smalldatetime' => 'datetime',
'time' => 'time',
'timestamp' => 'datetime',
'binary' => 'binary',
'image' => 'blob',
'long binary' => 'blob',
'uniqueidentifier' => 'guid',
'varbinary' => 'binary',
];
}
}
OHA YOOOO