diff --git a/DatabaseMysql.php b/DatabaseMysql.php index a7ecbbf..87fb91f 100644 --- a/DatabaseMysql.php +++ b/DatabaseMysql.php @@ -4,7 +4,8 @@ * Very stable interface for MySQL - object-oriented at last :) * Select builder is inspired by MediaWiki's one. * Also usable for querying SphinxQL. - * (c) Vitaliy Filippov, 2012-2013 + * Version: 2015-05-12 + * (c) Vitaliy Filippov, 2012-2015 */ if (!defined('MS_HASH')) @@ -18,7 +19,13 @@ if (!defined('MS_HASH')) define('MS_RESULT', 8); } -class DatabaseException extends Exception {} +class DatabaseException extends Exception +{ + function isDuplicateKey() + { + return $this->getCode() == 1062; + } +} if (!interface_exists('Database')) { @@ -30,7 +37,7 @@ class DatabaseMysql implements Database var $host, $port, $socket, $username, $password, $dbname; var $tableNames = array(); - var $queryLogFile; + var $queryLogFile, $loggedQueries = ''; var $reconnect = true; var $autoBegin; var $ondestroy = 'commit'; @@ -89,6 +96,10 @@ class DatabaseMysql implements Database $this->transactions = array(false); $this->$o(); } + if ($this->queryLogFile) + { + file_put_contents($this->queryLogFile, $this->loggedQueries, FILE_APPEND); + } } function connect() @@ -167,7 +178,7 @@ class DatabaseMysql implements Database $this->queryCount++; if ($this->queryLogFile) { - file_put_contents($this->queryLogFile, date("[Y-m-d H:i:s] ").$sql."\n", FILE_APPEND); + $this->loggedQueries .= date("[Y-m-d H:i:s] ").$sql."\n"; } $r = $this->link->query($sql, $fetchMode); if (!$r) @@ -356,11 +367,36 @@ class DatabaseMysql implements Database else { if (is_array(reset($v))) + { + // (a,b) IN ((1,2), (3,4)) ... foreach ($v as &$l) + { $l = "(" . implode(",", array_map(array($this, 'quote'), $l)) . ")"; + } + $wh[] = "$k IN (" . implode(",", $v) . ")"; + } else - $v = array_map(array($this, 'quote'), $v); - $wh[] = "$k IN (" . implode(",", $v) . ")"; + { + $r = ''; + $null = false; + foreach ($v as $i => $l) + { + if ($l === NULL) + { + $null = true; + } + else + { + $r .= $this->quote($l).','; + } + } + $r = $r !== '' ? "$k IN (" . substr($r, 0, -1) . ")" : ''; + if ($null) + { + $r = $r !== '' ? "($r OR $k IS NULL)" : "$k IS NULL"; + } + $wh[] = $r; + } } } elseif (preg_match('/^-?\d+(\.\d+)?$/s', $v)) // int/float @@ -403,6 +439,7 @@ class DatabaseMysql implements Database * Sphinx Search extensions: * 'WITHIN GROUP ORDER BY' => array($orderby_field => 'ASC') * 'FIELD_WEIGHTS' => array('field' => , ...) + * 'RANKER' => bm25|sph04|...|expr('...ranker expression...') */ function select_builder($tables, $fields, $where, $options = NULL) { @@ -449,15 +486,24 @@ class DatabaseMysql implements Database $sql .= " WITHIN GROUP ORDER BY ".$this->order_option($options['WITHIN GROUP ORDER BY']); } $sql .= $this->limit_option($options); - if (!empty($options['FIELD_WEIGHTS'])) + if (!empty($options['FIELD_WEIGHTS']) || !empty($options['RANKER'])) { // Sphinx Search extension - $weights = array(); - foreach ($options['FIELD_WEIGHTS'] as $f => $w) + $opt = array(); + if (!empty($options['FIELD_WEIGHTS'])) { - $weights[] = "`$f`=$w"; + $weights = array(); + foreach ($options['FIELD_WEIGHTS'] as $f => $w) + { + $weights[] = "`$f`=$w"; + } + $opt[] = "field_weights=(".implode(', ', $weights).")"; } - $sql .= " OPTION field_weights=(".implode(', ', $weights).")"; + if (!empty($options['RANKER'])) + { + $opt[] = "ranker=".$options['RANKER']; + } + $sql .= " OPTION ".implode(', ', $opt); } if (isset($options['FOR UPDATE'])) $sql .= ' FOR UPDATE';