type) { case 'select': if ($this->selectRowNumber) { $orderBy = $this->selectRowNumber['orderBy']; $orderColumnAlias = $this->selectRowNumber['orderColumnAlias']; $column = "ROW_NUMBER() AS $orderColumnAlias"; if ($this->select === null) { $query = PHP_EOL . 'SELECT 1' . (string) $this->from . (string) $this->where; } else { $tmpOffset = $this->offset; $tmpLimit = $this->limit; $this->offset = 0; $this->limit = 0; $tmpOrder = $this->order; $this->order = null; $query = parent::__toString(); $column = "w.*, $column"; $this->order = $tmpOrder; $this->offset = $tmpOffset; $this->limit = $tmpLimit; } // Special sqlite query to count ROW_NUMBER $query = PHP_EOL . "SELECT $column" . PHP_EOL . "FROM ($query" . PHP_EOL . "ORDER BY $orderBy" . PHP_EOL . ') AS w,(SELECT ROW_NUMBER(0)) AS r' // Forbid to flatten subqueries. . ((string) $this->order ?: PHP_EOL . 'ORDER BY NULL'); return $this->processLimit($query, $this->limit, $this->offset); } break; case 'querySet': $query = $this->querySet; if ($query->order || $query->limit || $query->offset) { // If ORDER BY or LIMIT statement exist then parentheses is required for the first query $query = PHP_EOL . "SELECT * FROM ($query)"; } if ($this->merge) { // Special case for merge foreach ($this->merge as $element) { $query .= (string) $element; } } if ($this->order) { $query .= (string) $this->order; } return $query; case 'update': if ($this->join) { $table = $this->update->getElements(); $table = $table[0]; $tableName = explode(' ', $table); $tableName = $tableName[0]; if ($this->columns === null) { $fields = $this->db->getTableColumns($tableName); foreach ($fields as $key => $value) { $fields[$key] = $key; } $this->columns = new QueryElement('()', $fields); } $fields = $this->columns->getElements(); $elements = $this->set->getElements(); foreach ($elements as $nameValue) { $setArray = explode(' = ', $nameValue, 2); if ($setArray[0][0] === '`') { // Unquote column name $setArray[0] = substr($setArray[0], 1, -1); } $fields[$setArray[0]] = $setArray[1]; } $select = new static($this->db); $select->select(array_values($fields)) ->from($table); $select->join = $this->join; $select->where = $this->where; return 'INSERT OR REPLACE INTO ' . $tableName . ' (' . implode(',', array_keys($fields)) . ')' . (string) $select; } } return parent::__toString(); } /** * Gets the number of characters in a string. * * Note, use 'length' to find the number of bytes in a string. * * Usage: * $query->select($query->charLength('a')); * * @param string $field A value. * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * * @return string The required char length call. * * @since 1.1.0 */ public function charLength($field, $operator = null, $condition = null) { $statement = 'length(' . $field . ')'; if ($operator !== null && $condition !== null) { $statement .= ' ' . $operator . ' ' . $condition; } return $statement; } /** * Concatenates an array of column names or values. * * Usage: * $query->select($query->concatenate(array('a', 'b'))); * * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * * @return string The concatenated values. * * @since 1.1.0 */ public function concatenate($values, $separator = null) { if ($separator !== null) { return implode(' || ' . $this->quote($separator) . ' || ', $values); } return implode(' || ', $values); } /** * Method to modify a query already in string format with the needed additions to make the query limited to a particular number of * results, or start at a particular offset. * * @param string $query The query in string format * @param integer $limit The limit for the result set * @param integer $offset The offset for the result set * * @return string * * @since 1.0 */ public function processLimit($query, $limit, $offset = 0) { if ($limit > 0 || $offset > 0) { $query .= ' LIMIT ' . $offset . ', ' . $limit; } return $query; } /** * Return the number of the current row. * * Usage: * $query->select('id'); * $query->selectRowNumber('ordering,publish_up DESC', 'new_ordering'); * $query->from('#__content'); * * @param string $orderBy An expression of ordering for window function. * @param string $orderColumnAlias An alias for new ordering column. * * @return $this * * @since 2.0.0 * @throws \RuntimeException */ public function selectRowNumber($orderBy, $orderColumnAlias) { $this->validateRowNumber($orderBy, $orderColumnAlias); return $this; } /** * Add a query to UNION with the current query. * * Usage: * $query->union('SELECT name FROM #__foo') * $query->union('SELECT name FROM #__foo', true) * * @param DatabaseQuery|string $query The DatabaseQuery object or string to union. * @param boolean $distinct True to only return distinct rows from the union. * * @return $this * * @since 1.0 */ public function union($query, $distinct = true) { // Set up the name with parentheses, the DISTINCT flag is redundant return $this->merge($distinct ? 'UNION SELECT * FROM ()' : 'UNION ALL SELECT * FROM ()', $query); } /** * Aggregate function to get input values concatenated into a string, separated by delimiter * * Usage: * $query->groupConcat('id', ','); * * @param string $expression The expression to apply concatenation to, this may be a column name or complex SQL statement. * @param string $separator The delimiter of each concatenated value * * @return string Input values concatenated into a string, separated by delimiter * * @since 2.0.0 */ public function groupConcat($expression, $separator = ',') { return 'group_concat(' . $expression . ', ' . $this->quote($separator) . ')'; } }