diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index e881148a5fa7..ff67d1f5eb3c 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -39,6 +39,7 @@ namespace CodeIgniter\Database; use CodeIgniter\Database\Exceptions\DatabaseException; +use CodeIgniter\Database\Exceptions\DataException; /** * Class BaseBuilder @@ -137,6 +138,13 @@ class BaseBuilder */ public $QBOrderBy = []; + /** + * QB NO ESCAPE data + * + * @var array + */ + public $QBNoEscape = []; + /** * QB data sets * @@ -264,11 +272,11 @@ public function getBinds(): array * Generates the SELECT portion of the query * * @param string|array $select - * @param mixed $escape + * @param boolean $escape * * @return BaseBuilder */ - public function select($select = '*', $escape = null) + public function select($select = '*', bool $escape = null) { if (is_string($select)) { @@ -317,7 +325,7 @@ public function select($select = '*', $escape = null) * * @return BaseBuilder */ - public function selectMax($select = '', $alias = '') + public function selectMax(string $select = '', string $alias = '') { return $this->maxMinAvgSum($select, $alias, 'MAX'); } @@ -334,7 +342,7 @@ public function selectMax($select = '', $alias = '') * * @return BaseBuilder */ - public function selectMin($select = '', $alias = '') + public function selectMin(string $select = '', string $alias = '') { return $this->maxMinAvgSum($select, $alias, 'MIN'); } @@ -351,7 +359,7 @@ public function selectMin($select = '', $alias = '') * * @return BaseBuilder */ - public function selectAvg($select = '', $alias = '') + public function selectAvg(string $select = '', string $alias = '') { return $this->maxMinAvgSum($select, $alias, 'AVG'); } @@ -368,7 +376,7 @@ public function selectAvg($select = '', $alias = '') * * @return BaseBuilder */ - public function selectSum($select = '', $alias = '') + public function selectSum(string $select = '', string $alias = '') { return $this->maxMinAvgSum($select, $alias, 'SUM'); } @@ -388,13 +396,19 @@ public function selectSum($select = '', $alias = '') * @param string $type * * @return BaseBuilder + * @throws \CodeIgniter\Database\Exceptions\DataException * @throws \CodeIgniter\Database\Exceptions\DatabaseException */ - protected function maxMinAvgSum($select = '', $alias = '', $type = 'MAX') + protected function maxMinAvgSum(string $select = '', string $alias = '', string $type = 'MAX') { - if (! is_string($select) || $select === '') + if ($select === '') { - throw new DatabaseException('The query you submitted is not valid.'); + throw DataException::forEmptyInputGiven('Select'); + } + + if (strpos($select, ',') !== false) + { + throw DataException::forInvalidArgument('column name not separated by comma'); } $type = strtoupper($type); @@ -426,7 +440,7 @@ protected function maxMinAvgSum($select = '', $alias = '', $type = 'MAX') * * @return string */ - protected function createAliasFromTable($item) + protected function createAliasFromTable(string $item): string { if (strpos($item, '.') !== false) { @@ -449,9 +463,9 @@ protected function createAliasFromTable($item) * * @return BaseBuilder */ - public function distinct($val = true) + public function distinct(bool $val = true) { - $this->QBDistinct = is_bool($val) ? $val : true; + $this->QBDistinct = $val; return $this; } @@ -468,7 +482,7 @@ public function distinct($val = true) * * @return BaseBuilder */ - public function from($from, $overwrite = false) + public function from($from, bool $overwrite = false) { if ($overwrite === true) { @@ -510,14 +524,14 @@ public function from($from, $overwrite = false) * * Generates the JOIN portion of the query * - * @param string $table - * @param string $cond The join condition - * @param string $type The type of join - * @param string $escape Whether not to try to escape identifiers + * @param string $table + * @param string $cond The join condition + * @param string $type The type of join + * @param boolean $escape Whether not to try to escape identifiers * * @return BaseBuilder */ - public function join($table, $cond, $type = '', $escape = null) + public function join(string $table, string $cond, string $type = '', bool $escape = null) { if ($type !== '') { @@ -605,7 +619,7 @@ public function join($table, $cond, $type = '', $escape = null) * * @return BaseBuilder */ - public function where($key, $value = null, $escape = null) + public function where($key, $value = null, bool $escape = null) { return $this->whereHaving('QBWhere', $key, $value, 'AND ', $escape); } @@ -624,7 +638,7 @@ public function where($key, $value = null, $escape = null) * * @return BaseBuilder */ - public function orWhere($key, $value = null, $escape = null) + public function orWhere($key, $value = null, bool $escape = null) { return $this->whereHaving('QBWhere', $key, $value, 'OR ', $escape); } @@ -647,7 +661,7 @@ public function orWhere($key, $value = null, $escape = null) * * @return BaseBuilder */ - protected function whereHaving($qb_key, $key, $value = null, $type = 'AND ', $escape = null) + protected function whereHaving(string $qb_key, $key, $value = null, string $type = 'AND ', bool $escape = null) { if (! is_array($key)) { @@ -689,6 +703,8 @@ protected function whereHaving($qb_key, $key, $value = null, $type = 'AND ', $es { $k .= $op; } + + $v = " :$bind:"; } elseif (! $this->hasOperator($k)) { @@ -700,8 +716,6 @@ protected function whereHaving($qb_key, $key, $value = null, $type = 'AND ', $es $k = substr($k, 0, $match[0][1]) . ($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'); } - $v = ! is_null($v) ? " :$bind:" : $v; - $this->{$qb_key}[] = [ 'condition' => $prefix . $k . $v, 'escape' => $escape, @@ -725,7 +739,7 @@ protected function whereHaving($qb_key, $key, $value = null, $type = 'AND ', $es * * @return BaseBuilder */ - public function whereIn($key = null, $values = null, $escape = null) + public function whereIn(string $key = null, array $values = null, bool $escape = null) { return $this->_whereIn($key, $values, false, 'AND ', $escape); } @@ -744,7 +758,7 @@ public function whereIn($key = null, $values = null, $escape = null) * * @return BaseBuilder */ - public function orWhereIn($key = null, $values = null, $escape = null) + public function orWhereIn(string $key = null, array $values = null, bool $escape = null) { return $this->_whereIn($key, $values, false, 'OR ', $escape); } @@ -763,7 +777,7 @@ public function orWhereIn($key = null, $values = null, $escape = null) * * @return BaseBuilder */ - public function whereNotIn($key = null, $values = null, $escape = null) + public function whereNotIn(string $key = null, array $values = null, bool $escape = null) { return $this->_whereIn($key, $values, true, 'AND ', $escape); } @@ -782,7 +796,7 @@ public function whereNotIn($key = null, $values = null, $escape = null) * * @return BaseBuilder */ - public function orWhereNotIn($key = null, $values = null, $escape = null) + public function orWhereNotIn(string $key = null, array $values = null, bool $escape = null) { return $this->_whereIn($key, $values, true, 'OR ', $escape); } @@ -805,18 +819,13 @@ public function orWhereNotIn($key = null, $values = null, $escape = null) * * @return BaseBuilder */ - protected function _whereIn($key = null, $values = null, $not = false, $type = 'AND ', $escape = null) + protected function _whereIn(string $key = null, array $values = null, bool $not = false, string $type = 'AND ', bool $escape = null) { if ($key === null || $values === null) { return $this; } - if (! is_array($values)) - { - $values = [$values]; - } - is_bool($escape) || $escape = $this->db->protectIdentifiers; $ok = $key; @@ -859,7 +868,7 @@ protected function _whereIn($key = null, $values = null, $not = false, $type = ' * * @return BaseBuilder */ - public function like($field, $match = '', $side = 'both', $escape = null, $insensitiveSearch = false) + public function like($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false) { return $this->_like($field, $match, 'AND ', $side, '', $escape, $insensitiveSearch); } @@ -880,7 +889,7 @@ public function like($field, $match = '', $side = 'both', $escape = null, $insen * * @return BaseBuilder */ - public function notLike($field, $match = '', $side = 'both', $escape = null, $insensitiveSearch = false) + public function notLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false) { return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape, $insensitiveSearch); } @@ -901,7 +910,7 @@ public function notLike($field, $match = '', $side = 'both', $escape = null, $in * * @return BaseBuilder */ - public function orLike($field, $match = '', $side = 'both', $escape = null, $insensitiveSearch = false) + public function orLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false) { return $this->_like($field, $match, 'OR ', $side, '', $escape, $insensitiveSearch); } @@ -922,7 +931,7 @@ public function orLike($field, $match = '', $side = 'both', $escape = null, $ins * * @return BaseBuilder */ - public function orNotLike($field, $match = '', $side = 'both', $escape = null, $insensitiveSearch = false) + public function orNotLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false) { return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape, $insensitiveSearch); } @@ -947,7 +956,7 @@ public function orNotLike($field, $match = '', $side = 'both', $escape = null, $ * * @return BaseBuilder */ - protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = null, $insensitiveSearch = false) + protected function _like($field, string $match = '', string $type = 'AND ', string $side = 'both', string $not = '', bool $escape = null, bool $insensitiveSearch = false) { if (! is_array($field)) { @@ -1007,17 +1016,16 @@ protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $n /** * Platform independent LIKE statement builder. * - * @param string|null $prefix - * @param string $column - * @param string|null $not - * @param string $bind - * @param boolean $insensitiveSearch + * @param string $prefix + * @param string $column + * @param string $not + * @param string $bind + * @param boolean $insensitiveSearch * * @return string $like_statement */ public function _like_statement(string $prefix = null, string $column, string $not = null, string $bind, bool $insensitiveSearch = false): string { - // TODO fmertins: $column param seems to require a default value? Because $prefix has... $like_statement = "{$prefix} {$column} {$not} LIKE :{$bind}:"; if ($insensitiveSearch === true) @@ -1038,7 +1046,7 @@ public function _like_statement(string $prefix = null, string $column, string $n * * @return BaseBuilder */ - public function groupStart($not = '', $type = 'AND ') + public function groupStart(string $not = '', string $type = 'AND ') { $type = $this->groupGetType($type); @@ -1124,11 +1132,11 @@ public function groupEnd() * * @return string */ - protected function groupGetType($type) + protected function groupGetType(string $type): string { if ($this->QBWhereGroupStarted) { - $type = ''; + $type = ''; $this->QBWhereGroupStarted = false; } @@ -1140,12 +1148,12 @@ protected function groupGetType($type) /** * GROUP BY * - * @param string $by - * @param boolean $escape + * @param string|array $by + * @param boolean $escape * * @return BaseBuilder */ - public function groupBy($by, $escape = null) + public function groupBy($by, bool $escape = null) { is_bool($escape) || $escape = $this->db->protectIdentifiers; @@ -1179,13 +1187,13 @@ public function groupBy($by, $escape = null) * * Separates multiple calls with 'AND'. * - * @param string $key - * @param string $value - * @param boolean $escape + * @param string|array $key + * @param mixed $value + * @param boolean $escape * * @return BaseBuilder */ - public function having($key, $value = null, $escape = null) + public function having($key, $value = null, bool $escape = null) { return $this->whereHaving('QBHaving', $key, $value, 'AND ', $escape); } @@ -1197,13 +1205,13 @@ public function having($key, $value = null, $escape = null) * * Separates multiple calls with 'OR'. * - * @param string $key - * @param string $value - * @param boolean $escape + * @param string|array $key + * @param mixed $value + * @param boolean $escape * * @return BaseBuilder */ - public function orHaving($key, $value = null, $escape = null) + public function orHaving($key, $value = null, bool $escape = null) { return $this->whereHaving('QBHaving', $key, $value, 'OR ', $escape); } @@ -1213,13 +1221,13 @@ public function orHaving($key, $value = null, $escape = null) /** * ORDER BY * - * @param string $orderby + * @param string $orderBy * @param string $direction ASC, DESC or RANDOM * @param boolean $escape * * @return BaseBuilder */ - public function orderBy($orderby, $direction = '', $escape = null) + public function orderBy(string $orderBy, string $direction = '', bool $escape = null) { $direction = strtoupper(trim($direction)); @@ -1228,9 +1236,9 @@ public function orderBy($orderby, $direction = '', $escape = null) $direction = ''; // Do we have a seed value? - $orderby = ctype_digit((string) $orderby) ? sprintf($this->randomKeyword[1], $orderby) : $this->randomKeyword[0]; + $orderBy = ctype_digit((string) $orderBy) ? sprintf($this->randomKeyword[1], $orderBy) : $this->randomKeyword[0]; } - elseif (empty($orderby)) + elseif (empty($orderBy)) { return $this; } @@ -1244,7 +1252,7 @@ public function orderBy($orderby, $direction = '', $escape = null) if ($escape === false) { $qb_orderby[] = [ - 'field' => $orderby, + 'field' => $orderBy, 'direction' => $direction, 'escape' => false, ]; @@ -1252,18 +1260,21 @@ public function orderBy($orderby, $direction = '', $escape = null) else { $qb_orderby = []; - foreach (explode(',', $orderby) as $field) + foreach (explode(',', $orderBy) as $field) { - $qb_orderby[] = ($direction === '' && - preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE)) ? [ - 'field' => ltrim(substr($field, 0, $match[0][1])), - 'direction' => ' ' . $match[1][0], - 'escape' => true, - ] : [ - 'field' => trim($field), - 'direction' => $direction, - 'escape' => true, - ]; + $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE)) + ? + [ + 'field' => ltrim(substr($field, 0, $match[0][1])), + 'direction' => ' ' . $match[1][0], + 'escape' => true, + ] + : + [ + 'field' => trim($field), + 'direction' => $direction, + 'escape' => true, + ]; } } @@ -1306,7 +1317,7 @@ public function limit(int $value = null, int $offset = 0) * * @return BaseBuilder */ - public function offset($offset) + public function offset(int $offset) { if (! empty($offset)) { @@ -1327,7 +1338,7 @@ public function offset($offset) * * @return string */ - protected function _limit($sql) + protected function _limit(string $sql): string { return $sql . ' LIMIT ' . ($this->QBOffset ? $this->QBOffset . ', ' : '') . $this->QBLimit; } @@ -1345,7 +1356,7 @@ protected function _limit($sql) * * @return BaseBuilder */ - public function set($key, $value = '', $escape = null) + public function set($key, string $value = '', bool $escape = null) { $key = $this->objectToArray($key); @@ -1360,7 +1371,7 @@ public function set($key, $value = '', $escape = null) { if ($escape) { - $bind = $this->setBind($k, $v, $escape); + $bind = $this->setBind($k, $v, $escape); $this->QBSet[$this->db->protectIdentifiers($k, false, $escape)] = ":$bind:"; } else @@ -1382,7 +1393,7 @@ public function set($key, $value = '', $escape = null) * * @return array */ - public function getSetData(bool $clean = false) + public function getSetData(bool $clean = false): array { $data = $this->QBSet; @@ -1405,7 +1416,7 @@ public function getSetData(bool $clean = false) * * @return string */ - public function getCompiledSelect($reset = true) + public function getCompiledSelect(bool $reset = true): string { $select = $this->compileSelect(); @@ -1425,7 +1436,7 @@ public function getCompiledSelect($reset = true) * * @param string $sql * - * @return mixed|string + * @return string */ protected function compileFinalQuery(string $sql): string { @@ -1453,7 +1464,7 @@ protected function compileFinalQuery(string $sql): string * * @return ResultInterface */ - public function get(int $limit = null, int $offset = 0, $returnSQL = false, $reset = true) + public function get(int $limit = null, int $offset = 0, bool $returnSQL = false, bool $reset = true) { if (! is_null($limit)) { @@ -1486,9 +1497,9 @@ public function get(int $limit = null, int $offset = 0, $returnSQL = false, $res * @param boolean $reset Are we want to clear query builder values? * @param boolean $test Are we running automated tests? * - * @return integer + * @return integer|string when $test = true */ - public function countAll($reset = true, $test = false) + public function countAll(bool $reset = true, bool $test = false) { $table = $this->QBFrom[0]; @@ -1527,22 +1538,25 @@ public function countAll($reset = true, $test = false) * @param boolean $reset * @param boolean $test The reset clause * - * @return integer + * @return integer|string when $test = true */ - public function countAllResults($reset = true, $test = false) + public function countAllResults(bool $reset = true, bool $test = false) { // ORDER BY usage is often problematic here (most notably // on Microsoft SQL Server) and ultimately unnecessary // for selecting COUNT(*) ... - $orderby = []; + $orderBy = []; if (! empty($this->QBOrderBy)) { - $orderby = $this->QBOrderBy; + $orderBy = $this->QBOrderBy; $this->QBOrderBy = null; } - $sql = ($this->QBDistinct === true) ? $this->countString . $this->db->protectIdentifiers('numrows') . "\nFROM (\n" . - $this->compileSelect() . "\n) CI_count_all_results" : $this->compileSelect($this->countString . $this->db->protectIdentifiers('numrows')); + $sql = ($this->QBDistinct === true) + ? + $this->countString . $this->db->protectIdentifiers('numrows') . "\nFROM (\n" . $this->compileSelect() . "\n) CI_count_all_results" + : + $this->compileSelect($this->countString . $this->db->protectIdentifiers('numrows')); if ($test) { @@ -1558,7 +1572,7 @@ public function countAllResults($reset = true, $test = false) // If we've previously reset the QBOrderBy values, get them back elseif (! isset($this->QBOrderBy)) { - $this->QBOrderBy = $orderby ?? []; + $this->QBOrderBy = $orderBy ?? []; } $row = (! $result instanceof ResultInterface) @@ -1580,13 +1594,13 @@ public function countAllResults($reset = true, $test = false) * * Allows the where clause, limit and offset to be added directly * - * @param string $where - * @param integer $limit - * @param integer $offset + * @param string|array $where + * @param integer $limit + * @param integer $offset * * @return ResultInterface */ - public function getWhere($where = null, $limit = null, $offset = null) + public function getWhere($where = null, int $limit = null, int $offset = null) { if ($where !== null) { @@ -1620,7 +1634,7 @@ public function getWhere($where = null, $limit = null, $offset = null) * @return integer Number of rows inserted or FALSE on failure * @throws DatabaseException */ - public function insertBatch($set = null, $escape = null, $batchSize = 100, $testing = false) + public function insertBatch(array $set = null, bool $escape = null, int $batchSize = 100, bool $testing = false) { if ($set === null) { @@ -1689,7 +1703,7 @@ public function insertBatch($set = null, $escape = null, $batchSize = 100, $test * * @return string */ - protected function _insertBatch($table, $keys, $values) + protected function _insertBatch(string $table, array $keys, array $values): string { return 'INSERT INTO ' . $table . ' (' . implode(', ', $keys) . ') VALUES ' . implode(', ', $values); } @@ -1703,9 +1717,9 @@ protected function _insertBatch($table, $keys, $values) * @param string $value * @param boolean $escape * - * @return BaseBuilder + * @return BaseBuilder|null */ - public function setInsertBatch($key, $value = '', $escape = null) + public function setInsertBatch($key, string $value = '', bool $escape = null) { $key = $this->batchObjectToArray($key); @@ -1727,7 +1741,7 @@ public function setInsertBatch($key, $value = '', $escape = null) // batch function above returns an error on an empty array $this->QBSet[] = []; - return; + return null; } ksort($row); // puts $row in the same order as our keys @@ -1762,7 +1776,7 @@ public function setInsertBatch($key, $value = '', $escape = null) * * @return string */ - public function getCompiledInsert($reset = true) + public function getCompiledInsert(bool $reset = true): string { if ($this->validateInsert() === false) { @@ -1796,7 +1810,7 @@ public function getCompiledInsert($reset = true) * * @return BaseResult|Query|false */ - public function insert($set = null, $escape = null, $test = false) + public function insert(array $set = null, bool $escape = null, bool $test = false) { if ($set !== null) { @@ -1825,6 +1839,8 @@ public function insert($set = null, $escape = null, $test = false) return $result; } + + return false; } //-------------------------------------------------------------------- @@ -1836,10 +1852,10 @@ public function insert($set = null, $escape = null, $test = false) * validate that the there data is actually being set and that table * has been chosen to be inserted into. * - * @return string + * @return bool * @throws DatabaseException */ - protected function validateInsert() + protected function validateInsert(): bool { if (empty($this->QBSet)) { @@ -1867,7 +1883,7 @@ protected function validateInsert() * * @return string */ - protected function _insert($table, array $keys, array $unescapedKeys) + protected function _insert(string $table, array $keys, array $unescapedKeys): string { return 'INSERT INTO ' . $table . ' (' . implode(', ', $keys) . ') VALUES (' . implode(', ', $unescapedKeys) . ')'; } @@ -1885,7 +1901,7 @@ protected function _insert($table, array $keys, array $unescapedKeys) * @return BaseResult|Query|string|false * @throws DatabaseException */ - public function replace($set = null, $returnSQL = false) + public function replace(array $set = null, bool $returnSQL = false) { if ($set !== null) { @@ -1923,7 +1939,7 @@ public function replace($set = null, $returnSQL = false) * * @return string */ - protected function _replace($table, $keys, $values) + protected function _replace(string $table, array $keys, array $values): string { return 'REPLACE INTO ' . $table . ' (' . implode(', ', $keys) . ') VALUES (' . implode(', ', $values) . ')'; } @@ -1940,7 +1956,7 @@ protected function _replace($table, $keys, $values) * * @return string */ - protected function _fromTables() + protected function _fromTables(): string { return implode(', ', $this->QBFrom); } @@ -1956,7 +1972,7 @@ protected function _fromTables() * * @return string */ - public function getCompiledUpdate($reset = true) + public function getCompiledUpdate(bool $reset = true): string { if ($this->validateUpdate() === false) { @@ -1987,7 +2003,7 @@ public function getCompiledUpdate($reset = true) * * @return boolean TRUE on success, FALSE on failure */ - public function update($set = null, $where = null, int $limit = null, $test = false) + public function update(array $set = null, $where = null, int $limit = null, bool $test = false): bool { if ($set !== null) { @@ -2046,8 +2062,10 @@ public function update($set = null, $where = null, int $limit = null, $test = fa * * @return string */ - protected function _update($table, $values) + protected function _update(string $table, array $values): string { + $valstr = []; + foreach ($values as $key => $val) { $valstr[] = $key . ' = ' . $val; @@ -2071,7 +2089,7 @@ protected function _update($table, $values) * @return boolean * @throws \CodeIgniter\Database\Exceptions\DatabaseException */ - protected function validateUpdate() + protected function validateUpdate(): bool { if (empty($this->QBSet)) { @@ -2101,7 +2119,7 @@ protected function validateUpdate() * @return mixed Number of rows affected, SQL string, or FALSE on failure * @throws \CodeIgniter\Database\Exceptions\DatabaseException */ - public function updateBatch($set = null, $index = null, $batchSize = 100, $returnSQL = false) + public function updateBatch(array $set = null, string $index = null, int $batchSize = 100, bool $returnSQL = false) { if ($index === null) { @@ -2142,7 +2160,7 @@ public function updateBatch($set = null, $index = null, $batchSize = 100, $retur // Batch this baby $affected_rows = 0; - $savedSQL = []; + $savedSQL = []; for ($i = 0, $total = count($this->QBSet); $i < $total; $i += $batchSize) { $sql = $this->_updateBatch($table, array_slice($this->QBSet, $i, $batchSize), $this->db->protectIdentifiers($index) @@ -2179,9 +2197,10 @@ public function updateBatch($set = null, $index = null, $batchSize = 100, $retur * * @return string */ - protected function _updateBatch($table, $values, $index) + protected function _updateBatch(string $table, array $values, string $index): string { $ids = []; + $final = []; foreach ($values as $key => $val) { $ids[] = $val[$index]; @@ -2213,20 +2232,20 @@ protected function _updateBatch($table, $values, $index) /** * The "setUpdateBatch" function. Allows key/value pairs to be set for batch updating * - * @param array $key - * @param string $index - * @param boolean $escape + * @param array|object $key + * @param string $index + * @param boolean $escape * - * @return BaseBuilder + * @return BaseBuilder|null * @throws \CodeIgniter\Database\Exceptions\DatabaseException */ - public function setUpdateBatch($key, $index = '', $escape = null) + public function setUpdateBatch($key, string $index = '', bool $escape = null) { $key = $this->batchObjectToArray($key); if (! is_array($key)) { - return; + return null; } is_bool($escape) || $escape = $this->db->protectIdentifiers; @@ -2268,7 +2287,7 @@ public function setUpdateBatch($key, $index = '', $escape = null) * @param boolean $test * @return boolean TRUE on success, FALSE on failure */ - public function emptyTable($test = false) + public function emptyTable(bool $test = false) { $table = $this->QBFrom[0]; @@ -2297,7 +2316,7 @@ public function emptyTable($test = false) * * @return boolean TRUE on success, FALSE on failure */ - public function truncate($test = false) + public function truncate(bool $test = false) { $table = $this->QBFrom[0]; @@ -2327,7 +2346,7 @@ public function truncate($test = false) * * @return string */ - protected function _truncate($table) + protected function _truncate(string $table): string { return 'TRUNCATE ' . $table; } @@ -2343,13 +2362,11 @@ protected function _truncate($table) * * @return string */ - public function getCompiledDelete($reset = true) + public function getCompiledDelete(bool $reset = true): string { $table = $this->QBFrom[0]; - $this->returnDeleteSQL = true; - $sql = $this->delete($table, '', null, $reset); - $this->returnDeleteSQL = false; + $sql = $this->delete($table, '', $reset, true); return $this->compileFinalQuery($sql); } @@ -2362,14 +2379,14 @@ public function getCompiledDelete($reset = true) * Compiles a delete string and runs the query * * @param mixed $where The where clause - * @param mixed $limit The limit clause + * @param integer $limit The limit clause * @param boolean $reset_data * @param boolean $returnSQL * * @return mixed * @throws \CodeIgniter\Database\Exceptions\DatabaseException */ - public function delete($where = '', $limit = null, $reset_data = true, $returnSQL = false) + public function delete($where = '', int $limit = null, bool $reset_data = true, bool $returnSQL = false) { $table = $this->db->protectIdentifiers($this->QBFrom[0], true, null, false); @@ -2462,7 +2479,7 @@ public function decrement(string $column, int $value = 1) * * @return string */ - protected function _delete($table) + protected function _delete(string $table): string { return 'DELETE FROM ' . $table . $this->compileWhereHaving('QBWhere') . ($this->QBLimit ? ' LIMIT ' . $this->QBLimit : ''); @@ -2475,9 +2492,9 @@ protected function _delete($table) * * Used to track SQL statements written with aliased tables. * - * @param string $table The table to inspect + * @param string|array $table The table to inspect * - * @return string + * @return string|void */ protected function trackAliases($table) { @@ -2487,8 +2504,6 @@ protected function trackAliases($table) { $this->trackAliases($t); } - - return; } // Does the string contain a comma? If so, we need to separate @@ -2520,11 +2535,11 @@ protected function trackAliases($table) * Generates a query string based on which functions were used. * Should not be called directly. * - * @param boolean $select_override + * @param mixed $select_override * * @return string */ - protected function compileSelect($select_override = false) + protected function compileSelect($select_override = false): string { // Write the "select" portion of the query if ($select_override !== false) @@ -2594,7 +2609,7 @@ protected function compileSelect($select_override = false) * * @return string SQL statement */ - protected function compileWhereHaving($qb_key) + protected function compileWhereHaving(string $qb_key): string { if (! empty($this->$qb_key)) { @@ -2636,7 +2651,6 @@ protected function compileWhereHaving($qb_key) if (! empty($matches[4])) { - // $this->isLiteral($matches[4]) OR $matches[4] = $this->db->protectIdentifiers(trim($matches[4])); $matches[4] = ' ' . $matches[4]; } @@ -2667,7 +2681,7 @@ protected function compileWhereHaving($qb_key) * * @return string SQL statement */ - protected function compileGroupBy() + protected function compileGroupBy(): string { if (! empty($this->QBGroupBy)) { @@ -2702,7 +2716,7 @@ protected function compileGroupBy() * * @return string SQL statement */ - protected function compileOrderBy() + protected function compileOrderBy(): string { if (is_array($this->QBOrderBy) && ! empty($this->QBOrderBy)) { @@ -2733,9 +2747,9 @@ protected function compileOrderBy() * * Takes an object as input and converts the class variables to array key/vals * - * @param object $object + * @param mixed $object * - * @return array + * @return mixed */ protected function objectToArray($object) { @@ -2764,9 +2778,9 @@ protected function objectToArray($object) * * Takes an object as input and converts the class variables to array key/vals * - * @param object $object + * @param mixed $object * - * @return array + * @return mixed */ protected function batchObjectToArray($object) { @@ -2806,7 +2820,7 @@ protected function batchObjectToArray($object) * * @return boolean */ - protected function isLiteral($str) + protected function isLiteral(string $str): bool { $str = trim($str); @@ -2850,8 +2864,10 @@ public function resetQuery() * Resets the query builder values. Called by the get() function * * @param array $qb_reset_items An array of fields to reset + * + * @return void */ - protected function resetRun($qb_reset_items) + protected function resetRun(array $qb_reset_items) { foreach ($qb_reset_items as $item => $default_value) { @@ -2913,7 +2929,7 @@ protected function resetWrite() * * @return boolean */ - protected function hasOperator($str) + protected function hasOperator(string $str): bool { return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str)); } @@ -2926,9 +2942,9 @@ protected function hasOperator($str) * @param string $str * @param boolean $list * - * @return string + * @return mixed */ - protected function getOperator($str, bool $list = false) + protected function getOperator(string $str, bool $list = false) { static $_operators; @@ -2963,12 +2979,12 @@ protected function getOperator($str, bool $list = false) * arrays instead, so lets take advantage of that here. * * @param string $key - * @param null $value + * @param mixed $value * @param boolean $escape * * @return string */ - protected function setBind(string $key, $value = null, bool $escape = true) + protected function setBind(string $key, $value = null, bool $escape = true): string { if (! array_key_exists($key, $this->binds)) { diff --git a/system/Database/Exceptions/DataException.php b/system/Database/Exceptions/DataException.php index 7230eca20493..966c6ef43f6f 100644 --- a/system/Database/Exceptions/DataException.php +++ b/system/Database/Exceptions/DataException.php @@ -51,6 +51,12 @@ public static function forTableNotFound(string $table) return new static(lang('Database.tableNotFound', [$table])); } + + public static function forEmptyInputGiven(string $argument) + { + return new static(lang('Database.forEmptyInputGiven', [$argument])); + } + public static function forFindColumnHaveMultipleColumns() { return new static(lang('Database.forFindColumnHaveMultipleColumns')); diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index 2de81cb63bd5..7ab065aa9992 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -61,33 +61,33 @@ class Builder extends BaseBuilder /** * ORDER BY * - * @param string $orderby + * @param string $orderBy * @param string $direction ASC, DESC or RANDOM * @param boolean $escape * * @return BaseBuilder */ - public function orderBy($orderby, $direction = '', $escape = null) + public function orderBy(string $orderBy, string $direction = '', bool $escape = null) { $direction = strtoupper(trim($direction)); if ($direction === 'RANDOM') { - if (! is_float($orderby) && ctype_digit((string) $orderby)) + if (! is_float($orderBy) && ctype_digit((string) $orderBy)) { - $orderby = (float) ($orderby > 1 ? "0.{$orderby}" : $orderby); + $orderBy = (float) ($orderBy > 1 ? "0.{$orderBy}" : $orderBy); } - if (is_float($orderby)) + if (is_float($orderBy)) { - $this->db->simpleQuery("SET SEED {$orderby}"); + $this->db->simpleQuery("SET SEED {$orderBy}"); } - $orderby = $this->randomKeyword[0]; + $orderBy = $this->randomKeyword[0]; $direction = ''; $escape = false; } - return parent::orderBy($orderby, $direction, $escape); + return parent::orderBy($orderBy, $direction, $escape); } //-------------------------------------------------------------------- @@ -145,7 +145,7 @@ public function decrement(string $column, int $value = 1) * @throws DatabaseException * @internal param true $bool returns the generated SQL, false executes the query. */ - public function replace($set = null, $returnSQL = false) + public function replace(array $set = null, bool $returnSQL = false) { if ($set !== null) { @@ -200,8 +200,8 @@ public function replace($set = null, $returnSQL = false) * * Compiles a delete string and runs the query * - * @param string $where - * @param null $limit + * @param mixed $where + * @param integer $limit * @param boolean $reset_data * @param boolean $returnSQL * @@ -211,7 +211,7 @@ public function replace($set = null, $returnSQL = false) * @internal param the $mixed limit clause * @internal param $bool */ - public function delete($where = '', $limit = null, $reset_data = true, $returnSQL = false) + public function delete($where = '', int $limit = null, bool $reset_data = true, bool $returnSQL = false) { if (! empty($limit) || ! empty($this->QBLimit)) { @@ -232,7 +232,7 @@ public function delete($where = '', $limit = null, $reset_data = true, $returnSQ * * @return string */ - protected function _limit($sql) + protected function _limit(string $sql): string { return $sql . ' LIMIT ' . $this->QBLimit . ($this->QBOffset ? " OFFSET {$this->QBOffset}" : ''); } @@ -252,7 +252,7 @@ protected function _limit($sql) * @internal param the $string table name * @internal param the $array update data */ - protected function _update($table, $values) + protected function _update(string $table, array $values): string { if (! empty($this->QBLimit)) { @@ -276,7 +276,7 @@ protected function _update($table, $values) * * @return string */ - protected function _updateBatch($table, $values, $index) + protected function _updateBatch(string $table, array $values, string $index): string { $ids = []; foreach ($values as $key => $val) @@ -316,7 +316,7 @@ protected function _updateBatch($table, $values, $index) * * @return string */ - protected function _delete($table) + protected function _delete(string $table): string { $this->QBLimit = false; return parent::_delete($table); @@ -336,7 +336,7 @@ protected function _delete($table) * * @return string */ - protected function _truncate($table) + protected function _truncate(string $table): string { return 'TRUNCATE ' . $table . ' RESTART IDENTITY'; } @@ -351,11 +351,11 @@ protected function _truncate($table) * * @see https://www.postgresql.org/docs/9.2/static/functions-matching.html * - * @param string|null $prefix - * @param string $column - * @param string|null $not - * @param string $bind - * @param boolean $insensitiveSearch + * @param string $prefix + * @param string $column + * @param string $not + * @param string $bind + * @param boolean $insensitiveSearch * * @return string $like_statement */ diff --git a/system/Database/SQLite3/Builder.php b/system/Database/SQLite3/Builder.php index 11f9d7ec2dbe..4d1c84e213e6 100644 --- a/system/Database/SQLite3/Builder.php +++ b/system/Database/SQLite3/Builder.php @@ -82,7 +82,7 @@ class Builder extends BaseBuilder * * @return string */ - protected function _replace($table, $keys, $values) + protected function _replace(string $table, array $keys, array $values): string { return 'INSERT OR ' . parent::_replace($table, $keys, $values); } @@ -100,7 +100,7 @@ protected function _replace($table, $keys, $values) * @param string $table * @return string */ - protected function _truncate($table) + protected function _truncate(string $table): string { return 'DELETE FROM ' . $table; } diff --git a/system/Language/en/Database.php b/system/Language/en/Database.php index 8f8149f2c982..9afce1863724 100644 --- a/system/Language/en/Database.php +++ b/system/Language/en/Database.php @@ -26,5 +26,6 @@ 'featureUnavailable' => 'This feature is not available for the database you are using.', 'tableNotFound' => 'Table `{0}` was not found in the current database.', 'noPrimaryKey' => '`{0}` model class does not specify a Primary Key.', + 'forEmptyInputGiven' => 'Empty statement is given for the field `{0}`', 'forFindColumnHaveMultipleColumns' => 'Only single column allowed in Column name.', ]; diff --git a/tests/system/Database/Builder/EmptyTest.php b/tests/system/Database/Builder/EmptyTest.php index 1720ce76549b..835ab3fbcd86 100644 --- a/tests/system/Database/Builder/EmptyTest.php +++ b/tests/system/Database/Builder/EmptyTest.php @@ -20,8 +20,7 @@ protected function setUp() public function testEmptyWithNoTable() { - $builder = new BaseBuilder('jobs', $this->db); - $builder->returnDeleteSQL = true; + $builder = new BaseBuilder('jobs', $this->db); $answer = $builder->emptyTable(true); diff --git a/tests/system/Database/Builder/SelectTest.php b/tests/system/Database/Builder/SelectTest.php index 58fe22f22867..1623149e7317 100644 --- a/tests/system/Database/Builder/SelectTest.php +++ b/tests/system/Database/Builder/SelectTest.php @@ -1,6 +1,7 @@ db); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); - $this->expectExceptionMessage('The query you submitted is not valid.'); + $this->expectException(DataException::class); + $this->expectExceptionMessage('Empty statement is given for the field `Select`'); $builder->selectSum(''); } @@ -222,4 +223,17 @@ public function testSelectMaxWithDotNameAndNoAlias() } //-------------------------------------------------------------------- + + public function testSelectMinThrowsExceptionOnMultipleColumn() + { + $builder = new BaseBuilder('users', $this->db); + + $this->expectException(DataException::class); + $this->expectExceptionMessage('You must provide a valid column name not separated by comma.'); + + $builder->selectSum('name,role'); + } + + //-------------------------------------------------------------------- + }