Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
15.38% covered (danger)
15.38%
4 / 26
8.33% covered (danger)
8.33%
1 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
MySQLPlatform
15.38% covered (danger)
15.38%
4 / 26
8.33% covered (danger)
8.33%
1 / 12
237.70
0.00% covered (danger)
0.00%
0 / 1
 getIdentifierQuoteChar
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildStringCast
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildIntegerCast
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 normalizeJoinType
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
5.02
 useIndexClause
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 ignoreIndexClause
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 deleteJoinSqlText
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 isTransactableQuery
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 buildExcludedValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 lockSQLText
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 unlockSQLText
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 makeLockName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6namespace Wikimedia\Rdbms\Platform;
7
8use Wikimedia\Rdbms\DBLanguageError;
9use Wikimedia\Rdbms\Query;
10
11/**
12 * @since 1.39
13 * @see ISQLPlatform
14 */
15class MySQLPlatform extends SQLPlatform {
16    /** @inheritDoc */
17    protected function getIdentifierQuoteChar() {
18        return '`';
19    }
20
21    /** @inheritDoc */
22    public function buildStringCast( $field ) {
23        return "CAST( $field AS BINARY )";
24    }
25
26    /**
27     * @param string $field Field or column to cast
28     * @return string
29     */
30    public function buildIntegerCast( $field ) {
31        return 'CAST( ' . $field . ' AS SIGNED )';
32    }
33
34    /** @inheritDoc */
35    protected function normalizeJoinType( string $joinType ) {
36        switch ( strtoupper( $joinType ) ) {
37            case 'STRAIGHT_JOIN':
38            case 'STRAIGHT JOIN':
39                return 'STRAIGHT_JOIN';
40
41            default:
42                return parent::normalizeJoinType( $joinType );
43        }
44    }
45
46    /**
47     * @param string $index
48     * @return string
49     */
50    public function useIndexClause( $index ) {
51        return "FORCE INDEX (" . $index . ")";
52    }
53
54    /**
55     * @param string $index
56     * @return string
57     */
58    public function ignoreIndexClause( $index ) {
59        return "IGNORE INDEX (" . $index . ")";
60    }
61
62    /** @inheritDoc */
63    public function deleteJoinSqlText( $delTable, $joinTable, $delVar, $joinVar, $conds ) {
64        if ( !$conds ) {
65            throw new DBLanguageError( __METHOD__ . ' called with empty $conds' );
66        }
67
68        $delTable = $this->tableName( $delTable );
69        $joinTable = $this->tableName( $joinTable );
70        $sql = "DELETE $delTable FROM $delTable$joinTable WHERE $delVar=$joinVar ";
71
72        if ( $conds != '*' ) {
73            $sql .= ' AND ' . $this->makeList( $conds, self::LIST_AND );
74        }
75
76        return $sql;
77    }
78
79    /** @inheritDoc */
80    public function isTransactableQuery( Query $sql ) {
81        return parent::isTransactableQuery( $sql ) &&
82            // TODO: Use query verb
83            !preg_match( '/^SELECT\s+(GET|RELEASE|IS_FREE)_LOCK\(/', $sql->getSQL() );
84    }
85
86    /** @inheritDoc */
87    public function buildExcludedValue( $column ) {
88        /* @see DatabaseMySQL::upsert() */
89        // Within "INSERT INTO ON DUPLICATE KEY UPDATE" statements:
90        //   - MySQL>= 8.0.20 supports and prefers "VALUES ... AS".
91        //   - MariaDB >= 10.3.3 supports and prefers VALUE().
92        //   - Both support the old VALUES() function
93        // https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
94        // https://mariadb.com/kb/en/insert-on-duplicate-key-update/
95        return "VALUES($column)";
96    }
97
98    /** @inheritDoc */
99    public function lockSQLText( $lockName, $timeout ) {
100        $encName = $this->quoter->addQuotes( $this->makeLockName( $lockName ) );
101        // Unlike NOW(), SYSDATE() gets the time at invocation rather than query start.
102        // The precision argument is silently ignored for MySQL < 5.6 and MariaDB < 5.3.
103        // https://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_sysdate
104        // https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
105        return "SELECT IF(GET_LOCK($encName,$timeout),UNIX_TIMESTAMP(SYSDATE(6)),NULL) AS acquired";
106    }
107
108    /** @inheritDoc */
109    public function unlockSQLText( $lockName ) {
110        $encName = $this->quoter->addQuotes( $this->makeLockName( $lockName ) );
111        return "SELECT RELEASE_LOCK($encName) AS released";
112    }
113
114    /** @inheritDoc */
115    public function makeLockName( $lockName ) {
116        // https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html#function_get-lock
117        // MySQL 5.7+ enforces a 64 char length limit.
118        return ( strlen( $lockName ) > 64 ) ? sha1( $lockName ) : $lockName;
119    }
120}