Template and DatabaseMysql fixes
parent
5b65c532fa
commit
3c42bf9861
|
@ -17,14 +17,19 @@ if (!defined('MS_HASH'))
|
|||
define('MS_RESULT', 8);
|
||||
}
|
||||
|
||||
class DatabaseException extends Exception {}
|
||||
|
||||
class DatabaseMysql
|
||||
{
|
||||
var $host, $port, $socket, $username, $password, $dbName;
|
||||
|
||||
var $link;
|
||||
var $tableNames = array();
|
||||
var $queryCount = 0;
|
||||
var $queryLogFile;
|
||||
var $reconnect = true;
|
||||
|
||||
var $queryCount = 0;
|
||||
var $link;
|
||||
var $transactions;
|
||||
|
||||
/**
|
||||
* Creates a MySQL connection object.
|
||||
|
@ -46,7 +51,7 @@ class DatabaseMysql
|
|||
}
|
||||
else
|
||||
{
|
||||
if ($host[1])
|
||||
if (isset($host[1]))
|
||||
{
|
||||
$port = $host[1];
|
||||
}
|
||||
|
@ -56,7 +61,6 @@ class DatabaseMysql
|
|||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->dbname = $dbname;
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
function connect()
|
||||
|
@ -89,7 +93,13 @@ class DatabaseMysql
|
|||
function quote($value)
|
||||
{
|
||||
if ($value === NULL)
|
||||
{
|
||||
return "NULL";
|
||||
}
|
||||
if (!$this->link)
|
||||
{
|
||||
$this->connect();
|
||||
}
|
||||
return "'" . $this->link->real_escape_string($value) . "'";
|
||||
}
|
||||
|
||||
|
@ -100,9 +110,100 @@ class DatabaseMysql
|
|||
{
|
||||
file_put_contents($this->queryLogFile, date("[Y-m-d H:i:s] ").$sql."\n", FILE_APPEND);
|
||||
}
|
||||
return $this->link->query($sql, $fetchMode);
|
||||
if (!$this->link)
|
||||
{
|
||||
$this->connect();
|
||||
}
|
||||
$r = $this->link->query($sql, $fetchMode);
|
||||
if (!$r)
|
||||
{
|
||||
if ($this->link->errno == 2006 && $this->reconnect)
|
||||
{
|
||||
// "MySQL server has gone away"
|
||||
$this->link = false;
|
||||
}
|
||||
throw new DatabaseException($this->link->error, $this->link->errno);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a transaction, supports nested calls and savepoints.
|
||||
* @param boolean $savepoint Creates savepoints only this parameter is true.
|
||||
*/
|
||||
function begin($savepoint = false)
|
||||
{
|
||||
$this->transactions[] = $savepoint;
|
||||
$n = count($this->transactions);
|
||||
if ($n == 1)
|
||||
{
|
||||
return $this->query("BEGIN");
|
||||
}
|
||||
elseif ($savepoint)
|
||||
{
|
||||
return $this->query("SAVEPOINT sp$n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits transaction or releases last savepoint.
|
||||
* If there is no last savepoint, just returns true.
|
||||
*/
|
||||
function commit()
|
||||
{
|
||||
$savepoint = array_pop($this->transactions);
|
||||
if (!$this->transactions)
|
||||
{
|
||||
return $this->query("COMMIT");
|
||||
}
|
||||
elseif ($savepoint)
|
||||
{
|
||||
return $this->query("RELEASE SAVEPOINT sp".count($this->transactions));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollbacks transaction or last savepoint.
|
||||
* If there is no savepoint, returns false.
|
||||
*/
|
||||
function rollback()
|
||||
{
|
||||
$savepoint = array_pop($this->transactions);
|
||||
if (!$this->transactions)
|
||||
{
|
||||
return $this->query("ROLLBACK");
|
||||
}
|
||||
elseif ($savepoint)
|
||||
{
|
||||
return $this->query("ROLLBACK TO SAVEPOINT sp".count($this->transactions));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function errno()
|
||||
{
|
||||
return $this->link->errno;
|
||||
}
|
||||
|
||||
function error()
|
||||
{
|
||||
return $this->link->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds WHERE-part of an SQL query.
|
||||
* $where can also be a string - then it's passed as-is.
|
||||
*
|
||||
* @param array $where Query conditions:
|
||||
* array(
|
||||
* 'conditional expression',
|
||||
* 'field_name' => 'value',
|
||||
* 'field_name' => array('one', 'of', 'values'),
|
||||
* 'field1,field2' => array(array(1, 2), array(3, 4)),
|
||||
* )
|
||||
*/
|
||||
function where_builder($where)
|
||||
{
|
||||
if (!is_array($where))
|
||||
|
@ -140,6 +241,24 @@ class DatabaseMysql
|
|||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an SQL query text.
|
||||
*
|
||||
* @param mixed $tables see $this->tablesBuilder()
|
||||
* @param mixed $fields Field definitions - either a string or an array.
|
||||
* Strings are passed to resulting query text as-is.
|
||||
* Arrays have the following format:
|
||||
* array('field1', 'alias2' => 'expression2', ...)
|
||||
* @param mixed $where see $this->whereBuilder()
|
||||
* @param array $options query options - array of:
|
||||
* 'CALC_FOUND_ROWS'
|
||||
* 'NO_CACHE' or 'CACHE'
|
||||
* 'FOR UPDATE' or 'LOCK IN SHARE MODE'
|
||||
* 'GROUP BY' => array($groupby_field1 => 'ASC', $groupby_field2 => 'DESC')
|
||||
* 'ORDER BY' => array($orderby_field1 => 'ASC', $orderby_field2 => 'DESC')
|
||||
* 'LIMIT' => array($limit, $offset) or array($limit) or just $limit
|
||||
* 'OFFSET' => $offset, for the case when 'LIMIT' is just $limit
|
||||
*/
|
||||
function select_builder($tables, $fields, $where, $options = NULL)
|
||||
{
|
||||
if (!$options)
|
||||
|
@ -151,19 +270,25 @@ class DatabaseMysql
|
|||
$options[$v] = true;
|
||||
}
|
||||
if (is_array($fields))
|
||||
{
|
||||
foreach ($fields as $k => $v)
|
||||
if (!ctype_digit($k))
|
||||
$fields[$k] = "$v AS ".$this->quoteId($k);
|
||||
$fields = join(',', $fields);
|
||||
}
|
||||
$where = $this->where_builder($where);
|
||||
$tables = $this->tables_builder($tables);
|
||||
$sql = 'SELECT ';
|
||||
if ($options['CALC_FOUND_ROWS'] || $options['SQL_CALC_FOUND_ROWS'])
|
||||
if (isset($options['CALC_FOUND_ROWS']) || isset($options['SQL_CALC_FOUND_ROWS']))
|
||||
$sql .= 'SQL_CALC_FOUND_ROWS ';
|
||||
if ($options['NO_CACHE'] || $options['SQL_NO_CACHE'])
|
||||
if (isset($options['NO_CACHE']) || isset($options['SQL_NO_CACHE']))
|
||||
$sql .= 'SQL_NO_CACHE ';
|
||||
elseif ($options['CACHE'] || $options['SQL_CACHE'])
|
||||
elseif (isset($options['CACHE']) || isset($options['SQL_CACHE']))
|
||||
$sql .= 'SQL_CACHE ';
|
||||
$sql .= "$fields FROM $tables WHERE $where";
|
||||
if ($g = $options['GROUP BY'])
|
||||
if (isset($options['GROUP BY']))
|
||||
{
|
||||
$g = $options['GROUP BY'];
|
||||
if (is_array($g))
|
||||
{
|
||||
$g1 = array();
|
||||
|
@ -178,8 +303,9 @@ class DatabaseMysql
|
|||
}
|
||||
$sql .= " GROUP BY $g";
|
||||
}
|
||||
if ($g = $options['ORDER BY'])
|
||||
if (isset($options['ORDER BY']))
|
||||
{
|
||||
$g = $options['ORDER BY'];
|
||||
if (is_array($g))
|
||||
{
|
||||
$g1 = array();
|
||||
|
@ -194,20 +320,44 @@ class DatabaseMysql
|
|||
}
|
||||
$sql .= " ORDER BY $g";
|
||||
}
|
||||
if ($g = $options['LIMIT'])
|
||||
{
|
||||
if (is_array($g))
|
||||
$g = join(',', $g);
|
||||
if ($g)
|
||||
$sql .= " LIMIT $g";
|
||||
}
|
||||
if ($options['FOR UPDATE'])
|
||||
$sql .= $this->limit_option($options);
|
||||
if (isset($options['FOR UPDATE']))
|
||||
$sql .= ' FOR UPDATE';
|
||||
elseif ($options['LOCK IN SHARE MODE'])
|
||||
elseif (isset($options['LOCK IN SHARE MODE']))
|
||||
$sql .= ' LOCK IN SHARE MODE';
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a single LIMIT or LIMIT and OFFSET options.
|
||||
*/
|
||||
function limit_option($options)
|
||||
{
|
||||
if (isset($options['LIMIT']))
|
||||
{
|
||||
$g = $options['LIMIT'];
|
||||
if (is_array($g))
|
||||
$g = join(',', $g);
|
||||
elseif ($g && isset($options['OFFSET']))
|
||||
$g = "$options[OFFSET], $g";
|
||||
if ($g)
|
||||
return " LIMIT $g";
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds FROM-part of an SQL query.
|
||||
*
|
||||
* $tables = array(
|
||||
* 'table',
|
||||
* 'alias' => 'table',
|
||||
* 'alias' => array('INNER', 'table_name', $where_for_on_clause),
|
||||
* 'alias' => array('INNER', $nested_tables),
|
||||
* )
|
||||
* or just a string "`table1` INNER JOIN `table2` ON ..."
|
||||
* names taken into `backticks` will be transformed using $this->tableNames
|
||||
*/
|
||||
function tables_builder($tables)
|
||||
{
|
||||
if (is_array($tables))
|
||||
|
@ -255,15 +405,31 @@ class DatabaseMysql
|
|||
|
||||
function tables_builder_pregcb1($m)
|
||||
{
|
||||
$t = $this->tableNames[$m[2]];
|
||||
if (!$t)
|
||||
$t = $m[2];
|
||||
return $m[1].$t;
|
||||
if (isset($this->tableNames[$m[2]]))
|
||||
return $m[1].$this->tableNames[$m[2]];
|
||||
return $m[1].$m[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a SELECT query and return results.
|
||||
*
|
||||
* Usage: either
|
||||
* $this->select($tables, $fields, $where, $options, $format)
|
||||
* using $this->select_builder() or
|
||||
* $this->select($sql_text, $format)
|
||||
* using query text.
|
||||
*
|
||||
* @param int $format Return format, bitmask of MS_XX constants:
|
||||
* MS_RESULT = return mysqli result object to manually fetch from
|
||||
* MS_LIST = return rows as indexed arrays
|
||||
* MS_HASH = return rows as associative arrays (default)
|
||||
* MS_ROW = only return the first row
|
||||
* MS_COL = only return the first column
|
||||
* MS_VALUE = only return the first cell (just 1 value)
|
||||
*/
|
||||
function select($tables, $fields = '*', $where = 1, $options = NULL, $format = 0)
|
||||
{
|
||||
if (!strcmp(intval($fields), "$fields"))
|
||||
if (ctype_digit("$fields"))
|
||||
{
|
||||
$sql = $tables;
|
||||
$format = $fields;
|
||||
|
@ -280,10 +446,10 @@ class DatabaseMysql
|
|||
$r = array();
|
||||
if ($format & MS_ROW)
|
||||
{
|
||||
if (!count($r))
|
||||
return NULL;
|
||||
if ($format & MS_COL)
|
||||
{
|
||||
if (!count($r))
|
||||
return NULL;
|
||||
$r = $r[0];
|
||||
$k = array_keys($r);
|
||||
$r = $r[$k[0]];
|
||||
|
@ -311,29 +477,37 @@ class DatabaseMysql
|
|||
return $this->select('SELECT FOUND_ROWS()', MS_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a set of rows.
|
||||
* @param mixed $tables see $this->tables_builder()
|
||||
* @param mixed $where see $this->where_builder()
|
||||
* @param array $options Options for query:
|
||||
* 'LIMIT' => array($limit, $offset) or array($limit) or just $limit
|
||||
* 'OFFSET' => $offset, for the case when 'LIMIT' is just $limit
|
||||
*/
|
||||
function delete($tables, $where, $options = NULL)
|
||||
{
|
||||
$tables = $this->tables_builder($tables);
|
||||
$where = $this->where_builder($where);
|
||||
$sql = "DELETE FROM $tables WHERE $where";
|
||||
if (is_array($options))
|
||||
{
|
||||
if ($g = $options['LIMIT'])
|
||||
{
|
||||
if (is_array($g))
|
||||
$g = join(',', $g);
|
||||
if ($g)
|
||||
$sql .= " LIMIT $g";
|
||||
}
|
||||
}
|
||||
$sql .= $this->limit_option($options);
|
||||
$this->query($sql);
|
||||
return $this->link->affected_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an INSERT query.
|
||||
* @param string $table Table name to insert rows to.
|
||||
* @param array $rows Array of table rows to be inserted.
|
||||
* @param boolean $onduplicatekey If true, include
|
||||
* ON DUPLICATE KEY UPDATE column=VALUES(column) for all columns.
|
||||
*/
|
||||
function insert_builder($table, $rows, $onduplicatekey = false)
|
||||
{
|
||||
if ($this->tableNames[$table])
|
||||
if (isset($this->tableNames[$table]))
|
||||
{
|
||||
$table = $this->tableNames[$table];
|
||||
}
|
||||
$key = array_keys($rows[0]);
|
||||
foreach ($rows as &$r)
|
||||
{
|
||||
|
@ -355,6 +529,12 @@ class DatabaseMysql
|
|||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a single row into $table and return inserted ID.
|
||||
* @param string $table Table name to insert row to.
|
||||
* @param array $rows Row to be inserted.
|
||||
* @return int $insert_id Autoincrement ID of inserted row (if appropriate).
|
||||
*/
|
||||
function insert_row($table, $row)
|
||||
{
|
||||
$sql = $this->insert_builder($table, array($row));
|
||||
|
@ -368,6 +548,19 @@ class DatabaseMysql
|
|||
return $this->link->insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update or insert rows into $table.
|
||||
* Update query: $this->update($table, $set, $where, $options);
|
||||
* Insert-or-update query: $this->update($table, $rows);
|
||||
*
|
||||
* @param string $table Table name to update.
|
||||
* @param array $rows One row or array of rows for insert-or-update query.
|
||||
* @param array $set Assoc array with values for update query.
|
||||
* @param array $where Conditions for update query, see $this->where_builder().
|
||||
* @param array $options Options for update query:
|
||||
* 'LIMIT' => array($limit, $offset) or array($limit) or just $limit
|
||||
* 'OFFSET' => $offset, for the case when 'LIMIT' is just $limit
|
||||
*/
|
||||
function update($table, $rows, $where = NULL, $options = NULL)
|
||||
{
|
||||
if (!$rows)
|
||||
|
@ -394,16 +587,7 @@ class DatabaseMysql
|
|||
}
|
||||
$where = $this->where_builder($where);
|
||||
$sql = 'UPDATE ' . $this->tables_builder($table) . ' SET ' . implode(', ', $sql) . ' WHERE ' . $where;
|
||||
if (is_array($options))
|
||||
{
|
||||
if ($g = $options['LIMIT'])
|
||||
{
|
||||
if (is_array($g))
|
||||
$g = join(',', $g);
|
||||
if ($g)
|
||||
$sql .= " LIMIT $g";
|
||||
}
|
||||
}
|
||||
$sql .= $this->limit_option($options);
|
||||
}
|
||||
if ($this->query($sql))
|
||||
return $this->link->affected_rows;
|
||||
|
|
Loading…
Reference in New Issue