diff options
Diffstat (limited to 'system/database/DB_query_builder.php')
-rw-r--r-- | system/database/DB_query_builder.php | 154 |
1 files changed, 113 insertions, 41 deletions
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php index 933108498..de6aa04fc 100644 --- a/system/database/DB_query_builder.php +++ b/system/database/DB_query_builder.php @@ -526,19 +526,8 @@ abstract class CI_DB_query_builder extends CI_DB_driver { */ public function join($table, $cond, $type = '', $escape = NULL) { - if ($type !== '') - { - $type = strtoupper(trim($type)); - - if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER', 'FULL OUTER', 'FULL'), TRUE)) - { - $type = ''; - } - else - { - $type .= ' '; - } - } + $type = trim(strtoupper($type).' JOIN'); + preg_match('#^(NATURAL\s+)?((LEFT|RIGHT|FULL)\s+)?((INNER|OUTER)\s+)?JOIN$#', $type) OR $type = 'JOIN'; // Extract any aliases that might exist. We use this information // in the protect_identifiers to know whether to add a table prefix @@ -546,7 +535,11 @@ abstract class CI_DB_query_builder extends CI_DB_driver { is_bool($escape) OR $escape = $this->_protect_identifiers; - if ( ! $this->_has_operator($cond)) + if (strpos($type, 'NATURAL') === 0) + { + $cond = ''; + } + elseif ( ! $this->_has_operator($cond)) { $cond = ' USING ('.($escape ? $this->escape_identifiers($cond) : $cond).')'; } @@ -595,7 +588,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { } // Assemble the JOIN statement - $this->qb_join[] = $join = $type.'JOIN '.$table.$cond; + $this->qb_join[] = $join = $type.' '.$table.$cond; if ($this->qb_caching === TRUE) { @@ -699,11 +692,11 @@ abstract class CI_DB_query_builder extends CI_DB_driver { $k = substr($k, 0, $match[0][1]).($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'); } - ${$qb_key} = array('condition' => $prefix.$k, 'value' => $v, 'escape' => $escape); - $this->{$qb_key}[] = ${$qb_key}; + $$qb_key = array('condition' => $prefix.$k, 'value' => $v, 'escape' => $escape); + $this->{$qb_key}[] = $$qb_key; if ($this->qb_caching === TRUE) { - $this->{$qb_cache_key}[] = ${$qb_key}; + $this->{$qb_cache_key}[] = $$qb_key; $this->qb_cache_exists[] = substr($qb_key, 3); } @@ -725,9 +718,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * @param bool $escape * @return CI_DB_query_builder */ - public function where_in($key = NULL, $values = NULL, $escape = NULL) + public function where_in($key, array $values, $escape = NULL) { - return $this->_where_in($key, $values, FALSE, 'AND ', $escape); + return $this->_wh_in('qb_where', $key, $values, FALSE, 'AND ', $escape); } // -------------------------------------------------------------------- @@ -743,9 +736,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * @param bool $escape * @return CI_DB_query_builder */ - public function or_where_in($key = NULL, $values = NULL, $escape = NULL) + public function or_where_in($key, array $values, $escape = NULL) { - return $this->_where_in($key, $values, FALSE, 'OR ', $escape); + return $this->_wh_in('qb_where', $key, $values, FALSE, 'OR ', $escape); } // -------------------------------------------------------------------- @@ -761,9 +754,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * @param bool $escape * @return CI_DB_query_builder */ - public function where_not_in($key = NULL, $values = NULL, $escape = NULL) + public function where_not_in($key, array $values, $escape = NULL) { - return $this->_where_in($key, $values, TRUE, 'AND ', $escape); + return $this->_wh_in('qb_where', $key, $values, TRUE, 'AND ', $escape); } // -------------------------------------------------------------------- @@ -779,21 +772,98 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * @param bool $escape * @return CI_DB_query_builder */ - public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL) + public function or_where_not_in($key, array $values, $escape = NULL) + { + return $this->_wh_in('qb_where', $key, $values, TRUE, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * HAVING IN + * + * Generates a HAVING field IN('item', 'item') SQL query, + * joined with 'AND' if appropriate. + * + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape + * @return CI_DB_query_builder + */ + public function having_in($key, array $values, $escape = NULL) + { + return $this->_wh_in('qb_having', $key, $values, FALSE, 'AND ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * OR HAVING IN + * + * Generates a HAVING field IN('item', 'item') SQL query, + * joined with 'OR' if appropriate. + * + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape + * @return CI_DB_query_builder + */ + public function or_having_in($key, array $values, $escape = NULL) + { + return $this->_wh_in('qb_having', $key, $values, FALSE, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * HAVING NOT IN + * + * Generates a HAVING field NOT IN('item', 'item') SQL query, + * joined with 'AND' if appropriate. + * + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape + * @return CI_DB_query_builder + */ + public function having_not_in($key, array $values, $escape = NULL) { - return $this->_where_in($key, $values, TRUE, 'OR ', $escape); + return $this->_wh_in('qb_having', $key, $values, TRUE, 'AND ', $escape); } // -------------------------------------------------------------------- /** - * Internal WHERE IN + * OR HAVING NOT IN + * + * Generates a HAVING field NOT IN('item', 'item') SQL query, + * joined with 'OR' if appropriate. + * + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape + * @return CI_DB_query_builder + */ + public function or_having_not_in($key, array $values, $escape = NULL) + { + return $this->_wh_in('qb_having', $key, $values, TRUE, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * Internal WHERE/HAVING IN * * @used-by where_in() * @used-by or_where_in() * @used-by where_not_in() * @used-by or_where_not_in() + * @used-by having_in() + * @used-by or_having_in() + * @used-by having_not_in() + * @used-by or_having_not_in() * + * @param string $qb_key 'qb_where' or 'qb_having' * @param string $key The field to search * @param array $values The values searched on * @param bool $not If the statement would be IN or NOT IN @@ -801,16 +871,18 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * @param bool $escape * @return CI_DB_query_builder */ - protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL) + protected function _wh_in($qb_key, $key, array $values, $not = FALSE, $type = 'AND ', $escape = NULL) { - if ($key === NULL OR $values === NULL) + $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where'; + + if (empty($key) OR ! is_string($key)) { - return $this; + throw new InvalidArgumentException(sprintf('%s() expects $key to be a non-empty string', debug_backtrace(0, 2)[1]['function'])); } - if ( ! is_array($values)) + if (empty($values)) { - $values = array($values); + throw new InvalidArgumentException(sprintf('%s() expects $values to be a non-empty array', debug_backtrace(0, 2)[1]['function'])); } is_bool($escape) OR $escape = $this->_protect_identifiers; @@ -819,32 +891,32 @@ abstract class CI_DB_query_builder extends CI_DB_driver { if ($escape === TRUE) { - $where_in = array(); + $wh_in = array(); foreach ($values as $value) { - $where_in[] = $this->escape($value); + $wh_in[] = $this->escape($value); } } else { - $where_in = array_values($values); + $wh_in = array_values($values); } - $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); - $where_in = array( - 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')', + $wh_in = array( + 'condition' => $prefix.$key.$not.' IN('.implode(', ', $wh_in).')', 'value' => NULL, 'escape' => $escape ); - $this->qb_where[] = $where_in; + $this->{$qb_key}[] = $wh_in; if ($this->qb_caching === TRUE) { - $this->qb_cache_where[] = $where_in; - $this->qb_cache_exists[] = 'where'; + $this->{$qb_cache_key}[] = $wh_in; + $this->qb_cache_exists[] = substr($qb_key, 3); } return $this; |