Grammar.php
TLDR
The file src/Illuminate/Database/Query/Grammars/Grammar.php
is a part of the Laravel framework and provides the Grammar class for generating SQL queries based on the query builder in the Laravel database package.
Methods
compileSelect
This method compiles a select query into SQL.
compileComponents
This method compiles the components necessary for a select clause.
compileAggregate
This method compiles an aggregated select clause.
compileColumns
This method compiles the "select *" portion of the query.
compileFrom
This method compiles the "from" portion of the query.
compileJoins
This method compiles the "join" portions of the query.
compileWheres
This method compiles the "where" portions of the query.
compileWheresToArray
This method gets an array of all the where clauses for the query.
concatenateWhereClauses
This method formats the where clause statements into one string.
whereRaw
This method compiles a raw where clause.
whereBasic
This method compiles a basic where clause.
whereBitwise
This method compiles a bitwise operator where clause.
whereIn
This method compiles a "where in" clause.
whereNotIn
This method compiles a "where not in" clause.
whereNotInRaw
This method compiles a "where not in raw" clause.
whereInRaw
This method compiles a "where in raw" clause.
whereNull
This method compiles a "where null" clause.
whereNotNull
This method compiles a "where not null" clause.
whereBetween
This method compiles a "between" where clause.
whereBetweenColumns
This method compiles a "between columns" where clause.
whereDate
This method compiles a "where date" clause.
whereTime
This method compiles a "where time" clause.
whereDay
This method compiles a "where day" clause.
whereMonth
This method compiles a "where month" clause.
whereYear
This method compiles a "where year" clause.
whereColumn
This method compiles a where clause comparing two columns.
whereNested
This method compiles a nested where clause.
whereSub
This method compiles a where condition with a sub-select.
whereExists
This method compiles a where exists clause.
whereNotExists
This method compiles a where not exists clause.
whereRowValues
This method compiles a where row values condition.
whereJsonBoolean
This method compiles a "where JSON boolean" clause.
whereJsonContains
This method compiles a "where JSON contains" clause.
compileJsonContains
This method compiles a "JSON contains" statement into SQL.
whereJsonContainsKey
This method compiles a "where JSON contains key" clause.
compileJsonContainsKey
This method compiles a "JSON contains key" statement into SQL.
whereJsonLength
This method compiles a "where JSON length" clause.
compileJsonLength
This method compiles a "JSON length" statement into SQL.
compileJsonValueCast
This method compiles a "JSON value cast" statement into SQL.
whereFullText
This method compiles a "where fulltext" clause.
whereExpression
This method compiles a clause based on an expression.
compileGroups
This method compiles the "group by" portions of the query.
compileHavings
This method compiles the "having" portions of the query.
compileHaving
This method compiles a single having clause.
compileBasicHaving
This method compiles a basic having clause.
compileHavingBetween
This method compiles a "between" having clause.
compileHavingNull
This method compiles a having null clause.
compileHavingNotNull
This method compiles a having not null clause.
compileHavingBit
This method compiles a having clause involving a bit operator.
compileHavingExpression
This method compiles a having clause involving an expression.
compileNestedHavings
This method compiles a nested having clause.
compileOrders
This method compiles the "order by" portions of the query.
compileOrdersToArray
This method compiles the query orders to an array.
compileRandom
This method compiles the random statement into SQL.
compileLimit
This method compiles the "limit" portion of the query.
compileOffset
This method compiles the "offset" portion of the query.
compileUnions
This method compiles the "union" queries attached to the main query.
compileUnion
This method compiles a single union statement.
wrapUnion
This method wraps a union subquery in parentheses.
compileUnionAggregate
This method compiles a union aggregate query into SQL.
compileExists
This method compiles an exists statement into SQL.
compileInsert
This method compiles an insert statement into SQL.
compileInsertOrIgnore
This method compiles an insert ignore statement into SQL.
compileInsertGetId
This method compiles an insert and get ID statement into SQL.
compileInsertUsing
This method compiles an insert statement using a subquery into SQL.
compileUpdate
This method compiles an update statement into SQL.
compileUpdateColumns
This method compiles the columns for an update statement.
compileUpdateWithoutJoins
This method compiles an update statement without joins into SQL.
compileUpdateWithJoins
This method compiles an update statement with joins into SQL.
compileUpsert
This method compiles an "upsert" statement into SQL.
prepareBindingsForUpdate
This method prepares the bindings for an update statement.
compileDelete
This method compiles a delete statement into SQL.
compileDeleteWithoutJoins
This method compiles a delete statement without joins into SQL.
compileDeleteWithJoins
This method compiles a delete statement with joins into SQL.
prepareBindingsForDelete
This method prepares the bindings for a delete statement.
compileTruncate
This method compiles a truncate table statement into SQL.
compileLock
This method compiles the lock into SQL.
compileSavepoint
This method compiles the SQL statement to define a savepoint.
compileSavepointRollBack
This method compiles the SQL statement to execute a savepoint rollback.
wrapJsonBooleanSelector
This method wraps the given JSON selector for boolean values.
wrapJsonBooleanValue
This method wraps the given JSON boolean value.
concatenate
This method concatenates an array of segments, removing empties.
removeLeadingBoolean
This method removes the leading boolean from a statement.
substituteBindingsIntoRawSql
This method substitutes the given bindings into the given raw SQL query.
getOperators
This method gets the grammar specific operators.
getBitwiseOperators
This method gets the grammar specific bitwise operators.
Classes
None.
<?php
namespace Illuminate\Database\Query\Grammars;
use Illuminate\Contracts\Database\Query\Expression;
use Illuminate\Database\Concerns\CompilesJsonPaths;
use Illuminate\Database\Grammar as BaseGrammar;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Arr;
use RuntimeException;
class Grammar extends BaseGrammar
{
use CompilesJsonPaths;
/**
* The grammar specific operators.
*
* @var array
*/
protected $operators = [];
/**
* The grammar specific bitwise operators.
*
* @var array
*/
protected $bitwiseOperators = [];
/**
* The components that make up a select clause.
*
* @var string[]
*/
protected $selectComponents = [
'aggregate',
'columns',
'from',
'indexHint',
'joins',
'wheres',
'groups',
'havings',
'orders',
'limit',
'offset',
'lock',
];
/**
* Compile a select query into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileSelect(Builder $query)
{
if (($query->unions || $query->havings) && $query->aggregate) {
return $this->compileUnionAggregate($query);
}
// If the query does not have any columns set, we'll set the columns to the
// * character to just get all of the columns from the database. Then we
// can build the query and concatenate all the pieces together as one.
$original = $query->columns;
if (is_null($query->columns)) {
$query->columns = ['*'];
}
// To compile the query, we'll spin through each component of the query and
// see if that component exists. If it does we'll just call the compiler
// function for the component which is responsible for making the SQL.
$sql = trim($this->concatenate(
$this->compileComponents($query))
);
if ($query->unions) {
$sql = $this->wrapUnion($sql).' '.$this->compileUnions($query);
}
$query->columns = $original;
return $sql;
}
/**
* Compile the components necessary for a select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
protected function compileComponents(Builder $query)
{
$sql = [];
foreach ($this->selectComponents as $component) {
if (isset($query->$component)) {
$method = 'compile'.ucfirst($component);
$sql[$component] = $this->$method($query, $query->$component);
}
}
return $sql;
}
/**
* Compile an aggregated select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $aggregate
* @return string
*/
protected function compileAggregate(Builder $query, $aggregate)
{
$column = $this->columnize($aggregate['columns']);
// If the query has a "distinct" constraint and we're not asking for all columns
// we need to prepend "distinct" onto the column name so that the query takes
// it into account when it performs the aggregating operations on the data.
if (is_array($query->distinct)) {
$column = 'distinct '.$this->columnize($query->distinct);
} elseif ($query->distinct && $column !== '*') {
$column = 'distinct '.$column;
}
return 'select '.$aggregate['function'].'('.$column.') as aggregate';
}
/**
* Compile the "select *" portion of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $columns
* @return string|null
*/
protected function compileColumns(Builder $query, $columns)
{
// If the query is actually performing an aggregating select, we will let that
// compiler handle the building of the select clauses, as it will need some
// more syntax that is best handled by that function to keep things neat.
if (! is_null($query->aggregate)) {
return;
}
if ($query->distinct) {
$select = 'select distinct ';
} else {
$select = 'select ';
}
return $select.$this->columnize($columns);
}
/**
* Compile the "from" portion of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @return string
*/
protected function compileFrom(Builder $query, $table)
{
return 'from '.$this->wrapTable($table);
}
/**
* Compile the "join" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $joins
* @return string
*/
protected function compileJoins(Builder $query, $joins)
{
return collect($joins)->map(function ($join) use ($query) {
$table = $this->wrapTable($join->table);
$nestedJoins = is_null($join->joins) ? '' : ' '.$this->compileJoins($query, $join->joins);
$tableAndNestedJoins = is_null($join->joins) ? $table : '('.$table.$nestedJoins.')';
return trim("{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}");
})->implode(' ');
}
/**
* Compile the "where" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileWheres(Builder $query)
{
// Each type of where clause has its own compiler function, which is responsible
// for actually creating the where clauses SQL. This helps keep the code nice
// and maintainable since each clause has a very small method that it uses.
if (is_null($query->wheres)) {
return '';
}
// If we actually have some where clauses, we will strip off the first boolean
// operator, which is added by the query builders for convenience so we can
// avoid checking for the first clauses in each of the compilers methods.
if (count($sql = $this->compileWheresToArray($query)) > 0) {
return $this->concatenateWhereClauses($query, $sql);
}
return '';
}
/**
* Get an array of all the where clauses for the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
protected function compileWheresToArray($query)
{
return collect($query->wheres)->map(function ($where) use ($query) {
return $where['boolean'].' '.$this->{"where{$where['type']}"}($query, $where);
})->all();
}
/**
* Format the where clause statements into one string.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $sql
* @return string
*/
protected function concatenateWhereClauses($query, $sql)
{
$conjunction = $query instanceof JoinClause ? 'on' : 'where';
return $conjunction.' '.$this->removeLeadingBoolean(implode(' ', $sql));
}
/**
* Compile a raw where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereRaw(Builder $query, $where)
{
return $where['sql'] instanceof Expression ? $where['sql']->getValue($this) : $where['sql'];
}
/**
* Compile a basic where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereBasic(Builder $query, $where)
{
$value = $this->parameter($where['value']);
$operator = str_replace('?', '??', $where['operator']);
return $this->wrap($where['column']).' '.$operator.' '.$value;
}
/**
* Compile a bitwise operator where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereBitwise(Builder $query, $where)
{
return $this->whereBasic($query, $where);
}
/**
* Compile a "where in" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereIn(Builder $query, $where)
{
if (! empty($where['values'])) {
return $this->wrap($where['column']).' in ('.$this->parameterize($where['values']).')';
}
return '0 = 1';
}
/**
* Compile a "where not in" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotIn(Builder $query, $where)
{
if (! empty($where['values'])) {
return $this->wrap($where['column']).' not in ('.$this->parameterize($where['values']).')';
}
return '1 = 1';
}
/**
* Compile a "where not in raw" clause.
*
* For safety, whereIntegerInRaw ensures this method is only used with integer values.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotInRaw(Builder $query, $where)
{
if (! empty($where['values'])) {
return $this->wrap($where['column']).' not in ('.implode(', ', $where['values']).')';
}
return '1 = 1';
}
/**
* Compile a "where in raw" clause.
*
* For safety, whereIntegerInRaw ensures this method is only used with integer values.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereInRaw(Builder $query, $where)
{
if (! empty($where['values'])) {
return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')';
}
return '0 = 1';
}
/**
* Compile a "where null" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNull(Builder $query, $where)
{
return $this->wrap($where['column']).' is null';
}
/**
* Compile a "where not null" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotNull(Builder $query, $where)
{
return $this->wrap($where['column']).' is not null';
}
/**
* Compile a "between" where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereBetween(Builder $query, $where)
{
$between = $where['not'] ? 'not between' : 'between';
$min = $this->parameter(is_array($where['values']) ? reset($where['values']) : $where['values'][0]);
$max = $this->parameter(is_array($where['values']) ? end($where['values']) : $where['values'][1]);
return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max;
}
/**
* Compile a "between" where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereBetweenColumns(Builder $query, $where)
{
$between = $where['not'] ? 'not between' : 'between';
$min = $this->wrap(is_array($where['values']) ? reset($where['values']) : $where['values'][0]);
$max = $this->wrap(is_array($where['values']) ? end($where['values']) : $where['values'][1]);
return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max;
}
/**
* Compile a "where date" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDate(Builder $query, $where)
{
return $this->dateBasedWhere('date', $query, $where);
}
/**
* Compile a "where time" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereTime(Builder $query, $where)
{
return $this->dateBasedWhere('time', $query, $where);
}
/**
* Compile a "where day" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDay(Builder $query, $where)
{
return $this->dateBasedWhere('day', $query, $where);
}
/**
* Compile a "where month" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereMonth(Builder $query, $where)
{
return $this->dateBasedWhere('month', $query, $where);
}
/**
* Compile a "where year" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereYear(Builder $query, $where)
{
return $this->dateBasedWhere('year', $query, $where);
}
/**
* Compile a date based where clause.
*
* @param string $type
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function dateBasedWhere($type, Builder $query, $where)
{
$value = $this->parameter($where['value']);
return $type.'('.$this->wrap($where['column']).') '.$where['operator'].' '.$value;
}
/**
* Compile a where clause comparing two columns.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereColumn(Builder $query, $where)
{
return $this->wrap($where['first']).' '.$where['operator'].' '.$this->wrap($where['second']);
}
/**
* Compile a nested where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNested(Builder $query, $where)
{
// Here we will calculate what portion of the string we need to remove. If this
// is a join clause query, we need to remove the "on" portion of the SQL and
// if it is a normal query we need to take the leading "where" of queries.
$offset = $where['query'] instanceof JoinClause ? 3 : 6;
return '('.substr($this->compileWheres($where['query']), $offset).')';
}
/**
* Compile a where condition with a sub-select.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereSub(Builder $query, $where)
{
$select = $this->compileSelect($where['query']);
return $this->wrap($where['column']).' '.$where['operator']." ($select)";
}
/**
* Compile a where exists clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereExists(Builder $query, $where)
{
return 'exists ('.$this->compileSelect($where['query']).')';
}
/**
* Compile a where exists clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotExists(Builder $query, $where)
{
return 'not exists ('.$this->compileSelect($where['query']).')';
}
/**
* Compile a where row values condition.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereRowValues(Builder $query, $where)
{
$columns = $this->columnize($where['columns']);
$values = $this->parameterize($where['values']);
return '('.$columns.') '.$where['operator'].' ('.$values.')';
}
/**
* Compile a "where JSON boolean" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereJsonBoolean(Builder $query, $where)
{
$column = $this->wrapJsonBooleanSelector($where['column']);
$value = $this->wrapJsonBooleanValue(
$this->parameter($where['value'])
);
return $column.' '.$where['operator'].' '.$value;
}
/**
* Compile a "where JSON contains" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereJsonContains(Builder $query, $where)
{
$not = $where['not'] ? 'not ' : '';
return $not.$this->compileJsonContains(
$where['column'],
$this->parameter($where['value'])
);
}
/**
* Compile a "JSON contains" statement into SQL.
*
* @param string $column
* @param string $value
* @return string
*
* @throws \RuntimeException
*/
protected function compileJsonContains($column, $value)
{
throw new RuntimeException('This database engine does not support JSON contains operations.');
}
/**
* Prepare the binding for a "JSON contains" statement.
*
* @param mixed $binding
* @return string
*/
public function prepareBindingForJsonContains($binding)
{
return json_encode($binding, JSON_UNESCAPED_UNICODE);
}
/**
* Compile a "where JSON contains key" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereJsonContainsKey(Builder $query, $where)
{
$not = $where['not'] ? 'not ' : '';
return $not.$this->compileJsonContainsKey(
$where['column']
);
}
/**
* Compile a "JSON contains key" statement into SQL.
*
* @param string $column
* @return string
*
* @throws \RuntimeException
*/
protected function compileJsonContainsKey($column)
{
throw new RuntimeException('This database engine does not support JSON contains key operations.');
}
/**
* Compile a "where JSON length" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereJsonLength(Builder $query, $where)
{
return $this->compileJsonLength(
$where['column'],
$where['operator'],
$this->parameter($where['value'])
);
}
/**
* Compile a "JSON length" statement into SQL.
*
* @param string $column
* @param string $operator
* @param string $value
* @return string
*
* @throws \RuntimeException
*/
protected function compileJsonLength($column, $operator, $value)
{
throw new RuntimeException('This database engine does not support JSON length operations.');
}
/**
* Compile a "JSON value cast" statement into SQL.
*
* @param string $value
* @return string
*/
public function compileJsonValueCast($value)
{
return $value;
}
/**
* Compile a "where fulltext" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
public function whereFullText(Builder $query, $where)
{
throw new RuntimeException('This database engine does not support fulltext search operations.');
}
/**
* Compile a clause based on an expression.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
public function whereExpression(Builder $query, $where)
{
return $where['column']->getValue($this);
}
/**
* Compile the "group by" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $groups
* @return string
*/
protected function compileGroups(Builder $query, $groups)
{
return 'group by '.$this->columnize($groups);
}
/**
* Compile the "having" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileHavings(Builder $query)
{
return 'having '.$this->removeLeadingBoolean(collect($query->havings)->map(function ($having) {
return $having['boolean'].' '.$this->compileHaving($having);
})->implode(' '));
}
/**
* Compile a single having clause.
*
* @param array $having
* @return string
*/
protected function compileHaving(array $having)
{
// If the having clause is "raw", we can just return the clause straight away
// without doing any more processing on it. Otherwise, we will compile the
// clause into SQL based on the components that make it up from builder.
return match ($having['type']) {
'Raw' => $having['sql'],
'between' => $this->compileHavingBetween($having),
'Null' => $this->compileHavingNull($having),
'NotNull' => $this->compileHavingNotNull($having),
'bit' => $this->compileHavingBit($having),
'Expression' => $this->compileHavingExpression($having),
'Nested' => $this->compileNestedHavings($having),
default => $this->compileBasicHaving($having),
};
}
/**
* Compile a basic having clause.
*
* @param array $having
* @return string
*/
protected function compileBasicHaving($having)
{
$column = $this->wrap($having['column']);
$parameter = $this->parameter($having['value']);
return $column.' '.$having['operator'].' '.$parameter;
}
/**
* Compile a "between" having clause.
*
* @param array $having
* @return string
*/
protected function compileHavingBetween($having)
{
$between = $having['not'] ? 'not between' : 'between';
$column = $this->wrap($having['column']);
$min = $this->parameter(head($having['values']));
$max = $this->parameter(last($having['values']));
return $column.' '.$between.' '.$min.' and '.$max;
}
/**
* Compile a having null clause.
*
* @param array $having
* @return string
*/
protected function compileHavingNull($having)
{
$column = $this->wrap($having['column']);
return $column.' is null';
}
/**
* Compile a having not null clause.
*
* @param array $having
* @return string
*/
protected function compileHavingNotNull($having)
{
$column = $this->wrap($having['column']);
return $column.' is not null';
}
/**
* Compile a having clause involving a bit operator.
*
* @param array $having
* @return string
*/
protected function compileHavingBit($having)
{
$column = $this->wrap($having['column']);
$parameter = $this->parameter($having['value']);
return '('.$column.' '.$having['operator'].' '.$parameter.') != 0';
}
/**
* Compile a having clause involving an expression.
*
* @param array $having
* @return string
*/
protected function compileHavingExpression($having)
{
return $having['column']->getValue($this);
}
/**
* Compile a nested having clause.
*
* @param array $having
* @return string
*/
protected function compileNestedHavings($having)
{
return '('.substr($this->compileHavings($having['query']), 7).')';
}
/**
* Compile the "order by" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $orders
* @return string
*/
protected function compileOrders(Builder $query, $orders)
{
if (! empty($orders)) {
return 'order by '.implode(', ', $this->compileOrdersToArray($query, $orders));
}
return '';
}
/**
* Compile the query orders to an array.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $orders
* @return array
*/
protected function compileOrdersToArray(Builder $query, $orders)
{
return array_map(function ($order) {
return $order['sql'] ?? $this->wrap($order['column']).' '.$order['direction'];
}, $orders);
}
/**
* Compile the random statement into SQL.
*
* @param string|int $seed
* @return string
*/
public function compileRandom($seed)
{
return 'RANDOM()';
}
/**
* Compile the "limit" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $limit
* @return string
*/
protected function compileLimit(Builder $query, $limit)
{
return 'limit '.(int) $limit;
}
/**
* Compile the "offset" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $offset
* @return string
*/
protected function compileOffset(Builder $query, $offset)
{
return 'offset '.(int) $offset;
}
/**
* Compile the "union" queries attached to the main query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileUnions(Builder $query)
{
$sql = '';
foreach ($query->unions as $union) {
$sql .= $this->compileUnion($union);
}
if (! empty($query->unionOrders)) {
$sql .= ' '.$this->compileOrders($query, $query->unionOrders);
}
if (isset($query->unionLimit)) {
$sql .= ' '.$this->compileLimit($query, $query->unionLimit);
}
if (isset($query->unionOffset)) {
$sql .= ' '.$this->compileOffset($query, $query->unionOffset);
}
return ltrim($sql);
}
/**
* Compile a single union statement.
*
* @param array $union
* @return string
*/
protected function compileUnion(array $union)
{
$conjunction = $union['all'] ? ' union all ' : ' union ';
return $conjunction.$this->wrapUnion($union['query']->toSql());
}
/**
* Wrap a union subquery in parentheses.
*
* @param string $sql
* @return string
*/
protected function wrapUnion($sql)
{
return '('.$sql.')';
}
/**
* Compile a union aggregate query into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileUnionAggregate(Builder $query)
{
$sql = $this->compileAggregate($query, $query->aggregate);
$query->aggregate = null;
return $sql.' from ('.$this->compileSelect($query).') as '.$this->wrapTable('temp_table');
}
/**
* Compile an exists statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileExists(Builder $query)
{
$select = $this->compileSelect($query);
return "select exists({$select}) as {$this->wrap('exists')}";
}
/**
* Compile an insert statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsert(Builder $query, array $values)
{
// Essentially we will force every insert to be treated as a batch insert which
// simply makes creating the SQL easier for us since we can utilize the same
// basic routine regardless of an amount of records given to us to insert.
$table = $this->wrapTable($query->from);
if (empty($values)) {
return "insert into {$table} default values";
}
if (! is_array(reset($values))) {
$values = [$values];
}
$columns = $this->columnize(array_keys(reset($values)));
// We need to build a list of parameter place-holders of values that are bound
// to the query. Each insert should have the exact same number of parameter
// bindings so we will loop through the record and parameterize them all.
$parameters = collect($values)->map(function ($record) {
return '('.$this->parameterize($record).')';
})->implode(', ');
return "insert into $table ($columns) values $parameters";
}
/**
* Compile an insert ignore statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*
* @throws \RuntimeException
*/
public function compileInsertOrIgnore(Builder $query, array $values)
{
throw new RuntimeException('This database engine does not support inserting while ignoring errors.');
}
/**
* Compile an insert and get ID statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @param string $sequence
* @return string
*/
public function compileInsertGetId(Builder $query, $values, $sequence)
{
return $this->compileInsert($query, $values);
}
/**
* Compile an insert statement using a subquery into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $columns
* @param string $sql
* @return string
*/
public function compileInsertUsing(Builder $query, array $columns, string $sql)
{
$table = $this->wrapTable($query->from);
if (empty($columns) || $columns === ['*']) {
return "insert into {$table} $sql";
}
return "insert into {$table} ({$this->columnize($columns)}) $sql";
}
/**
* Compile an update statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileUpdate(Builder $query, array $values)
{
$table = $this->wrapTable($query->from);
$columns = $this->compileUpdateColumns($query, $values);
$where = $this->compileWheres($query);
return trim(
isset($query->joins)
? $this->compileUpdateWithJoins($query, $table, $columns, $where)
: $this->compileUpdateWithoutJoins($query, $table, $columns, $where)
);
}
/**
* Compile the columns for an update statement.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
protected function compileUpdateColumns(Builder $query, array $values)
{
return collect($values)->map(function ($value, $key) {
return $this->wrap($key).' = '.$this->parameter($value);
})->implode(', ');
}
/**
* Compile an update statement without joins into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @param string $columns
* @param string $where
* @return string
*/
protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where)
{
return "update {$table} set {$columns} {$where}";
}
/**
* Compile an update statement with joins into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @param string $columns
* @param string $where
* @return string
*/
protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where)
{
$joins = $this->compileJoins($query, $query->joins);
return "update {$table} {$joins} set {$columns} {$where}";
}
/**
* Compile an "upsert" statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @param array $uniqueBy
* @param array $update
* @return string
*
* @throws \RuntimeException
*/
public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
{
throw new RuntimeException('This database engine does not support upserts.');
}
/**
* Prepare the bindings for an update statement.
*
* @param array $bindings
* @param array $values
* @return array
*/
public function prepareBindingsForUpdate(array $bindings, array $values)
{
$cleanBindings = Arr::except($bindings, ['select', 'join']);
return array_values(
array_merge($bindings['join'], $values, Arr::flatten($cleanBindings))
);
}
/**
* Compile a delete statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileDelete(Builder $query)
{
$table = $this->wrapTable($query->from);
$where = $this->compileWheres($query);
return trim(
isset($query->joins)
? $this->compileDeleteWithJoins($query, $table, $where)
: $this->compileDeleteWithoutJoins($query, $table, $where)
);
}
/**
* Compile a delete statement without joins into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @param string $where
* @return string
*/
protected function compileDeleteWithoutJoins(Builder $query, $table, $where)
{
return "delete from {$table} {$where}";
}
/**
* Compile a delete statement with joins into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @param string $where
* @return string
*/
protected function compileDeleteWithJoins(Builder $query, $table, $where)
{
$alias = last(explode(' as ', $table));
$joins = $this->compileJoins($query, $query->joins);
return "delete {$alias} from {$table} {$joins} {$where}";
}
/**
* Prepare the bindings for a delete statement.
*
* @param array $bindings
* @return array
*/
public function prepareBindingsForDelete(array $bindings)
{
return Arr::flatten(
Arr::except($bindings, 'select')
);
}
/**
* Compile a truncate table statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
public function compileTruncate(Builder $query)
{
return ['truncate table '.$this->wrapTable($query->from) => []];
}
/**
* Compile the lock into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param bool|string $value
* @return string
*/
protected function compileLock(Builder $query, $value)
{
return is_string($value) ? $value : '';
}
/**
* Determine if the grammar supports savepoints.
*
* @return bool
*/
public function supportsSavepoints()
{
return true;
}
/**
* Compile the SQL statement to define a savepoint.
*
* @param string $name
* @return string
*/
public function compileSavepoint($name)
{
return 'SAVEPOINT '.$name;
}
/**
* Compile the SQL statement to execute a savepoint rollback.
*
* @param string $name
* @return string
*/
public function compileSavepointRollBack($name)
{
return 'ROLLBACK TO SAVEPOINT '.$name;
}
/**
* Wrap the given JSON selector for boolean values.
*
* @param string $value
* @return string
*/
protected function wrapJsonBooleanSelector($value)
{
return $this->wrapJsonSelector($value);
}
/**
* Wrap the given JSON boolean value.
*
* @param string $value
* @return string
*/
protected function wrapJsonBooleanValue($value)
{
return $value;
}
/**
* Concatenate an array of segments, removing empties.
*
* @param array $segments
* @return string
*/
protected function concatenate($segments)
{
return implode(' ', array_filter($segments, function ($value) {
return (string) $value !== '';
}));
}
/**
* Remove the leading boolean from a statement.
*
* @param string $value
* @return string
*/
protected function removeLeadingBoolean($value)
{
return preg_replace('/and |or /i', '', $value, 1);
}
/**
* Substitute the given bindings into the given raw SQL query.
*
* @param string $sql
* @param array $bindings
* @return string
*/
public function substituteBindingsIntoRawSql($sql, $bindings)
{
$bindings = array_map(fn ($value) => $this->escape($value), $bindings);
$query = '';
$isStringLiteral = false;
for ($i = 0; $i < strlen($sql); $i++) {
$char = $sql[$i];
$nextChar = $sql[$i + 1] ?? null;
// Single quotes can be escaped as '' according to the SQL standard while
// MySQL uses \'. Postgres has operators like ?| that must get encoded
// in PHP like ??|. We should skip over the escaped characters here.
if (in_array($char.$nextChar, ["\'", "''", '??'])) {
$query .= $char.$nextChar;
$i += 1;
} elseif ($char === "'") { // Starting / leaving string literal...
$query .= $char;
$isStringLiteral = ! $isStringLiteral;
} elseif ($char === '?' && ! $isStringLiteral) { // Substitutable binding...
$query .= array_shift($bindings) ?? '?';
} else { // Normal character...
$query .= $char;
}
}
return $query;
}
/**
* Get the grammar specific operators.
*
* @return array
*/
public function getOperators()
{
return $this->operators;
}
/**
* Get the grammar specific bitwise operators.
*
* @return array
*/
public function getBitwiseOperators()
{
return $this->bitwiseOperators;
}
}