Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libraries/joomla/database/driver/postgresql.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class JDatabaseDriverPostgresql extends JDatabaseDriver
* @var string
* @since 12.1
*/
protected static $dbMinimum = '8.3.18';
protected static $dbMinimum = '8.4.2';

/**
* Operator used for concatenation
Expand Down
51 changes: 51 additions & 0 deletions libraries/joomla/database/driver/sqlite.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,57 @@ public function __destruct()
$this->connection = null;
}

/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 12.1
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}

parent::connect();

$this->connection->sqliteCreateFunction(
'ROW_NUMBER',
function($init = null)
{
static $rownum, $partition;

if ($init !== null)
{
$rownum = $init;
$partition = null;

return $rownum;
}

$args = func_get_args();
array_shift($args);

$partitionBy = $args ? implode(',', $args) : null;

if ($partitionBy === null || $partitionBy === $partition)
{
$rownum++;
}
else
{
$rownum = 1;
$partition = $partitionBy;
}

return $rownum;
}
);
}

/**
* Disconnects the database.
*
Expand Down
121 changes: 107 additions & 14 deletions libraries/joomla/database/query.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ abstract class JDatabaseQuery
*/
protected $unionAll = null;

/**
* @var array Details of window function.
* @since __DEPLOY_VERSION__
*/
protected $selectRowNumber = null;

/**
* Magic method to provide method alias support for quote() and quoteName().
*
Expand Down Expand Up @@ -241,24 +247,27 @@ public function __toString()
$query .= (string) $this->where;
}

if ($this->group)
if ($this->selectRowNumber === null)
{
$query .= (string) $this->group;
}
if ($this->group)
{
$query .= (string) $this->group;
}

if ($this->having)
{
$query .= (string) $this->having;
}
if ($this->having)
{
$query .= (string) $this->having;
}

if ($this->union)
{
$query .= (string) $this->union;
}
if ($this->union)
{
$query .= (string) $this->union;
}

if ($this->unionAll)
{
$query .= (string) $this->unionAll;
if ($this->unionAll)
{
$query .= (string) $this->unionAll;
}
}

if ($this->order)
Expand Down Expand Up @@ -468,6 +477,7 @@ public function clear($clause = null)
case 'select':
$this->select = null;
$this->type = null;
$this->selectRowNumber = null;
break;

case 'delete':
Expand Down Expand Up @@ -552,6 +562,7 @@ public function clear($clause = null)
default:
$this->type = null;
$this->select = null;
$this->selectRowNumber = null;
$this->delete = null;
$this->update = null;
$this->insert = null;
Expand Down Expand Up @@ -1817,4 +1828,86 @@ public function findInSet($value, $set)
{
return "";
}

/**
* Validate arguments which are passed to selectRowNumber method and set up common variables.
*
* @param string $orderBy An expression of ordering for window function.
* @param string $orderColumnAlias An alias for new ordering column.
* @param string $partitionBy An expression of grouping for window function.
* @param string $partitionColumnAlias An alias for calculated grouping column.
*
* @return void
*
* @since __DEPLOY_VERSION__
* @throws RuntimeException
*/
protected function validateRowNumber($orderBy, $orderColumnAlias, $partitionBy = null, $partitionColumnAlias = null)
{
if ($this->selectRowNumber)
{
throw new RuntimeException("Method 'selectRowNumber' can be called only once per instance.");
}

// Required by sqlite
if ($partitionBy !== null && $partitionColumnAlias !== null)
{
if (strpos($partitionBy, ',') !== false)
{
$this->select($this->concatenate(explode(',', $partitionBy), ',') . ' AS ' . $partitionColumnAlias);
}
else
{
$this->select($partitionBy . ' AS ' . $partitionColumnAlias);
}

}
else
{
$this->type = 'select';
}

$this->selectRowNumber = array(
'orderBy' => $orderBy,
'orderColumnAlias' => $orderColumnAlias,
'partitionBy' => $partitionBy,
'partitionColumnAlias' => $partitionColumnAlias,
);
}

/**
* Return the number of the current row, support for partition, starting from 1
*
* 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.
* @param string $partitionBy An expression of grouping for window function.
* @param string $partitionColumnAlias An alias for calculated grouping column.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since __DEPLOY_VERSION__
* @throws RuntimeException
*/
public function selectRowNumber($orderBy, $orderColumnAlias, $partitionBy = null, $partitionColumnAlias = null)
{
$this->validateRowNumber($orderBy, $orderColumnAlias, $partitionBy, $partitionColumnAlias);

$column = "ROW_NUMBER() OVER (";

if ($partitionBy !== null)
{
$column .= "PARTITION BY $partitionBy ";
}

$column .= "ORDER BY $orderBy) AS $orderColumnAlias";

$this->select($column);

return $this;
}
}
79 changes: 79 additions & 0 deletions libraries/joomla/database/query/mysqli.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,52 @@ class JDatabaseQueryMysqli extends JDatabaseQuery implements JDatabaseQueryLimit
*/
protected $limit;

/**
* Magic function to convert the query to a string.
*
* @return string The completed query.
*
* @since 11.1
*/
public function __toString()
{
switch ($this->type)
{
case 'select':
if ($this->selectRowNumber)
{
$orderBy = $this->selectRowNumber['orderBy'];

if ($this->selectRowNumber['partitionBy'] !== null && $this->selectRowNumber['partitionColumnAlias'] !== null)
{
$orderBy = $this->selectRowNumber['partitionBy'] . ',' . $orderBy;
}

$tmpOffset = $this->offset;
$tmpLimit = $this->limit;
$this->offset = 0;
$this->limit = 0;
$tmpOrder = $this->order;
$this->order = new JDatabaseQueryElement('ORDER BY', $orderBy);
$query = parent::__toString();
$this->order = $tmpOrder;
$this->offset = $tmpOffset;
$this->limit = $tmpLimit;

if ($this->offset || $this->limit || $this->order)
{
// Add support for second order by, offset and limit
$query = PHP_EOL . "SELECT * FROM ( " . (string) $query . " ) w" . (string) $this->order;
$query = $this->processLimit($query, $this->limit, $this->offset);
}

return $query;
}
}

return parent::__toString();
}

/**
* Method to modify a query already in string format with the needed
* additions to make the query limited to a particular number of
Expand Down Expand Up @@ -162,4 +208,37 @@ public function findInSet($value, $set)
{
return " find_in_set(" . $value . ", " . $set . ")";
}

/**
* Return the number of the current row, support for partition, starting from 1
*
* @param string $orderBy An expression of ordering for window function.
* @param string $orderColumnAlias An alias for new ordering column.
* @param string $partitionBy An expression of grouping for window function.
* @param string $partitionColumnAlias An alias for calculated grouping column.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since __DEPLOY_VERSION__
* @throws RuntimeException
*/
public function selectRowNumber($orderBy, $orderColumnAlias, $partitionBy = null, $partitionColumnAlias = null)
{
$this->validateRowNumber($orderBy, $orderColumnAlias, $partitionBy, $partitionColumnAlias);

if ($partitionBy !== null && $partitionColumnAlias !== null)
{
$column = "(SELECT @rownum := IF(@group = CONCAT_WS(',', $partitionBy)"
. " OR ((@group := CONCAT_WS(',', $partitionBy)) AND 0), @rownum + 1, 1)"
. " FROM (SELECT @rownum := 0, @group := '') AS r) AS $orderColumnAlias";
}
else
{
$column = "(SELECT @rownum := @rownum + 1 FROM (SELECT @rownum := 0) AS r) AS $orderColumnAlias";
}

$this->select($column);

return $this;
}
}
33 changes: 28 additions & 5 deletions libraries/joomla/database/query/postgresql.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ public function __toString()
$query .= (string) $this->where;
}

if ($this->selectRowNumber)
{
if ($this->order)
{
$query .= (string) $this->order;
}

break;
}

if ($this->group)
{
$query .= (string) $this->group;
Expand Down Expand Up @@ -123,23 +133,36 @@ public function __toString()

if ($this->join)
{
$onWord = ' ON ';
$tmpFrom = $this->from;
$tmpWhere = $this->where ? clone $this->where : null;
$this->from = null;

// Workaround for special case of JOIN with UPDATE
foreach ($this->join as $join)
{
$joinElem = $join->getElements();

$joinArray = explode($onWord, $joinElem[0]);
$joinArray = preg_split('/\sON\s/i', $joinElem[0], 2);

$this->from($joinArray[0]);
$this->where($joinArray[1]);

if (isset($joinArray[1]))
{
$this->where($joinArray[1]);
}
}

$query .= (string) $this->from;
}

if ($this->where)
if ($this->where)
{
$query .= (string) $this->where;
}

$this->from = $tmpFrom;
$this->where = $tmpWhere;
}
elseif ($this->where)
{
$query .= (string) $this->where;
}
Expand Down
Loading