Merge changes from develop
diff --git a/.travis.yml b/.travis.yml
index 62acf05..1c7e876 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,4 +29,4 @@
branches:
only:
- develop
- - /^feature\/.+$/
\ No newline at end of file
+ - /^feature.+/
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index ea2a53e..ea56d38 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -1124,30 +1124,19 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause
- * @param array the limit clause
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
foreach ($values as $key => $val)
{
$valstr[] = $key.' = '.$val;
}
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
- .($limit ? ' LIMIT '.$limit : '');
+ .$this->_compile_wh('qb_where')
+ .$this->_compile_order_by()
+ .($this->qb_limit ? ' LIMIT '.$this->qb_limit : '');
}
// --------------------------------------------------------------------
@@ -1160,7 +1149,7 @@
*/
protected function _has_operator($str)
{
- return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL|BETWEEN)/i', trim($str));
+ return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str));
}
// --------------------------------------------------------------------
@@ -1173,8 +1162,31 @@
*/
protected function _get_operator($str)
{
- return preg_match('/(=|!|<|>| IS NULL| IS NOT NULL| BETWEEN)/i', $str, $match)
- ? $match[1] : FALSE;
+ static $_operators;
+
+ if (empty($_operators))
+ {
+ $_les = ($this->_like_escape_str !== '')
+ ? preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)))
+ : '';
+
+ $_operators = array(
+ '\s*(?:<|>|!)?=\s*', // =, <=, >=, !=
+ '\s*<>?\s*', // <, <>
+ '\s*>\s*', // >
+ '\s+IS NULL', // IS NULL
+ '\s+IS NOT NULL', // IS NOT NULL
+ '\s+BETWEEN\s+\S+\s+AND\s+\S+', // BETWEEN value AND value
+ '\s+IN\s*\([^\)]+\)', // IN(list)
+ '\s+NOT IN\s*\([^\)]+\)', // NOT IN (list)
+ '\s+LIKE\s+\S+'.$_les, // LIKE 'expr'[ ESCAPE '%s']
+ '\s+NOT LIKE\s+\S+'.$_les // NOT LIKE 'expr'[ ESCAPE '%s']
+ );
+
+ }
+
+ return preg_match('/'.implode('|', $_operators).'/i', $str, $match)
+ ? $match[0] : FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 54510ec..139f467 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -47,7 +47,6 @@
protected $qb_from = array();
protected $qb_join = array();
protected $qb_where = array();
- protected $qb_like = array();
protected $qb_groupby = array();
protected $qb_having = array();
protected $qb_keys = array();
@@ -55,7 +54,6 @@
protected $qb_offset = FALSE;
protected $qb_orderby = array();
protected $qb_set = array();
- protected $qb_wherein = array();
protected $qb_aliased_tables = array();
protected $qb_store_array = array();
protected $qb_where_group_started = FALSE;
@@ -417,7 +415,7 @@
*/
public function where($key, $value = NULL, $escape = NULL)
{
- return $this->_where($key, $value, 'AND ', $escape);
+ return $this->_wh('qb_where', $key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
@@ -435,24 +433,27 @@
*/
public function or_where($key, $value = NULL, $escape = NULL)
{
- return $this->_where($key, $value, 'OR ', $escape);
+ return $this->_wh('qb_where', $key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * Called by where(), or_where(), having(), or_having()
*
+ * @param string 'qb_where' or 'qb_having'
* @param mixed
* @param mixed
* @param string
- * @param mixed
+ * @param bool
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -463,17 +464,10 @@
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- if ($escape === TRUE)
- {
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->escape_identifiers(trim(substr($k, 0, strpos($k, $op)))).' '.strstr($k, $op)
- : $this->escape_identifiers(trim($k));
- }
-
if (is_null($v) && ! $this->_has_operator($k))
{
// value appears not to have been set, assign the test to IS NULL
@@ -484,7 +478,7 @@
{
if ($escape === TRUE)
{
- $v = ' '.$this->escape($v);
+ $v = ' '.(is_int($v) ? $v : $this->escape($v));
}
if ( ! $this->_has_operator($k))
@@ -493,11 +487,11 @@
}
}
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
@@ -602,27 +596,25 @@
$not = ($not) ? ' NOT' : '';
+ $where_in = array();
foreach ($values as $value)
{
- $this->qb_wherein[] = $this->escape($value);
- }
-
- if ($escape === TRUE)
- {
- $key = $this->escape_identifiers(trim($key));
+ $wherein[] = $this->escape($value);
}
$prefix = (count($this->qb_where) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type);
- $this->qb_where[] = $where_in = $prefix.$key.$not.' IN ('.implode(', ', $this->qb_wherein).') ';
+ $where_in = array(
+ 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')',
+ 'escape' => $escape
+ );
+ $this->qb_where[] = $where_in;
if ($this->qb_caching === TRUE)
{
$this->qb_cache_where[] = $where_in;
$this->qb_cache_exists[] = 'where';
}
- // reset the array for multiple calls
- $this->qb_wherein = array();
return $this;
}
@@ -635,12 +627,14 @@
* multiple calls with AND
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function like($field, $match = '', $side = 'both')
+ public function like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'AND ', $side);
+ return $this->_like($field, $match, 'AND ', $side, '', $escape);
}
// --------------------------------------------------------------------
@@ -652,12 +646,14 @@
* multiple calls with AND
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function not_like($field, $match = '', $side = 'both')
+ public function not_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'AND ', $side, 'NOT');
+ return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape);
}
// --------------------------------------------------------------------
@@ -669,12 +665,14 @@
* multiple calls with OR
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function or_like($field, $match = '', $side = 'both')
+ public function or_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'OR ', $side);
+ return $this->_like($field, $match, 'OR ', $side, '', $escape);
}
// --------------------------------------------------------------------
@@ -686,12 +684,14 @@
* multiple calls with OR
*
* @param mixed
- * @param mixed
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- public function or_not_like($field, $match = '', $side = 'both')
+ public function or_not_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'OR ', $side, 'NOT');
+ return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape);
}
// --------------------------------------------------------------------
@@ -699,56 +699,60 @@
/**
* Like
*
- * Called by like() or orlike()
+ * Called by like(), or_like(), not_like, or_not_like()
*
* @param mixed
- * @param mixed
* @param string
+ * @param string
+ * @param string
+ * @param string
+ * @param bool
* @return object
*/
- protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
+ protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = NULL)
{
if ( ! is_array($field))
{
$field = array($field => $match);
}
+ is_bool($escape) OR $escape = $this->_protect_identifiers;
+ $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ ? $this->_group_get_type('') : $this->_group_get_type($type);
+
foreach ($field as $k => $v)
{
- $k = $this->protect_identifiers($k);
- $prefix = (count($this->qb_like) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type);
$v = $this->escape_like_str($v);
if ($side === 'none')
{
- $like_statement = "{$prefix} $k $not LIKE '{$v}'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}'";
}
elseif ($side === 'before')
{
- $like_statement = "{$prefix} $k $not LIKE '%{$v}'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}'";
}
elseif ($side === 'after')
{
- $like_statement = "{$prefix} $k $not LIKE '{$v}%'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}%'";
}
else
{
- $like_statement = "{$prefix} $k $not LIKE '%{$v}%'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}%'";
}
// some platforms require an escape sequence definition for LIKE wildcards
if ($this->_like_escape_str !== '')
{
- $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ $like_statement .= sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
- $this->qb_like[] = $like_statement;
+ $this->qb_where[] = array('condition' => $like_statement, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_like[] = $like_statement;
- $this->qb_cache_exists[] = 'like';
+ $this->qb_cache_where[] = $like_statement;
+ $this->qb_cache_exists[] = 'where';
}
-
}
return $this;
@@ -769,11 +773,15 @@
$this->qb_where_group_started = TRUE;
$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
- $this->qb_where[] = $value = $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (';
+ $where = array(
+ 'condition' => $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (',
+ 'escape' => FALSE
+ );
+ $this->qb_where[] = $where;
if ($this->qb_caching)
{
- $this->qb_cache_where[] = $value;
+ $this->qb_cache_where[] = $where;
}
return $this;
@@ -825,11 +833,15 @@
public function group_end()
{
$this->qb_where_group_started = FALSE;
- $this->qb_where[] = $value = str_repeat(' ', $this->qb_where_group_count--) . ')';
+ $where = array(
+ 'condition' => str_repeat(' ', $this->qb_where_group_count--).')',
+ 'escape' => FALSE
+ );
+ $this->qb_where[] = $where;
if ($this->qb_caching)
{
- $this->qb_cache_where[] = $value;
+ $this->qb_cache_where[] = $where;
}
return $this;
@@ -862,13 +874,18 @@
* GROUP BY
*
* @param string
+ * @param bool
* @return object
*/
- public function group_by($by)
+ public function group_by($by, $escape = NULL)
{
+ is_bool($escape) OR $escape = $this->_protect_identifiers;
+
if (is_string($by))
{
- $by = explode(',', $by);
+ $by = ($escape === TRUE)
+ ? explode(',', $by)
+ : array($by);
}
foreach ($by as $val)
@@ -877,8 +894,9 @@
if ($val !== '')
{
- $this->qb_groupby[] = $val = $this->protect_identifiers($val);
+ $val = array('field' => $val, 'escape' => $escape);
+ $this->qb_groupby[] = $val;
if ($this->qb_caching === TRUE)
{
$this->qb_cache_groupby[] = $val;
@@ -904,7 +922,7 @@
*/
public function having($key, $value = '', $escape = NULL)
{
- return $this->_having($key, $value, 'AND ', $escape);
+ return $this->_wh('qb_having', $key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
@@ -921,58 +939,7 @@
*/
public function or_having($key, $value = '', $escape = NULL)
{
- return $this->_having($key, $value, 'OR ', $escape);
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Sets the HAVING values
- *
- * Called by having() or or_having()
- *
- * @param string
- * @param string
- * @param string
- * @param bool
- * @return object
- */
- protected function _having($key, $value = '', $type = 'AND ', $escape = NULL)
- {
- if ( ! is_array($key))
- {
- $key = array($key => $value);
- }
-
- is_bool($escape) OR $escape = $this->_protect_identifiers;
-
- foreach ($key as $k => $v)
- {
- $prefix = (count($this->qb_having) === 0) ? '' : $type;
-
- $k = $this->_has_operator($k)
- ? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
- : $this->protect_identifiers($k, FALSE, $escape);
-
- if ( ! $this->_has_operator($k))
- {
- $k .= ' = ';
- }
-
- if ($v !== '')
- {
- $v = ' '.$this->escape($v);
- }
-
- $this->qb_having[] = $prefix.$k.$v;
- if ($this->qb_caching === TRUE)
- {
- $this->qb_cache_having[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'having';
- }
- }
-
- return $this;
+ return $this->_wh('qb_having', $key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
@@ -981,54 +948,50 @@
* Sets the ORDER BY value
*
* @param string
- * @param string direction: asc or desc
+ * @param string direction: ASC or DESC
* @param bool enable field name escaping
* @return object
*/
public function order_by($orderby, $direction = '', $escape = NULL)
{
- if (strtolower($direction) === 'random')
+ $direction = trim($direction);
+
+ if (strtolower($direction) === 'random' OR $orderby === $this->_random_keyword)
{
- $orderby = ''; // Random results want or don't need a field name
- $direction = $this->_random_keyword;
+ // Random ordered results don't need a field name
+ $orderby = $this->_random_keyword;
+ $direction = '';
}
- elseif (trim($direction) !== '')
+ elseif (empty($orderby))
{
- $direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : ' ASC';
+ return $this;
+ }
+ elseif ($direction !== '')
+ {
+ $direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : '';
}
is_bool($escape) OR $escape = $this->_protect_identifiers;
- if ($escape === TRUE && strpos($orderby, ',') !== FALSE)
+ if ($escape === FALSE)
{
- $temp = array();
- foreach (explode(',', $orderby) as $part)
+ $qb_orderby[] = array(array('field' => $orderby, 'direction' => $direction, $escape => FALSE));
+ }
+ else
+ {
+ $qb_orderby = array();
+ foreach (explode(',', $orderby) as $field)
{
- $part = trim($part);
- if ( ! in_array($part, $this->qb_aliased_tables))
- {
- $part = preg_match('/^(.+)\s+(ASC|DESC)$/i', $part, $matches)
- ? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
- : $this->protect_identifiers($part);
- }
-
- $temp[] = $part;
+ $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE))
+ ? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE)
+ : array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE);
}
-
- $orderby = implode(', ', $temp);
- }
- elseif ($direction !== $this->_random_keyword && $escape === TRUE)
- {
- $orderby = preg_match('/^(.+)\s+(ASC|DESC)$/i', $orderby, $matches)
- ? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
- : $this->protect_identifiers($orderby);
}
- $this->qb_orderby[] = $orderby_statement = $orderby.$direction;
-
+ $this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_orderby[] = $orderby_statement;
+ $this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby);
$this->qb_cache_exists[] = 'orderby';
}
@@ -1044,7 +1007,7 @@
* @param int the offset value
* @return object
*/
- public function limit($value, $offset = NULL)
+ public function limit($value, $offset = FALSE)
{
is_null($value) OR $this->qb_limit = (int) $value;
empty($offset) OR $this->qb_offset = (int) $offset;
@@ -1074,13 +1037,11 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.($offset ? $offset.', ' : '').$limit;
+ return $sql.' LIMIT '.($this->qb_offset ? $this->qb_offset.', ' : '').$this->qb_limit;
}
// --------------------------------------------------------------------
@@ -1557,7 +1518,7 @@
return FALSE;
}
- $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit);
+ $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set);
if ($reset === TRUE)
{
@@ -1604,7 +1565,7 @@
$this->limit($limit);
}
- $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit, $this->qb_like);
+ $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set);
$this->_reset_write();
return $this->query($sql);
@@ -1686,7 +1647,7 @@
// Batch this baby
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
- $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index), $this->qb_where));
+ $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index)));
}
$this->_reset_write();
@@ -1892,12 +1853,12 @@
$this->limit($limit);
}
- if (count($this->qb_where) === 0 && count($this->qb_wherein) === 0 && count($this->qb_like) === 0)
+ if (count($this->qb_where) === 0)
{
return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE;
}
- $sql = $this->_delete($table, $this->qb_where, $this->qb_like, $this->qb_limit);
+ $sql = $this->_delete($table);
if ($reset_data)
{
$this->_reset_write();
@@ -1914,21 +1875,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table
- .(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '')
- .($limit ? ' LIMIT '.(int) $limit : '');
+ return 'DELETE FROM '.$table.$this->_compile_wh('qb_where')
+ .($this->qb_limit ? ' LIMIT '.$this->qb_limit : '');
}
// --------------------------------------------------------------------
@@ -2066,47 +2018,15 @@
$sql .= "\n".implode("\n", $this->qb_join);
}
- // Write the "WHERE" portion of the query
- if (count($this->qb_where) > 0 OR count($this->qb_like) > 0)
+ $sql .= $this->_compile_wh('qb_where')
+ .$this->_compile_group_by()
+ .$this->_compile_wh('qb_having')
+ .$this->_compile_order_by(); // ORDER BY
+
+ // LIMIT
+ if ($this->qb_limit)
{
- $sql .= "\nWHERE ";
- }
-
- $sql .= implode("\n", $this->qb_where);
-
- // Write the "LIKE" portion of the query
- if (count($this->qb_like) > 0)
- {
- if (count($this->qb_where) > 0)
- {
- $sql .= "\nAND ";
- }
-
- $sql .= implode("\n", $this->qb_like);
- }
-
- // Write the "GROUP BY" portion of the query
- if (count($this->qb_groupby) > 0)
- {
- $sql .= "\nGROUP BY ".implode(', ', $this->qb_groupby);
- }
-
- // Write the "HAVING" portion of the query
- if (count($this->qb_having) > 0)
- {
- $sql .= "\nHAVING ".implode("\n", $this->qb_having);
- }
-
- // Write the "ORDER BY" portion of the query
- if (count($this->qb_orderby) > 0)
- {
- $sql .= "\nORDER BY ".implode(', ', $this->qb_orderby);
- }
-
- // Write the "LIMIT" portion of the query
- if (is_numeric($this->qb_limit))
- {
- return $this->_limit($sql."\n", $this->qb_limit, $this->qb_offset);
+ return $this->_limit($sql."\n");
}
return $sql;
@@ -2115,6 +2035,128 @@
// --------------------------------------------------------------------
/**
+ * Compile WHERE, HAVING statements
+ *
+ * Escapes identifiers in WHERE and HAVING statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * where(), or_where(), having(), or_having are called prior to from(),
+ * join() and dbprefix is added only if needed.
+ *
+ * @param string 'qb_where' or 'qb_having'
+ * @return string SQL statement
+ */
+ protected function _compile_wh($qb_key)
+ {
+ if (count($this->$qb_key) > 0)
+ {
+ $sql = ($qb_key === 'qb_having') ? "\nHAVING " : "\nWHERE ";
+
+ for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++)
+ {
+ if ($this->{$qb_key}[$i]['escape'] === FALSE)
+ {
+ $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
+ continue;
+ }
+
+ $op = preg_quote($this->_get_operator($this->{$qb_key}[$i]['condition']));
+ if ( ! preg_match('/^(\s*(?:AND|OR)\s+)?(\(?)(.*)('.$op.')(.*(?<!\)))?(\)?)$/i', $this->{$qb_key}[$i]['condition'], $matches))
+ {
+ $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
+ continue;
+ }
+
+ // $matches = array(
+ // 0 => 'OR (test <= foo)', /* the whole thing */
+ // 1 => 'OR ', /* optional */
+ // 2 => '(', /* optional */
+ // 3 => 'test', /* the field name */
+ // 4 => ' <= ', /* $op */
+ // 5 => 'foo', /* optional, if $op is e.g. 'IS NULL' */
+ // 6 => ')' /* optional */
+ // );
+ empty($matches[5]) OR $matches[5] = ' '.$this->protect_identifiers(trim($matches[5]));
+ $this->{$qb_key}[$i] = $matches[1].$matches[2].$this->protect_identifiers(trim($matches[3]))
+ .' '.trim($matches[4]).$matches[5].$matches[6];
+ }
+
+ return implode("\n", $this->$qb_key);
+ }
+
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile GROUP BY
+ *
+ * Escapes identifiers in GROUP BY statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * group_by() is called prior to from(), join() and dbprefix is added
+ * only if needed.
+ *
+ * @return string SQL statement
+ */
+ protected function _compile_group_by()
+ {
+ if (count($this->qb_groupby) > 0)
+ {
+ $sql = "\nGROUP BY ";
+
+ for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++)
+ {
+ $this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE)
+ ? $this->qb_groupby[$i]['field']
+ : $this->protect_identifiers($qb_groupby[$i]['field']);
+ }
+
+ $sql .= implode(', ', $this->qb_groupby);
+ }
+
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile ORDER BY
+ *
+ * Escapes identifiers in ORDER BY statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * order_by() is called prior to from(), join() and dbprefix is added
+ * only if needed.
+ *
+ * @return string SQL statement
+ */
+ protected function _compile_order_by()
+ {
+ if (count($this->qb_orderby) > 0)
+ {
+ $sql = "\nORDER BY ";
+
+ for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++)
+ {
+ if ($this->qb_orderby[$i]['escape'] !== FALSE)
+ {
+ $this->qb_orderby[$i]['field'] = $this->protect_identifiers($field);
+ }
+
+ $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction'];
+ }
+
+ $sql .= implode(', ', $this->qb_orderby);
+ }
+
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Object to Array
*
* Takes an object as input and converts the class variables to array key/vals
@@ -2321,11 +2363,9 @@
'qb_from' => array(),
'qb_join' => array(),
'qb_where' => array(),
- 'qb_like' => array(),
'qb_groupby' => array(),
'qb_having' => array(),
'qb_orderby' => array(),
- 'qb_wherein' => array(),
'qb_aliased_tables' => array(),
'qb_no_escape' => array(),
'qb_distinct' => FALSE,
@@ -2350,7 +2390,6 @@
'qb_set' => array(),
'qb_from' => array(),
'qb_where' => array(),
- 'qb_like' => array(),
'qb_orderby' => array(),
'qb_keys' => array(),
'qb_limit' => FALSE
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index 01d0ee3..7f8f297 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -394,10 +394,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -421,9 +421,9 @@
.'ELSE '.$k.' END, ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN ('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php
index ab1d1b8..96d6f65 100644
--- a/system/database/drivers/ibase/ibase_driver.php
+++ b/system/database/drivers/ibase/ibase_driver.php
@@ -281,7 +281,10 @@
*/
protected function _field_data($table)
{
- return $this->_limit('SELECT * FROM '.$this->protect_identifiers($table), 1, NULL);
+ $this->qb_limit = 1;
+ $sql = $this->_limit('SELECT * FROM '.$this->protect_identifiers($table));
+ $this->qb_limit = 0;
+ return $sql;
}
// --------------------------------------------------------------------
@@ -308,29 +311,12 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '');
+ $this->qb_limit = FALSE;
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -359,19 +345,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -382,22 +361,20 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// Limit clause depends on if Interbase or Firebird
if (stripos($this->version(), 'firebird') !== FALSE)
{
- $select = 'FIRST '. (int) $limit
- .($offset ? ' SKIP '. (int) $offset : '');
+ $select = 'FIRST '.$this->qb_limit
+ .($this->qb_offset ? ' SKIP '.$this->qb_offset : '');
}
else
{
$select = 'ROWS '
- .($offset ? (int) $offset.' TO '.($limit + $offset) : (int) $limit);
+ .($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
}
return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index a5ace02..4369bbe 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -368,27 +368,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).' WHERE '.$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -417,23 +403,16 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -444,33 +423,25 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- // As of SQL Server 2012 (11.0.*) OFFSET is supported
- if (version_compare($this->version(), '11', '>='))
- {
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
- }
-
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
// however an ORDER BY clause is required for it to work
- if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+ if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
$sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 7262591..60bcf3c 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -430,10 +430,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -457,9 +457,9 @@
.'ELSE '.$k.' END, ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index b5a1e26..934694c 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -438,10 +438,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -465,11 +465,9 @@
.'ELSE '.$k.' END, ';
}
- $where = ($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 72cbce5..8e4f4ef 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -591,20 +591,17 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
+ if ($this->qb_limit)
+ {
+ $this->where('rownum <= ',$this->qb_limit, FALSE);
+ $this->qb_limit = FALSE;
+ }
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
- empty($limit) OR $conditions[] = 'rownum <= '.$limit;
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -615,15 +612,13 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
$this->limit_used = TRUE;
- return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit + 1).')'
- .($offset ? ' WHERE rnum >= '.($offset + 1): '');
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
+ .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): '');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index c1f6ccf..741b741 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -289,6 +289,24 @@
// --------------------------------------------------------------------
/**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string the table name
+ * @param array the update data
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Truncate statement
*
* Generates a platform-specific truncate string from the supplied data
@@ -307,6 +325,22 @@
// --------------------------------------------------------------------
/**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string the table name
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 0ffe3bc..f4509b1 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -356,14 +356,12 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
- $where = ($where !== '' && count($where) >=1) ? implode(' ', $where).' AND ' : '';
-
foreach ($values as $key => $val)
{
$ids[] = $val[$index];
@@ -377,9 +375,7 @@
}
}
- $sql = 'UPDATE '.$table.' SET ';
$cases = '';
-
foreach ($final as $k => $v)
{
$cases .= $k.' = CASE '."\n";
@@ -392,10 +388,9 @@
$cases .= 'ELSE '.$k.' END, ';
}
- $sql .= substr($cases, 0, -2);
- $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
- return $sql;
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
index efc0500..438d312 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
@@ -136,27 +136,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -167,21 +153,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -192,13 +169,11 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
index cb18a5c..d2a484d 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
@@ -129,10 +129,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -156,9 +156,9 @@
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
index 7c4b008..782bb53 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
@@ -159,27 +159,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -190,23 +176,16 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -217,27 +196,25 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
// however an ORDER BY clause is required for it to work
- if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+ if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
$sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
index 6fba764..32d1f21 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
@@ -145,29 +145,12 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '');
+ $this->qb_limit = FALSE;
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -196,19 +179,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -219,22 +195,20 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// Limit clause depends on if Interbase or Firebird
if (stripos($this->version(), 'firebird') !== FALSE)
{
- $select = 'FIRST '. (int) $limit
- .($offset > 0 ? ' SKIP '. (int) $offset : '');
+ $select = 'FIRST '.$this->qb_limit
+ .($this->qb_offset > 0 ? ' SKIP '.$this->qb_offset : '');
}
else
{
$select = 'ROWS '
- .($offset > 0 ? (int) $offset.' TO '.($limit + $offset) : (int) $limit);
+ .($this->qb_offset > 0 ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
}
return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
index 399182e..22a5f92 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
@@ -171,27 +171,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -202,21 +188,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
index 0281215..8dd4301 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
@@ -165,27 +165,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -214,21 +200,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -239,13 +216,11 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- $select = 'SELECT '.($offset ? 'SKIP '.$offset : '').'FIRST '.$limit.' ';
+ $select = 'SELECT '.($this->qb_offset ? 'SKIP '.$this->qb_offset : '').'FIRST '.$this->qb_limit.' ';
return preg_replace('/^(SELECT\s)/i', $select, $sql, 1);
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
index 4244688..9ffb93e 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
@@ -157,10 +157,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -184,9 +184,9 @@
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
index d584d1f..b03218f 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
@@ -174,20 +174,17 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
+ if ($this->qb_limit)
+ {
+ $this->where('rownum <= ',$this->qb_limit, FALSE);
+ $this->qb_limit = FALSE;
+ }
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
- empty($limit) OR $conditions[] = 'rownum <= '.$limit;
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -198,14 +195,12 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit + 1).')'
- .($offset ? ' WHERE rnum >= '.($offset + 1): '');
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
+ .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): '');
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
index e7ab3fd..5944d55 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
@@ -162,27 +162,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -211,21 +197,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return 'DELETE FROM '.$table.$conditions;
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -236,13 +213,11 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
+ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$this->qb_limit.' ', $sql);
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
index 2a68781..74d56e6 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
@@ -148,27 +148,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -180,10 +166,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -202,14 +188,14 @@
$cases = '';
foreach ($final as $k => $v)
{
- $cases .= $k.' = (CASE '.$k."\n"
+ $cases .= $k.' = (CASE '.$index."\n"
.implode("\n", $v)."\n"
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -220,19 +206,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -243,29 +222,31 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * Called by where(), or_where(), having(), or_having()
*
+ * @param string 'qb_where' or 'qb_having'
* @param mixed
* @param mixed
* @param string
+ * @param bool
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -276,14 +257,10 @@
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->protect_identifiers(substr($k, 0, strpos($k, $op)), FALSE, $escape).strstr($k, $op)
- : $this->protect_identifiers($k, FALSE, $escape);
-
if (is_null($v) && ! $this->_has_operator($k))
{
// value appears not to have been set, assign the test to IS NULL
@@ -292,13 +269,13 @@
if ( ! is_null($v))
{
- if ($escape === TRUE)
+ if (is_bool($v))
{
- $v = ' '.$this->escape($v);
+ $v = ' '.($v ? 'TRUE' : 'FALSE');
}
- elseif (is_bool($v))
+ elseif ($escape === TRUE)
{
- $v = ($v ? ' TRUE' : ' FALSE');
+ $v = ' '.(is_int($v) ? $v : $this->escape($v));
}
if ( ! $this->_has_operator($k))
@@ -307,11 +284,11 @@
}
}
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
index fd1c4b2..5b1cd97 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
@@ -188,27 +188,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -219,23 +205,16 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -246,32 +225,30 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// As of SQL Server 2012 (11.0.*) OFFSET is supported
if (version_compare($this->version(), '11', '>='))
{
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+ return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
}
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// An ORDER BY clause is required for ROW_NUMBER() to work
- if ($offset && ! empty($this->qb_orderby))
+ if ($this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
$sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 2a91a89..19f384c 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -463,27 +463,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -495,10 +481,10 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
+ * @param string the where key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -522,9 +508,9 @@
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -535,19 +521,12 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -558,30 +537,31 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * Called by where(), or_where(), having(), or_having()
*
+ * @param string 'qb_where' or 'qb_having'
* @param mixed
* @param mixed
* @param string
- * @param mixed
+ * @param bool
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -592,17 +572,10 @@
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- if ($escape === TRUE)
- {
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->escape_identifiers(trim(substr($k, 0, strpos($k, $op)))).' '.strstr($k, $op)
- : $this->escape_identifiers(trim($k));
- }
-
if (is_null($v) && ! $this->_has_operator($k))
{
// value appears not to have been set, assign the test to IS NULL
@@ -611,13 +584,13 @@
if ( ! is_null($v))
{
- if ($escape === TRUE)
+ if (is_bool($v))
{
- $v = ' '.$this->escape($v);
+ $v = ' '.($v ? 'TRUE' : 'FALSE');
}
- elseif (is_bool($v))
+ elseif ($escape === TRUE)
{
- $v = ($v ? ' TRUE' : ' FALSE');
+ $v = ' '.(is_int($v) ? $v : $this->escape($v));
}
if ( ! $this->_has_operator($k))
@@ -626,11 +599,11 @@
}
}
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 3ffbd4c..6594292 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -364,27 +364,13 @@
*
* @param string the table name
* @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -413,23 +399,16 @@
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
-
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
@@ -440,32 +419,30 @@
* Generates a platform-specific LIMIT clause
*
* @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// As of SQL Server 2012 (11.0.*) OFFSET is supported
if (version_compare($this->version(), '11', '>='))
{
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+ return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
}
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// An ORDER BY clause is required for ROW_NUMBER() to work
- if ($offset && ! empty($this->qb_orderby))
+ if ($this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
$sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);