SqlitePlatform.php 12.6 KB
Newer Older
1
<?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *  $Id$
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.doctrine-project.org>.
 */
21

22
namespace Doctrine\DBAL\Platforms;
23

24
use Doctrine\DBAL\DBALException;
25

26
/**
27 28
 * The SqlitePlatform class describes the specifics and dialects of the SQLite
 * database platform.
29 30
 *
 * @since 2.0
31
 * @author Roman Borschel <roman@code-factory.org>
32
 * @author Benjamin Eberlei <kontakt@beberlei.de>
33
 * @todo Rename: SQLitePlatform
34
 */
35
class SqlitePlatform extends AbstractPlatform
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
{
    /**
     * returns the regular expression operator
     *
     * @return string
     * @override
     */
    public function getRegexpExpression()
    {
        return 'RLIKE';
    }

    /**
     * Return string to call a variable with the current timestamp inside an SQL statement
     * There are three special variables for current date and time.
     *
     * @return string       sqlite function as string
     * @override
     */
    public function getNowExpression($type = 'timestamp')
    {
        switch ($type) {
            case 'time':
                return 'time(\'now\')';
            case 'date':
                return 'date(\'now\')';
            case 'timestamp':
            default:
                return 'datetime(\'now\')';
        }
    }

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    /**
     * Trim a string, leading/trailing/both and with a given char which defaults to space.
     *
     * @param string $str
     * @param int $pos
     * @param string $char
     * @return string
     */
    public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
    {
        $trimFn = '';
        $trimChar = ($char != false) ? (', ' . $char) : '';

        if ($pos == self::TRIM_LEADING) {
            $trimFn = 'LTRIM';
        } else if($pos == self::TRIM_TRAILING) {
            $trimFn = 'RTRIM';
        } else {
            $trimFn = 'TRIM';
        }

        return $trimFn . '(' . $str . $trimChar . ')';
    }

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
    /**
     * return string to call a function to get a substring inside an SQL statement
     *
     * Note: Not SQL92, but common functionality.
     *
     * SQLite only supports the 2 parameter variant of this function
     *
     * @param string $value         an sql string literal or column name/alias
     * @param integer $position     where to start the substring portion
     * @param integer $length       the substring portion length
     * @return string               SQL substring function with given parameters
     * @override
     */
    public function getSubstringExpression($value, $position, $length = null)
    {
        if ($length !== null) {
            return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
        }
        return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
    }

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    /**
     * returns the position of the first occurrence of substring $substr in string $str
     *
     * @param string $substr    literal string to find
     * @param string $str       literal string
     * @param int    $pos       position to start at, beginning of string by default
     * @return integer
     */
    public function getLocateExpression($str, $substr, $startPos = false)
    {
        if ($startPos == false) {
            return 'LOCATE('.$str.', '.$substr.')';
        } else {
            return 'LOCATE('.$str.', '.$substr.', '.$startPos.')';
        }
    }

130
    protected function _getTransactionIsolationLevelSQL($level)
romanb's avatar
romanb committed
131 132
    {
        switch ($level) {
133
            case \Doctrine\DBAL\Transaction::READ_UNCOMMITTED:
romanb's avatar
romanb committed
134
                return 0;
135 136 137
            case \Doctrine\DBAL\Transaction::READ_COMMITTED:
            case \Doctrine\DBAL\Transaction::REPEATABLE_READ:
            case \Doctrine\DBAL\Transaction::SERIALIZABLE:
romanb's avatar
romanb committed
138 139
                return 1;
            default:
140
                return parent::_getTransactionIsolationLevelSQL($level);
romanb's avatar
romanb committed
141 142
        }
    }
143

144
    public function getSetTransactionIsolationSQL($level)
romanb's avatar
romanb committed
145
    {
146
        return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level);
romanb's avatar
romanb committed
147
    }
148

149 150 151
    /** 
     * @override 
     */
152 153
    public function prefersIdentityColumns()
    {
154 155
        return true;
    }
156 157 158 159
    
    /** 
     * @override 
     */
160
    public function getBooleanTypeDeclarationSQL(array $field)
161 162 163
    {
        return 'BOOLEAN';
    }
164

165 166 167
    /** 
     * @override 
     */
168
    public function getIntegerTypeDeclarationSQL(array $field)
169
    {
170
        return $this->_getCommonIntegerTypeDeclarationSQL($field);
171 172
    }

173 174 175
    /** 
     * @override 
     */
176
    public function getBigIntTypeDeclarationSQL(array $field)
177
    {
178
        return $this->_getCommonIntegerTypeDeclarationSQL($field);
179 180
    }

181 182 183
    /** 
     * @override 
     */
184 185
    public function getTinyIntTypeDeclarationSql(array $field)
    {
186
        return $this->_getCommonIntegerTypeDeclarationSQL($field);
187 188
    }

189 190 191
    /** 
     * @override 
     */
192
    public function getSmallIntTypeDeclarationSQL(array $field)
193
    {
194
        return $this->_getCommonIntegerTypeDeclarationSQL($field);
195 196
    }

197 198 199
    /** 
     * @override 
     */
200 201
    public function getMediumIntTypeDeclarationSql(array $field)
    {
202
        return $this->_getCommonIntegerTypeDeclarationSQL($field);
203 204
    }

205 206 207
    /** 
     * @override 
     */
208
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
209 210 211
    {
        return 'DATETIME';
    }
212 213 214 215
    
    /**
     * @override
     */
216
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
217 218 219
    {
        return 'DATE';
    }
220

221 222 223
    /**
     * @override
     */
224
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
225 226 227 228
    {
        return 'TIME';
    }

229 230 231
    /** 
     * @override 
     */
232
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
233
    {
234 235
        $autoinc = ! empty($columnDef['autoincrement']) ? ' AUTOINCREMENT' : '';
        $pk = ! empty($columnDef['primary']) && ! empty($autoinc) ? ' PRIMARY KEY' : '';
236

237
        return 'INTEGER' . $pk . $autoinc;
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    }

    /**
     * create a new table
     *
     * @param string $name   Name of the database that should be created
     * @param array $fields  Associative array that contains the definition of each field of the new table
     *                       The indexes of the array entries are the names of the fields of the table an
     *                       the array entry values are associative arrays like those that are meant to be
     *                       passed with the field definitions to get[Type]Declaration() functions.
     *                          array(
     *                              'id' => array(
     *                                  'type' => 'integer',
     *                                  'unsigned' => 1
     *                                  'notnull' => 1
     *                                  'default' => 0
     *                              ),
     *                              'name' => array(
     *                                  'type' => 'text',
     *                                  'length' => 12
     *                              ),
     *                              'password' => array(
     *                                  'type' => 'text',
     *                                  'length' => 12
     *                              )
     *                          );
     * @param array $options  An associative array of table options:
     *
     * @return void
     * @override
     */
269
    protected function _getCreateTableSQL($name, array $columns, array $options = array())
270
    {
271
        $queryFields = $this->getColumnDeclarationListSQL($columns);
272 273

        $autoinc = false;
274
        foreach($columns as $field) {
275
            if (isset($field['autoincrement']) && $field['autoincrement']) {
276 277 278 279 280
                $autoinc = true;
                break;
            }
        }

281
        if ( ! $autoinc && isset($options['primary']) && ! empty($options['primary'])) {
282
            $keyColumns = array_unique(array_values($options['primary']));
romanb's avatar
romanb committed
283
            $keyColumns = array_map(array($this, 'quoteIdentifier'), $keyColumns);
284 285 286
            $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')';
        }

287
        $query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')';
288 289

        if (isset($options['indexes']) && ! empty($options['indexes'])) {
290
            foreach ($options['indexes'] as $index => $indexDef) {
291
                $query[] = $this->getCreateIndexSQL($indexDef, $name);
292 293 294 295
            }
        }
        if (isset($options['unique']) && ! empty($options['unique'])) {
            foreach ($options['unique'] as $index => $indexDef) {
296
                $query[] = $this->getCreateIndexSQL($indexDef, $name);
297 298 299 300 301 302 303 304
            }
        }
        return $query;
    }

    /**
     * {@inheritdoc}
     */
305
    public function getVarcharTypeDeclarationSQL(array $field)
306 307 308 309 310 311 312 313 314 315 316 317 318 319
    {
        if ( ! isset($field['length'])) {
            if (array_key_exists('default', $field)) {
                $field['length'] = $this->getVarcharMaxLength();
            } else {
                $field['length'] = false;
            }
        }
        $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
        $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;

        return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
                : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
    }
320
    
321
    public function getClobTypeDeclarationSQL(array $field)
322 323 324
    {
        return 'CLOB';
    }
325

326
    public function getListTableConstraintsSQL($table)
327
    {
328
        return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = '$table' AND sql NOT NULL ORDER BY name";
329 330
    }

331
    public function getListTableColumnsSQL($table)
332 333 334 335
    {
        return "PRAGMA table_info($table)";
    }

336
    public function getListTableIndexesSQL($table)
337 338 339 340
    {
        return "PRAGMA index_list($table)";
    }

341
    public function getListTablesSQL()
342 343 344 345 346 347
    {
        return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' "
             . "UNION ALL SELECT name FROM sqlite_temp_master "
             . "WHERE type = 'table' ORDER BY name";
    }

348
    public function getListViewsSQL($database)
349 350 351 352
    {
        return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
    }

353
    public function getCreateViewSQL($name, $sql)
354 355 356 357
    {
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
    }

358
    public function getDropViewSQL($name)
359 360 361 362
    {
        return 'DROP VIEW '. $name;
    }

363 364 365 366 367
    /**
     * SQLite does support foreign key constraints, but only in CREATE TABLE statements...
     * This really limits their usefulness and requires SQLite specific handling, so
     * we simply say that SQLite does NOT support foreign keys for now...
     *
368
     * @return boolean FALSE
369 370 371 372 373 374
     * @override
     */
    public function supportsForeignKeyConstraints()
    {
        return false;
    }
375

376 377 378 379 380
    public function supportsAlterTable()
    {
        return false;
    }

381 382 383 384 385 386 387 388 389
    /**
     * Get the platform name for this instance
     *
     * @return string
     */
    public function getName()
    {
        return 'sqlite';
    }
390 391 392 393

    /**
     * @inheritdoc
     */
394
    public function getTruncateTableSQL($tableName, $cascade = false)
395 396 397
    {
        return 'DELETE FROM '.$tableName;
    }
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

    /**
     * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction()
     *
     * @param  int|float $value
     * @return float
     */
    static public function udfSqrt($value)
    {
        return sqrt($value);
    }

    /**
     * User-defined function for Sqlite that implements MOD(a, b)
     */
    static public function udfMod($a, $b)
    {
        return ($a % $b);
    }
417 418 419 420 421 422 423 424 425 426 427 428 429 430

    /**
     * @param string $str
     * @param string $substr
     * @param int $offset
     */
    static public function udfLocate($str, $substr, $offset = 0)
    {
        $pos = strpos($str, $substr, $offset);
        if ($pos !== false) {
            return $pos+1;
        }
        return 0;
    }
431
}