Aleksander Machniak
2014-09-12 34a0902089a410d1f7dda78d1f8b0771333c09df
program/lib/Roundcube/rcube_db.php
@@ -50,6 +50,7 @@
    );
    const DEBUG_LINE_LENGTH = 4096;
    const DEFAULT_QUOTE     = '`';
    /**
     * Factory, returns driver-specific instance of the class
@@ -68,6 +69,7 @@
            'sybase'  => 'mssql',
            'dblib'   => 'mssql',
            'mysqli'  => 'mysql',
            'oci'     => 'oracle',
        );
        $driver = isset($driver_map[$driver]) ? $driver_map[$driver] : $driver;
@@ -237,8 +239,12 @@
        // Read or write ?
        $mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w';
        $start = '[' . $this->options['identifier_start'] . self::DEFAULT_QUOTE . ']';
        $end   = '[' . $this->options['identifier_end']   . self::DEFAULT_QUOTE . ']';
        $regex = '/(?:^|\s)(from|update|into|join)\s+'.$start.'?([a-z0-9._]+)'.$end.'?\s+/i';
        // find tables involved in this query
        if (preg_match_all('/(?:^|\s)(from|update|into|join)\s+'.$this->options['identifier_start'].'?([a-z0-9._]+)'.$this->options['identifier_end'].'?\s+/i', $query, $matches, PREG_SET_ORDER)) {
        if (preg_match_all($regex, $query, $matches, PREG_SET_ORDER)) {
            foreach ($matches as $m) {
                $table = $m[2];
@@ -407,6 +413,9 @@
            $query = $this->set_limit($query, $numrows, $offset);
        }
        // replace self::DEFAULT_QUOTE with driver-specific quoting
        $query = $this->query_parse($query);
        // Because in Roundcube we mostly use queries that are
        // executed only once, we will not use prepared queries
        $pos = 0;
@@ -430,6 +439,7 @@
        $query = str_replace('??', '?', $query);
        $query = rtrim($query, " \t\n\r\0\x0B;");
        // log query
        $this->debug($query);
        // destroy reference to previous result, required for SQLite driver (#1488874)
@@ -446,6 +456,51 @@
        $this->last_result = $result;
        return $result;
    }
    /**
     * Parse SQL query and replace identifier quoting
     *
     * @param string $query SQL query
     *
     * @return string SQL query
     */
    protected function query_parse($query)
    {
        $start = $this->options['identifier_start'];
        $end   = $this->options['identifier_end'];
        $quote = self::DEFAULT_QUOTE;
        if ($start == $quote) {
            return $query;
        }
        $pos = 0;
        $in  = false;
        while ($pos = strpos($query, $quote, $pos)) {
            if ($query[$pos+1] == $quote) {  // skip escaped quote
                $pos += 2;
            }
            else {
                if ($in) {
                    $q  = $end;
                    $in = false;
                }
                else {
                    $q  = $start;
                    $in = true;
                }
                $query = substr_replace($query, $q, $pos, 1);
                $pos++;
            }
        }
        // replace escaped quote back to normal, see self::quote()
        $query = str_replace($quote.$quote, $quote, $query);
        return $query;
    }
    /**
@@ -611,8 +666,7 @@
    {
        // get tables if not cached
        if ($this->tables === null) {
            $q = $this->query('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME',
                array($this->db_dsnw_array['database']));
            $q = $this->query('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_NAME');
            if ($q) {
                $this->tables = $q->fetchAll(PDO::FETCH_COLUMN, 0);
@@ -634,8 +688,8 @@
     */
    public function list_cols($table)
    {
        $q = $this->query('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?',
            array($table, $this->db_dsnw_array['database']));
        $q = $this->query('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?',
            array($table));
        if ($q) {
            return $q->fetchAll(PDO::FETCH_COLUMN, 0);
@@ -677,8 +731,13 @@
                'bool'    => PDO::PARAM_BOOL,
                'integer' => PDO::PARAM_INT,
            );
            $type = isset($map[$type]) ? $map[$type] : PDO::PARAM_STR;
            return strtr($this->dbh->quote($input, $type), array('?' => '??'));  // escape ?
            return strtr($this->dbh->quote($input, $type),
                // escape ? and `
                array('?' => '??', self::DEFAULT_QUOTE => self::DEFAULT_QUOTE.self::DEFAULT_QUOTE)
            );
        }
        return 'NULL';
@@ -917,15 +976,20 @@
    /**
     * Return correct name for a specific database table
     *
     * @param string $table Table name
     * @param string $table  Table name
     * @param bool   $quoted Quote table identifier
     *
     * @return string Translated table name
     */
    public function table_name($table)
    public function table_name($table, $quoted = false)
    {
        // add prefix to the table name if configured
        if (($prefix = $this->options['table_prefix']) && strpos($table, $prefix) !== 0) {
            return $prefix . $table;
            $table = $prefix . $table;
        }
        if ($quoted) {
            $table = $this->quote_identifier($table);
        }
        return $table;