1<?php
2
3namespace Doctrine\DBAL\Schema;
4
5use Doctrine\DBAL\Platforms\SQLAnywherePlatform;
6use Doctrine\DBAL\Types\Type;
7
8use function assert;
9use function is_string;
10use function preg_replace;
11
12/**
13 * SAP Sybase SQL Anywhere schema manager.
14 */
15class SQLAnywhereSchemaManager extends AbstractSchemaManager
16{
17    /**
18     * {@inheritdoc}
19     *
20     * Starts a database after creation
21     * as SQL Anywhere needs a database to be started
22     * before it can be used.
23     *
24     * @see startDatabase
25     */
26    public function createDatabase($database)
27    {
28        parent::createDatabase($database);
29        $this->startDatabase($database);
30    }
31
32    /**
33     * {@inheritdoc}
34     *
35     * Tries stopping a database before dropping
36     * as SQL Anywhere needs a database to be stopped
37     * before it can be dropped.
38     *
39     * @see stopDatabase
40     */
41    public function dropDatabase($database)
42    {
43        $this->tryMethod('stopDatabase', $database);
44        parent::dropDatabase($database);
45    }
46
47    /**
48     * Starts a database.
49     *
50     * @param string $database The name of the database to start.
51     *
52     * @return void
53     */
54    public function startDatabase($database)
55    {
56        assert($this->_platform instanceof SQLAnywherePlatform);
57        $this->_execSql($this->_platform->getStartDatabaseSQL($database));
58    }
59
60    /**
61     * Stops a database.
62     *
63     * @param string $database The name of the database to stop.
64     *
65     * @return void
66     */
67    public function stopDatabase($database)
68    {
69        assert($this->_platform instanceof SQLAnywherePlatform);
70        $this->_execSql($this->_platform->getStopDatabaseSQL($database));
71    }
72
73    /**
74     * {@inheritdoc}
75     */
76    protected function _getPortableDatabaseDefinition($database)
77    {
78        return $database['name'];
79    }
80
81    /**
82     * {@inheritdoc}
83     */
84    protected function _getPortableSequenceDefinition($sequence)
85    {
86        return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['start_with']);
87    }
88
89    /**
90     * {@inheritdoc}
91     */
92    protected function _getPortableTableColumnDefinition($tableColumn)
93    {
94        $type                   = $this->_platform->getDoctrineTypeMapping($tableColumn['type']);
95        $type                   = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
96        $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
97        $precision              = null;
98        $scale                  = null;
99        $fixed                  = false;
100        $default                = null;
101
102        if ($tableColumn['default'] !== null) {
103            // Strip quotes from default value.
104            $default = preg_replace(["/^'(.*)'$/", "/''/"], ['$1', "'"], $tableColumn['default']);
105
106            if ($default === 'autoincrement') {
107                $default = null;
108            }
109        }
110
111        switch ($tableColumn['type']) {
112            case 'binary':
113            case 'char':
114            case 'nchar':
115                $fixed = true;
116                break;
117        }
118
119        switch ($type) {
120            case 'decimal':
121            case 'float':
122                $precision = $tableColumn['length'];
123                $scale     = $tableColumn['scale'];
124                break;
125        }
126
127        return new Column(
128            $tableColumn['column_name'],
129            Type::getType($type),
130            [
131                'length'        => $type === 'string' ? $tableColumn['length'] : null,
132                'precision'     => $precision,
133                'scale'         => $scale,
134                'unsigned'      => (bool) $tableColumn['unsigned'],
135                'fixed'         => $fixed,
136                'notnull'       => (bool) $tableColumn['notnull'],
137                'default'       => $default,
138                'autoincrement' => (bool) $tableColumn['autoincrement'],
139                'comment'       => isset($tableColumn['comment']) && $tableColumn['comment'] !== ''
140                    ? $tableColumn['comment']
141                    : null,
142            ]
143        );
144    }
145
146    /**
147     * {@inheritdoc}
148     */
149    protected function _getPortableTableDefinition($table)
150    {
151        return $table['table_name'];
152    }
153
154    /**
155     * {@inheritdoc}
156     */
157    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
158    {
159        return new ForeignKeyConstraint(
160            $tableForeignKey['local_columns'],
161            $tableForeignKey['foreign_table'],
162            $tableForeignKey['foreign_columns'],
163            $tableForeignKey['name'],
164            $tableForeignKey['options']
165        );
166    }
167
168    /**
169     * {@inheritdoc}
170     */
171    protected function _getPortableTableForeignKeysList($tableForeignKeys)
172    {
173        $foreignKeys = [];
174
175        foreach ($tableForeignKeys as $tableForeignKey) {
176            if (! isset($foreignKeys[$tableForeignKey['index_name']])) {
177                $foreignKeys[$tableForeignKey['index_name']] = [
178                    'local_columns'   => [$tableForeignKey['local_column']],
179                    'foreign_table'   => $tableForeignKey['foreign_table'],
180                    'foreign_columns' => [$tableForeignKey['foreign_column']],
181                    'name'            => $tableForeignKey['index_name'],
182                    'options'         => [
183                        'notnull'           => $tableForeignKey['notnull'],
184                        'match'             => $tableForeignKey['match'],
185                        'onUpdate'          => $tableForeignKey['on_update'],
186                        'onDelete'          => $tableForeignKey['on_delete'],
187                        'check_on_commit'   => $tableForeignKey['check_on_commit'],
188                        'clustered'         => $tableForeignKey['clustered'],
189                        'for_olap_workload' => $tableForeignKey['for_olap_workload'],
190                    ],
191                ];
192            } else {
193                $foreignKeys[$tableForeignKey['index_name']]['local_columns'][]   = $tableForeignKey['local_column'];
194                $foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column'];
195            }
196        }
197
198        return parent::_getPortableTableForeignKeysList($foreignKeys);
199    }
200
201    /**
202     * {@inheritdoc}
203     */
204    protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
205    {
206        foreach ($tableIndexes as &$tableIndex) {
207            $tableIndex['primary'] = (bool) $tableIndex['primary'];
208            $tableIndex['flags']   = [];
209
210            if ($tableIndex['clustered']) {
211                $tableIndex['flags'][] = 'clustered';
212            }
213
214            if ($tableIndex['with_nulls_not_distinct']) {
215                $tableIndex['flags'][] = 'with_nulls_not_distinct';
216            }
217
218            if (! $tableIndex['for_olap_workload']) {
219                continue;
220            }
221
222            $tableIndex['flags'][] = 'for_olap_workload';
223        }
224
225        return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
226    }
227
228    /**
229     * {@inheritdoc}
230     */
231    protected function _getPortableViewDefinition($view)
232    {
233        $definition = preg_replace('/^.*\s+as\s+SELECT(.*)/i', 'SELECT$1', $view['view_def']);
234        assert(is_string($definition));
235
236        return new View($view['table_name'], $definition);
237    }
238}
239