Spade
Mini Shell
PK��[��database.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Database connector class.
*
* @since 1.7.0
* @deprecated 4.0
*/
abstract class JDatabase
{
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 1.7.0
* @throws RuntimeException
* @deprecated 4.0
*/
public function query()
{
JLog::add('JDatabase::query() is deprecated, use
JDatabaseDriver::execute() instead.', JLog::WARNING,
'deprecated');
return $this->execute();
}
/**
* Get a list of available database connectors. The list will only be
populated with connectors that both
* the class exists and the static test method returns true. This gives
us the ability to have a multitude
* of connector classes that are self-aware as to whether or not they are
able to be used on a given system.
*
* @return array An array of available database connectors.
*
* @since 1.7.0
* @deprecated 4.0
*/
public static function getConnectors()
{
JLog::add('JDatabase::getConnectors() is deprecated, use
JDatabaseDriver::getConnectors() instead.', JLog::WARNING,
'deprecated');
return JDatabaseDriver::getConnectors();
}
/**
* Gets the error message from the database connection.
*
* @param boolean $escaped True to escape the message string for use
in JavaScript.
*
* @return string The error message for the most recent query.
*
* @deprecated 4.0
* @since 1.7.0
*/
public function getErrorMsg($escaped = false)
{
JLog::add('JDatabase::getErrorMsg() is deprecated, use exception
handling instead.', JLog::WARNING, 'deprecated');
if ($escaped)
{
return addslashes($this->errorMsg);
}
else
{
return $this->errorMsg;
}
}
/**
* Gets the error number from the database connection.
*
* @return integer The error number for the most recent query.
*
* @since 1.7.0
* @deprecated 4.0
*/
public function getErrorNum()
{
JLog::add('JDatabase::getErrorNum() is deprecated, use exception
handling instead.', JLog::WARNING, 'deprecated');
return $this->errorNum;
}
/**
* Method to return a JDatabaseDriver instance based on the given options.
There are three global options and then
* the rest are specific to the database driver. The 'driver'
option defines which JDatabaseDriver class is
* used for the connection -- the default is 'mysqli'. The
'database' option determines which database is to
* be used for the connection. The 'select' option determines
whether the connector should automatically select
* the chosen database.
*
* Instances are unique to the given options and new objects are only
created when a unique options array is
* passed into the method. This ensures that we don't end up with
unnecessary database connection resources.
*
* @param array $options Parameters to be passed to the database
driver.
*
* @return JDatabaseDriver A database object.
*
* @since 1.7.0
* @deprecated 4.0
*/
public static function getInstance($options = array())
{
JLog::add('JDatabase::getInstance() is deprecated, use
JDatabaseDriver::getInstance() instead.', JLog::WARNING,
'deprecated');
return JDatabaseDriver::getInstance($options);
}
/**
* Splits a string of multiple queries into an array of individual
queries.
*
* @param string $query Input SQL string with which to split into
individual queries.
*
* @return array The queries from the input string separated into an
array.
*
* @since 1.7.0
* @deprecated 4.0
*/
public static function splitSql($query)
{
JLog::add('JDatabase::splitSql() is deprecated, use
JDatabaseDriver::splitSql() instead.', JLog::WARNING,
'deprecated');
return JDatabaseDriver::splitSql($query);
}
/**
* Return the most recent error message for the database connector.
*
* @param boolean $showSQL True to display the SQL statement sent to
the database as well as the error.
*
* @return string The error message for the most recent query.
*
* @since 1.7.0
* @deprecated 4.0
*/
public function stderr($showSQL = false)
{
JLog::add('JDatabase::stderr() is deprecated.', JLog::WARNING,
'deprecated');
if ($this->errorNum != 0)
{
return JText::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED',
$this->errorNum, $this->errorMsg)
. ($showSQL ? "<br />SQL =
<pre>$this->sql</pre>" : '');
}
else
{
return JText::_('JLIB_DATABASE_FUNCTION_NOERROR');
}
}
/**
* Test to see if the connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 1.7.0
* @deprecated 4.0 - Use JDatabaseDriver::isSupported() instead.
*/
public static function test()
{
JLog::add('JDatabase::test() is deprecated. Use
JDatabaseDriver::isSupported() instead.', JLog::WARNING,
'deprecated');
return static::isSupported();
}
}
PK��[�Q==driver/joomla.phpnu�[���<?php
/**
* @package FrameworkOnFramework
* @subpackage database
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
* @note This file has been modified by the Joomla! Project and no
longer reflects the original work of its author.
*
* This file is adapted from the Joomla! Platform. It is used to iterate a
database cursor returning FOFTable objects
* instead of plain stdClass objects
*/
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;
/**
* This crazy three line bit is required to convince Joomla! to load
JDatabaseInterface which is on the same file as the
* abstract JDatabaseDriver class for reasons that beat me. It makes no
sense. Furthermore, jimport on Joomla! 3.4
* doesn't seem to actually load the file, merely registering the
association in the autoloader. Hence the class_exists
* in here.
*/
jimport('joomla.database.driver');
jimport('joomla.database.driver.mysqli');
class_exists('JDatabaseDriver', true);
/**
* Joomla! pass-through database driver.
*/
class FOFDatabaseDriverJoomla extends FOFDatabase implements
FOFDatabaseInterface
{
/** @var FOFDatabase The real database connection object */
private $dbo;
/**
* @var string The character(s) used to quote SQL statement names such
as table names or field names,
* etc. The child classes should define this as
necessary. If a single character string the
* same character is used for both sides of the quoted
name, else the first character will be
* used for the opening quote and the second for the
closing quote.
* @since 11.1
*/
protected $nameQuote = '';
/**
* Is this driver supported
*
* @since 11.2
*/
public static function isSupported()
{
return true;
}
/**
* Database object constructor
*
* @param array $options List of options used to configure the
connection
*/
public function __construct($options = array())
{
// Get best matching Akeeba Backup driver instance
$this->dbo = JFactory::getDbo();
$reflection = new ReflectionClass($this->dbo);
try
{
$refProp = $reflection->getProperty('nameQuote');
$refProp->setAccessible(true);
$this->nameQuote = $refProp->getValue($this->dbo);
}
catch (Exception $e)
{
$this->nameQuote = '`';
}
}
public function close()
{
if (method_exists($this->dbo, 'close'))
{
$this->dbo->close();
}
elseif (method_exists($this->dbo, 'disconnect'))
{
$this->dbo->disconnect();
}
}
public function disconnect()
{
$this->close();
}
public function open()
{
if (method_exists($this->dbo, 'open'))
{
$this->dbo->open();
}
elseif (method_exists($this->dbo, 'connect'))
{
$this->dbo->connect();
}
}
public function connect()
{
$this->open();
}
public function connected()
{
if (method_exists($this->dbo, 'connected'))
{
return $this->dbo->connected();
}
return true;
}
public function escape($text, $extra = false)
{
return $this->dbo->escape($text, $extra);
}
public function execute()
{
if (method_exists($this->dbo, 'execute'))
{
return $this->dbo->execute();
}
return $this->dbo->query();
}
public function getAffectedRows()
{
if (method_exists($this->dbo, 'getAffectedRows'))
{
return $this->dbo->getAffectedRows();
}
return 0;
}
public function getCollation()
{
if (method_exists($this->dbo, 'getCollation'))
{
return $this->dbo->getCollation();
}
return 'utf8_general_ci';
}
public function getConnection()
{
if (method_exists($this->dbo, 'getConnection'))
{
return $this->dbo->getConnection();
}
return null;
}
public function getCount()
{
if (method_exists($this->dbo, 'getCount'))
{
return $this->dbo->getCount();
}
return 0;
}
public function getDateFormat()
{
if (method_exists($this->dbo, 'getDateFormat'))
{
return $this->dbo->getDateFormat();
}
return 'Y-m-d H:i:s';;
}
public function getMinimum()
{
if (method_exists($this->dbo, 'getMinimum'))
{
return $this->dbo->getMinimum();
}
return '5.0.40';
}
public function getNullDate()
{
if (method_exists($this->dbo, 'getNullDate'))
{
return $this->dbo->getNullDate();
}
return '0000-00-00 00:00:00';
}
public function getNumRows($cursor = null)
{
if (method_exists($this->dbo, 'getNumRows'))
{
return $this->dbo->getNumRows($cursor);
}
return 0;
}
public function getQuery($new = false)
{
if (method_exists($this->dbo, 'getQuery'))
{
return $this->dbo->getQuery($new);
}
return null;
}
public function getTableColumns($table, $typeOnly = true)
{
if (method_exists($this->dbo, 'getTableColumns'))
{
return $this->dbo->getTableColumns($table, $typeOnly);
}
$result = $this->dbo->getTableFields(array($table), $typeOnly);
return $result[$table];
}
public function getTableKeys($tables)
{
if (method_exists($this->dbo, 'getTableKeys'))
{
return $this->dbo->getTableKeys($tables);
}
return array();
}
public function getTableList()
{
if (method_exists($this->dbo, 'getTableList'))
{
return $this->dbo->getTableList();
}
return array();
}
public function getVersion()
{
if (method_exists($this->dbo, 'getVersion'))
{
return $this->dbo->getVersion();
}
return '5.0.40';
}
public function insertid()
{
if (method_exists($this->dbo, 'insertid'))
{
return $this->dbo->insertid();
}
return null;
}
public function insertObject($table, &$object, $key = null)
{
if (method_exists($this->dbo, 'insertObject'))
{
return $this->dbo->insertObject($table, $object, $key);
}
return null;
}
public function loadAssoc()
{
if (method_exists($this->dbo, 'loadAssoc'))
{
return $this->dbo->loadAssoc();
}
return null;
}
public function loadAssocList($key = null, $column = null)
{
if (method_exists($this->dbo, 'loadAssocList'))
{
return $this->dbo->loadAssocList($key, $column);
}
return null;
}
public function loadObject($class = 'stdClass')
{
if (method_exists($this->dbo, 'loadObject'))
{
return $this->dbo->loadObject($class);
}
return null;
}
public function loadObjectList($key = '', $class =
'stdClass')
{
if (method_exists($this->dbo, 'loadObjectList'))
{
return $this->dbo->loadObjectList($key, $class);
}
return null;
}
public function loadResult()
{
if (method_exists($this->dbo, 'loadResult'))
{
return $this->dbo->loadResult();
}
return null;
}
public function loadRow()
{
if (method_exists($this->dbo, 'loadRow'))
{
return $this->dbo->loadRow();
}
return null;
}
public function loadRowList($key = null)
{
if (method_exists($this->dbo, 'loadRowList'))
{
return $this->dbo->loadRowList($key);
}
return null;
}
public function lockTable($tableName)
{
if (method_exists($this->dbo, 'lockTable'))
{
return $this->dbo->lockTable($this);
}
return $this;
}
public function quote($text, $escape = true)
{
if (method_exists($this->dbo, 'quote'))
{
return $this->dbo->quote($text, $escape);
}
return $text;
}
public function select($database)
{
if (method_exists($this->dbo, 'select'))
{
return $this->dbo->select($database);
}
return false;
}
public function setQuery($query, $offset = 0, $limit = 0)
{
if (method_exists($this->dbo, 'setQuery'))
{
return $this->dbo->setQuery($query, $offset, $limit);
}
return false;
}
public function transactionCommit($toSavepoint = false)
{
if (method_exists($this->dbo, 'transactionCommit'))
{
$this->dbo->transactionCommit($toSavepoint);
}
}
public function transactionRollback($toSavepoint = false)
{
if (method_exists($this->dbo, 'transactionRollback'))
{
$this->dbo->transactionRollback($toSavepoint);
}
}
public function transactionStart($asSavepoint = false)
{
if (method_exists($this->dbo, 'transactionStart'))
{
$this->dbo->transactionStart($asSavepoint);
}
}
public function unlockTables()
{
if (method_exists($this->dbo, 'unlockTables'))
{
return $this->dbo->unlockTables();
}
return $this;
}
public function updateObject($table, &$object, $key, $nulls = false)
{
if (method_exists($this->dbo, 'updateObject'))
{
return $this->dbo->updateObject($table, $object, $key, $nulls);
}
return false;
}
public function getLog()
{
if (method_exists($this->dbo, 'getLog'))
{
return $this->dbo->getLog();
}
return array();
}
public function dropTable($table, $ifExists = true)
{
if (method_exists($this->dbo, 'dropTable'))
{
return $this->dbo->dropTable($table, $ifExists);
}
return $this;
}
public function getTableCreate($tables)
{
if (method_exists($this->dbo, 'getTableCreate'))
{
return $this->dbo->getTableCreate($tables);
}
return array();
}
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
if (method_exists($this->dbo, 'renameTable'))
{
return $this->dbo->renameTable($oldTable, $newTable, $backup,
$prefix);
}
return $this;
}
public function setUtf()
{
if (method_exists($this->dbo, 'setUtf'))
{
return $this->dbo->setUtf();
}
return false;
}
protected function freeResult($cursor = null)
{
return false;
}
/**
* Method to get an array of values from the
<var>$offset</var> field in each row of the result set from
* the database query.
*
* @param integer $offset The row offset to use to build the result
array.
*
* @return mixed The return value or null if the query failed.
*
* @since 11.1
* @throws RuntimeException
*/
public function loadColumn($offset = 0)
{
if (method_exists($this->dbo, 'loadColumn'))
{
return $this->dbo->loadColumn($offset);
}
return $this->dbo->loadResultArray($offset);
}
/**
* Wrap an SQL statement identifier name such as column, table or database
names in quotes to prevent injection
* risks and reserved word conflicts.
*
* @param mixed $name The identifier name to wrap in quotes, or an
array of identifier names to wrap in quotes.
* Each type supports dot-notation name.
* @param mixed $as The AS query part associated to $name. It can be
string or array, in latter case it has to be
* same length of $name; if is null there will not
be any AS part for string or array element.
*
* @return mixed The quote wrapped name, same type of $name.
*
* @since 11.1
*/
public function quoteName($name, $as = null)
{
if (is_string($name))
{
$quotedName = $this->quoteNameStr(explode('.', $name));
$quotedAs = '';
if (!is_null($as))
{
settype($as, 'array');
$quotedAs .= ' AS ' . $this->quoteNameStr($as);
}
return $quotedName . $quotedAs;
}
else
{
$fin = array();
if (is_null($as))
{
foreach ($name as $str)
{
$fin[] = $this->quoteName($str);
}
}
elseif (is_array($name) && (count($name) == count($as)))
{
$count = count($name);
for ($i = 0; $i < $count; $i++)
{
$fin[] = $this->quoteName($name[$i], $as[$i]);
}
}
return $fin;
}
}
/**
* Quote strings coming from quoteName call.
*
* @param array $strArr Array of strings coming from quoteName
dot-explosion.
*
* @return string Dot-imploded string of quoted parts.
*
* @since 11.3
*/
protected function quoteNameStr($strArr)
{
$parts = array();
$q = $this->nameQuote;
foreach ($strArr as $part)
{
if (is_null($part))
{
continue;
}
if (strlen($q) == 1)
{
$parts[] = $q . $part . $q;
}
else
{
$parts[] = $q[0] . $part . $q[1];
}
}
return implode('.', $parts);
}
/**
* Gets the error message from the database connection.
*
* @param boolean $escaped True to escape the message string for use
in JavaScript.
*
* @return string The error message for the most recent query.
*
* @since 11.1
*/
public function getErrorMsg($escaped = false)
{
if (method_exists($this->dbo, 'getErrorMsg'))
{
$errorMessage = $this->dbo->getErrorMsg();
}
else
{
$errorMessage = $this->errorMsg;
}
if ($escaped)
{
return addslashes($errorMessage);
}
return $errorMessage;
}
/**
* Gets the error number from the database connection.
*
* @return integer The error number for the most recent query.
*
* @since 11.1
* @deprecated 13.3 (Platform) & 4.0 (CMS)
*/
public function getErrorNum()
{
if (method_exists($this->dbo, 'getErrorNum'))
{
$errorNum = $this->dbo->getErrorNum();
}
else
{
$errorNum = $this->getErrorNum;
}
return $errorNum;
}
/**
* Return the most recent error message for the database connector.
*
* @param boolean $showSQL True to display the SQL statement sent to
the database as well as the error.
*
* @return string The error message for the most recent query.
*/
public function stderr($showSQL = false)
{
if (method_exists($this->dbo, 'stderr'))
{
return $this->dbo->stderr($showSQL);
}
return parent::stderr($showSQL);
}
/**
* Magic method to proxy all calls to the loaded database driver object
*/
public function __call($name, array $arguments)
{
if (is_null($this->dbo))
{
throw new Exception('FOF database driver is not loaded');
}
if (method_exists($this->dbo, $name) || in_array($name,
array('q', 'nq', 'qn', 'query')))
{
switch ($name)
{
case 'execute':
$name = 'query';
break;
case 'q':
$name = 'quote';
break;
case 'qn':
case 'nq':
switch (count($arguments))
{
case 0 :
$result = $this->quoteName();
break;
case 1 :
$result = $this->quoteName($arguments[0]);
break;
case 2:
default:
$result = $this->quoteName($arguments[0], $arguments[1]);
break;
}
return $result;
break;
}
switch (count($arguments))
{
case 0 :
$result = $this->dbo->$name();
break;
case 1 :
$result = $this->dbo->$name($arguments[0]);
break;
case 2:
$result = $this->dbo->$name($arguments[0], $arguments[1]);
break;
case 3:
$result = $this->dbo->$name($arguments[0], $arguments[1],
$arguments[2]);
break;
case 4:
$result = $this->dbo->$name($arguments[0], $arguments[1],
$arguments[2], $arguments[3]);
break;
case 5:
$result = $this->dbo->$name($arguments[0], $arguments[1],
$arguments[2], $arguments[3], $arguments[4]);
break;
default:
// Resort to using call_user_func_array for many segments
$result = call_user_func_array(array($this->dbo, $name),
$arguments);
}
if (class_exists('JDatabase') && is_object($result)
&& ($result instanceof JDatabase))
{
return $this;
}
return $result;
}
else
{
throw new \Exception('Method ' . $name . ' not found in
FOFDatabase');
}
}
public function __get($name)
{
if (isset($this->dbo->$name) || property_exists($this->dbo,
$name))
{
return $this->dbo->$name;
}
else
{
$this->dbo->$name = null;
user_error('Database driver does not support property ' .
$name);
}
}
public function __set($name, $value)
{
if (isset($this->dbo->name) || property_exists($this->dbo,
$name))
{
$this->dbo->$name = $value;
}
else
{
$this->dbo->$name = null;
user_error('Database driver not support property ' . $name);
}
}
}
PK��[�kp0�7�7driver/mysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL database driver
*
* @link https://dev.mysql.com/doc/
* @since 3.0.0
* @deprecated 4.0 Use MySQLi or PDO MySQL instead
*/
class JDatabaseDriverMysql extends JDatabaseDriverMysqli
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'mysql';
/**
* Constructor.
*
* @param array $options Array of database options with keys: host,
user, password, database, select.
*
* @since 3.0.0
*/
public function __construct($options)
{
// PHP's `mysql` extension is not present in PHP 7, block
instantiation in this environment
if (PHP_MAJOR_VERSION >= 7)
{
throw new JDatabaseExceptionUnsupported(
'This driver is unsupported in PHP 7, please use the MySQLi or PDO
MySQL driver instead.'
);
}
// Get some basic values from the options.
$options['host'] = (isset($options['host'])) ?
$options['host'] : 'localhost';
$options['user'] = (isset($options['user'])) ?
$options['user'] : '';
$options['password'] = (isset($options['password']))
? $options['password'] : '';
$options['database'] = (isset($options['database']))
? $options['database'] : '';
$options['select'] = (isset($options['select'])) ?
(bool) $options['select'] : true;
// Finalize initialisation.
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
// Make sure the MySQL extension for PHP is installed and enabled.
if (!self::isSupported())
{
throw new JDatabaseExceptionUnsupported('Make sure the MySQL
extension for PHP is installed and enabled.');
}
// Attempt to connect to the server.
if (!($this->connection = @
mysql_connect($this->options['host'],
$this->options['user'],
$this->options['password'], true)))
{
throw new JDatabaseExceptionConnecting('Could not connect to MySQL
server.');
}
// Set sql_mode to non_strict mode
mysql_query("SET @@SESSION.sql_mode = '';",
$this->connection);
// If auto-select is enabled select the given database.
if ($this->options['select'] &&
!empty($this->options['database']))
{
$this->select($this->options['database']);
}
// Pre-populate the UTF-8 Multibyte compatibility flag based on server
version
$this->utf8mb4 = $this->serverClaimsUtf8mb4Support();
// Set the character set (needed for MySQL 4.1.2+).
$this->utf = $this->setUtf();
// Disable query cache and turn profiling ON in debug mode.
if ($this->debug)
{
mysql_query('SET query_cache_type = 0;',
$this->connection);
if ($this->hasProfiling())
{
mysql_query('SET profiling_history_size = 100, profiling =
1;', $this->connection);
}
}
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
// Close the connection.
if (is_resource($this->connection))
{
foreach ($this->disconnectHandlers as $h)
{
call_user_func_array($h, array( &$this));
}
mysql_close($this->connection);
}
$this->connection = null;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 3.0.0
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
$this->connect();
$result = mysql_real_escape_string($text, $this->getConnection());
if ($extra)
{
$result = addcslashes($result, '%_');
}
return $result;
}
/**
* Test to see if the MySQL connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return PHP_MAJOR_VERSION < 7 &&
function_exists('mysql_connect');
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 3.0.0
*/
public function connected()
{
if (is_resource($this->connection))
{
return @mysql_ping($this->connection);
}
return false;
}
/**
* Get the number of affected rows by the last INSERT, UPDATE, REPLACE or
DELETE for the previous executed SQL statement.
*
* @return integer The number of affected rows.
*
* @since 3.0.0
*/
public function getAffectedRows()
{
$this->connect();
return mysql_affected_rows($this->connection);
}
/**
* Get the number of returned rows for the previous executed SQL
statement.
* This command is only valid for statements like SELECT or SHOW that
return an actual result set.
* To retrieve the number of rows affected by an INSERT, UPDATE, REPLACE
or DELETE query, use getAffectedRows().
*
* @param resource $cursor An optional database cursor resource to
extract the row count from.
*
* @return integer The number of returned rows.
*
* @since 3.0.0
*/
public function getNumRows($cursor = null)
{
$this->connect();
return mysql_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.0.0
*/
public function getVersion()
{
$this->connect();
return mysql_get_server_info($this->connection);
}
/**
* Method to get the auto-incremented value from the last INSERT
statement.
*
* @return integer The value of the auto-increment field from the last
inserted row.
*
* @since 3.0.0
*/
public function insertid()
{
$this->connect();
return mysql_insert_id($this->connection);
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function execute()
{
$this->connect();
// Take a local copy so that we don't modify the original query and
cause issues later
$query = $this->replacePrefix((string) $this->sql);
if (!($this->sql instanceof JDatabaseQuery) &&
($this->limit > 0 || $this->offset > 0))
{
$query .= ' LIMIT ' . $this->offset . ', ' .
$this->limit;
}
if (!is_resource($this->connection))
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
// Increment the query counter.
$this->count++;
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Add the query to the object queue.
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
$this->timings[] = microtime(true);
}
// Execute the query. Error suppression is used here to prevent
warnings/notices that the connection has been lost.
$this->cursor = @mysql_query($query, $this->connection);
if ($this->debug)
{
$this->timings[] = microtime(true);
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
{
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
else
{
$this->callStacks[] = debug_backtrace();
}
}
// If an error occurred handle it.
if (!$this->cursor)
{
// Get the error number and message before we execute any more queries.
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
// Check if the server was disconnected.
if (!$this->connected())
{
try
{
// Attempt to reconnect.
$this->connection = null;
$this->connect();
}
// If connect fails, ignore that exception and throw the normal
exception.
catch (RuntimeException $e)
{
// Get the error number and message.
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum, $e);
}
// Since we were able to reconnect, run the query again.
return $this->execute();
}
// The server was not disconnected.
else
{
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
}
return $this->cursor;
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
if (!$database)
{
return false;
}
if (!mysql_select_db($database, $this->connection))
{
throw new JDatabaseExceptionConnecting('Could not connect to MySQL
database.');
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 3.0.0
*/
public function setUtf()
{
// If UTF is not supported return false immediately
if (!$this->utf)
{
return false;
}
// Make sure we're connected to the server
$this->connect();
// Which charset should I use, plain utf8 or multibyte utf8mb4?
$charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8';
$result = @mysql_set_charset($charset, $this->connection);
/**
* If I could not set the utf8mb4 charset then the server doesn't
support utf8mb4 despite claiming otherwise.
* This happens on old MySQL server versions (less than 5.5.3) using the
mysqlnd PHP driver. Since mysqlnd
* masks the server version and reports only its own we can not be sure
if the server actually does support
* UTF-8 Multibyte (i.e. it's MySQL 5.5.3 or later). Since the
utf8mb4 charset is undefined in this case we
* catch the error and determine that utf8mb4 is not supported!
*/
if (!$result && $this->utf8mb4)
{
$this->utf8mb4 = false;
$result = @mysql_set_charset('utf8', $this->connection);
}
return $result;
}
/**
* Method to fetch a row from the result set cursor as an array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchArray($cursor = null)
{
return mysql_fetch_row($cursor ? $cursor : $this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an associative
array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchAssoc($cursor = null)
{
return mysql_fetch_assoc($cursor ? $cursor : $this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
* @param string $class The class name to use for the returned row
object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject($cursor = null, $class =
'stdClass')
{
return mysql_fetch_object($cursor ? $cursor : $this->cursor, $class);
}
/**
* Method to free up the memory used for the result set.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult($cursor = null)
{
mysql_free_result($cursor ? $cursor : $this->cursor);
}
/**
* Internal function to check if profiling is available
*
* @return boolean
*
* @since 3.1.3
*/
private function hasProfiling()
{
try
{
$res = mysql_query("SHOW VARIABLES LIKE
'have_profiling'", $this->connection);
$row = mysql_fetch_assoc($res);
return isset($row);
}
catch (Exception $e)
{
return false;
}
}
/**
* Does the database server claim to have support for UTF-8 Multibyte
(utf8mb4) collation?
*
* libmysql supports utf8mb4 since 5.5.3 (same version as the MySQL
server). mysqlnd supports utf8mb4 since 5.0.9.
*
* @return boolean
*
* @since CMS 3.5.0
*/
private function serverClaimsUtf8mb4Support()
{
$client_version = mysql_get_client_info();
$server_version = $this->getVersion();
if (version_compare($server_version, '5.5.3',
'<'))
{
return false;
}
else
{
if (strpos($client_version, 'mysqlnd') !== false)
{
$client_version = preg_replace('/^\D+([\d.]+).*/',
'$1', $client_version);
return version_compare($client_version, '5.0.9',
'>=');
}
else
{
return version_compare($client_version, '5.5.3',
'>=');
}
}
}
/**
* Return the actual SQL Error number
*
* @return integer The SQL Error number
*
* @since 3.4.6
*/
protected function getErrorNumber()
{
return (int) mysql_errno($this->connection);
}
/**
* Return the actual SQL Error message
*
* @return string The SQL Error message
*
* @since 3.4.6
*/
protected function getErrorMessage()
{
$errorMessage = (string) mysql_error($this->connection);
// Replace the Databaseprefix with `#__` if we are not in Debug
if (!$this->debug)
{
$errorMessage = str_replace($this->tablePrefix, '#__',
$errorMessage);
}
return $errorMessage;
}
}
PK��[�'�HaHadriver/mysqli.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQLi database driver
*
* @link https://www.php.net/manual/en/book.mysqli.php
* @since 3.0.0
*/
class JDatabaseDriverMysqli extends JDatabaseDriver
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'mysqli';
/**
* The type of the database server family supported by this driver.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType = 'mysql';
/**
* @var mysqli The database connection resource.
* @since 1.7.0
*/
protected $connection;
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.0.1
*/
protected $nameQuote = '`';
/**
* The null or zero representation of a timestamp for the database driver.
This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 3.0.1
*/
protected $nullDate = '0000-00-00 00:00:00';
/**
* @var string The minimum supported database version.
* @since 3.0.1
*/
protected static $dbMinimum = '5.0.4';
/**
* Constructor.
*
* @param array $options List of options used to configure the
connection
*
* @since 3.0.0
*/
public function __construct($options)
{
// Get some basic values from the options.
$options['host'] = (isset($options['host'])) ?
$options['host'] : 'localhost';
$options['user'] = (isset($options['user'])) ?
$options['user'] : '';
$options['password'] = (isset($options['password']))
? $options['password'] : '';
$options['database'] = (isset($options['database']))
? $options['database'] : '';
$options['select'] = (isset($options['select'])) ?
(bool) $options['select'] : true;
$options['port'] = (isset($options['port'])) ?
(int) $options['port'] : null;
$options['socket'] = (isset($options['socket'])) ?
$options['socket'] : null;
// Finalize initialisation.
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
/*
* Unlike mysql_connect(), mysqli_connect() takes the port and socket as
separate arguments. Therefore, we
* have to extract them from the host string.
*/
$port = isset($this->options['port']) ?
$this->options['port'] : 3306;
$regex =
'/^(?P<host>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:(?P<port>.+))?$/';
if (preg_match($regex, $this->options['host'], $matches))
{
// It's an IPv4 address with or without port
$this->options['host'] = $matches['host'];
if (!empty($matches['port']))
{
$port = $matches['port'];
}
}
elseif
(preg_match('/^(?P<host>\[.*\])(:(?P<port>.+))?$/',
$this->options['host'], $matches))
{
// We assume square-bracketed IPv6 address with or without port, e.g.
[fe80:102::2%eth1]:3306
$this->options['host'] = $matches['host'];
if (!empty($matches['port']))
{
$port = $matches['port'];
}
}
elseif
(preg_match('/^(?P<host>(\w+:\/{2,3})?[a-z0-9\.\-]+)(:(?P<port>[^:]+))?$/i',
$this->options['host'], $matches))
{
// Named host (e.g example.com or localhost) with or without port
$this->options['host'] = $matches['host'];
if (!empty($matches['port']))
{
$port = $matches['port'];
}
}
elseif (preg_match('/^:(?P<port>[^:]+)$/',
$this->options['host'], $matches))
{
// Empty host, just port, e.g. ':3306'
$this->options['host'] = 'localhost';
$port = $matches['port'];
}
// ... else we assume normal (naked) IPv6 address, so host and port stay
as they are or default
// Get the port number or socket name
if (is_numeric($port))
{
$this->options['port'] = (int) $port;
}
else
{
$this->options['socket'] = $port;
}
// Make sure the MySQLi extension for PHP is installed and enabled.
if (!self::isSupported())
{
throw new JDatabaseExceptionUnsupported('The MySQLi extension for
PHP is not installed or enabled.');
}
$this->connection = @mysqli_connect(
$this->options['host'],
$this->options['user'],
$this->options['password'], null,
$this->options['port'], $this->options['socket']
);
// Attempt to connect to the server.
if (!$this->connection)
{
throw new JDatabaseExceptionConnecting('Could not connect to MySQL
server.');
}
// Set sql_mode to non_strict mode
mysqli_query($this->connection, "SET @@SESSION.sql_mode =
'';");
// If auto-select is enabled select the given database.
if ($this->options['select'] &&
!empty($this->options['database']))
{
$this->select($this->options['database']);
}
// Pre-populate the UTF-8 Multibyte compatibility flag based on server
version
$this->utf8mb4 = $this->serverClaimsUtf8mb4Support();
// Set the character set (needed for MySQL 4.1.2+).
$this->utf = $this->setUtf();
// Disable query cache and turn profiling ON in debug mode.
if ($this->debug)
{
mysqli_query($this->connection, 'SET query_cache_type =
0;');
if ($this->hasProfiling())
{
mysqli_query($this->connection, 'SET profiling_history_size =
100, profiling = 1;');
}
}
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
// Close the connection.
if ($this->connection instanceof mysqli &&
$this->connection->stat() !== false)
{
foreach ($this->disconnectHandlers as $h)
{
call_user_func_array($h, array( &$this));
}
mysqli_close($this->connection);
}
$this->connection = null;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 3.0.0
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
$this->connect();
$result = mysqli_real_escape_string($this->getConnection(), $text);
if ($extra)
{
$result = addcslashes($result, '%_');
}
return $result;
}
/**
* Test to see if the MySQL connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return function_exists('mysqli_connect');
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 3.0.0
*/
public function connected()
{
if (is_object($this->connection))
{
return mysqli_ping($this->connection);
}
return false;
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return JDatabaseDriverMysqli Returns this object to support
chaining.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$query = $this->getQuery(true);
$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS
' : '') . $query->quoteName($tableName));
$this->execute();
return $this;
}
/**
* Get the number of affected rows by the last INSERT, UPDATE, REPLACE or
DELETE for the previous executed SQL statement.
*
* @return integer The number of affected rows.
*
* @since 3.0.0
*/
public function getAffectedRows()
{
$this->connect();
return mysqli_affected_rows($this->connection);
}
/**
* Method to get the database collation.
*
* @return mixed The collation in use by the database (string) or
boolean false if not supported.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function getCollation()
{
$this->connect();
// Attempt to get the database collation by accessing the server system
variable.
$this->setQuery('SHOW VARIABLES LIKE
"collation_database"');
$result = $this->loadObject();
if (property_exists($result, 'Value'))
{
return $result->Value;
}
else
{
return false;
}
}
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
$this->connect();
// Attempt to get the database collation by accessing the server system
variable.
$this->setQuery('SHOW VARIABLES LIKE
"collation_connection"');
$result = $this->loadObject();
if (property_exists($result, 'Value'))
{
return $result->Value;
}
else
{
return false;
}
}
/**
* Get the number of returned rows for the previous executed SQL
statement.
* This command is only valid for statements like SELECT or SHOW that
return an actual result set.
* To retrieve the number of rows affected by an INSERT, UPDATE, REPLACE
or DELETE query, use getAffectedRows().
*
* @param resource $cursor An optional database cursor resource to
extract the row count from.
*
* @return integer The number of returned rows.
*
* @since 3.0.0
*/
public function getNumRows($cursor = null)
{
return mysqli_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableCreate($tables)
{
$this->connect();
$result = array();
// Sanitize input to an array and iterate over the list.
settype($tables, 'array');
foreach ($tables as $table)
{
// Set the query to get the table CREATE statement.
$this->setQuery('SHOW CREATE table ' .
$this->quoteName($this->escape($table)));
$row = $this->loadRow();
// Populate the result array based on the create statements.
$result[$table] = $row[1];
}
return $result;
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$result = array();
// Set the query to get the table fields statement.
$this->setQuery('SHOW FULL COLUMNS FROM ' .
$this->quoteName($this->escape($table)));
$fields = $this->loadObjectList();
// If we only want the type as the value add just that to the list.
if ($typeOnly)
{
foreach ($fields as $field)
{
$result[$field->Field] = preg_replace('/[(0-9)]/',
'', $field->Type);
}
}
// If we want the whole field data object add that to the list.
else
{
foreach ($fields as $field)
{
$result[$field->Field] = $field;
}
}
return $result;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
// Get the details columns information.
$this->setQuery('SHOW KEYS FROM ' .
$this->quoteName($table));
$keys = $this->loadObjectList();
return $keys;
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function getTableList()
{
$this->connect();
// Set the query to get the tables statement.
$this->setQuery('SHOW TABLES');
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.0.0
*/
public function getVersion()
{
$this->connect();
return mysqli_get_server_info($this->connection);
}
/**
* Method to get the auto-incremented value from the last INSERT
statement.
*
* @return mixed The value of the auto-increment field from the last
inserted row.
* If the value is greater than maximal int value, it will
return a string.
*
* @since 3.0.0
*/
public function insertid()
{
$this->connect();
return mysqli_insert_id($this->connection);
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseDriverMysqli Returns this object to support
chaining.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function lockTable($table)
{
$this->setQuery('LOCK TABLES ' . $this->quoteName($table)
. ' WRITE')->execute();
return $this;
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function execute()
{
$this->connect();
// Take a local copy so that we don't modify the original query and
cause issues later
$query = $this->replacePrefix((string) $this->sql);
if (!($this->sql instanceof JDatabaseQuery) &&
($this->limit > 0 || $this->offset > 0))
{
$query .= ' LIMIT ' . $this->offset . ', ' .
$this->limit;
}
if (!is_object($this->connection))
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
// Increment the query counter.
$this->count++;
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
$memoryBefore = null;
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Add the query to the object queue.
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
$this->timings[] = microtime(true);
if (is_object($this->cursor))
{
// Avoid warning if result already freed by third-party library
@$this->freeResult();
}
$memoryBefore = memory_get_usage();
}
// Execute the query. Error suppression is used here to prevent
warnings/notices that the connection has been lost.
$this->cursor = @mysqli_query($this->connection, $query);
if ($this->debug)
{
$this->timings[] = microtime(true);
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
{
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
else
{
$this->callStacks[] = debug_backtrace();
}
$this->callStacks[count($this->callStacks) -
1][0]['memory'] = array(
$memoryBefore,
memory_get_usage(),
is_object($this->cursor) ? $this->getNumRows() : null,
);
}
// If an error occurred handle it.
if (!$this->cursor)
{
// Get the error number and message before we execute any more queries.
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
// Check if the server was disconnected.
if (!$this->connected())
{
try
{
// Attempt to reconnect.
$this->connection = null;
$this->connect();
}
// If connect fails, ignore that exception and throw the normal
exception.
catch (RuntimeException $e)
{
// Get the error number and message.
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum, $e);
}
// Since we were able to reconnect, run the query again.
return $this->execute();
}
// The server was not disconnected.
else
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
}
return $this->cursor;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by MySQL.
* @param string $prefix Not used by MySQL.
*
* @return JDatabaseDriverMysqli Returns this object to support
chaining.
*
* @since 3.0.1
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$this->setQuery('RENAME TABLE ' . $oldTable . ' TO
' . $newTable)->execute();
return $this;
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
if (!$database)
{
return false;
}
if (!mysqli_select_db($this->connection, $database))
{
throw new JDatabaseExceptionConnecting('Could not connect to MySQL
database.');
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 3.0.0
*/
public function setUtf()
{
// If UTF is not supported return false immediately
if (!$this->utf)
{
return false;
}
// Make sure we're connected to the server
$this->connect();
// Which charset should I use, plain utf8 or multibyte utf8mb4?
$charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8';
$result = @$this->connection->set_charset($charset);
/**
* If I could not set the utf8mb4 charset then the server doesn't
support utf8mb4 despite claiming otherwise.
* This happens on old MySQL server versions (less than 5.5.3) using the
mysqlnd PHP driver. Since mysqlnd
* masks the server version and reports only its own we can not be sure
if the server actually does support
* UTF-8 Multibyte (i.e. it's MySQL 5.5.3 or later). Since the
utf8mb4 charset is undefined in this case we
* catch the error and determine that utf8mb4 is not supported!
*/
if (!$result && $this->utf8mb4)
{
$this->utf8mb4 = false;
$result = @$this->connection->set_charset('utf8');
}
return $result;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.0.1
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('COMMIT')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$this->transactionDepth--;
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.0.1
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('ROLLBACK')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.0.1
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
if ($this->setQuery('START TRANSACTION')->execute())
{
$this->transactionDepth = 1;
}
return;
}
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
/**
* Method to fetch a row from the result set cursor as an array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchArray($cursor = null)
{
return mysqli_fetch_row($cursor ? $cursor : $this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an associative
array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchAssoc($cursor = null)
{
return mysqli_fetch_assoc($cursor ? $cursor : $this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
* @param string $class The class name to use for the returned row
object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject($cursor = null, $class =
'stdClass')
{
return mysqli_fetch_object($cursor ? $cursor : $this->cursor, $class);
}
/**
* Method to free up the memory used for the result set.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult($cursor = null)
{
mysqli_free_result($cursor ? $cursor : $this->cursor);
if ((! $cursor) || ($cursor === $this->cursor))
{
$this->cursor = null;
}
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriverMysqli Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function unlockTables()
{
$this->setQuery('UNLOCK TABLES')->execute();
return $this;
}
/**
* Internal function to check if profiling is available
*
* @return boolean
*
* @since 3.1.3
*/
private function hasProfiling()
{
try
{
$res = mysqli_query($this->connection, "SHOW VARIABLES LIKE
'have_profiling'");
$row = mysqli_fetch_assoc($res);
return isset($row);
}
catch (Exception $e)
{
return false;
}
}
/**
* Does the database server claim to have support for UTF-8 Multibyte
(utf8mb4) collation?
*
* libmysql supports utf8mb4 since 5.5.3 (same version as the MySQL
server). mysqlnd supports utf8mb4 since 5.0.9.
*
* @return boolean
*
* @since CMS 3.5.0
*/
private function serverClaimsUtf8mb4Support()
{
$client_version = mysqli_get_client_info();
$server_version = $this->getVersion();
if (version_compare($server_version, '5.5.3',
'<'))
{
return false;
}
else
{
if (strpos($client_version, 'mysqlnd') !== false)
{
$client_version = preg_replace('/^\D+([\d.]+).*/',
'$1', $client_version);
return version_compare($client_version, '5.0.9',
'>=');
}
else
{
return version_compare($client_version, '5.5.3',
'>=');
}
}
}
/**
* Return the actual SQL Error number
*
* @return integer The SQL Error number
*
* @since 3.4.6
*/
protected function getErrorNumber()
{
return (int) mysqli_errno($this->connection);
}
/**
* Return the actual SQL Error message
*
* @return string The SQL Error message
*
* @since 3.4.6
*/
protected function getErrorMessage()
{
$errorMessage = (string) mysqli_error($this->connection);
// Replace the Databaseprefix with `#__` if we are not in Debug
if (!$this->debug)
{
$errorMessage = str_replace($this->tablePrefix, '#__',
$errorMessage);
}
return $errorMessage;
}
}
PK ��[����=�=driver/oracle.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Oracle database driver
*
* @link https://www.php.net/pdo
* @since 3.0.0
*/
class JDatabaseDriverOracle extends JDatabaseDriverPdo
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'oracle';
/**
* The type of the database server family supported by this driver.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType = 'oracle';
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.0.0
*/
protected $nameQuote = '"';
/**
* Returns the current dateformat
*
* @var string
* @since 3.0.0
*/
protected $dateformat;
/**
* Returns the current character set
*
* @var string
* @since 3.0.0
*/
protected $charset;
/**
* Constructor.
*
* @param array $options List of options used to configure the
connection
*
* @since 3.0.0
*/
public function __construct($options)
{
$options['driver'] = 'oci';
$options['charset'] = (isset($options['charset']))
? $options['charset'] : 'AL32UTF8';
$options['dateformat'] =
(isset($options['dateformat'])) ?
$options['dateformat'] : 'RRRR-MM-DD HH24:MI:SS';
$this->charset = $options['charset'];
$this->dateformat = $options['dateformat'];
// Finalize initialisation
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
parent::connect();
if (isset($this->options['schema']))
{
$this->setQuery('ALTER SESSION SET CURRENT_SCHEMA = ' .
$this->quoteName($this->options['schema']))->execute();
}
$this->setDateFormat($this->dateformat);
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
// Close the connection.
$this->freeResult();
$this->connection = null;
}
/**
* Drops a table from the database.
*
* Note: The IF EXISTS flag is unused in the Oracle driver.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return JDatabaseDriverOracle Returns this object to support
chaining.
*
* @since 3.0.0
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$query = $this->getQuery(true)
->setQuery('DROP TABLE :tableName');
$query->bind(':tableName', $tableName);
$this->setQuery($query);
$this->execute();
return $this;
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database or boolean false
if not supported.
*
* @since 3.0.0
*/
public function getCollation()
{
return $this->charset;
}
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
return $this->charset;
}
/**
* Get a query to run and verify the database is operational.
*
* @return string The query to check the health of the DB.
*
* @since 3.0.1
*/
public function getConnectedQuery()
{
return 'SELECT 1 FROM dual';
}
/**
* Returns the current date format
* This method should be useful in the case that
* somebody actually wants to use a different
* date format and needs to check what the current
* one is to see if it needs to be changed.
*
* @return string The current date format
*
* @since 3.0.0
*/
public function getDateFormat()
{
return $this->dateformat;
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* Note: You must have the correct privileges before this method
* will return usable results!
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableCreate($tables)
{
$this->connect();
$result = array();
$query = $this->getQuery(true)
->select('dbms_metadata.get_ddl(:type, :tableName)')
->from('dual')
->bind(':type', 'TABLE');
// Sanitize input to an array and iterate over the list.
settype($tables, 'array');
foreach ($tables as $table)
{
$query->bind(':tableName', $table);
$this->setQuery($query);
$statement = (string) $this->loadResult();
$result[$table] = $statement;
}
return $result;
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$columns = array();
$query = $this->getQuery(true);
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
$table = strtoupper($table);
$query->select('*');
$query->from('ALL_TAB_COLUMNS');
$query->where('table_name = :tableName');
$prefixedTable = str_replace('#__',
strtoupper($this->tablePrefix), $table);
$query->bind(':tableName', $prefixedTable);
$this->setQuery($query);
$fields = $this->loadObjectList();
if ($typeOnly)
{
foreach ($fields as $field)
{
$columns[$field->COLUMN_NAME] = $field->DATA_TYPE;
}
}
else
{
foreach ($fields as $field)
{
$columns[$field->COLUMN_NAME] = $field;
$columns[$field->COLUMN_NAME]->Default = null;
}
}
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
return $columns;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
$query = $this->getQuery(true);
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
$table = strtoupper($table);
$query->select('*')
->from('ALL_CONSTRAINTS')
->where('table_name = :tableName')
->bind(':tableName', $table);
$this->setQuery($query);
$keys = $this->loadObjectList();
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
return $keys;
}
/**
* Method to get an array of all tables in the database (schema).
*
* @param string $databaseName The database (schema) name
* @param boolean $includeDatabaseName Whether to include the schema
name in the results
*
* @return array An array of all the tables in the database.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableList($databaseName = null, $includeDatabaseName =
false)
{
$this->connect();
$query = $this->getQuery(true);
if ($includeDatabaseName)
{
$query->select('owner, table_name');
}
else
{
$query->select('table_name');
}
$query->from('all_tables');
if ($databaseName)
{
$query->where('owner = :database')
->bind(':database', $databaseName);
}
$query->order('table_name');
$this->setQuery($query);
if ($includeDatabaseName)
{
$tables = $this->loadAssocList();
}
else
{
$tables = $this->loadColumn();
}
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.0.0
*/
public function getVersion()
{
$this->connect();
$this->setQuery("select value from nls_database_parameters where
parameter = 'NLS_RDBMS_VERSION'");
return $this->loadResult();
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
return true;
}
/**
* Sets the Oracle Date Format for the session
* Default date format for Oracle is = DD-MON-RR
* The default date format for this driver is:
* 'RRRR-MM-DD HH24:MI:SS' since it is the format
* that matches the MySQL one used within most Joomla
* tables.
*
* @param string $dateFormat Oracle Date Format String
*
* @return boolean
*
* @since 3.0.0
*/
public function setDateFormat($dateFormat = 'DD-MON-RR')
{
$this->connect();
$this->setQuery("ALTER SESSION SET NLS_DATE_FORMAT =
'$dateFormat'");
if (!$this->execute())
{
return false;
}
$this->setQuery("ALTER SESSION SET NLS_TIMESTAMP_FORMAT =
'$dateFormat'");
if (!$this->execute())
{
return false;
}
$this->dateformat = $dateFormat;
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* Returns false automatically for the Oracle driver since
* you can only set the character set when the connection
* is created.
*
* @return boolean True on success.
*
* @since 3.0.0
*/
public function setUtf()
{
return false;
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseDriverOracle Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function lockTable($table)
{
$this->setQuery('LOCK TABLE ' . $this->quoteName($table)
. ' IN EXCLUSIVE MODE')->execute();
return $this;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by Oracle.
* @param string $prefix Not used by Oracle.
*
* @return JDatabaseDriverOracle Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$this->setQuery('RENAME ' . $oldTable . ' TO ' .
$newTable)->execute();
return $this;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriverOracle Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function unlockTables()
{
$this->setQuery('COMMIT')->execute();
return $this;
}
/**
* Test to see if the PDO ODBC connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return class_exists('PDO') && in_array('oci',
PDO::getAvailableDrivers());
}
/**
* This function replaces a string identifier
<var>$prefix</var> with the string held is the
* <var>tablePrefix</var> class variable.
*
* @param string $query The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 1.7.0
*/
public function replacePrefix($query, $prefix = '#__')
{
$startPos = 0;
$quoteChar = "'";
$literal = '';
$query = trim($query);
$n = strlen($query);
while ($startPos < $n)
{
$ip = strpos($query, $prefix, $startPos);
if ($ip === false)
{
break;
}
$j = strpos($query, "'", $startPos);
if ($j === false)
{
$j = $n;
}
$literal .= str_replace($prefix, $this->tablePrefix, substr($query,
$startPos, $j - $startPos));
$startPos = $j;
$j = $startPos + 1;
if ($j >= $n)
{
break;
}
// Quote comes first, find end of quote
while (true)
{
$k = strpos($query, $quoteChar, $j);
$escaped = false;
if ($k === false)
{
break;
}
$l = $k - 1;
while ($l >= 0 && $query[$l] == '\\')
{
$l--;
$escaped = !$escaped;
}
if ($escaped)
{
$j = $k + 1;
continue;
}
break;
}
if ($k === false)
{
// Error in the query - no end quote; ignore it
break;
}
$literal .= substr($query, $startPos, $k - $startPos + 1);
$startPos = $k + 1;
}
if ($startPos < $n)
{
$literal .= substr($query, $startPos, $n - $startPos);
}
return $literal;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.1.4
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionCommit($toSavepoint);
}
else
{
$this->transactionDepth--;
}
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.1.4
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionRollback($toSavepoint);
}
else
{
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
}
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.1.4
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
return parent::transactionStart($asSavepoint);
}
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
/**
* Get the query strings to alter the character set and collation of a
table.
*
* @param string $tableName The name of the table
*
* @return string[] The queries required to alter the table's
character set and collation
*
* @since CMS 3.5.0
*/
public function getAlterTableCharacterSet($tableName)
{
return array();
}
/**
* Return the query string to create new Database.
* Each database driver, other than MySQL, need to override this member to
return correct string.
*
* @param stdClass $options Object used to pass user and database name
to database driver.
* This object must have "db_name" and
"db_user" set.
* @param boolean $utf True if the database supports the UTF-8
character set.
*
* @return string The query that creates database
*
* @since 3.0.1
*/
protected function getCreateDatabaseQuery($options, $utf)
{
return 'CREATE DATABASE ' .
$this->quoteName($options->db_name);
}
}
PK ��[:�֍�g�gdriver/pdo.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform PDO Database Driver Class
*
* @link https://www.php.net/pdo
* @since 3.0.0
*/
abstract class JDatabaseDriverPdo extends JDatabaseDriver
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'pdo';
/**
* @var PDO The database connection resource.
* @since 3.0.0
*/
protected $connection;
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.0.0
*/
protected $nameQuote = "'";
/**
* The null or zero representation of a timestamp for the database driver.
This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 3.0.0
*/
protected $nullDate = '0000-00-00 00:00:00';
/**
* @var resource The prepared statement.
* @since 3.0.0
*/
protected $prepared;
/**
* Contains the current query execution status
*
* @var array
* @since 3.0.0
*/
protected $executed = false;
/**
* Constructor.
*
* @param array $options List of options used to configure the
connection
*
* @since 3.0.0
*/
public function __construct($options)
{
// Get some basic values from the options.
$options['driver'] = (isset($options['driver'])) ?
$options['driver'] : 'odbc';
$options['dsn'] = (isset($options['dsn'])) ?
$options['dsn'] : '';
$options['host'] = (isset($options['host'])) ?
$options['host'] : 'localhost';
$options['database'] = (isset($options['database']))
? $options['database'] : '';
$options['user'] = (isset($options['user'])) ?
$options['user'] : '';
$options['password'] = (isset($options['password']))
? $options['password'] : '';
$options['driverOptions'] =
(isset($options['driverOptions'])) ?
$options['driverOptions'] : array();
$hostParts = explode(':', $options['host']);
if (!empty($hostParts[1]))
{
$options['host'] = $hostParts[0];
$options['port'] = $hostParts[1];
}
// Finalize initialisation
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
// Make sure the PDO extension for PHP is installed and enabled.
if (!self::isSupported())
{
throw new JDatabaseExceptionUnsupported('PDO Extension is not
available.', 1);
}
$replace = array();
$with = array();
// Find the correct PDO DSN Format to use:
switch ($this->options['driver'])
{
case 'cubrid':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 33000;
$format = 'cubrid:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
break;
case 'dblib':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 1433;
$format = 'dblib:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
break;
case 'firebird':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 3050;
$format = 'firebird:dbname=#DBNAME#';
$replace = array('#DBNAME#');
$with = array($this->options['database']);
break;
case 'ibm':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 56789;
if (!empty($this->options['dsn']))
{
$format = 'ibm:DSN=#DSN#';
$replace = array('#DSN#');
$with = array($this->options['dsn']);
}
else
{
$format =
'ibm:hostname=#HOST#;port=#PORT#;database=#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
}
break;
case 'informix':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 1526;
$this->options['protocol'] =
(isset($this->options['protocol'])) ?
$this->options['protocol'] : 'onsoctcp';
if (!empty($this->options['dsn']))
{
$format = 'informix:DSN=#DSN#';
$replace = array('#DSN#');
$with = array($this->options['dsn']);
}
else
{
$format =
'informix:host=#HOST#;service=#PORT#;database=#DBNAME#;server=#SERVER#;protocol=#PROTOCOL#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#', '#SERVER#', '#PROTOCOL#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database'],
$this->options['server'],
$this->options['protocol']);
}
break;
case 'mssql':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 1433;
$format = 'mssql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
break;
// The pdomysql case is a special case within the CMS environment
case 'pdomysql':
case 'mysql':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 3306;
$format =
'mysql:host=#HOST#;port=#PORT#;dbname=#DBNAME#;charset=#CHARSET#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#', '#CHARSET#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database'],
$this->options['charset']);
break;
case 'oci':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 1521;
$this->options['charset'] =
(isset($this->options['charset'])) ?
$this->options['charset'] : 'AL32UTF8';
if (!empty($this->options['dsn']))
{
$format = 'oci:dbname=#DSN#';
$replace = array('#DSN#');
$with = array($this->options['dsn']);
}
else
{
$format = 'oci:dbname=//#HOST#:#PORT#/#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
}
$format .= ';charset=' .
$this->options['charset'];
break;
case 'odbc':
$format = 'odbc:DSN=#DSN#;UID:#USER#;PWD=#PASSWORD#';
$replace = array('#DSN#', '#USER#',
'#PASSWORD#');
$with = array($this->options['dsn'],
$this->options['user'],
$this->options['password']);
break;
case 'pgsql':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 5432;
$format = 'pgsql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
break;
case 'sqlite':
if (isset($this->options['version']) &&
$this->options['version'] == 2)
{
$format = 'sqlite2:#DBNAME#';
}
else
{
$format = 'sqlite:#DBNAME#';
}
$replace = array('#DBNAME#');
$with = array($this->options['database']);
break;
case 'sybase':
$this->options['port'] =
(isset($this->options['port'])) ?
$this->options['port'] : 1433;
$format = 'mssql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
$replace = array('#HOST#', '#PORT#',
'#DBNAME#');
$with = array($this->options['host'],
$this->options['port'],
$this->options['database']);
break;
}
// Create the connection string:
$connectionString = str_replace($replace, $with, $format);
try
{
$this->connection = new PDO(
$connectionString,
$this->options['user'],
$this->options['password'],
$this->options['driverOptions']
);
}
catch (PDOException $e)
{
throw new JDatabaseExceptionConnecting('Could not connect to PDO:
' . $e->getMessage(), 2, $e);
}
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
foreach ($this->disconnectHandlers as $h)
{
call_user_func_array($h, array( &$this));
}
$this->freeResult();
$this->connection = null;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* Oracle escaping reference:
*
http://www.orafaq.com/wiki/SQL_FAQ#How_does_one_escape_special_characters_when_writing_SQL_queries.3F
*
* SQLite escaping notes:
* http://www.sqlite.org/faq.html#q14
*
* Method body is as implemented by the Zend Framework
*
* Note: Using query objects with bound variables is
* preferable to the below.
*
* @param string $text The string to be escaped.
* @param boolean $extra Unused optional parameter to provide extra
escaping.
*
* @return string The escaped string.
*
* @since 3.0.0
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
$text = str_replace("'", "''", $text);
return addcslashes($text, "\000\n\r\\\032");
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 3.0.0
* @throws RuntimeException
* @throws Exception
*/
public function execute()
{
$this->connect();
// Take a local copy so that we don't modify the original query and
cause issues later
$query = $this->replacePrefix((string) $this->sql);
if (!is_object($this->connection))
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
// Increment the query counter.
$this->count++;
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Add the query to the object queue.
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
$this->timings[] = microtime(true);
}
// Execute the query.
$this->executed = false;
if ($this->prepared instanceof PDOStatement)
{
// Bind the variables:
if ($this->sql instanceof JDatabaseQueryPreparable)
{
$bounded = $this->sql->getBounded();
foreach ($bounded as $key => $obj)
{
$this->prepared->bindParam($key, $obj->value,
$obj->dataType, $obj->length, $obj->driverOptions);
}
}
$this->executed = $this->prepared->execute();
}
if ($this->debug)
{
$this->timings[] = microtime(true);
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
{
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
else
{
$this->callStacks[] = debug_backtrace();
}
}
// If an error occurred handle it.
if (!$this->executed)
{
// Get the error number and message before we execute any more queries.
$errorNum = $this->getErrorNumber();
$errorMsg = $this->getErrorMessage();
// Check if the server was disconnected.
if (!$this->connected())
{
try
{
// Attempt to reconnect.
$this->connection = null;
$this->connect();
}
// If connect fails, ignore that exception and throw the normal
exception.
catch (RuntimeException $e)
{
// Get the error number and message.
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum, $e);
}
// Since we were able to reconnect, run the query again.
return $this->execute();
}
// The server was not disconnected.
else
{
// Get the error number and message from before we tried to reconnect.
$this->errorNum = $errorNum;
$this->errorMsg = $errorMsg;
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
}
return $this->prepared;
}
/**
* Retrieve a PDO database connection attribute
*
* Usage: $db->getOption(PDO::ATTR_CASE);
*
* @param mixed $key One of the PDO::ATTR_* Constants
*
* @return mixed
*
* @link https://www.php.net/manual/en/pdo.getattribute.php
* @since 3.0.0
*/
public function getOption($key)
{
$this->connect();
return $this->connection->getAttribute($key);
}
/**
* Get a query to run and verify the database is operational.
*
* @return string The query to check the health of the DB.
*
* @since 3.0.1
*/
public function getConnectedQuery()
{
return 'SELECT 1';
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.9.0
*/
public function getVersion()
{
$this->connect();
return $this->getOption(PDO::ATTR_SERVER_VERSION);
}
/**
* Sets an attribute on the PDO database handle.
*
* Usage: $db->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
*
* @param integer $key One of the PDO::ATTR_* Constants
* @param mixed $value One of the associated PDO Constants related
to the particular attribute key.
*
* @return boolean
*
* @link https://www.php.net/manual/en/pdo.setattribute.php
* @since 3.0.0
*/
public function setOption($key, $value)
{
$this->connect();
return $this->connection->setAttribute($key, $value);
}
/**
* Test to see if the PDO extension is available.
* Override as needed to check for specific PDO Drivers.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return defined('PDO::ATTR_DRIVER_NAME');
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 3.0.0
*/
public function connected()
{
// Flag to prevent recursion into this function.
static $checkingConnected = false;
if ($checkingConnected)
{
// Reset this flag and throw an exception.
$checkingConnected = true;
die('Recursion trying to check if connected.');
}
// Backup the query state.
$query = $this->sql;
$limit = $this->limit;
$offset = $this->offset;
$prepared = $this->prepared;
try
{
// Set the checking connection flag.
$checkingConnected = true;
// Run a simple query to check the connection.
$this->setQuery($this->getConnectedQuery());
$status = (bool) $this->loadResult();
}
// If we catch an exception here, we must not be connected.
catch (Exception $e)
{
$status = false;
}
// Restore the query state.
$this->sql = $query;
$this->limit = $limit;
$this->offset = $offset;
$this->prepared = $prepared;
$checkingConnected = false;
return $status;
}
/**
* Get the number of affected rows for the previous executed SQL
statement.
* Only applicable for DELETE, INSERT, or UPDATE statements.
*
* @return integer The number of affected rows.
*
* @since 3.0.0
*/
public function getAffectedRows()
{
$this->connect();
if ($this->prepared instanceof PDOStatement)
{
return $this->prepared->rowCount();
}
else
{
return 0;
}
}
/**
* Get the number of returned rows for the previous executed SQL
statement.
* Only applicable for DELETE, INSERT, or UPDATE statements.
*
* @param resource $cursor An optional database cursor resource to
extract the row count from.
*
* @return integer The number of returned rows.
*
* @since 3.0.0
*/
public function getNumRows($cursor = null)
{
$this->connect();
if ($cursor instanceof PDOStatement)
{
return $cursor->rowCount();
}
elseif ($this->prepared instanceof PDOStatement)
{
return $this->prepared->rowCount();
}
else
{
return 0;
}
}
/**
* Method to get the auto-incremented value from the last INSERT
statement.
*
* @return string The value of the auto-increment field from the last
inserted row.
*
* @since 3.0.0
*/
public function insertid()
{
$this->connect();
// Error suppress this to prevent PDO warning us that the driver
doesn't support this operation.
return @$this->connection->lastInsertId();
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
return true;
}
/**
* Sets the SQL statement string for later execution.
*
* @param mixed $query The SQL statement to set either as a
JDatabaseQuery object or a string.
* @param integer $offset The affected row offset to set.
* @param integer $limit The maximum affected rows to set.
* @param array $driverOptions The optional PDO driver options.
*
* @return JDatabaseDriver This object to support method chaining.
*
* @since 3.0.0
*/
public function setQuery($query, $offset = null, $limit = null,
$driverOptions = array())
{
$this->connect();
$this->freeResult();
if (is_string($query))
{
// Allows taking advantage of bound variables in a direct query:
$query = $this->getQuery(true)->setQuery($query);
}
if ($query instanceof JDatabaseQueryLimitable &&
!is_null($offset) && !is_null($limit))
{
$query = $query->processLimit($query, $limit, $offset);
}
// Create a stringified version of the query (with prefixes replaced):
$sql = $this->replacePrefix((string) $query);
// Use the stringified version in the prepare call:
$this->prepared = $this->connection->prepare($sql,
$driverOptions);
// Store reference to the original JDatabaseQuery instance within the
class.
// This is important since binding variables depends on it within
execute():
parent::setQuery($query, $offset, $limit);
return $this;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 3.0.0
*/
public function setUtf()
{
return false;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth == 1)
{
$this->connection->commit();
}
$this->transactionDepth--;
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth == 1)
{
$this->connection->rollBack();
}
$this->transactionDepth--;
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
$this->connection->beginTransaction();
}
$this->transactionDepth++;
}
/**
* Method to fetch a row from the result set cursor as an array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchArray($cursor = null)
{
if (!empty($cursor) && $cursor instanceof PDOStatement)
{
return $cursor->fetch(PDO::FETCH_NUM);
}
if ($this->prepared instanceof PDOStatement)
{
return $this->prepared->fetch(PDO::FETCH_NUM);
}
}
/**
* Method to fetch a row from the result set cursor as an associative
array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchAssoc($cursor = null)
{
if (!empty($cursor) && $cursor instanceof PDOStatement)
{
return $cursor->fetch(PDO::FETCH_ASSOC);
}
if ($this->prepared instanceof PDOStatement)
{
return $this->prepared->fetch(PDO::FETCH_ASSOC);
}
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
* @param string $class Unused, only necessary so method signature
will be the same as parent.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject($cursor = null, $class =
'stdClass')
{
if (!empty($cursor) && $cursor instanceof PDOStatement)
{
return $cursor->fetchObject($class);
}
if ($this->prepared instanceof PDOStatement)
{
return $this->prepared->fetchObject($class);
}
}
/**
* Method to free up the memory used for the result set.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult($cursor = null)
{
$this->executed = false;
if ($cursor instanceof PDOStatement)
{
$cursor->closeCursor();
$cursor = null;
}
if ($this->prepared instanceof PDOStatement)
{
$this->prepared->closeCursor();
$this->prepared = null;
}
}
/**
* Method to get the next row in the result set from the database query as
an object.
*
* @param string $class The class name to use for the returned row
object.
*
* @return mixed The result of the query as an array, false if there
are no more rows.
*
* @since 3.0.0
* @throws RuntimeException
* @deprecated 4.0 (CMS) Use getIterator() instead
*/
public function loadNextObject($class = 'stdClass')
{
JLog::add(__METHOD__ . '() is deprecated. Use
JDatabaseDriver::getIterator() instead.', JLog::WARNING,
'deprecated');
$this->connect();
// Execute the query and get the result set cursor.
if (!$this->executed)
{
if (!($this->execute()))
{
return $this->errorNum ? null : false;
}
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchObject(null, $class))
{
return $row;
}
// Free up system resources and return.
$this->freeResult();
return false;
}
/**
* Method to get the next row in the result set from the database query as
an array.
*
* @return mixed The result of the query as an array, false if there are
no more rows.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function loadNextAssoc()
{
$this->connect();
// Execute the query and get the result set cursor.
if (!$this->executed)
{
if (!($this->execute()))
{
return $this->errorNum ? null : false;
}
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchAssoc())
{
return $row;
}
// Free up system resources and return.
$this->freeResult();
return false;
}
/**
* Method to get the next row in the result set from the database query as
an array.
*
* @return mixed The result of the query as an array, false if there are
no more rows.
*
* @since 3.0.0
* @throws RuntimeException
* @deprecated 4.0 (CMS) Use getIterator() instead
*/
public function loadNextRow()
{
JLog::add(__METHOD__ . '() is deprecated. Use
JDatabaseDriver::getIterator() instead.', JLog::WARNING,
'deprecated');
$this->connect();
// Execute the query and get the result set cursor.
if (!$this->executed)
{
if (!($this->execute()))
{
return $this->errorNum ? null : false;
}
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchArray())
{
return $row;
}
// Free up system resources and return.
$this->freeResult();
return false;
}
/**
* PDO does not support serialize
*
* @return array
*
* @since 3.1.4
*/
public function __sleep()
{
$serializedProperties = array();
$reflect = new ReflectionClass($this);
// Get properties of the current class
$properties = $reflect->getProperties();
foreach ($properties as $property)
{
// Do not serialize properties that are PDO
if ($property->isStatic() == false &&
!($this->{$property->name} instanceof PDO))
{
$serializedProperties[] = $property->name;
}
}
return $serializedProperties;
}
/**
* Wake up after serialization
*
* @return array
*
* @since 3.1.4
*/
public function __wakeup()
{
// Get connection back
$this->__construct($this->options);
}
/**
* Return the actual SQL Error number
*
* @return integer The SQL Error number
*
* @since 3.4.6
*/
protected function getErrorNumber()
{
return (int) $this->connection->errorCode();
}
/**
* Return the actual SQL Error message
*
* @return string The SQL Error message
*
* @since 3.4.6
*/
protected function getErrorMessage()
{
// The SQL Error Information
$errorInfo = implode(', ',
$this->connection->errorInfo());
// Replace the Databaseprefix with `#__` if we are not in Debug
if (!$this->debug)
{
$errorInfo = str_replace($this->tablePrefix, '#__',
$errorInfo);
}
return $errorInfo;
}
}
PK ��[ �CQ5Q5driver/pdomysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL database driver supporting PDO based connections
*
* @link https://www.php.net/manual/en/ref.pdo-mysql.php
* @since 3.4
*/
class JDatabaseDriverPdomysql extends JDatabaseDriverPdo
{
/**
* The name of the database driver.
*
* @var string
* @since 3.4
*/
public $name = 'pdomysql';
/**
* The type of the database server family supported by this driver.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType = 'mysql';
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.4
*/
protected $nameQuote = '`';
/**
* The null or zero representation of a timestamp for the database driver.
This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 3.4
*/
protected $nullDate = '0000-00-00 00:00:00';
/**
* The minimum supported database version.
*
* @var string
* @since 3.4
*/
protected static $dbMinimum = '5.0.4';
/**
* Constructor.
*
* @param array $options Array of database options with keys: host,
user, password, database, select.
*
* @since 3.4
*/
public function __construct($options)
{
// Get some basic values from the options.
$options['driver'] = 'mysql';
if (!isset($options['charset']) ||
$options['charset'] == 'utf8')
{
$options['charset'] = 'utf8mb4';
}
/**
* Pre-populate the UTF-8 Multibyte compatibility flag. Unfortunately PDO
won't report the server version
* unless we're connected to it, and we cannot connect to it unless
we know if it supports utf8mb4, which requires
* us knowing the server version. Because of this chicken and egg issue,
we _assume_ it's supported and we'll just
* catch any problems at connection time.
*/
$this->utf8mb4 = ($options['charset'] ==
'utf8mb4');
// Finalize initialisation.
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.4
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
try
{
// Try to connect to MySQL
parent::connect();
}
catch (\RuntimeException $e)
{
// If the connection failed, but not because of the wrong character set,
then bubble up the exception.
if (!$this->utf8mb4)
{
throw $e;
}
/*
* Otherwise, try connecting again without using
* utf8mb4 and see if maybe that was the problem. If the
* connection succeeds, then we will have learned that the
* client end of the connection does not support utf8mb4.
*/
$this->utf8mb4 = false;
$this->options['charset'] = 'utf8';
parent::connect();
}
if ($this->utf8mb4)
{
/*
* At this point we know the client supports utf8mb4. Now
* we must check if the server supports utf8mb4 as well.
*/
$serverVersion =
$this->connection->getAttribute(PDO::ATTR_SERVER_VERSION);
$this->utf8mb4 = version_compare($serverVersion, '5.5.3',
'>=');
if (!$this->utf8mb4)
{
// Reconnect with the utf8 character set.
parent::disconnect();
$this->options['charset'] = 'utf8';
parent::connect();
}
}
$this->connection->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
// Set sql_mode to non_strict mode
$this->connection->query("SET @@SESSION.sql_mode =
'';");
// Disable query cache and turn profiling ON in debug mode.
if ($this->debug)
{
$this->connection->query('SET query_cache_type = 0;');
if ($this->hasProfiling())
{
$this->connection->query('SET profiling_history_size = 100,
profiling = 1;');
}
}
}
/**
* Test to see if the MySQL connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.4
*/
public static function isSupported()
{
return class_exists('PDO') &&
in_array('mysql', PDO::getAvailableDrivers());
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return JDatabaseDriverPdomysql Returns this object to support
chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$query = $this->getQuery(true);
$query->setQuery('DROP TABLE ' . ($ifExists ? 'IF
EXISTS ' : '') . $this->quoteName($tableName));
$this->setQuery($query);
$this->execute();
return $this;
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.4
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
$this->setQuery('USE ' . $this->quoteName($database));
$this->execute();
return $this;
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database (string) or
boolean false if not supported.
*
* @since 3.4
* @throws RuntimeException
*/
public function getCollation()
{
$this->connect();
// Attempt to get the database collation by accessing the server system
variable.
$this->setQuery('SHOW VARIABLES LIKE
"collation_database"');
$result = $this->loadObject();
if (property_exists($result, 'Value'))
{
return $result->Value;
}
else
{
return false;
}
}
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
$this->connect();
// Attempt to get the database collation by accessing the server system
variable.
$this->setQuery('SHOW VARIABLES LIKE
"collation_connection"');
$result = $this->loadObject();
if (property_exists($result, 'Value'))
{
return $result->Value;
}
else
{
return false;
}
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableCreate($tables)
{
$this->connect();
// Initialise variables.
$result = array();
// Sanitize input to an array and iterate over the list.
settype($tables, 'array');
foreach ($tables as $table)
{
$this->setQuery('SHOW CREATE TABLE ' .
$this->quoteName($table));
$row = $this->loadRow();
// Populate the result array based on the create statements.
$result[$table] = $row[1];
}
return $result;
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$result = array();
// Set the query to get the table fields statement.
$this->setQuery('SHOW FULL COLUMNS FROM ' .
$this->quoteName($table));
$fields = $this->loadObjectList();
// If we only want the type as the value add just that to the list.
if ($typeOnly)
{
foreach ($fields as $field)
{
$result[$field->Field] = preg_replace('/[(0-9)]/',
'', $field->Type);
}
}
// If we want the whole field data object add that to the list.
else
{
foreach ($fields as $field)
{
$result[$field->Field] = $field;
}
}
return $result;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
// Get the details columns information.
$this->setQuery('SHOW KEYS FROM ' .
$this->quoteName($table));
$keys = $this->loadObjectList();
return $keys;
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 3.4
* @throws RuntimeException
*/
public function getTableList()
{
$this->connect();
// Set the query to get the tables statement.
$this->setQuery('SHOW TABLES');
$tables = $this->loadColumn();
return $tables;
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseDriverPdomysql Returns this object to support
chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function lockTable($table)
{
$this->setQuery('LOCK TABLES ' . $this->quoteName($table)
. ' WRITE')->execute();
return $this;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by MySQL.
* @param string $prefix Not used by MySQL.
*
* @return JDatabaseDriverPdomysql Returns this object to support
chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$this->setQuery('RENAME TABLE ' .
$this->quoteName($oldTable) . ' TO ' .
$this->quoteName($newTable));
$this->execute();
return $this;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* Oracle escaping reference:
*
http://www.orafaq.com/wiki/SQL_FAQ#How_does_one_escape_special_characters_when_writing_SQL_queries.3F
*
* SQLite escaping notes:
* http://www.sqlite.org/faq.html#q14
*
* Method body is as implemented by the Zend Framework
*
* Note: Using query objects with bound variables is
* preferable to the below.
*
* @param string $text The string to be escaped.
* @param boolean $extra Unused optional parameter to provide extra
escaping.
*
* @return string The escaped string.
*
* @since 3.4
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
$this->connect();
$result = substr($this->connection->quote($text), 1, -1);
if ($extra)
{
$result = addcslashes($result, '%_');
}
return $result;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriverPdomysql Returns this object to support
chaining.
*
* @since 3.4
* @throws RuntimeException
*/
public function unlockTables()
{
$this->setQuery('UNLOCK TABLES')->execute();
return $this;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.4
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionCommit($toSavepoint);
}
else
{
$this->transactionDepth--;
}
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.4
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionRollback($toSavepoint);
}
else
{
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
}
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.4
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
parent::transactionStart($asSavepoint);
}
else
{
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
}
/**
* Internal function to check if profiling is available.
*
* @return boolean
*
* @since 3.9.1
*/
private function hasProfiling()
{
$result = $this->setQuery("SHOW VARIABLES LIKE
'have_profiling'")->loadAssoc();
return isset($result);
}
}
PK ��[�t�֠֠driver/postgresql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PostgreSQL database driver
*
* @since 3.0.0
* @deprecated 4.0 Use PDO PostgreSQL instead
*/
class JDatabaseDriverPostgresql extends JDatabaseDriver
{
/**
* The database driver name
*
* @var string
* @since 3.0.0
*/
public $name = 'postgresql';
/**
* The type of the database server family supported by this driver.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType = 'postgresql';
/**
* Quote for named objects
*
* @var string
* @since 3.0.0
*/
protected $nameQuote = '"';
/**
* The null/zero date string
*
* @var string
* @since 3.0.0
*/
protected $nullDate = '1970-01-01 00:00:00';
/**
* The minimum supported database version.
*
* @var string
* @since 3.0.0
*/
protected static $dbMinimum = '8.3.18';
/**
* Operator used for concatenation
*
* @var string
* @since 3.0.0
*/
protected $concat_operator = '||';
/**
* JDatabaseDriverPostgresqlQuery object returned by getQuery
*
* @var JDatabaseQueryPostgresql
* @since 3.0.0
*/
protected $queryObject = null;
/**
* Database object constructor
*
* @param array $options List of options used to configure the
connection
*
* @since 3.0.0
*/
public function __construct($options)
{
$options['host'] = (isset($options['host'])) ?
$options['host'] : 'localhost';
$options['user'] = (isset($options['user'])) ?
$options['user'] : '';
$options['password'] = (isset($options['password']))
? $options['password'] : '';
$options['database'] = (isset($options['database']))
? $options['database'] : '';
$options['port'] = (isset($options['port'])) ?
$options['port'] : null;
// Finalize initialization
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
// Make sure the postgresql extension for PHP is installed and enabled.
if (!self::isSupported())
{
throw new JDatabaseExceptionUnsupported('The pgsql extension for
PHP is not installed or enabled.');
}
/*
* pg_connect() takes the port as separate argument. Therefore, we
* have to extract it from the host string (if provided).
*/
// Check for empty port
if (!$this->options['port'])
{
// Port is empty or not set via options, check for port annotation (:)
in the host string
$tmp = substr(strstr($this->options['host'],
':'), 1);
if (!empty($tmp))
{
// Get the port number
if (is_numeric($tmp))
{
$this->options['port'] = $tmp;
}
// Extract the host name
$this->options['host'] =
substr($this->options['host'], 0,
strlen($this->options['host']) - (strlen($tmp) + 1));
// This will take care of the following notation: ":5432"
if ($this->options['host'] === '')
{
$this->options['host'] = 'localhost';
}
}
// No port annotation (:) found, setting port to default PostgreSQL port
5432
else
{
$this->options['port'] = '5432';
}
}
// Build the DSN for the connection.
$dsn = '';
if (!empty($this->options['host']))
{
$dsn .= "host={$this->options['host']}
port={$this->options['port']} ";
}
$dsn .= "dbname={$this->options['database']}
user={$this->options['user']}
password={$this->options['password']}";
// Attempt to connect to the server.
if (!($this->connection = @pg_connect($dsn)))
{
throw new JDatabaseExceptionConnecting('Error connecting to PGSQL
database.');
}
pg_set_error_verbosity($this->connection, PGSQL_ERRORS_DEFAULT);
pg_query($this->connection, 'SET
standard_conforming_strings=off');
pg_query($this->connection, 'SET
escape_string_warning=off');
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
// Close the connection.
if (is_resource($this->connection))
{
foreach ($this->disconnectHandlers as $h)
{
call_user_func_array($h, array( &$this));
}
pg_close($this->connection);
}
$this->connection = null;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 3.0.0
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
$this->connect();
$result = pg_escape_string($this->connection, $text);
if ($extra)
{
$result = addcslashes($result, '%_');
}
return $result;
}
/**
* Test to see if the PostgreSQL connector is available
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function test()
{
return function_exists('pg_connect');
}
/**
* Determines if the connection to the server is active.
*
* @return boolean
*
* @since 3.0.0
*/
public function connected()
{
$this->connect();
if (is_resource($this->connection))
{
return pg_ping($this->connection);
}
return false;
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return boolean
*
* @since 3.0.0
* @throws RuntimeException
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS
' : '') . $this->quoteName($tableName));
$this->execute();
return true;
}
/**
* Get the number of affected rows by the last INSERT, UPDATE, REPLACE or
DELETE for the previous executed SQL statement.
*
* @return integer The number of affected rows in the previous operation
*
* @since 3.0.0
*/
public function getAffectedRows()
{
$this->connect();
return pg_affected_rows($this->cursor);
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database or boolean false
if not supported.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getCollation()
{
$this->connect();
$this->setQuery('SHOW LC_COLLATE');
$array = $this->loadAssocList();
return $array[0]['lc_collate'];
}
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
return pg_client_encoding($this->connection);
}
/**
* Get the number of returned rows for the previous executed SQL
statement.
* This command is only valid for statements like SELECT or SHOW that
return an actual result set.
* To retrieve the number of rows affected by an INSERT, UPDATE, REPLACE
or DELETE query, use getAffectedRows().
*
* @param resource $cur An optional database cursor resource to
extract the row count from.
*
* @return integer The number of returned rows.
*
* @since 3.0.0
*/
public function getNumRows($cur = null)
{
$this->connect();
return pg_num_rows((int) $cur ? $cur : $this->cursor);
}
/**
* Get the current or query, or new JDatabaseQuery object.
*
* @param boolean $new False to return the last query set, True to
return a new JDatabaseQuery object.
* @param boolean $asObj False to return last query as string, true to
get JDatabaseQueryPostgresql object.
*
* @return JDatabaseQuery The current query object or a new object
extending the JDatabaseQuery class.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getQuery($new = false, $asObj = false)
{
if ($new)
{
$this->queryObject = new JDatabaseQueryPostgresql($this);
return $this->queryObject;
}
else
{
if ($asObj)
{
return $this->queryObject;
}
else
{
return $this->sql;
}
}
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* This is unsupported by PostgreSQL.
*
* @param mixed $tables A table name or a list of table names.
*
* @return string An empty char because this function is not supported
by PostgreSQL.
*
* @since 3.0.0
*/
public function getTableCreate($tables)
{
return '';
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table. For
PostgreSQL may start with a schema.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$result = array();
$tableSub = $this->replacePrefix($table);
$fn = explode('.', $tableSub);
if (count($fn) === 2)
{
$schema = $fn[0];
$tableSub = $fn[1];
}
else
{
$schema = $this->getDefaultSchema();
}
$this->setQuery('
SELECT a.attname AS "column_name",
pg_catalog.format_type(a.atttypid, a.atttypmod) as "type",
CASE WHEN a.attnotnull IS TRUE
THEN \'NO\'
ELSE \'YES\'
END AS "null",
CASE WHEN pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true) IS NOT
NULL
THEN pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true)
END as "Default",
CASE WHEN pg_catalog.col_description(a.attrelid, a.attnum) IS NULL
THEN \'\'
ELSE pg_catalog.col_description(a.attrelid, a.attnum)
END AS "comments"
FROM pg_catalog.pg_attribute a
LEFT JOIN pg_catalog.pg_attrdef adef ON a.attrelid=adef.adrelid AND
a.attnum=adef.adnum
LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid
WHERE a.attrelid =
(SELECT oid FROM pg_catalog.pg_class WHERE relname=' .
$this->quote($tableSub) . '
AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
nspname = ' . $this->quote($schema) . ')
)
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum'
);
$fields = $this->loadObjectList();
if ($typeOnly)
{
foreach ($fields as $field)
{
$result[$field->column_name] = preg_replace('/[(0-9)]/',
'', $field->type);
}
}
else
{
foreach ($fields as $field)
{
if (stristr(strtolower($field->type), 'character
varying'))
{
$field->Default = '';
}
if (stristr(strtolower($field->type), 'text'))
{
$field->Default = '';
}
// Do some dirty translation to MySQL output.
// TODO: Come up with and implement a standard across databases.
$result[$field->column_name] = (object) array(
'column_name' => $field->column_name,
'type' => $field->type,
'null' => $field->null,
'Default' => $field->Default,
'comments' => '',
'Field' => $field->column_name,
'Type' => $field->type,
'Null' => $field->null,
// TODO: Improve query above to return primary key info as well
// 'Key' => ($field->PK == '1' ?
'PRI' : '')
);
}
}
/* Change Postgresql's NULL::* type with PHP's null one */
foreach ($fields as $field)
{
if (preg_match('/^NULL::*/', $field->Default))
{
$field->Default = null;
}
}
return $result;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
// To check if table exists and prevent SQL injection
$tableList = $this->getTableList();
if (in_array($table, $tableList))
{
// Get the details columns information.
$this->setQuery('
SELECT indexname AS "idxName", indisprimary AS
"isPrimary", indisunique AS "isUnique",
CASE WHEN indisprimary = true THEN
( SELECT \'ALTER TABLE \' || tablename || \' ADD
\' || pg_catalog.pg_get_constraintdef(const.oid, true)
FROM pg_constraint AS const WHERE const.conname=
pgClassFirst.relname )
ELSE pg_catalog.pg_get_indexdef(indexrelid, 0, true)
END AS "Query"
FROM pg_indexes
LEFT JOIN pg_class AS pgClassFirst ON indexname=pgClassFirst.relname
LEFT JOIN pg_index AS pgIndex ON pgClassFirst.oid=pgIndex.indexrelid
WHERE tablename=' . $this->quote($table) . ' ORDER BY
indkey'
);
$keys = $this->loadObjectList();
return $keys;
}
return false;
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableList()
{
$this->connect();
$query = $this->getQuery(true)
->select('table_name')
->from('information_schema.tables')
->where('table_type=' . $this->quote('BASE
TABLE'))
->where('table_schema NOT IN (' .
$this->quote('pg_catalog') . ', ' .
$this->quote('information_schema') . ')')
->order('table_name ASC');
$this->setQuery($query);
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the details list of sequences for a table.
*
* @param string $table The name of the table.
*
* @return array An array of sequences specification for the table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableSequences($table)
{
$this->connect();
// To check if table exists and prevent SQL injection
$tableList = $this->getTableList();
if (in_array($table, $tableList))
{
$name = array(
's.relname', 'n.nspname', 't.relname',
'a.attname', 'info.data_type',
'info.minimum_value', 'info.maximum_value',
'info.increment', 'info.cycle_option',
);
$as = array('sequence', 'schema', 'table',
'column', 'data_type', 'minimum_value',
'maximum_value', 'increment',
'cycle_option');
if (version_compare($this->getVersion(), '9.1.0') >= 0)
{
$name[] .= 'info.start_value';
$as[] .= 'start_value';
}
// Get the details columns information.
$query = $this->getQuery(true)
->select($this->quoteName($name, $as))
->from('pg_class AS s')
->join('LEFT', "pg_depend d ON d.objid=s.oid AND
d.classid='pg_class'::regclass AND
d.refclassid='pg_class'::regclass")
->join('LEFT', 'pg_class t ON t.oid=d.refobjid')
->join('LEFT', 'pg_namespace n ON
n.oid=t.relnamespace')
->join('LEFT', 'pg_attribute a ON a.attrelid=t.oid
AND a.attnum=d.refobjsubid')
->join('LEFT', 'information_schema.sequences AS info
ON info.sequence_name=s.relname')
->where("s.relkind='S' AND d.deptype='a'
AND t.relname=" . $this->quote($table));
$this->setQuery($query);
$seq = $this->loadObjectList();
return $seq;
}
return false;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.0.0
*/
public function getVersion()
{
$this->connect();
$version = pg_version($this->connection);
return $version['server'];
}
/**
* Method to get the auto-incremented value from the last INSERT
statement.
* To be called after the INSERT statement, it's MANDATORY to have a
sequence on
* every primary key table.
*
* To get the auto incremented value it's possible to call this
function after
* INSERT INTO query, or use INSERT INTO with RETURNING clause.
*
* @example with insertid() call:
* $query = $this->getQuery(true)
* ->insert('jos_dbtest')
* ->columns('title,start_date,description')
* ->values("'testTitle2nd','1971-01-01','testDescription2nd'");
* $this->setQuery($query);
* $this->execute();
* $id = $this->insertid();
*
* @example with RETURNING clause:
* $query = $this->getQuery(true)
* ->insert('jos_dbtest')
* ->columns('title,start_date,description')
* ->values("'testTitle2nd','1971-01-01','testDescription2nd'")
* ->returning('id');
* $this->setQuery($query);
* $id = $this->loadResult();
*
* @return integer The value of the auto-increment field from the last
inserted row.
*
* @since 3.0.0
*/
public function insertid()
{
$this->connect();
$insertQuery = $this->getQuery(false, true);
$table = $insertQuery->__get('insert')->getElements();
/* find sequence column name */
$colNameQuery = $this->getQuery(true);
$colNameQuery->select('column_default')
->from('information_schema.columns')
->where('table_name=' .
$this->quote($this->replacePrefix(str_replace('"',
'', $table[0]))), 'AND')
->where("column_default LIKE '%nextval%'");
$this->setQuery($colNameQuery);
$colName = $this->loadRow();
$changedColName = str_replace('nextval', 'currval',
$colName);
$insertidQuery = $this->getQuery(true);
$insertidQuery->select($changedColName);
$this->setQuery($insertidQuery);
$insertVal = $this->loadRow();
return $insertVal[0];
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to unlock.
*
* @return JDatabaseDriverPostgresql Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function lockTable($tableName)
{
$this->transactionStart();
$this->setQuery('LOCK TABLE ' .
$this->quoteName($tableName) . ' IN ACCESS EXCLUSIVE
MODE')->execute();
return $this;
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function execute()
{
$this->connect();
// Take a local copy so that we don't modify the original query and
cause issues later
$query = $this->replacePrefix((string) $this->sql);
if (!($this->sql instanceof JDatabaseQuery) &&
($this->limit > 0 || $this->offset > 0))
{
$query .= ' LIMIT ' . $this->limit . ' OFFSET ' .
$this->offset;
}
if (!is_resource($this->connection))
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
// Increment the query counter.
$this->count++;
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Add the query to the object queue.
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
$this->timings[] = microtime(true);
if (is_object($this->cursor))
{
// Avoid warning if result already freed by third-party library
@$this->freeResult();
}
$memoryBefore = memory_get_usage();
}
// Execute the query. Error suppression is used here to prevent
warnings/notices that the connection has been lost.
$this->cursor = @pg_query($this->connection, $query);
if ($this->debug)
{
$this->timings[] = microtime(true);
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
{
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
else
{
$this->callStacks[] = debug_backtrace();
}
$this->callStacks[count($this->callStacks) -
1][0]['memory'] = array(
$memoryBefore,
memory_get_usage(),
is_resource($this->cursor) ? $this->getNumRows($this->cursor)
: null,
);
}
// If an error occurred handle it.
if (!$this->cursor)
{
// Get the error number and message before we execute any more queries.
$errorNum = $this->getErrorNumber();
$errorMsg = $this->getErrorMessage();
// Check if the server was disconnected.
if (!$this->connected())
{
try
{
// Attempt to reconnect.
$this->connection = null;
$this->connect();
}
// If connect fails, ignore that exception and throw the normal
exception.
catch (RuntimeException $e)
{
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
null, $e);
}
// Since we were able to reconnect, run the query again.
return $this->execute();
}
// The server was not disconnected.
else
{
// Get the error number and message from before we tried to reconnect.
$this->errorNum = $errorNum;
$this->errorMsg = $errorMsg;
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg);
}
}
return $this->cursor;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by PostgreSQL.
* @param string $prefix Not used by PostgreSQL.
*
* @return JDatabaseDriverPostgresql Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$this->connect();
// To check if table exists and prevent SQL injection
$tableList = $this->getTableList();
// Origin Table does not exist
if (!in_array($oldTable, $tableList))
{
// Origin Table not found
throw new RuntimeException('Table not found in Postgresql
database.');
}
else
{
/* Rename indexes */
$this->setQuery(
'SELECT relname
FROM pg_class
WHERE oid IN (
SELECT indexrelid
FROM pg_index, pg_class
WHERE pg_class.relname=' . $this->quote($oldTable, true) .
'
AND pg_class.oid=pg_index.indrelid );'
);
$oldIndexes = $this->loadColumn();
foreach ($oldIndexes as $oldIndex)
{
$changedIdxName = str_replace($oldTable, $newTable, $oldIndex);
$this->setQuery('ALTER INDEX ' .
$this->escape($oldIndex) . ' RENAME TO ' .
$this->escape($changedIdxName));
$this->execute();
}
/* Rename sequence */
$this->setQuery(
'SELECT relname
FROM pg_class
WHERE relkind = \'S\'
AND relnamespace IN (
SELECT oid
FROM pg_namespace
WHERE nspname NOT LIKE \'pg_%\'
AND nspname != \'information_schema\'
)
AND relname LIKE \'%' . $oldTable . '%\' ;'
);
$oldSequences = $this->loadColumn();
foreach ($oldSequences as $oldSequence)
{
$changedSequenceName = str_replace($oldTable, $newTable, $oldSequence);
$this->setQuery('ALTER SEQUENCE ' .
$this->escape($oldSequence) . ' RENAME TO ' .
$this->escape($changedSequenceName));
$this->execute();
}
/* Rename table */
$this->setQuery('ALTER TABLE ' .
$this->escape($oldTable) . ' RENAME TO ' .
$this->escape($newTable));
$this->execute();
}
return true;
}
/**
* Selects the database, but redundant for PostgreSQL
*
* @param string $database Database name to select.
*
* @return boolean Always true
*
* @since 3.0.0
*/
public function select($database)
{
return true;
}
/**
* Custom settings for UTF support
*
* @return integer Zero on success, -1 on failure
*
* @since 3.0.0
*/
public function setUtf()
{
$this->connect();
if (!function_exists('pg_set_client_encoding'))
{
return -1;
}
return pg_set_client_encoding($this->connection, 'UTF8');
}
/**
* This function return a field value as a prepared string to be used in a
SQL statement.
*
* @param array $columns Array of table's column returned by
::getTableColumns.
* @param string $fieldName The table field's name.
* @param string $fieldValue The variable value to quote and return.
*
* @return string The quoted string.
*
* @since 3.0.0
*/
public function sqlValue($columns, $fieldName, $fieldValue)
{
switch ($columns[$fieldName])
{
case 'boolean':
$val = 'NULL';
if ($fieldValue == 't')
{
$val = 'TRUE';
}
elseif ($fieldValue == 'f')
{
$val = 'FALSE';
}
break;
case 'bigint':
case 'bigserial':
case 'integer':
case 'money':
case 'numeric':
case 'real':
case 'smallint':
case 'serial':
case 'numeric,':
$val = strlen($fieldValue) == 0 ? 'NULL' : $fieldValue;
break;
case 'date':
case 'timestamp without time zone':
if (empty($fieldValue))
{
$fieldValue = $this->getNullDate();
}
$val = $this->quote($fieldValue);
break;
default:
$val = $this->quote($fieldValue);
break;
}
return $val;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('COMMIT')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$this->transactionDepth--;
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('ROLLBACK')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
$this->setQuery('RELEASE SAVEPOINT ' .
$this->quoteName($savepoint))->execute();
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
if ($this->setQuery('START TRANSACTION')->execute())
{
$this->transactionDepth = 1;
}
return;
}
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
/**
* Method to fetch a row from the result set cursor as an array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchArray($cursor = null)
{
return pg_fetch_row($cursor ? $cursor : $this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an associative
array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchAssoc($cursor = null)
{
return pg_fetch_assoc($cursor ? $cursor : $this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
* @param string $class The class name to use for the returned row
object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject($cursor = null, $class =
'stdClass')
{
return pg_fetch_object(is_null($cursor) ? $this->cursor : $cursor,
null, $class);
}
/**
* Method to free up the memory used for the result set.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult($cursor = null)
{
pg_free_result($cursor ? $cursor : $this->cursor);
}
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert
into.
* @param object &$object A reference to an object whose public
properties match the table fields.
* @param string $key The name of the primary key. If provided the
object property is updated.
*
* @return boolean True on success.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function insertObject($table, &$object, $key = null)
{
$columns = $this->getTableColumns($table);
$fields = array();
$values = array();
// Iterate over the object variables to build the query fields and
values.
foreach (get_object_vars($object) as $k => $v)
{
// Only process non-null scalars.
if (is_array($v) or is_object($v) or $v === null)
{
continue;
}
// Ignore any internal fields or primary keys with value 0.
if (($k[0] == '_') || ($k == $key && (($v === 0) ||
($v === '0'))))
{
continue;
}
// Prepare and sanitize the fields and values for the database query.
$fields[] = $this->quoteName($k);
$values[] = $this->sqlValue($columns, $k, $v);
}
// Create the base insert statement.
$query = $this->getQuery(true)
->insert($this->quoteName($table))
->columns($fields)
->values(implode(',', $values));
$retVal = false;
if ($key)
{
$query->returning($key);
// Set the query and execute the insert.
$this->setQuery($query);
$id = $this->loadResult();
if ($id)
{
$object->$key = $id;
$retVal = true;
}
}
else
{
// Set the query and execute the insert.
$this->setQuery($query);
if ($this->execute())
{
$retVal = true;
}
}
return $retVal;
}
/**
* Test to see if the PostgreSQL connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return function_exists('pg_connect');
}
/**
* Returns an array containing database's table list.
*
* @return array The database's table list.
*
* @since 3.0.0
*/
public function showTables()
{
$this->connect();
$query = $this->getQuery(true)
->select('table_name')
->from('information_schema.tables')
->where('table_type = ' . $this->quote('BASE
TABLE'))
->where('table_schema NOT IN (' .
$this->quote('pg_catalog') . ', ' .
$this->quote('information_schema') . ' )');
$this->setQuery($query);
$tableList = $this->loadColumn();
return $tableList;
}
/**
* Get the substring position inside a string
*
* @param string $substring The string being sought
* @param string $string The string/column being searched
*
* @return integer The position of $substring in $string
*
* @since 3.0.0
*/
public function getStringPositionSql($substring, $string)
{
$this->connect();
$query = "SELECT POSITION( $substring IN $string )";
$this->setQuery($query);
$position = $this->loadRow();
return $position['position'];
}
/**
* Generate a random value
*
* @return float The random generated number
*
* @since 3.0.0
*/
public function getRandom()
{
$this->connect();
$this->setQuery('SELECT RANDOM()');
$random = $this->loadAssoc();
return $random['random'];
}
/**
* Get the query string to alter the database character set.
*
* @param string $dbName The database name
*
* @return string The query that alter the database query string
*
* @since 3.0.0
*/
public function getAlterDbCharacterSet($dbName)
{
$query = 'ALTER DATABASE ' . $this->quoteName($dbName) .
' SET CLIENT_ENCODING TO ' . $this->quote('UTF8');
return $query;
}
/**
* Get the query string to create new Database in correct PostgreSQL
syntax.
*
* @param object $options object coming from "initialise"
function to pass user and database name to database driver.
* @param boolean $utf True if the database supports the UTF-8
character set, not used in PostgreSQL "CREATE DATABASE" query.
*
* @return string The query that creates database, owned by
$options['user']
*
* @since 3.0.0
*/
public function getCreateDbQuery($options, $utf)
{
$query = 'CREATE DATABASE ' .
$this->quoteName($options->db_name) . ' OWNER ' .
$this->quoteName($options->db_user);
if ($utf)
{
$query .= ' ENCODING ' . $this->quote('UTF-8');
}
return $query;
}
/**
* This function replaces a string identifier
<var>$prefix</var> with the string held is the
* <var>tablePrefix</var> class variable.
*
* @param string $query The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 3.0.0
*/
public function replacePrefix($query, $prefix = '#__')
{
$query = trim($query);
if (strpos($query, '\''))
{
// Sequence name quoted with ' ' but need to be replaced
if (strpos($query, 'currval'))
{
$query = explode('currval', $query);
for ($nIndex = 1, $nIndexMax = count($query); $nIndex < $nIndexMax;
$nIndex += 2)
{
$query[$nIndex] = str_replace($prefix, $this->tablePrefix,
$query[$nIndex]);
}
$query = implode('currval', $query);
}
// Sequence name quoted with ' ' but need to be replaced
if (strpos($query, 'nextval'))
{
$query = explode('nextval', $query);
for ($nIndex = 1, $nIndexMax = count($query); $nIndex < $nIndexMax;
$nIndex += 2)
{
$query[$nIndex] = str_replace($prefix, $this->tablePrefix,
$query[$nIndex]);
}
$query = implode('nextval', $query);
}
// Sequence name quoted with ' ' but need to be replaced
if (strpos($query, 'setval'))
{
$query = explode('setval', $query);
for ($nIndex = 1, $nIndexMax = count($query); $nIndex < $nIndexMax;
$nIndex += 2)
{
$query[$nIndex] = str_replace($prefix, $this->tablePrefix,
$query[$nIndex]);
}
$query = implode('setval', $query);
}
$explodedQuery = explode('\'', $query);
for ($nIndex = 0, $nIndexMax = count($explodedQuery); $nIndex <
$nIndexMax; $nIndex += 2)
{
if (strpos($explodedQuery[$nIndex], $prefix))
{
$explodedQuery[$nIndex] = str_replace($prefix, $this->tablePrefix,
$explodedQuery[$nIndex]);
}
}
$replacedQuery = implode('\'', $explodedQuery);
}
else
{
$replacedQuery = str_replace($prefix, $this->tablePrefix, $query);
}
return $replacedQuery;
}
/**
* Method to release a savepoint.
*
* @param string $savepointName Savepoint's name to release
*
* @return void
*
* @since 3.0.0
*/
public function releaseTransactionSavepoint($savepointName)
{
$this->connect();
$this->setQuery('RELEASE SAVEPOINT ' .
$this->quoteName($this->escape($savepointName)));
$this->execute();
}
/**
* Method to create a savepoint.
*
* @param string $savepointName Savepoint's name to create
*
* @return void
*
* @since 3.0.0
*/
public function transactionSavepoint($savepointName)
{
$this->connect();
$this->setQuery('SAVEPOINT ' .
$this->quoteName($this->escape($savepointName)));
$this->execute();
}
/**
* Unlocks tables in the database, this command does not exist in
PostgreSQL,
* it is automatically done on commit or rollback.
*
* @return JDatabaseDriverPostgresql Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function unlockTables()
{
$this->transactionCommit();
return $this;
}
/**
* Updates a row in a table based on an object's properties.
*
* @param string $table The name of the database table to update.
* @param object &$object A reference to an object whose public
properties match the table fields.
* @param array $key The name of the primary key.
* @param boolean $nulls True to update null fields or false to
ignore them.
*
* @return boolean True on success.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function updateObject($table, &$object, $key, $nulls = false)
{
$columns = $this->getTableColumns($table);
$fields = array();
$where = array();
if (is_string($key))
{
$key = array($key);
}
if (is_object($key))
{
$key = (array) $key;
}
// Create the base update statement.
$statement = 'UPDATE ' . $this->quoteName($table) . '
SET %s WHERE %s';
// Iterate over the object variables to build the query fields/value
pairs.
foreach (get_object_vars($object) as $k => $v)
{
// Only process scalars that are not internal fields.
if (is_array($v) or is_object($v) or $k[0] == '_')
{
continue;
}
// Set the primary key to the WHERE clause instead of a field to update.
if (in_array($k, $key))
{
$key_val = $this->sqlValue($columns, $k, $v);
$where[] = $this->quoteName($k) . '=' . $key_val;
continue;
}
// Prepare and sanitize the fields and values for the database query.
if ($v === null)
{
// If the value is null and we want to update nulls then set it.
if ($nulls)
{
$val = 'NULL';
}
// If the value is null and we do not want to update nulls then ignore
this field.
else
{
continue;
}
}
// The field is not null so we prep it for update.
else
{
$val = $this->sqlValue($columns, $k, $v);
}
// Add the field to be updated.
$fields[] = $this->quoteName($k) . '=' . $val;
}
// We don't have any fields to update.
if (empty($fields))
{
return true;
}
// Set the query and execute the update.
$this->setQuery(sprintf($statement, implode(',', $fields),
implode(' AND ', $where)));
return $this->execute();
}
/**
* Return the actual SQL Error number
*
* @return integer The SQL Error number
*
* @since 3.4.6
*
* @throws \JDatabaseExceptionExecuting Thrown if the global cursor is
false indicating a query failed
*/
protected function getErrorNumber()
{
if ($this->cursor === false)
{
$this->errorMsg = pg_last_error($this->connection);
throw new JDatabaseExceptionExecuting($this->sql,
$this->errorMsg);
}
return (int) pg_result_error_field($this->cursor, PGSQL_DIAG_SQLSTATE)
. ' ';
}
/**
* Return the actual SQL Error message
*
* @return string The SQL Error message
*
* @since 3.4.6
*/
protected function getErrorMessage()
{
$errorMessage = (string) pg_last_error($this->connection);
// Replace the Databaseprefix with `#__` if we are not in Debug
if (!$this->debug)
{
$errorMessage = str_replace($this->tablePrefix, '#__',
$errorMessage);
}
return $errorMessage;
}
/**
* Get the query strings to alter the character set and collation of a
table.
*
* @param string $tableName The name of the table
*
* @return string[] The queries required to alter the table's
character set and collation
*
* @since CMS 3.5.0
*/
public function getAlterTableCharacterSet($tableName)
{
return array();
}
/**
* Return the query string to create new Database.
* Each database driver, other than MySQL, need to override this member to
return correct string.
*
* @param stdClass $options Object used to pass user and database name
to database driver.
* This object must have "db_name" and
"db_user" set.
* @param boolean $utf True if the database supports the UTF-8
character set.
*
* @return string The query that creates database
*
* @since 3.0.1
*/
protected function getCreateDatabaseQuery($options, $utf)
{
return 'CREATE DATABASE ' .
$this->quoteName($options->db_name);
}
/**
* Quotes a binary string to database requirements for use in database
queries.
*
* @param mixed $data A binary string to quote.
*
* @return string The binary quoted input string.
*
* @since 3.9.12
*/
public function quoteBinary($data)
{
return "decode('" . bin2hex($data) . "',
'hex')";
}
/**
* Internal function to get the name of the default schema for the current
PostgreSQL connection.
* That is the schema where tables are created by Joomla.
*
* @return string
*
* @since 3.9.24
*/
private function getDefaultSchema()
{
// Supported since PostgreSQL 7.3
$this->setQuery('SELECT (current_schemas(false))[1]');
return $this->loadResult();
}
}
PK ��[�KKXRRdriver/sqlazure.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQL Server database driver
*
* @link
https://azure.microsoft.com/en-us/documentation/services/sql-database/
* @since 3.0.0
*/
class JDatabaseDriverSqlazure extends JDatabaseDriverSqlsrv
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'sqlazure';
}
PK ��[�s��//driver/sqlite.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQLite database driver
*
* @link https://www.php.net/pdo
* @since 3.0.0
*/
class JDatabaseDriverSqlite extends JDatabaseDriverPdo
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'sqlite';
/**
* The type of the database server family supported by this driver.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType = 'sqlite';
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.0.0
*/
protected $nameQuote = '`';
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @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.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
$this->freeResult();
$this->connection = null;
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return JDatabaseDriverSqlite Returns this object to support
chaining.
*
* @since 3.0.0
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$query = $this->getQuery(true);
$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS
' : '') . $query->quoteName($tableName));
$this->execute();
return $this;
}
/**
* Method to escape a string for usage in an SQLite statement.
*
* Note: Using query objects with bound variables is
* preferable to the below.
*
* @param string $text The string to be escaped.
* @param boolean $extra Unused optional parameter to provide extra
escaping.
*
* @return string The escaped string.
*
* @since 3.0.0
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
return SQLite3::escapeString($text);
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database or boolean false
if not supported.
*
* @since 3.0.0
*/
public function getCollation()
{
return $this->charset;
}
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
return $this->charset;
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* Note: Doesn't appear to have support in SQLite
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableCreate($tables)
{
$this->connect();
// Sanitize input to an array and iterate over the list.
settype($tables, 'array');
return $tables;
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$columns = array();
$query = $this->getQuery(true);
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
$table = strtoupper($table);
$query->setQuery('pragma table_info(' . $table .
')');
$this->setQuery($query);
$fields = $this->loadObjectList();
if ($typeOnly)
{
foreach ($fields as $field)
{
$columns[$field->NAME] = $field->TYPE;
}
}
else
{
foreach ($fields as $field)
{
// Do some dirty translation to MySQL output.
// TODO: Come up with and implement a standard across databases.
$columns[$field->NAME] = (object) array(
'Field' => $field->NAME,
'Type' => $field->TYPE,
'Null' => ($field->NOTNULL == '1' ?
'NO' : 'YES'),
'Default' => $field->DFLT_VALUE,
'Key' => ($field->PK != '0' ?
'PRI' : ''),
);
}
}
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
return $columns;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
$keys = array();
$query = $this->getQuery(true);
$fieldCasing = $this->getOption(PDO::ATTR_CASE);
$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
$table = strtoupper($table);
$query->setQuery('pragma table_info( ' . $table .
')');
// $query->bind(':tableName', $table);
$this->setQuery($query);
$rows = $this->loadObjectList();
foreach ($rows as $column)
{
if ($column->PK == 1)
{
$keys[$column->NAME] = $column;
}
}
$this->setOption(PDO::ATTR_CASE, $fieldCasing);
return $keys;
}
/**
* Method to get an array of all tables in the database (schema).
*
* @return array An array of all the tables in the database.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableList()
{
$this->connect();
$type = 'table';
$query = $this->getQuery(true)
->select('name')
->from('sqlite_master')
->where('type = :type')
->bind(':type', $type)
->order('name');
$this->setQuery($query);
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.0.0
*/
public function getVersion()
{
$this->connect();
$this->setQuery('SELECT sqlite_version()');
return $this->loadResult();
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* Returns false automatically for the Oracle driver since
* you can only set the character set when the connection
* is created.
*
* @return boolean True on success.
*
* @since 3.0.0
*/
public function setUtf()
{
$this->connect();
return false;
}
/**
* Locks a table in the database.
*
* @param string $table The name of the table to unlock.
*
* @return JDatabaseDriverSqlite Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function lockTable($table)
{
return $this;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by Sqlite.
* @param string $prefix Not used by Sqlite.
*
* @return JDatabaseDriverSqlite Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$this->setQuery('ALTER TABLE ' . $oldTable . ' RENAME
TO ' . $newTable)->execute();
return $this;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriverSqlite Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function unlockTables()
{
return $this;
}
/**
* Test to see if the PDO ODBC connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return class_exists('PDO') &&
in_array('sqlite', PDO::getAvailableDrivers());
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.1.4
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionCommit($toSavepoint);
}
else
{
$this->transactionDepth--;
}
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.1.4
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
parent::transactionRollback($toSavepoint);
}
else
{
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
}
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.1.4
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
parent::transactionStart($asSavepoint);
}
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
/**
* Get the query strings to alter the character set and collation of a
table.
*
* @param string $tableName The name of the table
*
* @return string[] The queries required to alter the table's
character set and collation
*
* @since CMS 3.5.0
*/
public function getAlterTableCharacterSet($tableName)
{
return array();
}
/**
* Return the query string to create new Database.
* Each database driver, other than MySQL, need to override this member to
return correct string.
*
* @param stdClass $options Object used to pass user and database name
to database driver.
* This object must have "db_name" and
"db_user" set.
* @param boolean $utf True if the database supports the UTF-8
character set.
*
* @return string The query that creates database
*
* @since 3.0.1
*/
protected function getCreateDatabaseQuery($options, $utf)
{
return 'CREATE DATABASE ' .
$this->quoteName($options->db_name);
}
}
PK ��[�)�$l$ldriver/sqlsrv.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQL Server database driver
*
* @link https://msdn.microsoft.com/en-us/library/cc296152(SQL.90).aspx
* @since 3.0.0
*/
class JDatabaseDriverSqlsrv extends JDatabaseDriver
{
/**
* The name of the database driver.
*
* @var string
* @since 3.0.0
*/
public $name = 'sqlsrv';
/**
* The type of the database server family supported by this driver.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType = 'mssql';
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.0.0
*/
protected $nameQuote = '[]';
/**
* The null or zero representation of a timestamp for the database driver.
This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 3.0.0
*/
protected $nullDate = '1900-01-01 00:00:00';
/**
* @var string The minimum supported database version.
* @since 3.0.0
*/
protected static $dbMinimum = '10.50.1600.1';
/**
* Test to see if the SQLSRV connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.0.0
*/
public static function isSupported()
{
return function_exists('sqlsrv_connect');
}
/**
* Constructor.
*
* @param array $options List of options used to configure the
connection
*
* @since 3.0.0
*/
public function __construct($options)
{
// Get some basic values from the options.
$options['host'] = (isset($options['host'])) ?
$options['host'] : 'localhost';
$options['user'] = (isset($options['user'])) ?
$options['user'] : '';
$options['password'] = (isset($options['password']))
? $options['password'] : '';
$options['database'] = (isset($options['database']))
? $options['database'] : '';
$options['select'] = (isset($options['select'])) ?
(bool) $options['select'] : true;
// Finalize initialisation
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function connect()
{
if ($this->connection)
{
return;
}
// Build the connection configuration array.
$config = array(
'Database' => $this->options['database'],
'uid' => $this->options['user'],
'pwd' => $this->options['password'],
'CharacterSet' => 'UTF-8',
'ReturnDatesAsStrings' => true,
);
// Make sure the SQLSRV extension for PHP is installed and enabled.
if (!self::isSupported())
{
throw new JDatabaseExceptionUnsupported('The sqlsrv extension for
PHP is not installed or enabled..');
}
// Attempt to connect to the server.
if (!($this->connection = @
sqlsrv_connect($this->options['host'], $config)))
{
throw new JDatabaseExceptionConnecting('Database sqlsrv_connect
failed, ' . print_r(sqlsrv_errors(), true));
}
// Make sure that DB warnings are not returned as errors.
sqlsrv_configure('WarningsReturnAsErrors', 0);
// If auto-select is enabled select the given database.
if ($this->options['select'] &&
!empty($this->options['database']))
{
$this->select($this->options['database']);
}
// Set charactersets.
$this->utf = $this->setUtf();
// Set QUOTED_IDENTIFIER always ON
sqlsrv_query($this->connection, 'SET QUOTED_IDENTIFIER ON');
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
public function disconnect()
{
// Close the connection.
if (is_resource($this->connection))
{
foreach ($this->disconnectHandlers as $h)
{
call_user_func_array($h, array( &$this));
}
sqlsrv_close($this->connection);
}
$this->connection = null;
}
/**
* Get table constraints
*
* @param string $tableName The name of the database table.
*
* @return array Any constraints available for the table.
*
* @since 3.0.0
*/
protected function getTableConstraints($tableName)
{
$this->connect();
$query = $this->getQuery(true);
$this->setQuery(
'SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_NAME = ' . $query->quote($tableName)
);
return $this->loadColumn();
}
/**
* Rename constraints.
*
* @param array $constraints Array(strings) of table constraints
* @param string $prefix A string
* @param string $backup A string
*
* @return void
*
* @since 3.0.0
*/
protected function renameConstraints($constraints = array(), $prefix =
null, $backup = null)
{
$this->connect();
foreach ($constraints as $constraint)
{
$this->setQuery('sp_rename ' . $constraint . ','
. str_replace($prefix, $backup, $constraint));
$this->execute();
}
}
/**
* Method to escape a string for usage in an SQL statement.
*
* The escaping for MSSQL isn't handled in the driver though that
would be nice. Because of this we need
* to handle the escaping ourselves.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 3.0.0
*/
public function escape($text, $extra = false)
{
if (is_int($text))
{
return $text;
}
if (is_float($text))
{
// Force the dot as a decimal point.
return str_replace(',', '.', $text);
}
$result = str_replace("'", "''",
$text);
// SQL Server does not accept NULL byte in query string
$result = str_replace("\0", "' + CHAR(0) +
N'", $result);
// Fix for SQL Server escape sequence, see
https://support.microsoft.com/en-us/kb/164291
$result = str_replace(
array("\\\n", "\\\r",
"\\\\\r\r\n"),
array("\\\\\n\n", "\\\\\r\r",
"\\\\\r\n\r\n"),
$result
);
if ($extra)
{
// Escape special chars
$result = str_replace(
array('[', '_', '%'),
array('[[]', '[_]', '[%]'),
$result
);
}
return $result;
}
/**
* Quotes and optionally escapes a string to database requirements for use
in database queries.
*
* @param mixed $text A string or an array of strings to quote.
* @param boolean $escape True (default) to escape the string, false
to leave it unchanged.
*
* @return string The quoted input string.
*
* @note Accepting an array of strings was added in 3.1.4.
* @since 1.7.0
*/
public function quote($text, $escape = true)
{
if (is_array($text))
{
return parent::quote($text, $escape);
}
// To support unicode on MSSQL we have to add prefix N
return 'N\'' . ($escape ? $this->escape($text) : $text)
. '\'';
}
/**
* Quotes a binary string to database requirements for use in database
queries.
*
* @param mixed $data A binary string to quote.
*
* @return string The binary quoted input string.
*
* @since 3.9.12
*/
public function quoteBinary($data)
{
// ODBC syntax for hexadecimal literals
return '0x' . bin2hex($data);
}
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 3.0.0
*/
public function connected()
{
// TODO: Run a blank query here
return true;
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return JDatabaseDriverSqlsrv Returns this object to support
chaining.
*
* @since 3.0.0
*/
public function dropTable($tableName, $ifExists = true)
{
$this->connect();
$query = $this->getQuery(true);
if ($ifExists)
{
$this->setQuery(
'IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE
TABLE_NAME = ' . $query->quote($tableName) . ') DROP TABLE
' . $tableName
);
}
else
{
$this->setQuery('DROP TABLE ' . $tableName);
}
$this->execute();
return $this;
}
/**
* Get the number of affected rows for the previous executed SQL
statement.
*
* @return integer The number of affected rows.
*
* @since 3.0.0
*/
public function getAffectedRows()
{
$this->connect();
return sqlsrv_rows_affected($this->cursor);
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database or boolean false
if not supported.
*
* @since 3.0.0
*/
public function getCollation()
{
// TODO: Not fake this
return 'MSSQL UTF-8 (UCS2)';
}
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
// TODO: Not fake this
return 'MSSQL UTF-8 (UCS2)';
}
/**
* Get the number of returned rows for the previous executed SQL
statement.
*
* @param resource $cursor An optional database cursor resource to
extract the row count from.
*
* @return integer The number of returned rows.
*
* @since 3.0.0
*/
public function getNumRows($cursor = null)
{
$this->connect();
return sqlsrv_num_rows($cursor ? $cursor : $this->cursor);
}
/**
* Retrieves field information about the given tables.
*
* @param mixed $table A table name
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$result = array();
$table_temp = $this->replacePrefix((string) $table);
// Set the query to get the table fields statement.
$this->setQuery(
'SELECT column_name as Field, data_type as Type, is_nullable as
\'Null\', column_default as \'Default\'' .
' FROM information_schema.columns WHERE table_name = ' .
$this->quote($table_temp)
);
$fields = $this->loadObjectList();
// If we only want the type as the value add just that to the list.
if ($typeOnly)
{
foreach ($fields as $field)
{
$result[$field->Field] = preg_replace('/[(0-9)]/',
'', $field->Type);
}
}
// If we want the whole field data object add that to the list.
else
{
foreach ($fields as $field)
{
$field->Default =
preg_replace("/(^(\(\(|\('|\(N'|\()|(('\)|(?<!\()\)\)|\))$))/i",
'', $field->Default);
$result[$field->Field] = $field;
}
}
return $result;
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* This is unsupported by MSSQL.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableCreate($tables)
{
$this->connect();
return '';
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
// TODO To implement.
return array();
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getTableList()
{
$this->connect();
// Set the query to get the tables statement.
$this->setQuery('SELECT name FROM ' .
$this->getDatabase() . '.sys.Tables WHERE type =
\'U\';');
$tables = $this->loadColumn();
return $tables;
}
/**
* Get the version of the database connector.
*
* @return string The database connector version.
*
* @since 3.0.0
*/
public function getVersion()
{
$this->connect();
$version = sqlsrv_server_info($this->connection);
return $version['SQLServerVersion'];
}
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert
into.
* @param object &$object A reference to an object whose public
properties match the table fields.
* @param string $key The name of the primary key. If provided the
object property is updated.
*
* @return boolean True on success.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function insertObject($table, &$object, $key = null)
{
$fields = array();
$values = array();
$statement = 'INSERT INTO ' . $this->quoteName($table) .
' (%s) VALUES (%s)';
foreach (get_object_vars($object) as $k => $v)
{
// Only process non-null scalars.
if (is_array($v) or is_object($v) or $v === null)
{
continue;
}
if (!$this->checkFieldExists($table, $k))
{
continue;
}
if ($k[0] == '_')
{
// Internal field
continue;
}
if ($k == $key && $key == 0)
{
continue;
}
$fields[] = $this->quoteName($k);
$values[] = $this->Quote($v);
}
// Set the query and execute the insert.
$this->setQuery(sprintf($statement, implode(',', $fields),
implode(',', $values)));
if (!$this->execute())
{
return false;
}
$id = $this->insertid();
if ($key && $id)
{
$object->$key = $id;
}
return true;
}
/**
* Method to get the auto-incremented value from the last INSERT
statement.
*
* @return integer The value of the auto-increment field from the last
inserted row.
*
* @since 3.0.0
*/
public function insertid()
{
$this->connect();
// TODO: SELECT IDENTITY
$this->setQuery('SELECT @@IDENTITY');
return (int) $this->loadResult();
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 3.0.0
* @throws RuntimeException
* @throws Exception
*/
public function execute()
{
$this->connect();
// Take a local copy so that we don't modify the original query and
cause issues later
$query = $this->replacePrefix((string) $this->sql);
if (!($this->sql instanceof JDatabaseQuery) &&
($this->limit > 0 || $this->offset > 0))
{
$query = $this->limit($query, $this->limit, $this->offset);
}
if (!is_resource($this->connection))
{
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
// Increment the query counter.
$this->count++;
// Reset the error values.
$this->errorNum = 0;
$this->errorMsg = '';
// If debugging is enabled then let's log the query.
if ($this->debug)
{
// Add the query to the object queue.
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
$this->timings[] = microtime(true);
}
// SQLSrv_num_rows requires a static or keyset cursor.
if (strncmp(ltrim(strtoupper($query)), 'SELECT',
strlen('SELECT')) == 0)
{
$array = array('Scrollable' => SQLSRV_CURSOR_KEYSET);
}
else
{
$array = array();
}
// Execute the query. Error suppression is used here to prevent
warnings/notices that the connection has been lost.
$this->cursor = @sqlsrv_query($this->connection, $query, array(),
$array);
if ($this->debug)
{
$this->timings[] = microtime(true);
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
{
$this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
else
{
$this->callStacks[] = debug_backtrace();
}
}
// If an error occurred handle it.
if (!$this->cursor)
{
// Get the error number and message before we execute any more queries.
$errorNum = $this->getErrorNumber();
$errorMsg = $this->getErrorMessage();
// Check if the server was disconnected.
if (!$this->connected())
{
try
{
// Attempt to reconnect.
$this->connection = null;
$this->connect();
}
// If connect fails, ignore that exception and throw the normal
exception.
catch (RuntimeException $e)
{
// Get the error number and message.
$this->errorNum = $this->getErrorNumber();
$this->errorMsg = $this->getErrorMessage();
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum, $e);
}
// Since we were able to reconnect, run the query again.
return $this->execute();
}
// The server was not disconnected.
else
{
// Get the error number and message from before we tried to reconnect.
$this->errorNum = $errorNum;
$this->errorMsg = $errorMsg;
// Throw the normal query exception.
JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED',
$this->errorNum, $this->errorMsg), JLog::ERROR,
'database-error');
throw new JDatabaseExceptionExecuting($query, $this->errorMsg,
$this->errorNum);
}
}
return $this->cursor;
}
/**
* This function replaces a string identifier
<var>$prefix</var> with the string held is the
* <var>tablePrefix</var> class variable.
*
* @param string $query The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 3.0.0
*/
public function replacePrefix($query, $prefix = '#__')
{
$query = trim($query);
if (strpos($query, "'"))
{
$parts = explode("'", $query);
for ($nIndex = 0, $size = count($parts); $nIndex < $size; $nIndex =
$nIndex + 2)
{
if (strpos($parts[$nIndex], $prefix) !== false)
{
$parts[$nIndex] = str_replace($prefix, $this->tablePrefix,
$parts[$nIndex]);
}
}
$query = implode("'", $parts);
}
else
{
$query = str_replace($prefix, $this->tablePrefix, $query);
}
return $query;
}
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function select($database)
{
$this->connect();
if (!$database)
{
return false;
}
if (!sqlsrv_query($this->connection, 'USE ' . $database,
null, array('scrollable' => SQLSRV_CURSOR_STATIC)))
{
throw new JDatabaseExceptionConnecting('Could not connect to SQL
Server database.');
}
return true;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 3.0.0
*/
public function setUtf()
{
return false;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('COMMIT TRANSACTION')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$this->transactionDepth--;
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('ROLLBACK TRANSACTION')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TRANSACTION ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.0.0
* @throws RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
if ($this->setQuery('BEGIN TRANSACTION')->execute())
{
$this->transactionDepth = 1;
}
return;
}
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('BEGIN TRANSACTION ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
/**
* Method to fetch a row from the result set cursor as an array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchArray($cursor = null)
{
return sqlsrv_fetch_array($cursor ? $cursor : $this->cursor,
SQLSRV_FETCH_NUMERIC);
}
/**
* Method to fetch a row from the result set cursor as an associative
array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchAssoc($cursor = null)
{
return sqlsrv_fetch_array($cursor ? $cursor : $this->cursor,
SQLSRV_FETCH_ASSOC);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
* @param string $class The class name to use for the returned row
object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject($cursor = null, $class =
'stdClass')
{
// Class has to be loaded for sqlsrv on windows platform
class_exists($class);
return sqlsrv_fetch_object($cursor ? $cursor : $this->cursor, $class);
}
/**
* Method to free up the memory used for the result set.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult($cursor = null)
{
sqlsrv_free_stmt($cursor ? $cursor : $this->cursor);
}
/**
* Method to check and see if a field exists in a table.
*
* @param string $table The table in which to verify the field.
* @param string $field The field to verify.
*
* @return boolean True if the field exists in the table.
*
* @since 3.0.0
*/
protected function checkFieldExists($table, $field)
{
$this->connect();
$table = $this->replacePrefix((string) $table);
$query = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME = '$table' AND COLUMN_NAME = '$field' ORDER
BY ORDINAL_POSITION";
$this->setQuery($query);
if ($this->loadResult())
{
return true;
}
else
{
return false;
}
}
/**
* Method to wrap an SQL statement to provide a LIMIT and OFFSET behavior
for scrolling through a result set.
*
* @param string $query The SQL statement to process.
* @param integer $limit The maximum affected rows to set.
* @param integer $offset The affected row offset to set.
*
* @return string The processed SQL statement.
*
* @since 3.0.0
*/
protected function limit($query, $limit, $offset)
{
if ($limit)
{
$total = $offset + $limit;
$position = stripos($query, 'SELECT');
$distinct = stripos($query, 'SELECT DISTINCT');
if ($position === $distinct)
{
$query = substr_replace($query, 'SELECT DISTINCT TOP ' .
(int) $total, $position, 15);
}
else
{
$query = substr_replace($query, 'SELECT TOP ' . (int) $total,
$position, 6);
}
}
if (!$offset)
{
return $query;
}
return PHP_EOL
. 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0))
AS RowNumber FROM ('
. $query
. PHP_EOL . ') AS A) AS A WHERE RowNumber > ' . (int)
$offset;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Table prefix
* @param string $prefix For the table - used to rename constraints
in non-mysql databases
*
* @return JDatabaseDriverSqlsrv Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$constraints = array();
if (!is_null($prefix) && !is_null($backup))
{
$constraints = $this->getTableConstraints($oldTable);
}
if (!empty($constraints))
{
$this->renameConstraints($constraints, $prefix, $backup);
}
$this->setQuery("sp_rename '" . $oldTable .
"', '" . $newTable . "'");
return $this->execute();
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to lock.
*
* @return JDatabaseDriverSqlsrv Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function lockTable($tableName)
{
return $this;
}
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriverSqlsrv Returns this object to support
chaining.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function unlockTables()
{
return $this;
}
/**
* Return the actual SQL Error number
*
* @return integer The SQL Error number
*
* @since 3.4.6
*/
protected function getErrorNumber()
{
$errors = sqlsrv_errors();
return $errors[0]['code'];
}
/**
* Return the actual SQL Error message
*
* @return string The SQL Error message
*
* @since 3.4.6
*/
protected function getErrorMessage()
{
$errors = sqlsrv_errors();
$errorMessage = (string) $errors[0]['message'];
// Replace the Databaseprefix with `#__` if we are not in Debug
if (!$this->debug)
{
$errorMessage = str_replace($this->tablePrefix, '#__',
$errorMessage);
}
return $errorMessage;
}
/**
* Get the query strings to alter the character set and collation of a
table.
*
* @param string $tableName The name of the table
*
* @return string[] The queries required to alter the table's
character set and collation
*
* @since CMS 3.5.0
*/
public function getAlterTableCharacterSet($tableName)
{
return array();
}
/**
* Return the query string to create new Database.
* Each database driver, other than MySQL, need to override this member to
return correct string.
*
* @param stdClass $options Object used to pass user and database name
to database driver.
* This object must have "db_name" and
"db_user" set.
* @param boolean $utf True if the database supports the UTF-8
character set.
*
* @return string The query that creates database
*
* @since 3.0.1
*/
protected function getCreateDatabaseQuery($options, $utf)
{
return 'CREATE DATABASE ' .
$this->quoteName($options->db_name);
}
}
PK ��[��UD�D�
driver.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform Database Driver Class
*
* @since 3.0.0
*
* @method string|array q() q($text, $escape = true) Alias for quote
method
* @method string|array qn() qn($name, $as = null) Alias for
quoteName method
*/
abstract class JDatabaseDriver extends JDatabase implements
JDatabaseInterface
{
/**
* The name of the database.
*
* @var string
* @since 2.5.0
*/
private $_database;
/**
* The name of the database driver.
*
* @var string
* @since 1.7.0
*/
public $name;
/**
* The type of the database server family supported by this driver.
Examples: mysql, oracle, postgresql, mssql,
* sqlite.
*
* @var string
* @since CMS 3.5.0
*/
public $serverType;
/**
* @var resource The database connection resource.
* @since 1.7.0
*/
protected $connection;
/**
* @var integer The number of SQL statements executed by the database
driver.
* @since 1.7.0
*/
protected $count = 0;
/**
* @var resource The database connection cursor from the last query.
* @since 1.7.0
*/
protected $cursor;
/**
* @var boolean The database driver debugging state.
* @since 1.7.0
*/
protected $debug = false;
/**
* @var integer The affected row limit for the current SQL statement.
* @since 1.7.0
*/
protected $limit = 0;
/**
* @var array The log of executed SQL statements by the database
driver.
* @since 1.7.0
*/
protected $log = array();
/**
* @var array The log of executed SQL statements timings (start and
stop microtimes) by the database driver.
* @since CMS 3.1.2
*/
protected $timings = array();
/**
* @var array The log of executed SQL statements timings (start and
stop microtimes) by the database driver.
* @since CMS 3.1.2
*/
protected $callStacks = array();
/**
* @var string The character(s) used to quote SQL statement names such
as table names or field names,
* etc. The child classes should define this as
necessary. If a single character string the
* same character is used for both sides of the quoted
name, else the first character will be
* used for the opening quote and the second for the
closing quote.
* @since 1.7.0
*/
protected $nameQuote;
/**
* @var string The null or zero representation of a timestamp for the
database driver. This should be
* defined in child classes to hold the appropriate value
for the engine.
* @since 1.7.0
*/
protected $nullDate;
/**
* @var integer The affected row offset to apply for the current SQL
statement.
* @since 1.7.0
*/
protected $offset = 0;
/**
* @var array Passed in upon instantiation and saved.
* @since 1.7.0
*/
protected $options;
/**
* @var JDatabaseQuery|string The current SQL statement to execute.
* @since 1.7.0
*/
protected $sql;
/**
* @var string The common database table prefix.
* @since 1.7.0
*/
protected $tablePrefix;
/**
* @var boolean True if the database engine supports UTF-8 character
encoding.
* @since 1.7.0
*/
protected $utf = true;
/**
* @var boolean True if the database engine supports UTF-8 Multibyte
(utf8mb4) character encoding.
* @since CMS 3.5.0
*/
protected $utf8mb4 = false;
/**
* @var integer The database error number
* @since 1.7.0
* @deprecated 3.0.0
*/
protected $errorNum = 0;
/**
* @var string The database error message
* @since 1.7.0
* @deprecated 3.0.0
*/
protected $errorMsg;
/**
* @var array JDatabaseDriver instances container.
* @since 1.7.0
*/
protected static $instances = array();
/**
* @var string The minimum supported database version.
* @since 3.0.0
*/
protected static $dbMinimum;
/**
* @var integer The depth of the current transaction.
* @since 3.1.4
*/
protected $transactionDepth = 0;
/**
* @var callable[] List of callables to call just before disconnecting
database
* @since CMS 3.1.2
*/
protected $disconnectHandlers = array();
/**
* Get a list of available database connectors. The list will only be
populated with connectors that both
* the class exists and the static test method returns true. This gives
us the ability to have a multitude
* of connector classes that are self-aware as to whether or not they are
able to be used on a given system.
*
* @return array An array of available database connectors.
*
* @since 1.7.0
*/
public static function getConnectors()
{
$connectors = array();
// Get an iterator and loop trough the driver classes.
$iterator = new DirectoryIterator(__DIR__ . '/driver');
/* @type $file DirectoryIterator */
foreach ($iterator as $file)
{
$fileName = $file->getFilename();
// Only load for php files.
if (!$file->isFile() || $file->getExtension() != 'php')
{
continue;
}
// Derive the class name from the type.
$class = str_ireplace('.php', '',
'JDatabaseDriver' . ucfirst(trim($fileName)));
// If the class doesn't exist we have nothing left to do but look
at the next type. We did our best.
if (!class_exists($class))
{
continue;
}
// Sweet! Our class exists, so now we just need to know if it passes
its test method.
if ($class::isSupported())
{
// Connector names should not have file extensions.
$connectors[] = str_ireplace('.php', '',
$fileName);
}
}
return $connectors;
}
/**
* Method to return a JDatabaseDriver instance based on the given options.
There are three global options and then
* the rest are specific to the database driver. The 'driver'
option defines which JDatabaseDriver class is
* used for the connection -- the default is 'mysqli'. The
'database' option determines which database is to
* be used for the connection. The 'select' option determines
whether the connector should automatically select
* the chosen database.
*
* Instances are unique to the given options and new objects are only
created when a unique options array is
* passed into the method. This ensures that we don't end up with
unnecessary database connection resources.
*
* @param array $options Parameters to be passed to the database
driver.
*
* @return JDatabaseDriver A database object.
*
* @since 1.7.0
* @throws RuntimeException
*/
public static function getInstance($options = array())
{
// Sanitize the database connector options.
$options['driver'] = (isset($options['driver'])) ?
preg_replace('/[^A-Z0-9_\.-]/i', '',
$options['driver']) : 'mysqli';
$options['database'] = (isset($options['database']))
? $options['database'] : null;
$options['select'] = (isset($options['select'])) ?
$options['select'] : true;
// If the selected driver is `mysql` and we are on PHP 7 or greater,
switch to the `mysqli` driver.
if ($options['driver'] === 'mysql' &&
PHP_MAJOR_VERSION >= 7)
{
// Check if we have support for the other MySQL drivers
$mysqliSupported = JDatabaseDriverMysqli::isSupported();
$pdoMysqlSupported = JDatabaseDriverPdomysql::isSupported();
// If neither is supported, then the user cannot use MySQL; throw an
exception
if (!$mysqliSupported && !$pdoMysqlSupported)
{
throw new JDatabaseExceptionUnsupported(
'The PHP `ext/mysql` extension is removed in PHP 7, cannot use
the `mysql` driver.'
. ' Also, this system does not support MySQLi or PDO MySQL.
Cannot instantiate database driver.'
);
}
// Prefer MySQLi as it is a closer replacement for the removed MySQL
driver, otherwise use the PDO driver
if ($mysqliSupported)
{
JLog::add(
'The PHP `ext/mysql` extension is removed in PHP 7, cannot use
the `mysql` driver. Trying `mysqli` instead.',
JLog::WARNING,
'deprecated'
);
$options['driver'] = 'mysqli';
}
else
{
JLog::add(
'The PHP `ext/mysql` extension is removed in PHP 7, cannot use
the `mysql` driver. Trying `pdomysql` instead.',
JLog::WARNING,
'deprecated'
);
$options['driver'] = 'pdomysql';
}
}
// Get the options signature for the database connector.
$signature = md5(serialize($options));
// If we already have a database connector instance for these options
then just use that.
if (empty(self::$instances[$signature]))
{
// Derive the class name from the driver.
$class = 'JDatabaseDriver' .
ucfirst(strtolower($options['driver']));
// If the class still doesn't exist we have nothing left to do but
throw an exception. We did our best.
if (!class_exists($class))
{
throw new JDatabaseExceptionUnsupported(sprintf('Unable to load
Database Driver: %s', $options['driver']));
}
// Create our new JDatabaseDriver connector based on the options given.
try
{
$instance = new $class($options);
}
catch (RuntimeException $e)
{
throw new JDatabaseExceptionConnecting(sprintf('Unable to connect
to the Database: %s', $e->getMessage()), $e->getCode(), $e);
}
// Set the new connector to the global instances based on signature.
self::$instances[$signature] = $instance;
}
return self::$instances[$signature];
}
/**
* Splits a string of multiple queries into an array of individual
queries.
* Single line or line end comments and multi line comments are stripped
off.
*
* @param string $sql Input SQL string with which to split into
individual queries.
*
* @return array The queries from the input string separated into an
array.
*
* @since 1.7.0
*/
public static function splitSql($sql)
{
$start = 0;
$open = false;
$comment = false;
$endString = '';
$end = strlen($sql);
$queries = array();
$query = '';
for ($i = 0; $i < $end; $i++)
{
$current = substr($sql, $i, 1);
$current2 = substr($sql, $i, 2);
$current3 = substr($sql, $i, 3);
$lenEndString = strlen($endString);
$testEnd = substr($sql, $i, $lenEndString);
if ($current == '"' || $current == "'" ||
$current2 == '--'
|| ($current2 == '/*' && $current3 != '/*!'
&& $current3 != '/*+')
|| ($current == '#' && $current3 != '#__')
|| ($comment && $testEnd == $endString))
{
// Check if quoted with previous backslash
$n = 2;
while (substr($sql, $i - $n + 1, 1) == '\\' && $n
< $i)
{
$n++;
}
// Not quoted
if ($n % 2 == 0)
{
if ($open)
{
if ($testEnd == $endString)
{
if ($comment)
{
$comment = false;
if ($lenEndString > 1)
{
$i += ($lenEndString - 1);
$current = substr($sql, $i, 1);
}
$start = $i + 1;
}
$open = false;
$endString = '';
}
}
else
{
$open = true;
if ($current2 == '--')
{
$endString = "\n";
$comment = true;
}
elseif ($current2 == '/*')
{
$endString = '*/';
$comment = true;
}
elseif ($current == '#')
{
$endString = "\n";
$comment = true;
}
else
{
$endString = $current;
}
if ($comment && $start < $i)
{
$query = $query . substr($sql, $start, ($i - $start));
}
}
}
}
if ($comment)
{
$start = $i + 1;
}
if (($current == ';' && !$open) || $i == $end - 1)
{
if ($start <= $i)
{
$query = $query . substr($sql, $start, ($i - $start + 1));
}
$query = trim($query);
if ($query)
{
if (($i == $end - 1) && ($current != ';'))
{
$query = $query . ';';
}
$queries[] = $query;
}
$query = '';
$start = $i + 1;
}
}
return $queries;
}
/**
* Magic method to provide method alias support for quote() and
quoteName().
*
* @param string $method The called method.
* @param array $args The array of arguments passed to the method.
*
* @return mixed The aliased method's return value or null.
*
* @since 1.7.0
*/
public function __call($method, $args)
{
if (empty($args))
{
return;
}
switch ($method)
{
case 'q':
return $this->quote($args[0], isset($args[1]) ? $args[1] : true);
break;
case 'qn':
return $this->quoteName($args[0], isset($args[1]) ? $args[1] :
null);
break;
}
}
/**
* Constructor.
*
* @param array $options List of options used to configure the
connection
*
* @since 1.7.0
*/
public function __construct($options)
{
// Initialise object variables.
$this->_database = (isset($options['database'])) ?
$options['database'] : '';
$this->tablePrefix = (isset($options['prefix'])) ?
$options['prefix'] : 'jos_';
$this->count = 0;
$this->errorNum = 0;
$this->log = array();
// Set class options.
$this->options = $options;
}
/**
* Alter database's character set, obtaining query string from
protected member.
*
* @param string $dbName The database name that will be altered
*
* @return string The query that alter the database query string
*
* @since 3.0.1
* @throws RuntimeException
*/
public function alterDbCharacterSet($dbName)
{
if (is_null($dbName))
{
throw new RuntimeException('Database name must not be null.');
}
$this->setQuery($this->getAlterDbCharacterSet($dbName));
return $this->execute();
}
/**
* Alter a table's character set, obtaining an array of queries to do
so from a protected method. The conversion is
* wrapped in a transaction, if supported by the database driver.
Otherwise the table will be locked before the
* conversion. This prevents data corruption.
*
* @param string $tableName The name of the table to alter
* @param boolean $rethrow True to rethrow database exceptions.
Default: false (exceptions are suppressed)
*
* @return boolean True if successful
*
* @since CMS 3.5.0
* @throws RuntimeException If the table name is empty
* @throws Exception Relayed from the database layer if a database error
occurs and $rethrow == true
*/
public function alterTableCharacterSet($tableName, $rethrow = false)
{
if (is_null($tableName))
{
throw new RuntimeException('Table name must not be null.');
}
$queries = $this->getAlterTableCharacterSet($tableName);
if (empty($queries))
{
return false;
}
$hasTransaction = true;
try
{
$this->transactionStart();
}
catch (Exception $e)
{
$hasTransaction = false;
$this->lockTable($tableName);
}
foreach ($queries as $query)
{
try
{
$this->setQuery($query)->execute();
}
catch (Exception $e)
{
if ($hasTransaction)
{
$this->transactionRollback();
}
else
{
$this->unlockTables();
}
if ($rethrow)
{
throw $e;
}
return false;
}
}
if ($hasTransaction)
{
try
{
$this->transactionCommit();
}
catch (Exception $e)
{
$this->transactionRollback();
if ($rethrow)
{
throw $e;
}
return false;
}
}
else
{
$this->unlockTables();
}
return true;
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.0.0
* @throws RuntimeException
*/
abstract public function connect();
/**
* Determines if the connection to the server is active.
*
* @return boolean True if connected to the database engine.
*
* @since 1.7.0
*/
abstract public function connected();
/**
* Create a new database using information from $options object, obtaining
query string
* from protected member.
*
* @param stdClass $options Object used to pass user and database name
to database driver.
* This object must have "db_name" and
"db_user" set.
* @param boolean $utf True if the database supports the UTF-8
character set.
*
* @return string The query that creates database
*
* @since 3.0.1
* @throws RuntimeException
*/
public function createDatabase($options, $utf = true)
{
if (is_null($options))
{
throw new RuntimeException('$options object must not be
null.');
}
elseif (empty($options->db_name))
{
throw new RuntimeException('$options object must have db_name
set.');
}
elseif (empty($options->db_user))
{
throw new RuntimeException('$options object must have db_user
set.');
}
$this->setQuery($this->getCreateDatabaseQuery($options, $utf));
return $this->execute();
}
/**
* Destructor.
*
* @since 3.8.0
*/
public function __destruct()
{
$this->disconnect();
}
/**
* Disconnects the database.
*
* @return void
*
* @since 3.0.0
*/
abstract public function disconnect();
/**
* Adds a function callable just before disconnecting the database.
Parameter of the callable is $this JDatabaseDriver
*
* @param callable $callable Function to call in disconnect() method
just before disconnecting from database
*
* @return void
*
* @since CMS 3.1.2
*/
public function addDisconnectHandler($callable)
{
$this->disconnectHandlers[] = $callable;
}
/**
* Drops a table from the database.
*
* @param string $table The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return JDatabaseDriver Returns this object to support chaining.
*
* @since 2.5.0
* @throws RuntimeException
*/
abstract public function dropTable($table, $ifExists = true);
/**
* Escapes a string for usage in an SQL statement.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 1.7.0
*/
abstract public function escape($text, $extra = false);
/**
* Method to fetch a row from the result set cursor as an array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 1.7.0
*/
abstract protected function fetchArray($cursor = null);
/**
* Method to fetch a row from the result set cursor as an associative
array.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 1.7.0
*/
abstract protected function fetchAssoc($cursor = null);
/**
* Method to fetch a row from the result set cursor as an object.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
* @param string $class The class name to use for the returned row
object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 1.7.0
*/
abstract protected function fetchObject($cursor = null, $class =
'stdClass');
/**
* Method to free up the memory used for the result set.
*
* @param mixed $cursor The optional result set cursor from which to
fetch the row.
*
* @return void
*
* @since 1.7.0
*/
abstract protected function freeResult($cursor = null);
/**
* Get the number of affected rows for the previous executed SQL
statement.
*
* @return integer The number of affected rows.
*
* @since 1.7.0
*/
abstract public function getAffectedRows();
/**
* Return the query string to alter the database character set.
*
* @param string $dbName The database name
*
* @return string The query that alter the database query string
*
* @since 3.0.1
*/
public function getAlterDbCharacterSet($dbName)
{
$charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8';
return 'ALTER DATABASE ' . $this->quoteName($dbName) .
' CHARACTER SET `' . $charset . '`';
}
/**
* Get the query strings to alter the character set and collation of a
table.
*
* @param string $tableName The name of the table
*
* @return string[] The queries required to alter the table's
character set and collation
*
* @since CMS 3.5.0
*/
public function getAlterTableCharacterSet($tableName)
{
$charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8';
$collation = $charset . '_unicode_ci';
$quotedTableName = $this->quoteName($tableName);
$queries = array();
$queries[] = "ALTER TABLE $quotedTableName CONVERT TO CHARACTER SET
$charset COLLATE $collation";
/**
* We also need to convert each text column, modifying their character
set and collation. This allows us to
* change, for example, a utf8_bin collated column to a utf8mb4_bin
collated column.
*/
$sql = "SHOW FULL COLUMNS FROM $quotedTableName";
$this->setQuery($sql);
$columns = $this->loadAssocList();
$columnMods = array();
if (is_array($columns))
{
foreach ($columns as $column)
{
// Make sure we are redefining only columns which do support a
collation
$col = (object) $column;
if (empty($col->Collation))
{
continue;
}
// Default new collation: utf8_unicode_ci or utf8mb4_unicode_ci
$newCollation = $charset . '_unicode_ci';
$collationParts = explode('_', $col->Collation);
/**
* If the collation is in the form charset_collationType_ci or
charset_collationType we have to change
* the charset but leave the collationType intact (e.g. utf8_bin must
become utf8mb4_bin, NOT
* utf8mb4_general_ci).
*/
if (count($collationParts) >= 2)
{
$ci = array_pop($collationParts);
$collationType = array_pop($collationParts);
$newCollation = $charset . '_' . $collationType .
'_' . $ci;
/**
* When the last part of the old collation is not _ci we have a
charset_collationType format,
* something like utf8_bin. Therefore the new collation only has *two*
parts.
*/
if ($ci != 'ci')
{
$newCollation = $charset . '_' . $ci;
}
}
// If the old and new collation is the same we don't have to
change the collation type
if (strtolower($newCollation) == strtolower($col->Collation))
{
continue;
}
$null = $col->Null == 'YES' ? 'NULL' : 'NOT
NULL';
$default = is_null($col->Default) ? '' : "DEFAULT
'" . $this->q($col->Default) . "'";
$columnMods[] = "MODIFY COLUMN `{$col->Field}` {$col->Type}
CHARACTER SET $charset COLLATE $newCollation $null $default";
}
}
if (count($columnMods))
{
$queries[] = "ALTER TABLE $quotedTableName " .
implode(',', $columnMods) .
" CHARACTER SET $charset COLLATE $collation";
}
return $queries;
}
/**
* Automatically downgrade a CREATE TABLE or ALTER TABLE query from
utf8mb4 (UTF-8 Multibyte) to plain utf8. Used
* when the server doesn't support UTF-8 Multibyte.
*
* @param string $query The query to convert
*
* @return string The converted query
*/
public function convertUtf8mb4QueryToUtf8($query)
{
if ($this->hasUTF8mb4Support())
{
return $query;
}
// If it's not an ALTER TABLE or CREATE TABLE command there's
nothing to convert
if (!preg_match('/^(ALTER|CREATE)\s+TABLE\s+/i', $query))
{
return $query;
}
// Don't do preg replacement if string does not exist
if (stripos($query, 'utf8mb4') === false)
{
return $query;
}
// Replace utf8mb4 with utf8 if not within single or double quotes or
name quotes
return
preg_replace('/[`"\'][^`"\']*[`"\'](*SKIP)(*FAIL)|utf8mb4/i',
'utf8', $query);
}
/**
* Return the query string to create new Database.
* Each database driver, other than MySQL, need to override this member to
return correct string.
*
* @param stdClass $options Object used to pass user and database name
to database driver.
* This object must have "db_name" and
"db_user" set.
* @param boolean $utf True if the database supports the UTF-8
character set.
*
* @return string The query that creates database
*
* @since 3.0.1
*/
protected function getCreateDatabaseQuery($options, $utf)
{
if ($utf)
{
$charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8';
$collation = $charset . '_unicode_ci';
return 'CREATE DATABASE ' .
$this->quoteName($options->db_name) . ' CHARACTER SET `' .
$charset . '` COLLATE `' . $collation . '`';
}
return 'CREATE DATABASE ' .
$this->quoteName($options->db_name);
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database or boolean false
if not supported.
*
* @since 1.7.0
*/
abstract public function getCollation();
/**
* Method to get the database connection collation, as reported by the
driver. If the connector doesn't support
* reporting this value please return an empty string.
*
* @return string
*/
public function getConnectionCollation()
{
return '';
}
/**
* Method that provides access to the underlying database connection.
Useful for when you need to call a
* proprietary method such as postgresql's lo_* methods.
*
* @return resource The underlying database connection resource.
*
* @since 1.7.0
*/
public function getConnection()
{
return $this->connection;
}
/**
* Get the total number of SQL statements executed by the database driver.
*
* @return integer
*
* @since 1.7.0
*/
public function getCount()
{
return $this->count;
}
/**
* Gets the name of the database used by this connection.
*
* @return string
*
* @since 2.5.0
*/
protected function getDatabase()
{
return $this->_database;
}
/**
* Returns a PHP date() function compliant date format for the database
driver.
*
* @return string The format string.
*
* @since 1.7.0
*/
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
/**
* Get the database driver SQL statement log.
*
* @return array SQL statements executed by the database driver.
*
* @since 1.7.0
*/
public function getLog()
{
return $this->log;
}
/**
* Get the database driver SQL statement log.
*
* @return array SQL statements executed by the database driver.
*
* @since CMS 3.1.2
*/
public function getTimings()
{
return $this->timings;
}
/**
* Get the database driver SQL statement log.
*
* @return array SQL statements executed by the database driver.
*
* @since CMS 3.1.2
*/
public function getCallStacks()
{
return $this->callStacks;
}
/**
* Get the minimum supported database version.
*
* @return string The minimum version number for the database driver.
*
* @since 3.0.0
*/
public function getMinimum()
{
return static::$dbMinimum;
}
/**
* Get the null or zero representation of a timestamp for the database
driver.
*
* @return string Null or zero representation of a timestamp.
*
* @since 1.7.0
*/
public function getNullDate()
{
return $this->nullDate;
}
/**
* Get the number of returned rows for the previous executed SQL
statement.
*
* @param resource $cursor An optional database cursor resource to
extract the row count from.
*
* @return integer The number of returned rows.
*
* @since 1.7.0
*/
abstract public function getNumRows($cursor = null);
/**
* Get the common table prefix for the database driver.
*
* @return string The common database table prefix.
*
* @since 1.7.0
*/
public function getPrefix()
{
return $this->tablePrefix;
}
/**
* Gets an exporter class object.
*
* @return JDatabaseExporter An exporter object.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getExporter()
{
// Derive the class name from the driver.
$class = 'JDatabaseExporter' . ucfirst($this->name);
// Make sure we have an exporter class for this driver.
if (!class_exists($class))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported('Database Exporter not
found.');
}
$o = new $class;
$o->setDbo($this);
return $o;
}
/**
* Gets an importer class object.
*
* @return JDatabaseImporter An importer object.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getImporter()
{
// Derive the class name from the driver.
$class = 'JDatabaseImporter' . ucfirst($this->name);
// Make sure we have an importer class for this driver.
if (!class_exists($class))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported('Database Importer not
found');
}
$o = new $class;
$o->setDbo($this);
return $o;
}
/**
* Get the name of the database driver. If $this->name is not set it
will try guessing the driver name from the
* class name.
*
* @return string
*
* @since CMS 3.5.0
*/
public function getName()
{
if (empty($this->name))
{
$className = get_class($this);
$className = str_replace('JDatabaseDriver', '',
$className);
$this->name = strtolower($className);
}
return $this->name;
}
/**
* Get the server family type, e.g. mysql, postgresql, oracle, sqlite,
mssql. If $this->serverType is not set it
* will attempt guessing the server family type from the driver name. If
this is not possible the driver name will
* be returned instead.
*
* @return string
*
* @since CMS 3.5.0
*/
public function getServerType()
{
if (empty($this->serverType))
{
$name = $this->getName();
if (stristr($name, 'mysql') !== false)
{
$this->serverType = 'mysql';
}
elseif (stristr($name, 'postgre') !== false)
{
$this->serverType = 'postgresql';
}
elseif (stristr($name, 'pgsql') !== false)
{
$this->serverType = 'postgresql';
}
elseif (stristr($name, 'oracle') !== false)
{
$this->serverType = 'oracle';
}
elseif (stristr($name, 'sqlite') !== false)
{
$this->serverType = 'sqlite';
}
elseif (stristr($name, 'sqlsrv') !== false)
{
$this->serverType = 'mssql';
}
elseif (stristr($name, 'mssql') !== false)
{
$this->serverType = 'mssql';
}
else
{
$this->serverType = $name;
}
}
return $this->serverType;
}
/**
* Get the current query object or a new JDatabaseQuery object.
*
* @param boolean $new False to return the current query object, True
to return a new JDatabaseQuery object.
*
* @return JDatabaseQuery The current query object or a new object
extending the JDatabaseQuery class.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function getQuery($new = false)
{
if ($new)
{
// Derive the class name from the driver.
$class = 'JDatabaseQuery' . ucfirst($this->name);
// Make sure we have a query class for this driver.
if (!class_exists($class))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported('Database Query Class not
found.');
}
return new $class($this);
}
else
{
return $this->sql;
}
}
/**
* Get a new iterator on the current query.
*
* @param string $column An option column to use as the iterator key.
* @param string $class The class of object that is returned.
*
* @return JDatabaseIterator A new database iterator.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getIterator($column = null, $class = 'stdClass')
{
// Derive the class name from the driver.
$iteratorClass = 'JDatabaseIterator' . ucfirst($this->name);
// Make sure we have an iterator class for this driver.
if (!class_exists($iteratorClass))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported(sprintf('class *%s* is not
defined', $iteratorClass));
}
// Return a new iterator
return new $iteratorClass($this->execute(), $column, $class);
}
/**
* Retrieves field information about the given tables.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True (default) to only return field types.
*
* @return array An array of fields by table.
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function getTableColumns($table, $typeOnly = true);
/**
* Shows the table CREATE statement that creates the given tables.
*
* @param mixed $tables A table name or a list of table names.
*
* @return array A list of the create SQL for the tables.
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function getTableCreate($tables);
/**
* Retrieves keys information about the given table.
*
* @param string $table The name of the table.
*
* @return array An array of keys for the table.
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function getTableKeys($table);
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function getTableList();
/**
* Determine whether or not the database engine supports UTF-8 character
encoding.
*
* @return boolean True if the database engine supports UTF-8 character
encoding.
*
* @since 1.7.0
* @deprecated 4.0 - Use hasUTFSupport() instead
*/
public function getUTFSupport()
{
JLog::add('JDatabaseDriver::getUTFSupport() is deprecated. Use
JDatabaseDriver::hasUTFSupport() instead.', JLog::WARNING,
'deprecated');
return $this->hasUTFSupport();
}
/**
* Determine whether or not the database engine supports UTF-8 character
encoding.
*
* @return boolean True if the database engine supports UTF-8 character
encoding.
*
* @since 3.0.0
*/
public function hasUTFSupport()
{
return $this->utf;
}
/**
* Determine whether the database engine support the UTF-8 Multibyte
(utf8mb4) character encoding. This applies to
* MySQL databases.
*
* @return boolean True if the database engine supports UTF-8 Multibyte.
*
* @since CMS 3.5.0
*/
public function hasUTF8mb4Support()
{
return $this->utf8mb4;
}
/**
* Get the version of the database connector
*
* @return string The database connector version.
*
* @since 1.7.0
*/
abstract public function getVersion();
/**
* Method to get the auto-incremented value from the last INSERT
statement.
*
* @return mixed The value of the auto-increment field from the last
inserted row.
*
* @since 1.7.0
*/
abstract public function insertid();
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert
into.
* @param object &$object A reference to an object whose public
properties match the table fields.
* @param string $key The name of the primary key. If provided the
object property is updated.
*
* @return boolean True on success.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function insertObject($table, &$object, $key = null)
{
$fields = array();
$values = array();
// Iterate over the object variables to build the query fields and
values.
foreach (get_object_vars($object) as $k => $v)
{
// Only process non-null scalars.
if (is_array($v) or is_object($v) or $v === null)
{
continue;
}
// Ignore any internal fields.
if ($k[0] == '_')
{
continue;
}
// Prepare and sanitize the fields and values for the database query.
$fields[] = $this->quoteName($k);
$values[] = $this->quote($v);
}
// Create the base insert statement.
$query = $this->getQuery(true)
->insert($this->quoteName($table))
->columns($fields)
->values(implode(',', $values));
// Set the query and execute the insert.
$this->setQuery($query);
if (!$this->execute())
{
return false;
}
// Update the primary key if it exists.
$id = $this->insertid();
if ($key && $id && is_string($key))
{
$object->$key = $id;
}
return true;
}
/**
* Method to check whether the installed database version is supported by
the database driver
*
* @return boolean True if the database version is supported
*
* @since 3.0.0
*/
public function isMinimumVersion()
{
return version_compare($this->getVersion(), static::$dbMinimum) >=
0;
}
/**
* Method to get the first row of the result set from the database query
as an associative array
* of ['field_name' => 'row_value'].
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadAssoc()
{
$this->connect();
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get the first row from the result set as an associative array.
if ($array = $this->fetchAssoc($cursor))
{
$ret = $array;
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get an array of the result set rows from the database query
where each row is an associative array
* of ['field_name' => 'row_value']. The array of
rows can optionally be keyed by a field name, but defaults to
* a sequential numeric array.
*
* NOTE: Choosing to key the result array by a non-unique field name can
result in unwanted
* behavior and should be avoided.
*
* @param string $key The name of a field on which to key the
result array.
* @param string $column An optional column name. Instead of the whole
row, only this column value will be in
* the result array.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadAssocList($key = null, $column = null)
{
$this->connect();
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get all of the rows from the result set.
while ($row = $this->fetchAssoc($cursor))
{
$value = ($column) ? (isset($row[$column]) ? $row[$column] : $row) :
$row;
if ($key)
{
$array[$row[$key]] = $value;
}
else
{
$array[] = $value;
}
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Method to get an array of values from the
<var>$offset</var> field in each row of the result set from
* the database query.
*
* @param integer $offset The row offset to use to build the result
array.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadColumn($offset = 0)
{
$this->connect();
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get all of the rows from the result set as arrays.
while ($row = $this->fetchArray($cursor))
{
$array[] = $row[$offset];
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Method to get the next row in the result set from the database query as
an object.
*
* @param string $class The class name to use for the returned row
object.
*
* @return mixed The result of the query as an array, false if there
are no more rows.
*
* @since 1.7.0
* @throws RuntimeException
* @deprecated 4.0 - Use getIterator() instead
*/
public function loadNextObject($class = 'stdClass')
{
JLog::add(__METHOD__ . '() is deprecated. Use
JDatabaseDriver::getIterator() instead.', JLog::WARNING,
'deprecated');
$this->connect();
static $cursor = null;
// Execute the query and get the result set cursor.
if (is_null($cursor))
{
if (!($cursor = $this->execute()))
{
return $this->errorNum ? null : false;
}
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchObject($cursor, $class))
{
return $row;
}
// Free up system resources and return.
$this->freeResult($cursor);
$cursor = null;
return false;
}
/**
* Method to get the next row in the result set from the database query as
an array.
*
* @return mixed The result of the query as an array, false if there are
no more rows.
*
* @since 1.7.0
* @throws RuntimeException
* @deprecated 4.0 (CMS) Use JDatabaseDriver::getIterator() instead
*/
public function loadNextRow()
{
JLog::add(__METHOD__ . '() is deprecated. Use
JDatabaseDriver::getIterator() instead.', JLog::WARNING,
'deprecated');
$this->connect();
static $cursor = null;
// Execute the query and get the result set cursor.
if (is_null($cursor))
{
if (!($cursor = $this->execute()))
{
return $this->errorNum ? null : false;
}
}
// Get the next row from the result set as an object of type $class.
if ($row = $this->fetchArray($cursor))
{
return $row;
}
// Free up system resources and return.
$this->freeResult($cursor);
$cursor = null;
return false;
}
/**
* Method to get the first row of the result set from the database query
as an object.
*
* @param string $class The class name to use for the returned row
object.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadObject($class = 'stdClass')
{
$this->connect();
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get the first row from the result set as an object of type $class.
if ($object = $this->fetchObject($cursor, $class))
{
$ret = $object;
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get an array of the result set rows from the database query
where each row is an object. The array
* of objects can optionally be keyed by a field name, but defaults to a
sequential numeric array.
*
* NOTE: Choosing to key the result array by a non-unique field name can
result in unwanted
* behavior and should be avoided.
*
* @param string $key The name of a field on which to key the result
array.
* @param string $class The class name to use for the returned row
objects.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadObjectList($key = '', $class =
'stdClass')
{
$this->connect();
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get all of the rows from the result set as objects of type $class.
while ($row = $this->fetchObject($cursor, $class))
{
if ($key)
{
$array[$row->$key] = $row;
}
else
{
$array[] = $row;
}
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Method to get the first field of the first row of the result set from
the database query.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadResult()
{
$this->connect();
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get the first row from the result set as an array.
if ($row = $this->fetchArray($cursor))
{
$ret = $row[0];
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get the first row of the result set from the database query
as an array. Columns are indexed
* numerically so the first column in the result set would be accessible
via <var>$row[0]</var>, etc.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadRow()
{
$this->connect();
$ret = null;
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get the first row from the result set as an array.
if ($row = $this->fetchArray($cursor))
{
$ret = $row;
}
// Free up system resources and return.
$this->freeResult($cursor);
return $ret;
}
/**
* Method to get an array of the result set rows from the database query
where each row is an array. The array
* of objects can optionally be keyed by a field offset, but defaults to a
sequential numeric array.
*
* NOTE: Choosing to key the result array by a non-unique field can result
in unwanted
* behavior and should be avoided.
*
* @param integer $index The index of a field on which to key the
result array.
*
* @return mixed The return value or null if the query failed.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function loadRowList($index = null)
{
$this->connect();
$array = array();
// Execute the query and get the result set cursor.
if (!($cursor = $this->execute()))
{
return;
}
// Get all of the rows from the result set as arrays.
while ($row = $this->fetchArray($cursor))
{
if ($index !== null)
{
$array[$row[$index]] = $row;
}
else
{
$array[] = $row;
}
}
// Free up system resources and return.
$this->freeResult($cursor);
return $array;
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to unlock.
*
* @return JDatabaseDriver Returns this object to support chaining.
*
* @since 2.5.0
* @throws RuntimeException
*/
abstract public function lockTable($tableName);
/**
* Quotes and optionally escapes a string to database requirements for use
in database queries.
*
* @param mixed $text A string or an array of strings to quote.
* @param boolean $escape True (default) to escape the string, false
to leave it unchanged.
*
* @return string|array The quoted input.
*
* @note Accepting an array of strings was added in 12.3.
* @since 1.7.0
*/
public function quote($text, $escape = true)
{
if (is_array($text))
{
foreach ($text as $k => $v)
{
$text[$k] = $this->quote($v, $escape);
}
return $text;
}
else
{
return '\'' . ($escape ? $this->escape($text) : $text)
. '\'';
}
}
/**
* Quotes a binary string to database requirements for use in database
queries.
*
* @param mixed $data A binary string to quote.
*
* @return string The binary quoted input string.
*
* @since 3.9.12
*/
public function quoteBinary($data)
{
// SQL standard syntax for hexadecimal literals
return "X'" . bin2hex($data) . "'";
}
/**
* Wrap an SQL statement identifier name such as column, table or database
names in quotes to prevent injection
* risks and reserved word conflicts.
*
* @param mixed $name The identifier name to wrap in quotes, or an
array of identifier names to wrap in quotes.
* Each type supports dot-notation name.
* @param mixed $as The AS query part associated to $name. It can be
string or array, in latter case it has to be
* same length of $name; if is null there will not
be any AS part for string or array element.
*
* @return mixed The quote wrapped name, same type of $name.
*
* @since 1.7.0
*/
public function quoteName($name, $as = null)
{
if (is_string($name))
{
$quotedName = $this->quoteNameStr(explode('.', $name));
$quotedAs = '';
if (!is_null($as))
{
settype($as, 'array');
$quotedAs .= ' AS ' . $this->quoteNameStr($as);
}
return $quotedName . $quotedAs;
}
else
{
$fin = array();
if (is_null($as))
{
foreach ($name as $str)
{
$fin[] = $this->quoteName($str);
}
}
elseif (is_array($name) && (count($name) == count($as)))
{
$count = count($name);
for ($i = 0; $i < $count; $i++)
{
$fin[] = $this->quoteName($name[$i], $as[$i]);
}
}
return $fin;
}
}
/**
* Quote strings coming from quoteName call.
*
* @param array $strArr Array of strings coming from quoteName
dot-explosion.
*
* @return string Dot-imploded string of quoted parts.
*
* @since 1.7.3
*/
protected function quoteNameStr($strArr)
{
$parts = array();
$q = $this->nameQuote;
foreach ($strArr as $part)
{
if (is_null($part))
{
continue;
}
if (strlen($q) == 1)
{
$parts[] = $q . str_replace($q, $q . $q, $part) . $q;
}
else
{
$parts[] = $q[0] . str_replace($q[1], $q[1] . $q[1], $part) . $q[1];
}
}
return implode('.', $parts);
}
/**
* This function replaces a string identifier
<var>$prefix</var> with the string held is the
* <var>tablePrefix</var> class variable.
*
* @param string $sql The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 1.7.0
*/
public function replacePrefix($sql, $prefix = '#__')
{
$startPos = 0;
$literal = '';
$sql = trim($sql);
$n = strlen($sql);
while ($startPos < $n)
{
$ip = strpos($sql, $prefix, $startPos);
if ($ip === false)
{
break;
}
$j = strpos($sql, "'", $startPos);
$k = strpos($sql, '"', $startPos);
if (($k !== false) && (($k < $j) || ($j === false)))
{
$quoteChar = '"';
$j = $k;
}
else
{
$quoteChar = "'";
}
if ($j === false)
{
$j = $n;
}
$literal .= str_replace($prefix, $this->tablePrefix, substr($sql,
$startPos, $j - $startPos));
$startPos = $j;
$j = $startPos + 1;
if ($j >= $n)
{
break;
}
// Quote comes first, find end of quote
while (true)
{
$k = strpos($sql, $quoteChar, $j);
$escaped = false;
if ($k === false)
{
break;
}
$l = $k - 1;
while ($l >= 0 && $sql[$l] == '\\')
{
$l--;
$escaped = !$escaped;
}
if ($escaped)
{
$j = $k + 1;
continue;
}
break;
}
if ($k === false)
{
// Error in the query - no end quote; ignore it
break;
}
$literal .= substr($sql, $startPos, $k - $startPos + 1);
$startPos = $k + 1;
}
if ($startPos < $n)
{
$literal .= substr($sql, $startPos, $n - $startPos);
}
return $literal;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Table prefix
* @param string $prefix For the table - used to rename constraints
in non-mysql databases
*
* @return JDatabaseDriver Returns this object to support chaining.
*
* @since 2.5.0
* @throws RuntimeException
*/
abstract public function renameTable($oldTable, $newTable, $backup = null,
$prefix = null);
/**
* Select a database for use.
*
* @param string $database The name of the database to select for use.
*
* @return boolean True if the database was successfully selected.
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function select($database);
/**
* Sets the database debugging state for the driver.
*
* @param boolean $level True to enable debugging.
*
* @return boolean The old debugging level.
*
* @since 1.7.0
* @deprecated 4.0 This will be removed in Joomla 4 without replacement
*/
public function setDebug($level)
{
$previous = $this->debug;
$this->debug = (bool) $level;
return $previous;
}
/**
* Sets the SQL statement string for later execution.
*
* @param mixed $query The SQL statement to set either as a
JDatabaseQuery object or a string.
* @param integer $offset The affected row offset to set.
* @param integer $limit The maximum affected rows to set.
*
* @return JDatabaseDriver This object to support method chaining.
*
* @since 1.7.0
*/
public function setQuery($query, $offset = 0, $limit = 0)
{
$this->sql = $query;
if ($query instanceof JDatabaseQueryLimitable)
{
if (!$limit && $query->limit)
{
$limit = $query->limit;
}
if (!$offset && $query->offset)
{
$offset = $query->offset;
}
$query->setLimit($limit, $offset);
}
else
{
$this->limit = (int) max(0, $limit);
$this->offset = (int) max(0, $offset);
}
return $this;
}
/**
* Set the connection to use UTF-8 character encoding.
*
* @return boolean True on success.
*
* @since 1.7.0
*/
abstract public function setUtf();
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function transactionCommit($toSavepoint = false);
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function transactionRollback($toSavepoint = false);
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 1.7.0
* @throws RuntimeException
*/
abstract public function transactionStart($asSavepoint = false);
/**
* Method to truncate a table.
*
* @param string $table The table to truncate
*
* @return void
*
* @since 1.7.3
* @throws RuntimeException
*/
public function truncateTable($table)
{
$this->setQuery('TRUNCATE TABLE ' .
$this->quoteName($table));
$this->execute();
}
/**
* Updates a row in a table based on an object's properties.
*
* @param string $table The name of the database table to
update.
* @param object &$object A reference to an object whose
public properties match the table fields.
* @param array|string $key The name of the primary key.
* @param boolean $nulls True to update null fields or false to
ignore them.
*
* @return boolean True on success.
*
* @since 1.7.0
* @throws RuntimeException
*/
public function updateObject($table, &$object, $key, $nulls = false)
{
$fields = array();
$where = array();
if (is_string($key))
{
$key = array($key);
}
if (is_object($key))
{
$key = (array) $key;
}
// Create the base update statement.
$statement = 'UPDATE ' . $this->quoteName($table) . '
SET %s WHERE %s';
// Iterate over the object variables to build the query fields/value
pairs.
foreach (get_object_vars($object) as $k => $v)
{
// Only process scalars that are not internal fields.
if (is_array($v) || is_object($v) || $k[0] === '_')
{
continue;
}
// Set the primary key to the WHERE clause instead of a field to update.
if (in_array($k, $key))
{
$where[] = $this->quoteName($k) . ($v === null ? ' IS
NULL' : ' = ' . $this->quote($v));
continue;
}
// Prepare and sanitize the fields and values for the database query.
if ($v === null)
{
// If the value is null and we want to update nulls then set it.
if ($nulls)
{
$val = 'NULL';
}
// If the value is null and we do not want to update nulls then ignore
this field.
else
{
continue;
}
}
// The field is not null so we prep it for update.
else
{
$val = $this->quote($v);
}
// Add the field to be updated.
$fields[] = $this->quoteName($k) . '=' . $val;
}
// We don't have any fields to update.
if (empty($fields))
{
return true;
}
// Set the query and execute the update.
$this->setQuery(sprintf($statement, implode(',', $fields),
implode(' AND ', $where)));
return $this->execute();
}
/**
* Execute the SQL statement.
*
* @return mixed A database cursor resource on success, boolean false on
failure.
*
* @since 3.0.0
* @throws RuntimeException
*/
abstract public function execute();
/**
* Unlocks tables in the database.
*
* @return JDatabaseDriver Returns this object to support chaining.
*
* @since 2.5.0
* @throws RuntimeException
*/
abstract public function unlockTables();
}
PK ��[::2jjfactory.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform Database Factory class
*
* @since 3.0.0
*/
class JDatabaseFactory
{
/**
* Contains the current JDatabaseFactory instance
*
* @var JDatabaseFactory
* @since 3.0.0
*/
private static $_instance = null;
/**
* Method to return a JDatabaseDriver instance based on the given options.
There are three global options and then
* the rest are specific to the database driver. The 'database'
option determines which database is to
* be used for the connection. The 'select' option determines
whether the connector should automatically select
* the chosen database.
*
* Instances are unique to the given options and new objects are only
created when a unique options array is
* passed into the method. This ensures that we don't end up with
unnecessary database connection resources.
*
* @param string $name Name of the database driver you'd like
to instantiate
* @param array $options Parameters to be passed to the database
driver.
*
* @return JDatabaseDriver A database driver object.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getDriver($name = 'mysqli', $options = array())
{
// Sanitize the database connector options.
$options['driver'] =
preg_replace('/[^A-Z0-9_\.-]/i', '', $name);
$options['database'] = (isset($options['database']))
? $options['database'] : null;
$options['select'] = (isset($options['select'])) ?
$options['select'] : true;
// Derive the class name from the driver.
$class = 'JDatabaseDriver' .
ucfirst(strtolower($options['driver']));
// If the class still doesn't exist we have nothing left to do but
throw an exception. We did our best.
if (!class_exists($class))
{
throw new JDatabaseExceptionUnsupported(sprintf('Unable to load
Database Driver: %s', $options['driver']));
}
// Create our new JDatabaseDriver connector based on the options given.
try
{
$instance = new $class($options);
}
catch (RuntimeException $e)
{
throw new JDatabaseExceptionConnecting(sprintf('Unable to connect
to the Database: %s', $e->getMessage()), $e->getCode(), $e);
}
return $instance;
}
/**
* Gets an exporter class object.
*
* @param string $name Name of the driver you want an
exporter for.
* @param JDatabaseDriver $db Optional JDatabaseDriver instance
*
* @return JDatabaseExporter An exporter object.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getExporter($name, JDatabaseDriver $db = null)
{
// Derive the class name from the driver.
$class = 'JDatabaseExporter' . ucfirst(strtolower($name));
// Make sure we have an exporter class for this driver.
if (!class_exists($class))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported('Database Exporter not
found.');
}
$o = new $class;
if ($db instanceof JDatabaseDriver)
{
$o->setDbo($db);
}
return $o;
}
/**
* Gets an importer class object.
*
* @param string $name Name of the driver you want an
importer for.
* @param JDatabaseDriver $db Optional JDatabaseDriver instance
*
* @return JDatabaseImporter An importer object.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getImporter($name, JDatabaseDriver $db = null)
{
// Derive the class name from the driver.
$class = 'JDatabaseImporter' . ucfirst(strtolower($name));
// Make sure we have an importer class for this driver.
if (!class_exists($class))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported('Database importer not
found.');
}
$o = new $class;
if ($db instanceof JDatabaseDriver)
{
$o->setDbo($db);
}
return $o;
}
/**
* Gets an instance of the factory object.
*
* @return JDatabaseFactory
*
* @since 3.0.0
*/
public static function getInstance()
{
return self::$_instance ? self::$_instance : new JDatabaseFactory;
}
/**
* Get the current query object or a new JDatabaseQuery object.
*
* @param string $name Name of the driver you want an query
object for.
* @param JDatabaseDriver $db Optional JDatabaseDriver instance
*
* @return JDatabaseQuery The current query object or a new object
extending the JDatabaseQuery class.
*
* @since 3.0.0
* @throws RuntimeException
*/
public function getQuery($name, JDatabaseDriver $db = null)
{
// Derive the class name from the driver.
$class = 'JDatabaseQuery' . ucfirst(strtolower($name));
// Make sure we have a query class for this driver.
if (!class_exists($class))
{
// If it doesn't exist we are at an impasse so throw an exception.
throw new JDatabaseExceptionUnsupported('Database Query class not
found');
}
return new $class($db);
}
/**
* Gets an instance of a factory object to return on subsequent calls of
getInstance.
*
* @param JDatabaseFactory $instance A JDatabaseFactory object.
*
* @return void
*
* @since 3.0.0
*/
public static function setInstance(JDatabaseFactory $instance = null)
{
self::$_instance = $instance;
}
}
PK ��[��GD�[�[
installer.phpnu�[���<?php
/**
* @package FrameworkOnFramework
* @subpackage database
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*
* This file is adapted from the Joomla! Platform. It is used to iterate a
database cursor returning FOFTable objects
* instead of plain stdClass objects
*/
class FOFDatabaseInstaller
{
/** @var FOFDatabase The database connector object */
private $db = null;
/**
* @var FOFInput Input variables
*/
protected $input = array();
/** @var string The directory where the XML schema files are stored */
private $xmlDirectory = null;
/** @var array A list of the base names of the XML schema files */
public $xmlFiles = array('mysql', 'mysqli',
'pdomysql', 'postgresql', 'sqlsrv',
'mssql');
/** @var array Internal cache for table list */
protected static $allTables = array();
/**
* Public constructor
*
* @param array $config The configuration array
*/
public function __construct($config = array())
{
// Make sure $config is an array
if (is_object($config))
{
$config = (array) $config;
}
elseif (!is_array($config))
{
$config = array();
}
// Get the input
if (array_key_exists('input', $config))
{
if ($config['input'] instanceof FOFInput)
{
$this->input = $config['input'];
}
else
{
$this->input = new FOFInput($config['input']);
}
}
else
{
$this->input = new FOFInput;
}
// Set the database object
if (array_key_exists('dbo', $config))
{
$this->db = $config['dbo'];
}
else
{
$this->db = FOFPlatform::getInstance()->getDbo();
}
// Set the $name/$_name variable
$component = $this->input->getCmd('option',
'com_foobar');
if (array_key_exists('option', $config))
{
$component = $config['option'];
}
// Figure out where the XML schema files are stored
if (array_key_exists('dbinstaller_directory', $config))
{
$this->xmlDirectory = $config['dbinstaller_directory'];
}
else
{
// Nothing is defined, assume the files are stored in the sql/xml
directory inside the component's administrator section
$directories =
FOFPlatform::getInstance()->getComponentBaseDirs($component);
$this->setXmlDirectory($directories['admin'] .
'/sql/xml');
}
// Do we have a set of XML files to look for?
if (array_key_exists('dbinstaller_files', $config))
{
$files = $config['dbinstaller_files'];
if (!is_array($files))
{
$files = explode(',', $files);
}
$this->xmlFiles = $files;
}
}
/**
* Sets the directory where XML schema files are stored
*
* @param string $xmlDirectory
*/
public function setXmlDirectory($xmlDirectory)
{
$this->xmlDirectory = $xmlDirectory;
}
/**
* Returns the directory where XML schema files are stored
*
* @return string
*/
public function getXmlDirectory()
{
return $this->xmlDirectory;
}
/**
* Creates or updates the database schema
*
* @return void
*
* @throws Exception When a database query fails and it doesn't
have the canfail flag
*/
public function updateSchema()
{
// Get the schema XML file
$xml = $this->findSchemaXml();
if (empty($xml))
{
return;
}
// Make sure there are SQL commands in this file
if (!$xml->sql)
{
return;
}
// Walk the sql > action tags to find all tables
/** @var SimpleXMLElement $actions */
$actions = $xml->sql->children();
/**
* The meta/autocollation node defines if I should automatically apply
the correct collation (utf8 or utf8mb4)
* to the database tables managed by the schema updater. When enabled
(default) the queries are automatically
* converted to the correct collation (utf8mb4_unicode_ci or
utf8_general_ci) depending on whether your Joomla!
* and MySQL server support Multibyte UTF-8 (UTF8MB4). Moreover, if
UTF8MB4 is supported, all CREATE TABLE
* queries are analyzed and the tables referenced in them are
auto-converted to the proper utf8mb4 collation.
*/
$autoCollationConversion = true;
if ($xml->meta->autocollation)
{
$value = (string) $xml->meta->autocollation;
$value = trim($value);
$value = strtolower($value);
$autoCollationConversion = in_array($value, array('true',
'1', 'on', 'yes'));
}
try
{
$hasUtf8mb4Support = $this->db->hasUTF8mb4Support();
}
catch (\Exception $e)
{
$hasUtf8mb4Support = false;
}
$tablesToConvert = array();
/** @var SimpleXMLElement $action */
foreach ($actions as $action)
{
// Get the attributes
$attributes = $action->attributes();
// Get the table / view name
$table = $attributes->table ? (string)$attributes->table :
'';
if (empty($table))
{
continue;
}
// Am I allowed to let this action fail?
$canFailAction = $attributes->canfail ? $attributes->canfail : 0;
// Evaluate conditions
$shouldExecute = true;
/** @var SimpleXMLElement $node */
foreach ($action->children() as $node)
{
if ($node->getName() == 'condition')
{
// Get the operator
$operator = $node->attributes()->operator ?
(string)$node->attributes()->operator : 'and';
$operator = empty($operator) ? 'and' : $operator;
$condition = $this->conditionMet($table, $node);
switch ($operator)
{
case 'not':
$shouldExecute = $shouldExecute && !$condition;
break;
case 'or':
$shouldExecute = $shouldExecute || $condition;
break;
case 'nor':
$shouldExecute = !$shouldExecute && !$condition;
break;
case 'xor':
$shouldExecute = ($shouldExecute xor $condition);
break;
case 'maybe':
$shouldExecute = $condition ? true : $shouldExecute;
break;
default:
$shouldExecute = $shouldExecute && $condition;
break;
}
}
// DO NOT USE BOOLEAN SHORT CIRCUIT EVALUATION!
// if (!$shouldExecute) break;
}
// Do I have to only collect the tables from CREATE TABLE queries?
$onlyCollectTables = !$shouldExecute && $autoCollationConversion
&& $hasUtf8mb4Support;
// Make sure all conditions are met OR I have to collect tables from
CREATE TABLE queries.
if (!$shouldExecute && !$onlyCollectTables)
{
continue;
}
// Execute queries
foreach ($action->children() as $node)
{
if ($node->getName() == 'query')
{
$query = (string) $node;
if ($autoCollationConversion && $hasUtf8mb4Support)
{
$this->extractTablesToConvert($query, $tablesToConvert);
}
// If we're only collecting tables do not run the queries
if ($onlyCollectTables)
{
continue;
}
$canFail = $node->attributes->canfail ?
(string)$node->attributes->canfail : $canFailAction;
if (is_string($canFail))
{
$canFail = strtoupper($canFail);
}
$canFail = (in_array($canFail, array(true, 1, 'YES',
'TRUE')));
// Do I need to automatically convert the collation of all CREATE /
ALTER queries?
if ($autoCollationConversion)
{
if ($hasUtf8mb4Support)
{
// We have UTF8MB4 support. Convert all queries to UTF8MB4.
$query = $this->convertUtf8QueryToUtf8mb4($query);
}
else
{
// We do not have UTF8MB4 support. Convert all queries to plain old
UTF8.
$query = $this->convertUtf8mb4QueryToUtf8($query);
}
}
$this->db->setQuery($query);
try
{
$this->db->execute();
}
catch (Exception $e)
{
// If we are not allowed to fail, throw back the exception we caught
if (!$canFail)
{
throw $e;
}
}
}
}
}
// Auto-convert the collation of tables if we are told to do so, have
utf8mb4 support and a list of tables.
if ($autoCollationConversion && $hasUtf8mb4Support &&
!empty($tablesToConvert))
{
$this->convertTablesToUtf8mb4($tablesToConvert);
}
}
/**
* Uninstalls the database schema
*
* @return void
*/
public function removeSchema()
{
// Get the schema XML file
$xml = $this->findSchemaXml();
if (empty($xml))
{
return;
}
// Make sure there are SQL commands in this file
if (!$xml->sql)
{
return;
}
// Walk the sql > action tags to find all tables
$tables = array();
/** @var SimpleXMLElement $actions */
$actions = $xml->sql->children();
/** @var SimpleXMLElement $action */
foreach ($actions as $action)
{
$attributes = $action->attributes();
$tables[] = (string)$attributes->table;
}
// Simplify the tables list
$tables = array_unique($tables);
// Start dropping tables
foreach ($tables as $table)
{
try
{
$this->db->dropTable($table);
}
catch (Exception $e)
{
// Do not fail if I can't drop the table
}
}
}
/**
* Find an suitable schema XML file for this database type and return the
SimpleXMLElement holding its information
*
* @return null|SimpleXMLElement Null if no suitable schema XML file is
found
*/
protected function findSchemaXml()
{
$driverType = $this->db->name;
$xml = null;
// And now look for the file
foreach ($this->xmlFiles as $baseName)
{
// Remove any accidental whitespace
$baseName = trim($baseName);
// Get the full path to the file
$fileName = $this->xmlDirectory . '/' . $baseName .
'.xml';
// Make sure the file exists
if (!@file_exists($fileName))
{
continue;
}
// Make sure the file is a valid XML document
try
{
$xml = new SimpleXMLElement($fileName, LIBXML_NONET, true);
}
catch (Exception $e)
{
$xml = null;
continue;
}
// Make sure the file is an XML schema file
if ($xml->getName() != 'schema')
{
$xml = null;
continue;
}
if (!$xml->meta)
{
$xml = null;
continue;
}
if (!$xml->meta->drivers)
{
$xml = null;
continue;
}
/** @var SimpleXMLElement $drivers */
$drivers = $xml->meta->drivers;
// Strict driver name match
foreach ($drivers->children() as $driverTypeTag)
{
$thisDriverType = (string)$driverTypeTag;
if ($thisDriverType == $driverType)
{
return $xml;
}
}
// Some custom database drivers use a non-standard $name variable. Let
try a relaxed match.
foreach ($drivers->children() as $driverTypeTag)
{
$thisDriverType = (string)$driverTypeTag;
if (
// e.g. $driverType = 'mysqlistupid', $thisDriverType =
'mysqli' => driver matched
strpos($driverType, $thisDriverType) === 0
// e.g. $driverType = 'stupidmysqli', $thisDriverType =
'mysqli' => driver matched
|| (substr($driverType, -strlen($thisDriverType)) == $thisDriverType)
)
{
return $xml;
}
}
$xml = null;
}
return $xml;
}
/**
* Checks if a condition is met
*
* @param string $table The table we're operating on
* @param SimpleXMLElement $node The condition definition node
*
* @return bool
*/
protected function conditionMet($table, SimpleXMLElement $node)
{
if (empty(static::$allTables))
{
static::$allTables = $this->db->getTableList();
}
// Does the table exist?
$tableNormal = $this->db->replacePrefix($table);
$tableExists = in_array($tableNormal, static::$allTables);
// Initialise
$condition = false;
// Get the condition's attributes
$attributes = $node->attributes();
$type = $attributes->type ? $attributes->type : null;
$value = $attributes->value ? (string) $attributes->value : null;
switch ($type)
{
// Check if a table or column is missing
case 'missing':
$fieldName = (string)$value;
if (empty($fieldName))
{
$condition = !$tableExists;
}
else
{
try
{
$tableColumns = $this->db->getTableColumns($tableNormal, true);
}
catch (\Exception $e)
{
$tableColumns = array();
}
$condition = !array_key_exists($fieldName, $tableColumns);
}
break;
// Check if a column type matches the "coltype" attribute
case 'type':
try
{
$tableColumns = $this->db->getTableColumns($tableNormal, false);
}
catch (\Exception $e)
{
$tableColumns = array();
}
$condition = false;
if (array_key_exists($value, $tableColumns))
{
$coltype = $attributes->coltype ? $attributes->coltype : null;
if (!empty($coltype))
{
$coltype = strtolower($coltype);
$currentType = strtolower($tableColumns[$value]->Type);
$condition = ($coltype == $currentType);
}
}
break;
// Check if a (named) index exists on the table. Currently only
supported on MySQL.
case 'index':
$indexName = (string) $value;
$condition = true;
if (!empty($indexName))
{
$indexName = str_replace('#__',
$this->db->getPrefix(), $indexName);
$condition = $this->hasIndex($tableNormal, $indexName);
}
break;
// Check if a table or column needs to be upgraded to utf8mb4
case 'utf8mb4upgrade':
$condition = false;
// Check if the driver and the database connection have UTF8MB4 support
try
{
$hasUtf8mb4Support = $this->db->hasUTF8mb4Support();
}
catch (\Exception $e)
{
$hasUtf8mb4Support = false;
}
if ($hasUtf8mb4Support)
{
$fieldName = (string)$value;
if (empty($fieldName))
{
$collation = $this->getTableCollation($tableNormal);
}
else
{
$collation = $this->getColumnCollation($tableNormal, $fieldName);
}
$parts = explode('_', $collation, 3);
$encoding = empty($parts[0]) ? '' : strtolower($parts[0]);
$condition = $encoding != 'utf8mb4';
}
break;
// Check if the result of a query matches our expectation
case 'equals':
$query = (string)$node;
$this->db->setQuery($query);
try
{
$result = $this->db->loadResult();
$condition = ($result == $value);
}
catch (Exception $e)
{
return false;
}
break;
// Always returns true
case 'true':
return true;
break;
default:
return false;
break;
}
return $condition;
}
/**
* Get the collation of a table. Uses an internal cache for efficiency.
*
* @param string $tableName The name of the table
*
* @return string The collation, e.g. "utf8_general_ci"
*/
private function getTableCollation($tableName)
{
static $cache = array();
$tableName = $this->db->replacePrefix($tableName);
if (!isset($cache[$tableName]))
{
$cache[$tableName] = $this->realGetTableCollation($tableName);
}
return $cache[$tableName];
}
/**
* Get the collation of a table. This is the internal method used by
getTableCollation.
*
* @param string $tableName The name of the table
*
* @return string The collation, e.g. "utf8_general_ci"
*/
private function realGetTableCollation($tableName)
{
try
{
$utf8Support = $this->db->hasUTFSupport();
}
catch (\Exception $e)
{
$utf8Support = false;
}
try
{
$utf8mb4Support = $utf8Support &&
$this->db->hasUTF8mb4Support();
}
catch (\Exception $e)
{
$utf8mb4Support = false;
}
$collation = $utf8mb4Support ? 'utf8mb4_unicode_ci' :
($utf8Support ? 'utf_general_ci' :
'latin1_swedish_ci');
$query = 'SHOW TABLE STATUS LIKE ' .
$this->db->q($tableName);
try
{
$row = $this->db->setQuery($query)->loadAssoc();
}
catch (\Exception $e)
{
return $collation;
}
if (empty($row))
{
return $collation;
}
if (!isset($row['Collation']))
{
return $collation;
}
if (empty($row['Collation']))
{
return $collation;
}
return $row['Collation'];
}
/**
* Get the collation of a column. Uses an internal cache for efficiency.
*
* @param string $tableName The name of the table
* @param string $columnName The name of the column
*
* @return string The collation, e.g. "utf8_general_ci"
*/
private function getColumnCollation($tableName, $columnName)
{
static $cache = array();
$tableName = $this->db->replacePrefix($tableName);
$columnName = $this->db->replacePrefix($columnName);
if (!isset($cache[$tableName]))
{
$cache[$tableName] = array();
}
if (!isset($cache[$tableName][$columnName]))
{
$cache[$tableName][$columnName] =
$this->realGetColumnCollation($tableName, $columnName);
}
return $cache[$tableName][$columnName];
}
/**
* Get the collation of a column. This is the internal method used by
getColumnCollation.
*
* @param string $tableName The name of the table
* @param string $columnName The name of the column
*
* @return string The collation, e.g. "utf8_general_ci"
*/
private function realGetColumnCollation($tableName, $columnName)
{
$collation = $this->getTableCollation($tableName);
$query = 'SHOW FULL COLUMNS FROM ' .
$this->db->qn($tableName) . ' LIKE ' .
$this->db->q($columnName);
try
{
$row = $this->db->setQuery($query)->loadAssoc();
}
catch (\Exception $e)
{
return $collation;
}
if (empty($row))
{
return $collation;
}
if (!isset($row['Collation']))
{
return $collation;
}
if (empty($row['Collation']))
{
return $collation;
}
return $row['Collation'];
}
/**
* Automatically downgrade a CREATE TABLE or ALTER TABLE query from
utf8mb4 (UTF-8 Multibyte) to plain utf8.
*
* We use our own method so we can be site it works even on Joomla! 3.4 or
earlier, where UTF8MB4 support is not
* implemented.
*
* @param string $query The query to convert
*
* @return string The converted query
*/
private function convertUtf8mb4QueryToUtf8($query)
{
// If it's not an ALTER TABLE or CREATE TABLE command there's
nothing to convert
$beginningOfQuery = substr($query, 0, 12);
$beginningOfQuery = strtoupper($beginningOfQuery);
if (!in_array($beginningOfQuery, array('ALTER TABLE ',
'CREATE TABLE')))
{
return $query;
}
// Replace utf8mb4 with utf8
$from = array(
'utf8mb4_unicode_ci',
'utf8mb4_',
'utf8mb4',
);
$to = array(
'utf8_general_ci', // Yeah, we convert utf8mb4_unicode_ci to
utf8_general_ci per Joomla!'s conventions
'utf8_',
'utf8',
);
return str_replace($from, $to, $query);
}
/**
* Automatically upgrade a CREATE TABLE or ALTER TABLE query from plain
utf8 to utf8mb4 (UTF-8 Multibyte).
*
* @param string $query The query to convert
*
* @return string The converted query
*/
private function convertUtf8QueryToUtf8mb4($query)
{
// If it's not an ALTER TABLE or CREATE TABLE command there's
nothing to convert
$beginningOfQuery = substr($query, 0, 12);
$beginningOfQuery = strtoupper($beginningOfQuery);
if (!in_array($beginningOfQuery, array('ALTER TABLE ',
'CREATE TABLE')))
{
return $query;
}
// Replace utf8 with utf8mb4
$from = array(
'utf8_general_ci',
'utf8_',
'utf8',
);
$to = array(
'utf8mb4_unicode_ci', // Yeah, we convert utf8_general_ci to
utf8mb4_unicode_ci per Joomla!'s conventions
'utf8mb4_',
'utf8mb4',
);
return str_replace($from, $to, $query);
}
/**
* Analyzes a query. If it's a CREATE TABLE query the table is added
to the $tables array.
*
* @param string $query The query to analyze
* @param string $tables The array where the name of the detected
table is added
*
* @return void
*/
private function extractTablesToConvert($query, &$tables)
{
// Normalize the whitespace of the query
$query = trim($query);
$query = str_replace(array("\r\n", "\r",
"\n"), ' ', $query);
while (strstr($query, ' ') !== false)
{
$query = str_replace(' ', ' ', $query);
}
// Is it a create table query?
$queryStart = substr($query, 0, 12);
$queryStart = strtoupper($queryStart);
if ($queryStart != 'CREATE TABLE')
{
return;
}
// Remove the CREATE TABLE keyword. Also, If there's an IF NOT
EXISTS clause remove it.
$query = substr($query, 12);
$query = str_ireplace('IF NOT EXISTS', '', $query);
$query = trim($query);
// Make sure there is a space between the table name and its definition,
denoted by an open parenthesis
$query = str_replace('(', ' (', $query);
// Now we should have the name of the table, a space and the rest of the
query. Extract the table name.
$parts = explode(' ', $query, 2);
$tableName = $parts[0];
/**
* The table name may be quoted. Since UTF8MB4 is only supported in
MySQL, the table name can only be
* quoted with surrounding backticks. Therefore we can trim backquotes
from the table name to unquote it!
**/
$tableName = trim($tableName, '`');
// Finally, add the table name to $tables if it doesn't already
exist.
if (!in_array($tableName, $tables))
{
$tables[] = $tableName;
}
}
/**
* Converts the collation of tables listed in $tablesToConvert to
utf8mb4_unicode_ci
*
* @param array $tablesToConvert The list of tables to convert
*
* @return void
*/
private function convertTablesToUtf8mb4($tablesToConvert)
{
try
{
$utf8mb4Support = $this->db->hasUTF8mb4Support();
}
catch (\Exception $e)
{
$utf8mb4Support = false;
}
// Make sure the database driver REALLY has support for converting
character sets
if (!$utf8mb4Support)
{
return;
}
asort($tablesToConvert);
foreach ($tablesToConvert as $tableName)
{
$collation = $this->getTableCollation($tableName);
$parts = explode('_', $collation, 3);
$encoding = empty($parts[0]) ? '' : strtolower($parts[0]);
if ($encoding != 'utf8mb4')
{
$queries = $this->db->getAlterTableCharacterSet($tableName);
try
{
foreach ($queries as $query)
{
$this->db->setQuery($query)->execute();
}
}
catch (\Exception $e)
{
// We ignore failed conversions. Remember, you MUST change your
indices MANUALLY.
}
}
}
}
/**
* Returns true if table $tableName has an index named $indexName or if
it's impossible to retrieve index names for
* the table (not enough privileges, not a MySQL database, ...)
*
* @param string $tableName The name of the table
* @param string $indexName The name of the index
*
* @return bool
*/
private function hasIndex($tableName, $indexName)
{
static $isMySQL = null;
static $cache = array();
if (is_null($isMySQL))
{
$driverType = $this->db->name;
$driverType = strtolower($driverType);
$isMySQL = true;
if (
!strpos($driverType, 'mysql') === 0
&& !(substr($driverType, -5) == 'mysql')
&& !(substr($driverType, -6) == 'mysqli')
)
{
$isMySQL = false;
}
}
// Not MySQL? Lie and return true.
if (!$isMySQL)
{
return true;
}
if (!isset($cache[$tableName]))
{
$cache[$tableName] = array();
}
if (!isset($cache[$tableName][$indexName]))
{
$cache[$tableName][$indexName] = true;
try
{
$indices = array();
$query = 'SHOW INDEXES FROM ' .
$this->db->qn($tableName);
$indexDefinitions =
$this->db->setQuery($query)->loadAssocList();
if (!empty($indexDefinitions) && is_array($indexDefinitions))
{
foreach ($indexDefinitions as $def)
{
$indices[] = $def['Key_name'];
}
$indices = array_unique($indices);
}
$cache[$tableName][$indexName] = in_array($indexName, $indices);
}
catch (\Exception $e)
{
// Ignore errors
}
}
return $cache[$tableName][$indexName];
}
}
PK ��[���''
interface.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform Database Interface
*
* @since 1.7.0
*/
interface JDatabaseInterface
{
/**
* Test to see if the connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 1.7.0
*/
public static function isSupported();
}
PK ��[�
�JQQiterator/azure.phpnu�[���<?php
/**
* @package FrameworkOnFramework
* @subpackage database
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*
* This file is adapted from the Joomla! Platform. It is used to iterate a
database cursor returning FOFTable objects
* instead of plain stdClass objects
*/
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;
/**
* SQL azure database iterator.
*/
class FOFDatabaseIteratorAzure extends FOFDatabaseIteratorSqlsrv
{
}
PK ��[6 0��iterator/mysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL database iterator.
*
* @link http://dev.mysql.com/doc/
* @since 3.0.0
* @deprecated 4.0 Use MySQLi or PDO MySQL instead
*/
class JDatabaseIteratorMysql extends JDatabaseIterator
{
/**
* Get the number of rows in the result set for the executed SQL given by
the cursor.
*
* @return integer The number of rows in the result set.
*
* @since 3.0.0
* @see Countable::count()
*/
public function count()
{
return mysql_num_rows($this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject()
{
return mysql_fetch_object($this->cursor, $this->class);
}
/**
* Method to free up the memory used for the result set.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult()
{
mysql_free_result($this->cursor);
}
}
PK ��[l]����iterator/mysqli.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQLi database iterator.
*
* @since 3.0.0
*/
class JDatabaseIteratorMysqli extends JDatabaseIterator
{
/**
* Get the number of rows in the result set for the executed SQL given by
the cursor.
*
* @return integer The number of rows in the result set.
*
* @since 3.0.0
* @see Countable::count()
*/
public function count()
{
return mysqli_num_rows($this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject()
{
return mysqli_fetch_object($this->cursor, $this->class);
}
/**
* Method to free up the memory used for the result set.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult()
{
mysqli_free_result($this->cursor);
}
}
PK ��[�V����iterator/oracle.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Oracle database iterator.
*
* @since 3.0.0
*/
class JDatabaseIteratorOracle extends JDatabaseIteratorPdo
{
}
PK ��[c�t��iterator/pdo.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PDO database iterator.
*
* @since 3.0.0
*/
class JDatabaseIteratorPdo extends JDatabaseIterator
{
/**
* Get the number of rows in the result set for the executed SQL given by
the cursor.
*
* @return integer The number of rows in the result set.
*
* @since 3.0.0
* @see Countable::count()
*/
public function count()
{
if (!empty($this->cursor) && $this->cursor instanceof
PDOStatement)
{
return $this->cursor->rowCount();
}
else
{
return 0;
}
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject()
{
if (!empty($this->cursor) && $this->cursor instanceof
PDOStatement)
{
return $this->cursor->fetchObject($this->class);
}
else
{
return false;
}
}
/**
* Method to free up the memory used for the result set.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult()
{
if (!empty($this->cursor) && $this->cursor instanceof
PDOStatement)
{
$this->cursor->closeCursor();
}
}
}
PK ��[g�Ziterator/pdomysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL database iterator for the PDO based MySQL database driver.
*
* @package Joomla.Platform
* @subpackage Database
* @link https://dev.mysql.com/doc/
* @since 3.4
*/
class JDatabaseIteratorPdomysql extends JDatabaseIteratorPdo
{
}
PK ��[�����iterator/postgresql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PostgreSQL database iterator.
*
* @since 3.2.0
* @deprecated 4.0 Use PDO PostgreSQL instead
*/
class JDatabaseIteratorPostgresql extends JDatabaseIterator
{
/**
* Get the number of rows in the result set for the executed SQL given by
the cursor.
*
* @return integer The number of rows in the result set.
*
* @since 3.2.0
* @see Countable::count()
*/
public function count()
{
return pg_num_rows($this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.2.0
*/
protected function fetchObject()
{
return pg_fetch_object($this->cursor, null, $this->class);
}
/**
* Method to free up the memory used for the result set.
*
* @return void
*
* @since 3.2.0
*/
protected function freeResult()
{
pg_free_result($this->cursor);
}
}
PK ��[Zn��iterator/sqlite.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQLite database iterator.
*
* @since 3.0.0
*/
class JDatabaseIteratorSqlite extends JDatabaseIteratorPdo
{
}
PK ��[-����iterator/sqlsrv.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQL server database iterator.
*
* @since 3.0.0
*/
class JDatabaseIteratorSqlsrv extends JDatabaseIterator
{
/**
* Get the number of rows in the result set for the executed SQL given by
the cursor.
*
* @return integer The number of rows in the result set.
*
* @since 3.0.0
* @see Countable::count()
*/
public function count()
{
return sqlsrv_num_rows($this->cursor);
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
protected function fetchObject()
{
return sqlsrv_fetch_object($this->cursor, $this->class);
}
/**
* Method to free up the memory used for the result set.
*
* @return void
*
* @since 3.0.0
*/
protected function freeResult()
{
sqlsrv_free_stmt($this->cursor);
}
}
PK ��[h�Jh��iterator.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform Database Driver Class
*
* @since 3.0.0
*/
abstract class JDatabaseIterator implements Countable, Iterator
{
/**
* The database cursor.
*
* @var mixed
* @since 3.0.0
*/
protected $cursor;
/**
* The class of object to create.
*
* @var string
* @since 3.0.0
*/
protected $class;
/**
* The name of the column to use for the key of the database record.
*
* @var mixed
* @since 3.0.0
*/
private $_column;
/**
* The current database record.
*
* @var mixed
* @since 3.0.0
*/
private $_current;
/**
* A numeric or string key for the current database record.
*
* @var int|string
* @since 3.0.0
*/
private $_key;
/**
* The number of fetched records.
*
* @var integer
* @since 3.0.0
*/
private $_fetched = 0;
/**
* Database iterator constructor.
*
* @param mixed $cursor The database cursor.
* @param string $column An option column to use as the iterator key.
* @param string $class The class of object that is returned.
*
* @throws InvalidArgumentException
*/
public function __construct($cursor, $column = null, $class =
'stdClass')
{
if (!class_exists($class))
{
throw new InvalidArgumentException(sprintf('new %s(*%s*,
cursor)', get_class($this), gettype($class)));
}
$this->cursor = $cursor;
$this->class = $class;
$this->_column = $column;
$this->_fetched = 0;
$this->next();
}
/**
* Database iterator destructor.
*
* @since 3.0.0
*/
public function __destruct()
{
if ($this->cursor)
{
$this->freeResult($this->cursor);
}
}
/**
* The current element in the iterator.
*
* @return object
*
* @see Iterator::current()
* @since 3.0.0
*/
public function current()
{
return $this->_current;
}
/**
* The key of the current element in the iterator.
*
* @return int|string
*
* @see Iterator::key()
* @since 3.0.0
*/
public function key()
{
return $this->_key;
}
/**
* Moves forward to the next result from the SQL query.
*
* @return void
*
* @see Iterator::next()
* @since 3.0.0
*/
public function next()
{
// Set the default key as being the number of fetched object
$this->_key = $this->_fetched;
// Try to get an object
$this->_current = $this->fetchObject();
// If an object has been found
if ($this->_current)
{
// Set the key as being the indexed column (if it exists)
if (isset($this->_current->{$this->_column}))
{
$this->_key = $this->_current->{$this->_column};
}
// Update the number of fetched object
$this->_fetched++;
}
}
/**
* Rewinds the iterator.
*
* This iterator cannot be rewound.
*
* @return void
*
* @see Iterator::rewind()
* @since 3.0.0
*/
public function rewind()
{
}
/**
* Checks if the current position of the iterator is valid.
*
* @return boolean
*
* @see Iterator::valid()
* @since 3.0.0
*/
public function valid()
{
return (boolean) $this->_current;
}
/**
* Method to fetch a row from the result set cursor as an object.
*
* @return mixed Either the next row from the result set or false if
there are no more rows.
*
* @since 3.0.0
*/
abstract protected function fetchObject();
/**
* Method to free up the memory used for the result set.
*
* @return void
*
* @since 3.0.0
*/
abstract protected function freeResult();
}
PK ��[�D�
�
query/element.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Element Class.
*
* @property-read string $name The name of the element.
* @property-read array $elements An array of elements.
* @property-read string $glue Glue piece.
*
* @since 1.7.0
*/
class JDatabaseQueryElement
{
/**
* @var string The name of the element.
* @since 1.7.0
*/
protected $name = null;
/**
* @var array An array of elements.
* @since 1.7.0
*/
protected $elements = null;
/**
* @var string Glue piece.
* @since 1.7.0
*/
protected $glue = null;
/**
* Constructor.
*
* @param string $name The name of the element.
* @param mixed $elements String or array.
* @param string $glue The glue for elements.
*
* @since 1.7.0
*/
public function __construct($name, $elements, $glue = ',')
{
$this->elements = array();
$this->name = $name;
$this->glue = $glue;
$this->append($elements);
}
/**
* Magic function to convert the query element to a string.
*
* @return string
*
* @since 1.7.0
*/
public function __toString()
{
if (substr($this->name, -2) == '()')
{
return PHP_EOL . substr($this->name, 0, -2) . '(' .
implode($this->glue, $this->elements) . ')';
}
else
{
return PHP_EOL . $this->name . ' ' .
implode($this->glue, $this->elements);
}
}
/**
* Appends element parts to the internal list.
*
* @param mixed $elements String or array.
*
* @return void
*
* @since 1.7.0
*/
public function append($elements)
{
if (is_array($elements))
{
$this->elements = array_merge($this->elements, $elements);
}
else
{
$this->elements[] = $elements;
}
}
/**
* Gets the elements of this element.
*
* @return array
*
* @since 1.7.0
*/
public function getElements()
{
return $this->elements;
}
/**
* Sets the name of this element.
*
* @param string $name Name of the element.
*
* @return JDatabaseQueryElement Returns this object to allow chaining.
*
* @since 3.6
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Method to provide deep copy support to nested objects and arrays
* when cloning.
*
* @return void
*
* @since 1.7.3
*/
public function __clone()
{
foreach ($this as $k => $v)
{
if (is_object($v) || is_array($v))
{
$this->{$k} = unserialize(serialize($v));
}
}
}
}
PK ��[?}P>��query/limitable.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Database Query Limitable Interface.
* Adds bind/unbind methods as well as a getBounded() method
* to retrieve the stored bounded variables on demand prior to
* query execution.
*
* @since 3.0.0
*/
interface JDatabaseQueryLimitable
{
/**
* 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. This method is used
* automatically by the __toString() method if it detects that the
* query implements the JDatabaseQueryLimitable interface.
*
* @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 3.0.0
*/
public function processLimit($query, $limit, $offset = 0);
/**
* Sets the offset and limit for the result set, if the database driver
supports it.
*
* Usage:
* $query->setLimit(100, 0); (retrieve 100 rows, starting at first
record)
* $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th
record)
*
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function setLimit($limit = 0, $offset = 0);
}
PK ��[��q��query/mysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @since 1.7.0
* @deprecated 4.0 Use MySQLi or PDO MySQL instead
*/
class JDatabaseQueryMysql extends JDatabaseQueryMysqli
{
}
PK ��[��
��query/mysqli.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @since 1.7.0
*/
class JDatabaseQueryMysqli extends JDatabaseQuery implements
JDatabaseQueryLimitable
{
/**
* @var integer The offset for the result set.
* @since 3.0.0
*/
protected $offset;
/**
* @var integer The limit for the result set.
* @since 3.0.0
*/
protected $limit;
/**
* Magic function to convert the query to a string.
*
* @return string The completed query.
*
* @since 1.7.0
*/
public function __toString()
{
switch ($this->type)
{
case 'select':
if ($this->selectRowNumber)
{
$orderBy = $this->selectRowNumber['orderBy'];
$tmpOffset = $this->offset;
$tmpLimit = $this->limit;
$this->offset = 0;
$this->limit = 0;
$tmpOrder = $this->order;
$this->order = null;
$query = parent::__toString();
$this->order = $tmpOrder;
$this->offset = $tmpOffset;
$this->limit = $tmpLimit;
// Add support for second order by, offset and limit
$query = PHP_EOL . 'SELECT * FROM (' . $query . PHP_EOL .
"ORDER BY $orderBy" . PHP_EOL . ') w';
if ($this->order)
{
$query .= (string) $this->order;
}
return $this->processLimit($query, $this->limit,
$this->offset);
}
}
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
* 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 3.0.0
*/
public function processLimit($query, $limit, $offset = 0)
{
if ($limit > 0 && $offset > 0)
{
$query .= ' LIMIT ' . $offset . ', ' . $limit;
}
elseif ($limit > 0)
{
$query .= ' LIMIT ' . $limit;
}
return $query;
}
/**
* Concatenates an array of column names or values.
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 1.7.0
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
$concat_string = 'CONCAT_WS(' . $this->quote($separator);
foreach ($values as $value)
{
$concat_string .= ', ' . $value;
}
return $concat_string . ')';
}
else
{
return 'CONCAT(' . implode(',', $values) .
')';
}
}
/**
* Sets the offset and limit for the result set, if the database driver
supports it.
*
* Usage:
* $query->setLimit(100, 0); (retrieve 100 rows, starting at first
record)
* $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th
record)
*
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function setLimit($limit = 0, $offset = 0)
{
$this->limit = (int) $limit;
$this->offset = (int) $offset;
return $this;
}
/**
* Return correct regexp operator for mysqli.
*
* Ensure that the regexp operator is mysqli compatible.
*
* Usage:
* $query->where('field ' . $query->regexp($search));
*
* @param string $value The regex pattern.
*
* @return string Returns the regex operator.
*
* @since 1.7.3
*/
public function regexp($value)
{
return ' REGEXP ' . $value;
}
/**
* Return correct rand() function for Mysql.
*
* Ensure that the rand() function is Mysql compatible.
*
* Usage:
* $query->Rand();
*
* @return string The correct rand function.
*
* @since 3.5
*/
public function Rand()
{
return ' RAND() ';
}
/**
* Return the number of the current row.
*
* @param string $orderBy An expression of ordering for
window function.
* @param string $orderColumnAlias An alias for new ordering column.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.7.0
* @throws RuntimeException
*/
public function selectRowNumber($orderBy, $orderColumnAlias)
{
$this->validateRowNumber($orderBy, $orderColumnAlias);
$this->select("(SELECT @rownum := @rownum + 1 FROM (SELECT
@rownum := 0) AS r) AS $orderColumnAlias");
return $this;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* Usage:
* $query->select($query->castAsChar('a'));
* $query->select($query->castAsChar('a', 40));
*
* @param string $value The value to cast as a char.
*
* @param string $len The length of the char.
*
* @return string Returns the cast value.
*
* @since 3.7.0
*/
public function castAsChar($value, $len = null)
{
if (!$len)
{
return $value;
}
else
{
return ' CAST(' . $value . ' AS CHAR(' . $len .
'))';
}
}
}
PK ��[�w<��query/oracle.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Oracle Query Building Class.
*
* @since 3.0.0
*/
class JDatabaseQueryOracle extends JDatabaseQueryPdo implements
JDatabaseQueryPreparable, JDatabaseQueryLimitable
{
/**
* @var integer The offset for the result set.
* @since 3.0.0
*/
protected $offset;
/**
* @var integer The limit for the result set.
* @since 3.0.0
*/
protected $limit;
/**
* @var array Bounded object array
* @since 3.0.0
*/
protected $bounded = array();
/**
* Method to add a variable to an internal array that will be bound to a
prepared SQL statement before query execution. Also
* removes a variable that has been bounded from the internal bounded
array when the passed in value is null.
*
* @param string|integer $key The key that will be used in
your SQL query to reference the value. Usually of
* the form ':key', but
can also be an integer.
* @param mixed &$value The value that will be
bound. The value is passed by reference to support output
* parameters such as those
possible with stored procedures.
* @param integer $dataType Constant corresponding to a
SQL datatype.
* @param integer $length The length of the variable.
Usually required for OUTPUT parameters.
* @param array $driverOptions Optional driver options to be
used.
*
* @return JDatabaseQueryOracle
*
* @since 3.0.0
*/
public function bind($key = null, &$value = null, $dataType =
PDO::PARAM_STR, $length = 0, $driverOptions = array())
{
// Case 1: Empty Key (reset $bounded array)
if (empty($key))
{
$this->bounded = array();
return $this;
}
// Case 2: Key Provided, null value (unset key from $bounded array)
if (is_null($value))
{
if (isset($this->bounded[$key]))
{
unset($this->bounded[$key]);
}
return $this;
}
$obj = new stdClass;
$obj->value = &$value;
$obj->dataType = $dataType;
$obj->length = $length;
$obj->driverOptions = $driverOptions;
// Case 3: Simply add the Key/Value into the bounded array
$this->bounded[$key] = $obj;
return $this;
}
/**
* Retrieves the bound parameters array when key is null and returns it by
reference. If a key is provided then that item is
* returned.
*
* @param mixed $key The bounded variable key to retrieve.
*
* @return mixed
*
* @since 3.0.0
*/
public function &getBounded($key = null)
{
if (empty($key))
{
return $this->bounded;
}
else
{
if (isset($this->bounded[$key]))
{
return $this->bounded[$key];
}
}
}
/**
* Clear data from the query or a specific clause of the query.
*
* @param string $clause Optionally, the name of the clause to clear,
or nothing to clear the whole query.
*
* @return JDatabaseQueryOracle Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function clear($clause = null)
{
switch ($clause)
{
case null:
$this->bounded = array();
break;
}
parent::clear($clause);
return $this;
}
/**
* 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. This method is used
* automatically by the __toString() method if it detects that the
* query implements the JDatabaseQueryLimitable interface.
*
* @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 3.0.0
*/
public function processLimit($query, $limit, $offset = 0)
{
// Check if we need to mangle the query.
if ($limit || $offset)
{
$query = 'SELECT joomla2.*
FROM (
SELECT joomla1.*, ROWNUM AS joomla_db_rownum
FROM (
' . $query . '
) joomla1
) joomla2';
// Check if the limit value is greater than zero.
if ($limit > 0)
{
$query .= ' WHERE joomla2.joomla_db_rownum BETWEEN ' .
($offset + 1) . ' AND ' . ($offset + $limit);
}
else
{
// Check if there is an offset and then use this.
if ($offset)
{
$query .= ' WHERE joomla2.joomla_db_rownum > ' . ($offset
+ 1);
}
}
}
return $query;
}
/**
* Sets the offset and limit for the result set, if the database driver
supports it.
*
* Usage:
* $query->setLimit(100, 0); (retrieve 100 rows, starting at first
record)
* $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th
record)
*
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return JDatabaseQueryOracle Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function setLimit($limit = 0, $offset = 0)
{
$this->limit = (int) $limit;
$this->offset = (int) $offset;
return $this;
}
}
PK ��[�����
query/pdo.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PDO Query Building Class.
*
* @since 3.0.0
*/
class JDatabaseQueryPdo extends JDatabaseQuery
{
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* Usage:
* $query->select($query->castAsChar('a'));
* $query->select($query->castAsChar('a', 40));
*
* @param string $value The value to cast as a char.
*
* @param string $len The length of the char.
*
* @return string Returns the cast value.
*
* @since 1.7.0
*/
public function castAsChar($value, $len = null)
{
if (!$len)
{
return $value;
}
else
{
return ' CAST(' . $value . ' AS CHAR(' . $len .
'))';
}
}
}
PK ��[h.���query/pdomysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @package Joomla.Platform
* @subpackage Database
* @since 3.4
*/
class JDatabaseQueryPdomysql extends JDatabaseQueryMysqli
{
}
PK ��[�Za�BBquery/postgresql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @since 1.7.3
* @deprecated 4.0 Use PDO PostgreSQL instead
*/
class JDatabaseQueryPostgresql extends JDatabaseQuery implements
JDatabaseQueryLimitable
{
/**
* @var object The FOR UPDATE element used in "FOR UPDATE"
lock
* @since 1.7.3
*/
protected $forUpdate = null;
/**
* @var object The FOR SHARE element used in "FOR SHARE"
lock
* @since 1.7.3
*/
protected $forShare = null;
/**
* @var object The NOWAIT element used in "FOR SHARE" and
"FOR UPDATE" lock
* @since 1.7.3
*/
protected $noWait = null;
/**
* @var object The LIMIT element
* @since 1.7.3
*/
protected $limit = null;
/**
* @var object The OFFSET element
* @since 1.7.3
*/
protected $offset = null;
/**
* @var object The RETURNING element of INSERT INTO
* @since 1.7.3
*/
protected $returning = null;
/**
* Magic function to convert the query to a string, only for postgresql
specific query
*
* @return string The completed query.
*
* @since 1.7.3
*/
public function __toString()
{
$query = '';
switch ($this->type)
{
case 'select':
if ($this->selectRowNumber &&
$this->selectRowNumber['native'] === false)
{
// Workaround for postgresql version less than 8.4.0
try
{
$this->db->setQuery('CREATE TEMP SEQUENCE
ROW_NUMBER');
$this->db->execute();
}
catch (JDatabaseExceptionExecuting $e)
{
// Do nothing, sequence exists
}
$orderBy = $this->selectRowNumber['orderBy'];
$orderColumnAlias =
$this->selectRowNumber['orderColumnAlias'];
$columns = "nextval('ROW_NUMBER') - 1 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();
$columns = "w.*, $columns";
$this->order = $tmpOrder;
$this->offset = $tmpOffset;
$this->limit = $tmpLimit;
}
// Add support for second order by, offset and limit
$query = PHP_EOL . "SELECT $columns FROM (" . $query .
PHP_EOL . "ORDER BY $orderBy"
. PHP_EOL . ") w,(SELECT setval('ROW_NUMBER', 1)) AS
r";
if ($this->order)
{
$query .= (string) $this->order;
}
break;
}
$query .= (string) $this->select;
$query .= (string) $this->from;
if ($this->join)
{
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->selectRowNumber)
{
if ($this->order)
{
$query .= (string) $this->order;
}
break;
}
if ($this->group)
{
$query .= (string) $this->group;
}
if ($this->having)
{
$query .= (string) $this->having;
}
if ($this->order)
{
$query .= (string) $this->order;
}
if ($this->forUpdate)
{
$query .= (string) $this->forUpdate;
}
else
{
if ($this->forShare)
{
$query .= (string) $this->forShare;
}
}
if ($this->noWait)
{
$query .= (string) $this->noWait;
}
break;
case 'update':
$query .= (string) $this->update;
$query .= (string) $this->set;
if ($this->join)
{
$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 = preg_split('/\sON\s/i', $joinElem[0]);
if (count($joinArray) > 2)
{
$condition = array_pop($joinArray);
$joinArray = array(implode(' ON ', $joinArray),
$condition);
}
$this->from($joinArray[0]);
if (isset($joinArray[1]))
{
$this->where($joinArray[1]);
}
}
$query .= (string) $this->from;
if ($this->where)
{
$query .= (string) $this->where;
}
$this->from = $tmpFrom;
$this->where = $tmpWhere;
}
elseif ($this->where)
{
$query .= (string) $this->where;
}
break;
case 'insert':
$query .= (string) $this->insert;
if ($this->values)
{
if ($this->columns)
{
$query .= (string) $this->columns;
}
$elements = $this->values->getElements();
if (!($elements[0] instanceof $this))
{
$query .= ' VALUES ';
}
$query .= (string) $this->values;
if ($this->returning)
{
$query .= (string) $this->returning;
}
}
break;
default:
$query = parent::__toString();
break;
}
if ($this instanceof JDatabaseQueryLimitable)
{
$query = $this->processLimit($query, $this->limit,
$this->offset);
}
return $query;
}
/**
* Clear data from the query or a specific clause of the query.
*
* @param string $clause Optionally, the name of the clause to clear,
or nothing to clear the whole query.
*
* @return JDatabaseQueryPostgresql Returns this object to allow
chaining.
*
* @since 1.7.3
*/
public function clear($clause = null)
{
switch ($clause)
{
case 'limit':
$this->limit = null;
break;
case 'offset':
$this->offset = null;
break;
case 'forUpdate':
$this->forUpdate = null;
break;
case 'forShare':
$this->forShare = null;
break;
case 'noWait':
$this->noWait = null;
break;
case 'returning':
$this->returning = null;
break;
case 'select':
case 'update':
case 'delete':
case 'insert':
case 'from':
case 'join':
case 'set':
case 'where':
case 'group':
case 'having':
case 'order':
case 'columns':
case 'values':
parent::clear($clause);
break;
default:
$this->type = null;
$this->limit = null;
$this->offset = null;
$this->forUpdate = null;
$this->forShare = null;
$this->noWait = null;
$this->returning = null;
parent::clear($clause);
break;
}
return $this;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* Usage:
* $query->select($query->castAsChar('a'));
* $query->select($query->castAsChar('a', 40));
*
* @param string $value The value to cast as a char.
*
* @param string $len The length of the char.
*
* @return string Returns the cast value.
*
* @since 1.7.3
*/
public function castAsChar($value, $len = null)
{
if (!$len)
{
return $value . '::text';
}
else
{
return ' CAST(' . $value . ' AS CHAR(' . $len .
'))';
}
}
/**
* Concatenates an array of column names or values.
*
* Usage:
* $query->select($query->concatenate(array('a',
'b')));
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 1.7.3
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return implode(' || ' . $this->quote($separator) . '
|| ', $values);
}
else
{
return implode(' || ', $values);
}
}
/**
* Gets the current date and time.
*
* @return string Return string used in query to obtain
*
* @since 1.7.3
*/
public function currentTimestamp()
{
return 'NOW()';
}
/**
* Sets the FOR UPDATE lock on select's output row
*
* @param string $tableName The table to lock
* @param string $glue The glue by which to join the conditions.
Defaults to ',' .
*
* @return JDatabaseQueryPostgresql FOR UPDATE query element
*
* @since 1.7.3
*/
public function forUpdate($tableName, $glue = ',')
{
$this->type = 'forUpdate';
if (is_null($this->forUpdate))
{
$glue = strtoupper($glue);
$this->forUpdate = new JDatabaseQueryElement('FOR UPDATE',
'OF ' . $tableName, "$glue ");
}
else
{
$this->forUpdate->append($tableName);
}
return $this;
}
/**
* Sets the FOR SHARE lock on select's output row
*
* @param string $tableName The table to lock
* @param string $glue The glue by which to join the conditions.
Defaults to ',' .
*
* @return JDatabaseQueryPostgresql FOR SHARE query element
*
* @since 1.7.3
*/
public function forShare($tableName, $glue = ',')
{
$this->type = 'forShare';
if (is_null($this->forShare))
{
$glue = strtoupper($glue);
$this->forShare = new JDatabaseQueryElement('FOR SHARE',
'OF ' . $tableName, "$glue ");
}
else
{
$this->forShare->append($tableName);
}
return $this;
}
/**
* Used to get a string to extract year from date column.
*
* Usage:
*
$query->select($query->year($query->quoteName('dateColumn')));
*
* @param string $date Date column containing year to be extracted.
*
* @return string Returns string to extract year from a date.
*
* @since 3.0.0
*/
public function year($date)
{
return 'EXTRACT (YEAR FROM ' . $date . ')';
}
/**
* Used to get a string to extract month from date column.
*
* Usage:
*
$query->select($query->month($query->quoteName('dateColumn')));
*
* @param string $date Date column containing month to be extracted.
*
* @return string Returns string to extract month from a date.
*
* @since 3.0.0
*/
public function month($date)
{
return 'EXTRACT (MONTH FROM ' . $date . ')';
}
/**
* Used to get a string to extract day from date column.
*
* Usage:
*
$query->select($query->day($query->quoteName('dateColumn')));
*
* @param string $date Date column containing day to be extracted.
*
* @return string Returns string to extract day from a date.
*
* @since 3.0.0
*/
public function day($date)
{
return 'EXTRACT (DAY FROM ' . $date . ')';
}
/**
* Used to get a string to extract hour from date column.
*
* Usage:
*
$query->select($query->hour($query->quoteName('dateColumn')));
*
* @param string $date Date column containing hour to be extracted.
*
* @return string Returns string to extract hour from a date.
*
* @since 3.0.0
*/
public function hour($date)
{
return 'EXTRACT (HOUR FROM ' . $date . ')';
}
/**
* Used to get a string to extract minute from date column.
*
* Usage:
*
$query->select($query->minute($query->quoteName('dateColumn')));
*
* @param string $date Date column containing minute to be extracted.
*
* @return string Returns string to extract minute from a date.
*
* @since 3.0.0
*/
public function minute($date)
{
return 'EXTRACT (MINUTE FROM ' . $date . ')';
}
/**
* Used to get a string to extract seconds from date column.
*
* Usage:
*
$query->select($query->second($query->quoteName('dateColumn')));
*
* @param string $date Date column containing second to be extracted.
*
* @return string Returns string to extract second from a date.
*
* @since 3.0.0
*/
public function second($date)
{
return 'EXTRACT (SECOND FROM ' . $date . ')';
}
/**
* Sets the NOWAIT lock on select's output row
*
* @return JDatabaseQueryPostgresql NO WAIT query element
*
* @since 1.7.3
*/
public function noWait ()
{
$this->type = 'noWait';
if (is_null($this->noWait))
{
$this->noWait = new JDatabaseQueryElement('NOWAIT', null);
}
return $this;
}
/**
* Set the LIMIT clause to the query
*
* @param integer $limit An int of how many row will be returned
*
* @return JDatabaseQueryPostgresql Returns this object to allow
chaining.
*
* @since 1.7.3
*/
public function limit($limit = 0)
{
if (is_null($this->limit))
{
$this->limit = new JDatabaseQueryElement('LIMIT', (int)
$limit);
}
return $this;
}
/**
* Set the OFFSET clause to the query
*
* @param integer $offset An int for skipping row
*
* @return JDatabaseQueryPostgresql Returns this object to allow
chaining.
*
* @since 1.7.3
*/
public function offset($offset = 0)
{
if (is_null($this->offset))
{
$this->offset = new JDatabaseQueryElement('OFFSET', (int)
$offset);
}
return $this;
}
/**
* Add the RETURNING element to INSERT INTO statement.
*
* @param mixed $pkCol The name of the primary key column.
*
* @return JDatabaseQueryPostgresql Returns this object to allow
chaining.
*
* @since 1.7.3
*/
public function returning($pkCol)
{
if (is_null($this->returning))
{
$this->returning = new JDatabaseQueryElement('RETURNING',
$pkCol);
}
return $this;
}
/**
* Sets the offset and limit for the result set, if the database driver
supports it.
*
* Usage:
* $query->setLimit(100, 0); (retrieve 100 rows, starting at first
record)
* $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th
record)
*
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return JDatabaseQueryPostgresql Returns this object to allow
chaining.
*
* @since 3.0.0
*/
public function setLimit($limit = 0, $offset = 0)
{
$this->limit = (int) $limit;
$this->offset = (int) $offset;
return $this;
}
/**
* 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 3.0.0
*/
public function processLimit($query, $limit, $offset = 0)
{
if ($limit > 0)
{
$query .= ' LIMIT ' . $limit;
}
if ($offset > 0)
{
$query .= ' OFFSET ' . $offset;
}
return $query;
}
/**
* Add to the current date and time in Postgresql.
* Usage:
* $query->select($query->dateAdd());
* Prefixing the interval with a - (negative sign) will cause subtraction
to be used.
*
* @param string $date The db quoted string representation of the
date to add to
* @param string $interval The string representation of the
appropriate number of units
* @param string $datePart The part of the date to perform the
addition on
*
* @return string The string with the appropriate sql for addition of
dates
*
* @since 3.2.0
* @note Not all drivers support all units. Check appropriate
references
* @link
http://www.postgresql.org/docs/9.0/static/functions-datetime.html.
*/
public function dateAdd($date, $interval, $datePart)
{
if (substr($interval, 0, 1) != '-')
{
return "timestamp " . $date . " + interval '" .
$interval . " " . $datePart . "'";
}
else
{
return "timestamp " . $date . " - interval '" .
ltrim($interval, '-') . " " . $datePart .
"'";
}
}
/**
* Return correct regexp operator for Postgresql.
*
* Ensure that the regexp operator is Postgresql compatible.
*
* Usage:
* $query->where('field ' . $query->regexp($search));
*
* @param string $value The regex pattern.
*
* @return string Returns the regex operator.
*
* @since 1.7.3
*/
public function regexp($value)
{
return ' ~* ' . $value;
}
/**
* Return correct rand() function for Postgresql.
*
* Ensure that the rand() function is Postgresql compatible.
*
* Usage:
* $query->Rand();
*
* @return string The correct rand function.
*
* @since 3.5
*/
public function Rand()
{
return ' RANDOM() ';
}
/**
* Return the number of the current row.
*
* @param string $orderBy An expression of ordering for
window function.
* @param string $orderColumnAlias An alias for new ordering column.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.7.0
* @throws RuntimeException
*/
public function selectRowNumber($orderBy, $orderColumnAlias)
{
$this->validateRowNumber($orderBy, $orderColumnAlias);
if (version_compare($this->db->getVersion(), '8.4.0')
>= 0)
{
$this->selectRowNumber['native'] = true;
$this->select("ROW_NUMBER() OVER (ORDER BY $orderBy) AS
$orderColumnAlias");
}
else
{
$this->selectRowNumber['native'] = false;
}
return $this;
}
}
PK ��[ T����query/preparable.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Database Query Preparable Interface.
* Adds bind/unbind methods as well as a getBounded() method
* to retrieve the stored bounded variables on demand prior to
* query execution.
*
* @since 3.0.0
*/
interface JDatabaseQueryPreparable
{
/**
* Method to add a variable to an internal array that will be bound to a
prepared SQL statement before query execution. Also
* removes a variable that has been bounded from the internal bounded
array when the passed in value is null.
*
* @param string|integer $key The key that will be used in
your SQL query to reference the value. Usually of
* the form ':key', but
can also be an integer.
* @param mixed &$value The value that will be
bound. The value is passed by reference to support output
* parameters such as those
possible with stored procedures.
* @param integer $dataType Constant corresponding to a
SQL datatype.
* @param integer $length The length of the variable.
Usually required for OUTPUT parameters.
* @param array $driverOptions Optional driver options to be
used.
*
* @return JDatabaseQuery
*
* @since 3.0.0
*/
public function bind($key = null, &$value = null, $dataType =
PDO::PARAM_STR, $length = 0, $driverOptions = array());
/**
* Retrieves the bound parameters array when key is null and returns it by
reference. If a key is provided then that item is
* returned.
*
* @param mixed $key The bounded variable key to retrieve.
*
* @return mixed
*
* @since 3.0.0
*/
public function &getBounded($key = null);
}
PK ��[L�;�88query/sqlazure.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @since 1.7.0
*/
class JDatabaseQuerySqlazure extends JDatabaseQuerySqlsrv
{
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
*
* @since 1.7.0
*/
protected $name_quotes = '';
}
PK ��[� �(�(query/sqlite.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQLite Query Building Class.
*
* @since 3.0.0
*/
class JDatabaseQuerySqlite extends JDatabaseQueryPdo implements
JDatabaseQueryPreparable, JDatabaseQueryLimitable
{
/**
* @var integer The offset for the result set.
* @since 3.0.0
*/
protected $offset;
/**
* @var integer The limit for the result set.
* @since 3.0.0
*/
protected $limit;
/**
* @var array Bounded object array
* @since 3.0.0
*/
protected $bounded = array();
/**
* Method to add a variable to an internal array that will be bound to a
prepared SQL statement before query execution. Also
* removes a variable that has been bounded from the internal bounded
array when the passed in value is null.
*
* @param string|integer $key The key that will be used in
your SQL query to reference the value. Usually of
* the form ':key', but
can also be an integer.
* @param mixed &$value The value that will be
bound. The value is passed by reference to support output
* parameters such as those
possible with stored procedures.
* @param integer $dataType Constant corresponding to a
SQL datatype.
* @param integer $length The length of the variable.
Usually required for OUTPUT parameters.
* @param array $driverOptions Optional driver options to be
used.
*
* @return JDatabaseQuerySqlite
*
* @since 3.0.0
*/
public function bind($key = null, &$value = null, $dataType =
PDO::PARAM_STR, $length = 0, $driverOptions = array())
{
// Case 1: Empty Key (reset $bounded array)
if (empty($key))
{
$this->bounded = array();
return $this;
}
// Case 2: Key Provided, null value (unset key from $bounded array)
if (is_null($value))
{
if (isset($this->bounded[$key]))
{
unset($this->bounded[$key]);
}
return $this;
}
$obj = new stdClass;
$obj->value = &$value;
$obj->dataType = $dataType;
$obj->length = $length;
$obj->driverOptions = $driverOptions;
// Case 3: Simply add the Key/Value into the bounded array
$this->bounded[$key] = $obj;
return $this;
}
/**
* Retrieves the bound parameters array when key is null and returns it by
reference. If a key is provided then that item is
* returned.
*
* @param mixed $key The bounded variable key to retrieve.
*
* @return mixed
*
* @since 3.0.0
*/
public function &getBounded($key = null)
{
if (empty($key))
{
return $this->bounded;
}
else
{
if (isset($this->bounded[$key]))
{
return $this->bounded[$key];
}
}
}
/**
* 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 $operator Comparison operator between charLength
integer value and $condition
* @param string $condition Integer value to compare charLength with.
*
* @return string The required char length call.
*
* @since 3.2.0
*/
public function charLength($field, $operator = null, $condition = null)
{
return 'length(' . $field . ')' . (isset($operator)
&& isset($condition) ? ' ' . $operator . ' ' .
$condition : '');
}
/**
* Clear data from the query or a specific clause of the query.
*
* @param string $clause Optionally, the name of the clause to clear,
or nothing to clear the whole query.
*
* @return JDatabaseQuerySqlite Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function clear($clause = null)
{
switch ($clause)
{
case null:
$this->bounded = array();
break;
}
parent::clear($clause);
return $this;
}
/**
* Concatenates an array of column names or values.
*
* Usage:
* $query->select($query->concatenate(array('a',
'b')));
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 1.7.0
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return implode(' || ' . $this->quote($separator) . '
|| ', $values);
}
else
{
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. This method is used
* automatically by the __toString() method if it detects that the
* query implements the JDatabaseQueryLimitable interface.
*
* @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 3.0.0
*/
public function processLimit($query, $limit, $offset = 0)
{
if ($limit > 0 || $offset > 0)
{
$query .= ' LIMIT ' . $offset . ', ' . $limit;
}
return $query;
}
/**
* Sets the offset and limit for the result set, if the database driver
supports it.
*
* Usage:
* $query->setLimit(100, 0); (retrieve 100 rows, starting at first
record)
* $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th
record)
*
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return JDatabaseQuerySqlite Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function setLimit($limit = 0, $offset = 0)
{
$this->limit = (int) $limit;
$this->offset = (int) $offset;
return $this;
}
/**
* Add to the current date and time.
* Usage:
* $query->select($query->dateAdd());
* Prefixing the interval with a - (negative sign) will cause subtraction
to be used.
*
* @param datetime $date The date or datetime to add to
* @param string $interval The string representation of the
appropriate number of units
* @param string $datePart The part of the date to perform the
addition on
*
* @return string The string with the appropriate sql for addition of
dates
*
* @since 3.2.0
* @link http://www.sqlite.org/lang_datefunc.html
*/
public function dateAdd($date, $interval, $datePart)
{
// SQLite does not support microseconds as a separate unit. Convert the
interval to seconds
if (strcasecmp($datePart, 'microseconds') == 0)
{
// Force the dot as a decimal point
$interval = str_replace(',', '.', .001 * $interval);
$datePart = 'seconds';
}
if (substr($interval, 0, 1) != '-')
{
return "datetime('" . $date . "', '+"
. $interval . " " . $datePart . "')";
}
else
{
return "datetime('" . $date . "', '"
. $interval . " " . $datePart . "')";
}
}
/**
* Gets the current date and time.
*
* Usage:
* $query->where('published_up <
'.$query->currentTimestamp());
*
* @return string
*
* @since 3.4
*/
public function currentTimestamp()
{
return 'CURRENT_TIMESTAMP';
}
/**
* Magic function to convert the query to a string.
*
* @return string The completed query.
*
* @since 1.7.0
*/
public function __toString()
{
switch ($this->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 '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 JDatabaseQueryElement('()',
$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 JDatabaseQuerySqlite($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();
}
/**
* Return the number of the current row.
*
* @param string $orderBy An expression of ordering for
window function.
* @param string $orderColumnAlias An alias for new ordering column.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.7.0
* @throws RuntimeException
*/
public function selectRowNumber($orderBy, $orderColumnAlias)
{
$this->validateRowNumber($orderBy, $orderColumnAlias);
return $this;
}
}
PK ��[h��{�]�]query/sqlsrv.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @since 1.7.0
*/
class JDatabaseQuerySqlsrv extends JDatabaseQuery implements
JDatabaseQueryLimitable
{
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 1.7.0
*/
protected $name_quotes = '`';
/**
* The null or zero representation of a timestamp for the database driver.
This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 1.7.0
*/
protected $null_date = '1900-01-01 00:00:00';
/**
* @var integer The affected row limit for the current SQL statement.
* @since 3.2
*/
protected $limit = 0;
/**
* @var integer The affected row offset to apply for the current SQL
statement.
* @since 3.2
*/
protected $offset = 0;
/**
* Magic function to convert the query to a string.
*
* @return string The completed query.
*
* @since 1.7.0
*/
public function __toString()
{
$query = '';
switch ($this->type)
{
case 'select':
// Add required aliases for offset or fixGroupColumns method
$columns = $this->fixSelectAliases();
$query = (string) $this->select;
if ($this->group)
{
$this->fixGroupColumns($columns);
}
$query .= (string) $this->from;
if ($this->join)
{
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->selectRowNumber === null)
{
if ($this->group)
{
$query .= (string) $this->group;
}
if ($this->having)
{
$query .= (string) $this->having;
}
}
if ($this->order)
{
$query .= (string) $this->order;
}
if ($this instanceof JDatabaseQueryLimitable &&
($this->limit > 0 || $this->offset > 0))
{
$query = $this->processLimit($query, $this->limit,
$this->offset);
}
break;
case 'insert':
$query .= (string) $this->insert;
// Set method
if ($this->set)
{
$query .= (string) $this->set;
}
// Columns-Values method
elseif ($this->values)
{
if ($this->columns)
{
$query .= (string) $this->columns;
}
$elements = $this->insert->getElements();
$tableName = array_shift($elements);
$query .= 'VALUES ';
$query .= (string) $this->values;
if ($this->autoIncrementField)
{
$query = 'SET IDENTITY_INSERT ' . $tableName . '
ON;' . $query . 'SET IDENTITY_INSERT ' . $tableName . '
OFF;';
}
if ($this->where)
{
$query .= (string) $this->where;
}
}
break;
case 'delete':
$query .= (string) $this->delete;
$query .= (string) $this->from;
if ($this->join)
{
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->order)
{
$query .= (string) $this->order;
}
break;
case 'update':
if ($this->join)
{
$tmpUpdate = $this->update;
$tmpFrom = $this->from;
$this->update = null;
$this->from = null;
$updateElem = $tmpUpdate->getElements();
$updateArray = explode(' ', $updateElem[0]);
// Use table alias if exists
$this->update(end($updateArray));
$this->from($updateElem[0]);
$query .= (string) $this->update;
$query .= (string) $this->set;
$query .= (string) $this->from;
$this->update = $tmpUpdate;
$this->from = $tmpFrom;
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
else
{
$query .= (string) $this->update;
$query .= (string) $this->set;
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->order)
{
$query .= (string) $this->order;
}
break;
default:
$query = parent::__toString();
break;
}
return $query;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* @param string $value The value to cast as a char.
*
* @param string $len The length of the char.
*
* @return string Returns the cast value.
*
* @since 1.7.0
*/
public function castAsChar($value, $len = null)
{
if (!$len)
{
return 'CAST(' . $value . ' as NVARCHAR(30))';
}
else
{
return 'CAST(' . $value . ' as NVARCHAR(' . $len .
'))';
}
}
/**
* Gets the function to determine the length of a character string.
*
* @param string $field A value.
* @param string $operator Comparison operator between charLength
integer value and $condition
* @param string $condition Integer value to compare charLength with.
*
* @return string The required char length call.
*
* @since 1.7.0
*/
public function charLength($field, $operator = null, $condition = null)
{
return 'DATALENGTH(' . $field . ')' .
(isset($operator) && isset($condition) ? ' ' . $operator
. ' ' . $condition : '');
}
/**
* Concatenates an array of column names or values.
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 1.7.0
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return '(' . implode('+' .
$this->quote($separator) . '+', $values) . ')';
}
else
{
return '(' . implode('+', $values) . ')';
}
}
/**
* Gets the current date and time.
*
* @return string
*
* @since 1.7.0
*/
public function currentTimestamp()
{
return 'GETDATE()';
}
/**
* Get the length of a string in bytes.
*
* @param string $value The string to measure.
*
* @return integer
*
* @since 1.7.0
*/
public function length($value)
{
return 'LEN(' . $value . ')';
}
/**
* Add to the current date and time.
* Usage:
* $query->select($query->dateAdd());
* Prefixing the interval with a - (negative sign) will cause subtraction
to be used.
*
* @param datetime $date The date to add to; type may be time or
datetime.
* @param string $interval The string representation of the
appropriate number of units
* @param string $datePart The part of the date to perform the
addition on
*
* @return string The string with the appropriate sql for addition of
dates
*
* @since 3.2.0
* @note Not all drivers support all units.
* @link http://msdn.microsoft.com/en-us/library/ms186819.aspx for more
information
*/
public function dateAdd($date, $interval, $datePart)
{
return 'DATEADD(' . $datePart . ', ' . $interval .
', ' . $date . ')';
}
/**
* 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 3.0.0
*/
public function processLimit($query, $limit, $offset = 0)
{
if ($limit)
{
$total = $offset + $limit;
$position = stripos($query, 'SELECT');
$distinct = stripos($query, 'SELECT DISTINCT');
if ($position === $distinct)
{
$query = substr_replace($query, 'SELECT DISTINCT TOP ' .
(int) $total, $position, 15);
}
else
{
$query = substr_replace($query, 'SELECT TOP ' . (int) $total,
$position, 6);
}
}
if (!$offset)
{
return $query;
}
return PHP_EOL
. 'SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0))
AS RowNumber FROM ('
. $query
. PHP_EOL . ') AS A) AS A WHERE RowNumber > ' . (int)
$offset;
}
/**
* Sets the offset and limit for the result set, if the database driver
supports it.
*
* Usage:
* $query->setLimit(100, 0); (retrieve 100 rows, starting at first
record)
* $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th
record)
*
* @param integer $limit The limit for the result set
* @param integer $offset The offset for the result set
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function setLimit($limit = 0, $offset = 0)
{
$this->limit = (int) $limit;
$this->offset = (int) $offset;
return $this;
}
/**
* Split a string of sql expression into an array of individual columns.
* Single line or line end comments and multi line comments are stripped
off.
* Always return at least one column.
*
* @param string $string Input string of sql expression like select
expression.
*
* @return array[] The columns from the input string separated into an
array.
*
* @since 3.7.0
*/
protected function splitSqlExpression($string)
{
// Append whitespace as equivalent to the last comma
$string .= ' ';
$colIdx = 0;
$start = 0;
$open = false;
$openC = 0;
$comment = false;
$endString = '';
$length = strlen($string);
$columns = array();
$column = array();
$current = '';
$previous = null;
$operators = array(
'+' => '',
'-' => '',
'*' => '',
'/' => '',
'%' => '',
'&' => '',
'|' => '',
'~' => '',
'^' => '',
);
$addBlock = function ($block) use (&$column, &$colIdx)
{
if (isset($column[$colIdx]))
{
$column[$colIdx] .= $block;
}
else
{
$column[$colIdx] = $block;
}
};
for ($i = 0; $i < $length; $i++)
{
$current = substr($string, $i, 1);
$current2 = substr($string, $i, 2);
$current3 = substr($string, $i, 3);
$lenEndString = strlen($endString);
$testEnd = substr($string, $i, $lenEndString);
if ($current == '[' || $current == '"' ||
$current == "'" || $current2 == '--'
|| ($current2 == '/*') || ($current == '#'
&& $current3 != '#__')
|| ($lenEndString && $testEnd == $endString))
{
if ($open)
{
if ($testEnd === $endString)
{
if ($comment)
{
if ($lenEndString > 1)
{
$i += ($lenEndString - 1);
}
// Move cursor after close tag of comment
$start = $i + 1;
$comment = false;
}
elseif ($current == "'" || $current == ']'
|| $current == '"')
{
// Check for escaped quote like '', ]] or ""
$n = 1;
while ($i + $n < $length && $string[$i + $n] == $current)
{
$n++;
}
// Jump to the last quote
$i += $n - 1;
if ($n % 2 === 0)
{
// There is only escaped quote
continue;
}
elseif ($n > 2)
{
// The last right close quote is not escaped
$current = $string[$i];
}
}
$open = false;
$endString = '';
}
}
else
{
$open = true;
if ($current == '#' || $current2 == '--')
{
$endString = "\n";
$comment = true;
}
elseif ($current2 == '/*')
{
$endString = '*/';
$comment = true;
}
elseif ($current == '[')
{
$endString = ']';
}
else
{
$endString = $current;
}
if ($comment && $start < $i)
{
// Add string exists before comment
$addBlock(substr($string, $start, $i - $start));
$previous = $string[$i - 1];
$start = $i;
}
}
}
elseif (!$open)
{
if ($current == '(')
{
$openC++;
$previous = $current;
}
elseif ($current == ')')
{
$openC--;
$previous = $current;
}
elseif ($current == '.')
{
if ($i === $start && $colIdx > 0 &&
!isset($column[$colIdx]))
{
// Remove whitepace placed before dot
$colIdx--;
}
$previous = $current;
}
elseif ($openC === 0)
{
if (ctype_space($current))
{
// Normalize whitepace
$string[$i] = ' ';
if ($start < $i)
{
// Add text placed before whitespace
$addBlock(substr($string, $start, $i - $start));
$colIdx++;
$previous = $string[$i - 1];
}
elseif (isset($column[$colIdx]))
{
if ($colIdx > 1 || !isset($operators[$previous]))
{
// There was whitespace after comment
$colIdx++;
}
}
// Move cursor forward
$start = $i + 1;
}
elseif (isset($operators[$current]) && ($current !==
'*' || $previous !== '.'))
{
if ($start < $i)
{
// Add text before operator
$addBlock(substr($string, $start, $i - $start));
$colIdx++;
}
elseif (!isset($column[$colIdx]) &&
isset($operators[$previous]))
{
// Do not create whitespace between operators
$colIdx--;
}
// Add operator
$addBlock($current);
$previous = $current;
$colIdx++;
// Move cursor forward
$start = $i + 1;
}
else
{
$previous = $current;
}
}
}
if (($current == ',' && !$open && $openC == 0)
|| $i == $length - 1)
{
if ($start < $i && !$comment)
{
// Save remaining text
$addBlock(substr($string, $start, $i - $start));
}
$columns[] = $column;
// Reset values
$column = array();
$colIdx = 0;
$previous = null;
// Column saved, move cursor forward after comma
$start = $i + 1;
}
}
return $columns;
}
/**
* Add required aliases to columns for select statement in subquery.
*
* @return array[] Array of columns with added missing aliases.
*
* @since 3.7.0
*/
protected function fixSelectAliases()
{
$operators = array(
'+' => '',
'-' => '',
'*' => '',
'/' => '',
'%' => '',
'&' => '',
'|' => '',
'~' => '',
'^' => '',
);
// Split into array and remove comments
$columns = $this->splitSqlExpression(implode(',',
$this->select->getElements()));
foreach ($columns as $i => $column)
{
$size = count($column);
if ($size == 0)
{
continue;
}
if ($size > 2 && strcasecmp($column[$size - 2],
'AS') === 0)
{
// Alias exists, replace it to uppercase
$columns[$i][$size - 2] = 'AS';
continue;
}
if ($i == 0 && stripos(' DISTINCT ALL ', "
$column[0] ") !== false)
{
// This words are reserved, they are not column names
array_shift($column);
$size--;
}
$lastWord = strtoupper($column[$size - 1]);
$length = strlen($lastWord);
$lastChar = $lastWord[$length - 1];
if ($lastChar == '*')
{
// Skip on wildcard
continue;
}
if ($lastChar == ')'
|| ($size == 1 && $lastChar == "'")
|| $lastWord[0] == '@'
|| $lastWord == 'NULL'
|| $lastWord == 'END'
|| is_numeric($lastWord))
{
/* Ends with:
* - SQL function
* - single static value like 'only '+'string'
* - @@var
* - NULL
* - CASE ... END
* - Numeric
*/
$columns[$i][] = 'AS';
$columns[$i][] = $this->quoteName('columnAlias' . $i);
continue;
}
if ($size == 1)
{
continue;
}
$lastChar2 = substr($column[$size - 2], -1);
// Check if column ends with '- a.x' or '- a. x'
if (isset($operators[$lastChar2])
|| ($size > 2 && $lastChar2 === '.' &&
isset($operators[substr($column[$size - 3], -1)])))
{
// Ignore plus signs if column start with them
if ($size != 2 || ltrim($column[0], '+') !== '' ||
$column[1][0] === "'")
{
// If operator exists before last word then alias is required for
subquery
$columns[$i][] = 'AS';
$columns[$i][] = $this->quoteName('columnAlias' . $i);
continue;
}
}
elseif ($column[$size - 1][0] !== '.' && $lastChar2
!== '.')
{
// If columns is like name name2 then second word is alias.
// Add missing AS before the alias, exception for 'a. x' and
'a .x'
array_splice($columns[$i], -1, 0, 'AS');
}
}
$selectColumns = array();
foreach ($columns as $i => $column)
{
$selectColumns[$i] = implode(' ', $column);
}
$this->select = new JDatabaseQueryElement('SELECT',
$selectColumns);
return $columns;
}
/**
* Add missing columns names to GROUP BY clause.
*
* @param array[] $selectColumns Array of columns from
splitSqlExpression method.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.7.0
*/
protected function fixGroupColumns($selectColumns)
{
// Cache tables columns
static $cacheCols = array();
// Known columns of all included tables
$knownColumnsByAlias = array();
$iquotes = array('"' => '', '['
=> '', "'" => '');
$nquotes = array('"', '[', ']');
// Aggregate functions
$aFuncs = array(
'AVG(',
'CHECKSUM_AGG(',
'COUNT(',
'COUNT_BIG(',
'GROUPING(',
'GROUPING_ID(',
'MIN(',
'MAX(',
'SUM(',
'STDEV(',
'STDEVP(',
'VAR(',
'VARP(',
);
// Aggregated columns
$filteredColumns = array();
// Aliases found in SELECT statement
$knownAliases = array();
$wildcardTables = array();
foreach ($selectColumns as $i => $column)
{
$size = count($column);
if ($size === 0)
{
continue;
}
if ($i == 0 && stripos(' DISTINCT ALL ', "
$column[0] ") !== false)
{
// These words are reserved, they are not column names
array_shift($selectColumns[0]);
array_shift($column);
$size--;
}
if ($size > 2 && $column[$size - 2] === 'AS')
{
// Save and remove AS alias
$alias = $column[$size - 1];
if (isset($iquotes[$alias[0]]))
{
$alias = substr($alias, 1, -1);
}
// Remove alias
$selectColumns[$i] = $column = array_slice($column, 0, -2);
if ($size === 3 || ($size === 4 &&
strpos('+-*/%&|~^', $column[0][0]) !== false))
{
$lastWord = $column[$size - 3];
if ($lastWord[0] === "'" || $lastWord ===
'NULL' || is_numeric($lastWord))
{
unset($selectColumns[$i]);
continue;
}
}
// Remember pair alias => column expression
$knownAliases[$alias] = implode(' ', $column);
}
$aggregated = false;
foreach ($column as $j => $block)
{
if (substr($block, -2) === '.*')
{
// Found column ends with .*
if (isset($iquotes[$block[0]]))
{
// Quoted table
$wildcardTables[] = substr($block, 1, -3);
}
else
{
$wildcardTables[] = substr($block, 0, -2);
}
}
elseif (str_ireplace($aFuncs, '', $block) != $block)
{
$aggregated = true;
}
if ($block[0] === "'")
{
// Shrink static strings which could contain column name
$column[$j] = "''";
}
}
if (!$aggregated)
{
// Without aggregated columns and aliases
$filteredColumns[] = implode(' ', $selectColumns[$i]);
}
// Without aliases and static strings
$selectColumns[$i] = implode(' ', $column);
}
// If select statement use table.* expression
if ($wildcardTables)
{
// Split FROM statement into list of tables
$tables = $this->splitSqlExpression(implode(',',
$this->from->getElements()));
foreach ($tables as $i => $table)
{
$table = implode(' ', $table);
// Exclude subquery from the FROM clause
if (strpos($table, '(') === false)
{
// Unquote
$table = str_replace($nquotes, '', $table);
$table = str_replace('#__', $this->db->getPrefix(),
$table);
$table = explode(' ', $table);
$alias = end($table);
$table = $table[0];
// Chek if exists a wildcard with current alias table?
if (in_array($alias, $wildcardTables, true))
{
if (!isset($cacheCols[$table]))
{
$cacheCols[$table] = $this->db->getTableColumns($table);
}
if ($this->join || $table != $alias)
{
foreach ($cacheCols[$table] as $name => $type)
{
$knownColumnsByAlias[$alias][] = $alias . '.' . $name;
}
}
else
{
foreach ($cacheCols[$table] as $name => $type)
{
$knownColumnsByAlias[$alias][] = $name;
}
}
}
}
}
// Now we need to get all tables from any joins
// Go through all joins and add them to the tables array
if ($this->join)
{
foreach ($this->join as $join)
{
// Unquote and replace prefix
$joinTbl = str_replace($nquotes, '', (string) $join);
$joinTbl = str_replace("#__", $this->db->getPrefix(),
$joinTbl);
// Exclude subquery
if (preg_match('/JOIN\s+(\w+)(?:\s+AS)?(?:\s+(\w+))?/i',
$joinTbl, $matches))
{
$table = $matches[1];
$alias = isset($matches[2]) ? $matches[2] : $table;
// Chek if exists a wildcard with current alias table?
if (in_array($alias, $wildcardTables, true))
{
if (!isset($cacheCols[$table]))
{
$cacheCols[$table] = $this->db->getTableColumns($table);
}
foreach ($cacheCols[$table] as $name => $type)
{
$knownColumnsByAlias[$alias][] = $alias . '.' . $name;
}
}
}
}
}
}
$selectExpression = implode(',', $selectColumns);
// Split into the right columns
$groupColumns = $this->splitSqlExpression(implode(',',
$this->group->getElements()));
// Remove column aliases from GROUP statement - SQLSRV does not support
it
foreach ($groupColumns as $i => $column)
{
$groupColumns[$i] = implode(' ', $column);
$column = str_replace($nquotes, '', $groupColumns[$i]);
if (isset($knownAliases[$column]))
{
// Be sure that this is not a valid column name
if (!preg_match('/\b' . preg_quote($column, '/') .
'\b/', $selectExpression))
{
// Replace column alias by column expression
$groupColumns[$i] = $knownAliases[$column];
}
}
}
// Find all alias.* and fill with proper table column names
foreach ($filteredColumns as $i => $column)
{
if (substr($column, -2) === '.*')
{
unset($filteredColumns[$i]);
// Extract alias.* columns into GROUP BY statement
$groupColumns = array_merge($groupColumns,
$knownColumnsByAlias[substr($column, 0, -2)]);
}
}
$groupColumns = array_merge($groupColumns, $filteredColumns);
if ($this->order)
{
// Remove direction suffixes
$dir = array(" DESC\v", " ASC\v");
$orderColumns = $this->splitSqlExpression(implode(',',
$this->order->getElements()));
foreach ($orderColumns as $i => $column)
{
$column = implode(' ', $column);
$orderColumns[$i] = $column = trim(str_ireplace($dir, '',
"$column\v"), "\v");
if (isset($knownAliases[str_replace($nquotes, '', $column)]))
{
unset($orderColumns[$i]);
}
if (str_ireplace($aFuncs, '', $column) != $column)
{
// Do not add aggregate expression
unset($orderColumns[$i]);
}
}
$groupColumns = array_merge($groupColumns, $orderColumns);
}
// Get a unique string of all column names that need to be included in
the group statement
$this->group = new JDatabaseQueryElement('GROUP BY',
array_unique($groupColumns));
return $this;
}
/**
* Return correct rand() function for MSSQL.
*
* Ensure that the rand() function is MSSQL compatible.
*
* Usage:
* $query->Rand();
*
* @return string The correct rand function.
*
* @since 3.5
*/
public function Rand()
{
return ' NEWID() ';
}
}
PK ��[�_����� query.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Query Building Class.
*
* @since 1.7.0
*
* @method string q() q($text, $escape = true) Alias for quote
method
* @method string qn() qn($name, $as = null) Alias for quoteName
method
* @method string e() e($text, $extra = false) Alias for escape
method
* @property-read JDatabaseQueryElement $type
* @property-read JDatabaseQueryElement $select
* @property-read JDatabaseQueryElement $group
* @property-read JDatabaseQueryElement $having
*/
abstract class JDatabaseQuery
{
/**
* @var JDatabaseDriver The database driver.
* @since 1.7.0
*/
protected $db = null;
/**
* @var string The SQL query (if a direct query string was provided).
* @since 3.0.0
*/
protected $sql = null;
/**
* @var string The query type.
* @since 1.7.0
*/
protected $type = '';
/**
* @var JDatabaseQueryElement The query element for a generic query
(type = null).
* @since 1.7.0
*/
protected $element = null;
/**
* @var JDatabaseQueryElement The select element.
* @since 1.7.0
*/
protected $select = null;
/**
* @var JDatabaseQueryElement The delete element.
* @since 1.7.0
*/
protected $delete = null;
/**
* @var JDatabaseQueryElement The update element.
* @since 1.7.0
*/
protected $update = null;
/**
* @var JDatabaseQueryElement The insert element.
* @since 1.7.0
*/
protected $insert = null;
/**
* @var JDatabaseQueryElement The from element.
* @since 1.7.0
*/
protected $from = null;
/**
* @var JDatabaseQueryElement The join element.
* @since 1.7.0
*/
protected $join = null;
/**
* @var JDatabaseQueryElement The set element.
* @since 1.7.0
*/
protected $set = null;
/**
* @var JDatabaseQueryElement The where element.
* @since 1.7.0
*/
protected $where = null;
/**
* @var JDatabaseQueryElement The group by element.
* @since 1.7.0
*/
protected $group = null;
/**
* @var JDatabaseQueryElement The having element.
* @since 1.7.0
*/
protected $having = null;
/**
* @var JDatabaseQueryElement The column list for an INSERT statement.
* @since 1.7.0
*/
protected $columns = null;
/**
* @var JDatabaseQueryElement The values list for an INSERT statement.
* @since 1.7.0
*/
protected $values = null;
/**
* @var JDatabaseQueryElement The order element.
* @since 1.7.0
*/
protected $order = null;
/**
* @var object The auto increment insert field element.
* @since 1.7.0
*/
protected $autoIncrementField = null;
/**
* @var JDatabaseQueryElement The call element.
* @since 3.0.0
*/
protected $call = null;
/**
* @var JDatabaseQueryElement The exec element.
* @since 3.0.0
*/
protected $exec = null;
/**
* @var JDatabaseQueryElement The union element.
* @since 3.0.0
* @deprecated 4.0 Will be transformed and moved to $merge variable.
*/
protected $union = null;
/**
* @var JDatabaseQueryElement The unionAll element.
* @since 3.2.0
* @deprecated 4.0 Will be transformed and moved to $merge variable.
*/
protected $unionAll = null;
/**
* @var array Details of window function.
* @since 3.7.0
*/
protected $selectRowNumber = null;
/**
* Magic method to provide method alias support for quote() and
quoteName().
*
* @param string $method The called method.
* @param array $args The array of arguments passed to the method.
*
* @return string The aliased method's return value or null.
*
* @since 1.7.0
*/
public function __call($method, $args)
{
if (empty($args))
{
return;
}
switch ($method)
{
case 'q':
return $this->quote($args[0], isset($args[1]) ? $args[1] : true);
break;
case 'qn':
return $this->quoteName($args[0], isset($args[1]) ? $args[1] :
null);
break;
case 'e':
return $this->escape($args[0], isset($args[1]) ? $args[1] : false);
break;
}
}
/**
* Class constructor.
*
* @param JDatabaseDriver $db The database driver.
*
* @since 1.7.0
*/
public function __construct(JDatabaseDriver $db = null)
{
$this->db = $db;
}
/**
* Magic function to convert the query to a string.
*
* @return string The completed query.
*
* @since 1.7.0
*/
public function __toString()
{
$query = '';
if ($this->sql)
{
return $this->sql;
}
switch ($this->type)
{
case 'element':
$query .= (string) $this->element;
break;
case 'select':
$query .= (string) $this->select;
$query .= (string) $this->from;
if ($this->join)
{
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->selectRowNumber === null)
{
if ($this->group)
{
$query .= (string) $this->group;
}
if ($this->having)
{
$query .= (string) $this->having;
}
if ($this->union)
{
$query .= (string) $this->union;
}
if ($this->unionAll)
{
$query .= (string) $this->unionAll;
}
}
if ($this->order)
{
$query .= (string) $this->order;
}
break;
case 'delete':
$query .= (string) $this->delete;
$query .= (string) $this->from;
if ($this->join)
{
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->order)
{
$query .= (string) $this->order;
}
break;
case 'update':
$query .= (string) $this->update;
if ($this->join)
{
// Special case for joins
foreach ($this->join as $join)
{
$query .= (string) $join;
}
}
$query .= (string) $this->set;
if ($this->where)
{
$query .= (string) $this->where;
}
if ($this->order)
{
$query .= (string) $this->order;
}
break;
case 'insert':
$query .= (string) $this->insert;
// Set method
if ($this->set)
{
$query .= (string) $this->set;
}
// Columns-Values method
elseif ($this->values)
{
if ($this->columns)
{
$query .= (string) $this->columns;
}
$elements = $this->values->getElements();
if (!($elements[0] instanceof $this))
{
$query .= ' VALUES ';
}
$query .= (string) $this->values;
}
break;
case 'call':
$query .= (string) $this->call;
break;
case 'exec':
$query .= (string) $this->exec;
break;
}
if ($this instanceof JDatabaseQueryLimitable)
{
$query = $this->processLimit($query, $this->limit,
$this->offset);
}
return $query;
}
/**
* Magic function to get protected variable value
*
* @param string $name The name of the variable.
*
* @return mixed
*
* @since 1.7.0
*/
public function __get($name)
{
return isset($this->$name) ? $this->$name : null;
}
/**
* Add a single column, or array of columns to the CALL clause of the
query.
*
* Note that you must not mix insert, update, delete and select method
calls when building a query.
* The call method can, however, be called multiple times in the same
query.
*
* Usage:
* $query->call('a.*')->call('b.id');
* $query->call(array('a.*', 'b.id'));
*
* @param mixed $columns A string or an array of field names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function call($columns)
{
$this->type = 'call';
if (is_null($this->call))
{
$this->call = new JDatabaseQueryElement('CALL', $columns);
}
else
{
$this->call->append($columns);
}
return $this;
}
/**
* Casts a value to a char.
*
* Ensure that the value is properly quoted before passing to the method.
*
* Usage:
* $query->select($query->castAsChar('a'));
*
* @param string $value The value to cast as a char.
*
* @return string Returns the cast value.
*
* @since 1.7.0
*/
public function castAsChar($value)
{
return $value;
}
/**
* 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 $operator Comparison operator between charLength
integer value and $condition
* @param string $condition Integer value to compare charLength with.
*
* @return string The required char length call.
*
* @since 1.7.0
*/
public function charLength($field, $operator = null, $condition = null)
{
return 'CHAR_LENGTH(' . $field . ')' .
(isset($operator) && isset($condition) ? ' ' . $operator
. ' ' . $condition : '');
}
/**
* Clear data from the query or a specific clause of the query.
*
* @param string $clause Optionally, the name of the clause to clear,
or nothing to clear the whole query.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function clear($clause = null)
{
$this->sql = null;
switch ($clause)
{
case 'select':
$this->select = null;
$this->type = null;
$this->selectRowNumber = null;
break;
case 'delete':
$this->delete = null;
$this->type = null;
break;
case 'update':
$this->update = null;
$this->type = null;
break;
case 'insert':
$this->insert = null;
$this->type = null;
$this->autoIncrementField = null;
break;
case 'from':
$this->from = null;
break;
case 'join':
$this->join = null;
break;
case 'set':
$this->set = null;
break;
case 'where':
$this->where = null;
break;
case 'group':
$this->group = null;
break;
case 'having':
$this->having = null;
break;
case 'order':
$this->order = null;
break;
case 'columns':
$this->columns = null;
break;
case 'values':
$this->values = null;
break;
case 'exec':
$this->exec = null;
$this->type = null;
break;
case 'call':
$this->call = null;
$this->type = null;
break;
case 'limit':
$this->offset = 0;
$this->limit = 0;
break;
case 'offset':
$this->offset = 0;
break;
case 'union':
$this->union = null;
break;
case 'unionAll':
$this->unionAll = null;
break;
default:
$this->type = null;
$this->select = null;
$this->selectRowNumber = null;
$this->delete = null;
$this->update = null;
$this->insert = null;
$this->from = null;
$this->join = null;
$this->set = null;
$this->where = null;
$this->group = null;
$this->having = null;
$this->order = null;
$this->columns = null;
$this->values = null;
$this->autoIncrementField = null;
$this->exec = null;
$this->call = null;
$this->union = null;
$this->unionAll = null;
$this->offset = 0;
$this->limit = 0;
break;
}
return $this;
}
/**
* Adds a column, or array of column names that would be used for an
INSERT INTO statement.
*
* @param mixed $columns A column name, or array of column names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function columns($columns)
{
if (is_null($this->columns))
{
$this->columns = new JDatabaseQueryElement('()', $columns);
}
else
{
$this->columns->append($columns);
}
return $this;
}
/**
* Concatenates an array of column names or values.
*
* Usage:
* $query->select($query->concatenate(array('a',
'b')));
*
* @param array $values An array of values to concatenate.
* @param string $separator As separator to place between each value.
*
* @return string The concatenated values.
*
* @since 1.7.0
*/
public function concatenate($values, $separator = null)
{
if ($separator)
{
return 'CONCATENATE(' . implode(' || ' .
$this->quote($separator) . ' || ', $values) . ')';
}
else
{
return 'CONCATENATE(' . implode(' || ', $values) .
')';
}
}
/**
* Gets the current date and time.
*
* Usage:
* $query->where('published_up <
'.$query->currentTimestamp());
*
* @return string
*
* @since 1.7.0
*/
public function currentTimestamp()
{
return 'CURRENT_TIMESTAMP()';
}
/**
* Returns a PHP date() function compliant date format for the database
driver.
*
* This method is provided for use where the query object is passed to a
function for modification.
* If you have direct access to the database object, it is recommended you
use the getDateFormat method directly.
*
* @return string The format string.
*
* @since 1.7.0
*/
public function dateFormat()
{
if (!($this->db instanceof JDatabaseDriver))
{
throw new
RuntimeException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->getDateFormat();
}
/**
* Creates a formatted dump of the query for debugging purposes.
*
* Usage:
* echo $query->dump();
*
* @return string
*
* @since 1.7.3
*/
public function dump()
{
return '<pre class="jdatabasequery">' .
str_replace('#__', $this->db->getPrefix(), $this) .
'</pre>';
}
/**
* Add a table name to the DELETE clause of the query.
*
* Note that you must not mix insert, update, delete and select method
calls when building a query.
*
* Usage:
* $query->delete('#__a')->where('id = 1');
*
* @param string $table The name of the table to delete from.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function delete($table = null)
{
$this->type = 'delete';
$this->delete = new JDatabaseQueryElement('DELETE', null);
if (!empty($table))
{
$this->from($table);
}
return $this;
}
/**
* Method to escape a string for usage in an SQL statement.
*
* This method is provided for use where the query object is passed to a
function for modification.
* If you have direct access to the database object, it is recommended you
use the escape method directly.
*
* Note that 'e' is an alias for this method as it is in
JDatabaseDriver.
*
* @param string $text The string to be escaped.
* @param boolean $extra Optional parameter to provide extra escaping.
*
* @return string The escaped string.
*
* @since 1.7.0
* @throws RuntimeException if the internal db property is not a valid
object.
*/
public function escape($text, $extra = false)
{
if (!($this->db instanceof JDatabaseDriver))
{
throw new
RuntimeException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->escape($text, $extra);
}
/**
* Add a single column, or array of columns to the EXEC clause of the
query.
*
* Note that you must not mix insert, update, delete and select method
calls when building a query.
* The exec method can, however, be called multiple times in the same
query.
*
* Usage:
* $query->exec('a.*')->exec('b.id');
* $query->exec(array('a.*', 'b.id'));
*
* @param mixed $columns A string or an array of field names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function exec($columns)
{
$this->type = 'exec';
if (is_null($this->exec))
{
$this->exec = new JDatabaseQueryElement('EXEC', $columns);
}
else
{
$this->exec->append($columns);
}
return $this;
}
/**
* Add a table to the FROM clause of the query.
*
* Note that while an array of tables can be provided, it is recommended
you use explicit joins.
*
* Usage:
* $query->select('*')->from('#__a');
*
* @param mixed $tables A string or array of table names.
* This can be a JDatabaseQuery object
(or a child of it) when used
* as a subquery in FROM clause along
with a value for $subQueryAlias.
* @param string $subQueryAlias Alias used when $tables is a
JDatabaseQuery.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @throws RuntimeException
*
* @since 1.7.0
*/
public function from($tables, $subQueryAlias = null)
{
if (is_null($this->from))
{
if ($tables instanceof $this)
{
if (is_null($subQueryAlias))
{
throw new
RuntimeException('JLIB_DATABASE_ERROR_NULL_SUBQUERY_ALIAS');
}
$tables = '( ' . (string) $tables . ' ) AS ' .
$this->quoteName($subQueryAlias);
}
$this->from = new JDatabaseQueryElement('FROM', $tables);
}
else
{
$this->from->append($tables);
}
return $this;
}
/**
* Used to get a string to extract year from date column.
*
* Usage:
*
$query->select($query->year($query->quoteName('dateColumn')));
*
* @param string $date Date column containing year to be extracted.
*
* @return string Returns string to extract year from a date.
*
* @since 3.0.0
*/
public function year($date)
{
return 'YEAR(' . $date . ')';
}
/**
* Used to get a string to extract month from date column.
*
* Usage:
*
$query->select($query->month($query->quoteName('dateColumn')));
*
* @param string $date Date column containing month to be extracted.
*
* @return string Returns string to extract month from a date.
*
* @since 3.0.0
*/
public function month($date)
{
return 'MONTH(' . $date . ')';
}
/**
* Used to get a string to extract day from date column.
*
* Usage:
*
$query->select($query->day($query->quoteName('dateColumn')));
*
* @param string $date Date column containing day to be extracted.
*
* @return string Returns string to extract day from a date.
*
* @since 3.0.0
*/
public function day($date)
{
return 'DAY(' . $date . ')';
}
/**
* Used to get a string to extract hour from date column.
*
* Usage:
*
$query->select($query->hour($query->quoteName('dateColumn')));
*
* @param string $date Date column containing hour to be extracted.
*
* @return string Returns string to extract hour from a date.
*
* @since 3.0.0
*/
public function hour($date)
{
return 'HOUR(' . $date . ')';
}
/**
* Used to get a string to extract minute from date column.
*
* Usage:
*
$query->select($query->minute($query->quoteName('dateColumn')));
*
* @param string $date Date column containing minute to be extracted.
*
* @return string Returns string to extract minute from a date.
*
* @since 3.0.0
*/
public function minute($date)
{
return 'MINUTE(' . $date . ')';
}
/**
* Used to get a string to extract seconds from date column.
*
* Usage:
*
$query->select($query->second($query->quoteName('dateColumn')));
*
* @param string $date Date column containing second to be extracted.
*
* @return string Returns string to extract second from a date.
*
* @since 3.0.0
*/
public function second($date)
{
return 'SECOND(' . $date . ')';
}
/**
* Add a grouping column to the GROUP clause of the query.
*
* Usage:
* $query->group('id');
*
* @param mixed $columns A string or array of ordering columns.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function group($columns)
{
if (is_null($this->group))
{
$this->group = new JDatabaseQueryElement('GROUP BY',
$columns);
}
else
{
$this->group->append($columns);
}
return $this;
}
/**
* A conditions to the HAVING clause of the query.
*
* Usage:
* $query->group('id')->having('COUNT(id) >
5');
*
* @param mixed $conditions A string or array of columns.
* @param string $glue The glue by which to join the conditions.
Defaults to AND.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function having($conditions, $glue = 'AND')
{
if (is_null($this->having))
{
$glue = strtoupper($glue);
$this->having = new JDatabaseQueryElement('HAVING',
$conditions, " $glue ");
}
else
{
$this->having->append($conditions);
}
return $this;
}
/**
* Add an INNER JOIN clause to the query.
*
* Usage:
* $query->innerJoin('b ON b.id =
a.id')->innerJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function innerJoin($condition)
{
$this->join('INNER', $condition);
return $this;
}
/**
* Add a table name to the INSERT clause of the query.
*
* Note that you must not mix insert, update, delete and select method
calls when building a query.
*
* Usage:
* $query->insert('#__a')->set('id = 1');
* $query->insert('#__a')->columns('id,
title')->values('1,2')->values('3,4');
* $query->insert('#__a')->columns('id,
title')->values(array('1,2', '3,4'));
*
* @param mixed $table The name of the table to insert data
into.
* @param boolean $incrementField The name of the field to auto
increment.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function insert($table, $incrementField=false)
{
$this->type = 'insert';
$this->insert = new JDatabaseQueryElement('INSERT INTO',
$table);
$this->autoIncrementField = $incrementField;
return $this;
}
/**
* Add a JOIN clause to the query.
*
* Usage:
* $query->join('INNER', 'b ON b.id = a.id);
*
* @param string $type The type of join. This string is
prepended to the JOIN keyword.
* @param string $conditions A string or array of conditions.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function join($type, $conditions)
{
if (is_null($this->join))
{
$this->join = array();
}
$this->join[] = new JDatabaseQueryElement(strtoupper($type) . '
JOIN', $conditions);
return $this;
}
/**
* Add a LEFT JOIN clause to the query.
*
* Usage:
* $query->leftJoin('b ON b.id = a.id')->leftJoin('c
ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function leftJoin($condition)
{
$this->join('LEFT', $condition);
return $this;
}
/**
* Get the length of a string in bytes.
*
* Note, use 'charLength' to find the number of characters in a
string.
*
* Usage:
* query->where($query->length('a').' > 3');
*
* @param string $value The string to measure.
*
* @return int
*
* @since 1.7.0
*/
public function length($value)
{
return 'LENGTH(' . $value . ')';
}
/**
* Get the null or zero representation of a timestamp for the database
driver.
*
* This method is provided for use where the query object is passed to a
function for modification.
* If you have direct access to the database object, it is recommended you
use the nullDate method directly.
*
* Usage:
* $query->where('modified_date <>
'.$query->nullDate());
*
* @param boolean $quoted Optionally wraps the null date in database
quotes (true by default).
*
* @return string Null or zero representation of a timestamp.
*
* @since 1.7.0
*/
public function nullDate($quoted = true)
{
if (!($this->db instanceof JDatabaseDriver))
{
throw new
RuntimeException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
$result = $this->db->getNullDate($quoted);
if ($quoted)
{
return $this->db->quote($result);
}
return $result;
}
/**
* Add an ordering column to the ORDER clause of the query.
*
* Usage:
* $query->order('foo')->order('bar');
* $query->order(array('foo','bar'));
*
* @param mixed $columns A string or array of ordering columns.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function order($columns)
{
if (is_null($this->order))
{
$this->order = new JDatabaseQueryElement('ORDER BY',
$columns);
}
else
{
$this->order->append($columns);
}
return $this;
}
/**
* Add an OUTER JOIN clause to the query.
*
* Usage:
* $query->outerJoin('b ON b.id =
a.id')->outerJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function outerJoin($condition)
{
$this->join('OUTER', $condition);
return $this;
}
/**
* Method to quote and optionally escape a string to database requirements
for insertion into the database.
*
* This method is provided for use where the query object is passed to a
function for modification.
* If you have direct access to the database object, it is recommended you
use the quote method directly.
*
* Note that 'q' is an alias for this method as it is in
JDatabaseDriver.
*
* Usage:
* $query->quote('fulltext');
* $query->q('fulltext');
* $query->q(array('option', 'fulltext'));
*
* @param mixed $text A string or an array of strings to quote.
* @param boolean $escape True to escape the string, false to leave it
unchanged.
*
* @return string The quoted input string.
*
* @since 1.7.0
* @throws RuntimeException if the internal db property is not a valid
object.
*/
public function quote($text, $escape = true)
{
if (!($this->db instanceof JDatabaseDriver))
{
throw new
RuntimeException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->quote($text, $escape);
}
/**
* Wrap an SQL statement identifier name such as column, table or database
names in quotes to prevent injection
* risks and reserved word conflicts.
*
* This method is provided for use where the query object is passed to a
function for modification.
* If you have direct access to the database object, it is recommended you
use the quoteName method directly.
*
* Note that 'qn' is an alias for this method as it is in
JDatabaseDriver.
*
* Usage:
* $query->quoteName('#__a');
* $query->qn('#__a');
*
* @param mixed $name The identifier name to wrap in quotes, or an
array of identifier names to wrap in quotes.
* Each type supports dot-notation name.
* @param mixed $as The AS query part associated to $name. It can be
string or array, in latter case it has to be
* same length of $name; if is null there will not
be any AS part for string or array element.
*
* @return mixed The quote wrapped name, same type of $name.
*
* @since 1.7.0
* @throws RuntimeException if the internal db property is not a valid
object.
*/
public function quoteName($name, $as = null)
{
if (!($this->db instanceof JDatabaseDriver))
{
throw new
RuntimeException('JLIB_DATABASE_ERROR_INVALID_DB_OBJECT');
}
return $this->db->quoteName($name, $as);
}
/**
* Add a RIGHT JOIN clause to the query.
*
* Usage:
* $query->rightJoin('b ON b.id =
a.id')->rightJoin('c ON c.id = b.id');
*
* @param string $condition The join condition.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function rightJoin($condition)
{
$this->join('RIGHT', $condition);
return $this;
}
/**
* Add a single column, or array of columns to the SELECT clause of the
query.
*
* Note that you must not mix insert, update, delete and select method
calls when building a query.
* The select method can, however, be called multiple times in the same
query.
*
* Usage:
* $query->select('a.*')->select('b.id');
* $query->select(array('a.*', 'b.id'));
*
* @param mixed $columns A string or an array of field names.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function select($columns)
{
$this->type = 'select';
if (is_null($this->select))
{
$this->select = new JDatabaseQueryElement('SELECT',
$columns);
}
else
{
$this->select->append($columns);
}
return $this;
}
/**
* Add a single condition string, or an array of strings to the SET clause
of the query.
*
* Usage:
* $query->set('a = 1')->set('b = 2');
* $query->set(array('a = 1', 'b = 2');
*
* @param mixed $conditions A string or array of string conditions.
* @param string $glue The glue by which to join the condition
strings. Defaults to ,.
* Note that the glue is set on first use
and cannot be changed.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function set($conditions, $glue = ',')
{
if (is_null($this->set))
{
$glue = strtoupper($glue);
$this->set = new JDatabaseQueryElement('SET', $conditions,
"\n\t$glue ");
}
else
{
$this->set->append($conditions);
}
return $this;
}
/**
* Allows a direct query to be provided to the database
* driver's setQuery() method, but still allow queries
* to have bounded variables.
*
* Usage:
* $query->setQuery('select * from #__users');
*
* @param mixed $sql An SQL Query
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.0.0
*/
public function setQuery($sql)
{
$this->sql = $sql;
return $this;
}
/**
* Add a table name to the UPDATE clause of the query.
*
* Note that you must not mix insert, update, delete and select method
calls when building a query.
*
* Usage:
* $query->update('#__foo')->set(...);
*
* @param string $table A table to update.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function update($table)
{
$this->type = 'update';
$this->update = new JDatabaseQueryElement('UPDATE', $table);
return $this;
}
/**
* Adds a tuple, or array of tuples that would be used as values for an
INSERT INTO statement.
*
* Usage:
* $query->values('1,2,3')->values('4,5,6');
* $query->values(array('1,2,3', '4,5,6'));
*
* @param string $values A single tuple, or array of tuples.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function values($values)
{
if (is_null($this->values))
{
$this->values = new JDatabaseQueryElement('()', $values,
'),(');
}
else
{
$this->values->append($values);
}
return $this;
}
/**
* Add a single condition, or an array of conditions to the WHERE clause
of the query.
*
* Usage:
* $query->where('a = 1')->where('b = 2');
* $query->where(array('a = 1', 'b = 2'));
*
* @param mixed $conditions A string or array of where conditions.
* @param string $glue The glue by which to join the conditions.
Defaults to AND.
* Note that the glue is set on first use
and cannot be changed.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 1.7.0
*/
public function where($conditions, $glue = 'AND')
{
if (is_null($this->where))
{
$glue = strtoupper($glue);
$this->where = new JDatabaseQueryElement('WHERE',
$conditions, " $glue ");
}
else
{
$this->where->append($conditions);
}
return $this;
}
/**
* Extend the WHERE clause with a single condition or an array of
conditions, with a potentially
* different logical operator from the one in the current WHERE clause.
*
* Usage:
* $query->where(array('a = 1', 'b =
2'))->extendWhere('XOR', array('c = 3', 'd
= 4'));
* will produce: WHERE ((a = 1 AND b = 2) XOR (c = 3 AND d = 4)
*
* @param string $outerGlue The glue by which to join the conditions
to the current WHERE conditions.
* @param mixed $conditions A string or array of WHERE conditions.
* @param string $innerGlue The glue by which to join the conditions.
Defaults to AND.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.6
*/
public function extendWhere($outerGlue, $conditions, $innerGlue =
'AND')
{
// Replace the current WHERE with a new one which has the old one as an
unnamed child.
$this->where = new JDatabaseQueryElement('WHERE',
$this->where->setName('()'), " $outerGlue ");
// Append the new conditions as a new unnamed child.
$this->where->append(new JDatabaseQueryElement('()',
$conditions, " $innerGlue "));
return $this;
}
/**
* Extend the WHERE clause with an OR and a single condition or an array
of conditions.
*
* Usage:
* $query->where(array('a = 1', 'b =
2'))->orWhere(array('c = 3', 'd = 4'));
* will produce: WHERE ((a = 1 AND b = 2) OR (c = 3 AND d = 4)
*
* @param mixed $conditions A string or array of WHERE conditions.
* @param string $glue The glue by which to join the conditions.
Defaults to AND.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.6
*/
public function orWhere($conditions, $glue = 'AND')
{
return $this->extendWhere('OR', $conditions, $glue);
}
/**
* Extend the WHERE clause with an AND and a single condition or an array
of conditions.
*
* Usage:
* $query->where(array('a = 1', 'b =
2'))->andWhere(array('c = 3', 'd = 4'));
* will produce: WHERE ((a = 1 AND b = 2) AND (c = 3 OR d = 4)
*
* @param mixed $conditions A string or array of WHERE conditions.
* @param string $glue The glue by which to join the conditions.
Defaults to OR.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.6
*/
public function andWhere($conditions, $glue = 'OR')
{
return $this->extendWhere('AND', $conditions, $glue);
}
/**
* Method to provide deep copy support to nested objects and
* arrays when cloning.
*
* @return void
*
* @since 1.7.3
*/
public function __clone()
{
foreach ($this as $k => $v)
{
if ($k === 'db')
{
continue;
}
if (is_object($v) || is_array($v))
{
$this->{$k} = unserialize(serialize($v));
}
}
}
/**
* Add a query to UNION with the current query.
* Multiple unions each require separate statements and create an array of
unions.
*
* Usage (the $query base query MUST be a select query):
* $query->union('SELECT name FROM #__foo')
* $query->union('SELECT name FROM #__foo', true)
* $query->union($query2)->union($query3)
*
* The $query attribute as an array is deprecated and will not be
supported in 4.0.
*
* $query->union(array('SELECT name FROM
#__foo','SELECT name FROM #__bar'))
* $query->union(array($query2, $query3))
*
* @param mixed $query The JDatabaseQuery object or string to
union.
* @param boolean $distinct True to only return distinct rows from the
union.
* @param string $glue The glue by which to join the conditions.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @link http://dev.mysql.com/doc/refman/5.0/en/union.html
*
* @since 3.0.0
*/
public function union($query, $distinct = false, $glue = '')
{
// Set up the DISTINCT flag, the name with parentheses, and the glue.
if ($distinct)
{
$name = 'UNION DISTINCT ()';
$glue = ')' . PHP_EOL . 'UNION DISTINCT (';
}
else
{
$glue = ')' . PHP_EOL . 'UNION (';
$name = 'UNION ()';
}
if (is_array($query))
{
JLog::add('Query attribute as an array is deprecated.',
JLog::WARNING, 'deprecated');
}
// Get the JDatabaseQueryElement if it does not exist
if (is_null($this->union))
{
$this->union = new JDatabaseQueryElement($name, $query,
"$glue");
}
// Otherwise append the second UNION.
else
{
$this->union->append($query);
}
return $this;
}
/**
* Add a query to UNION DISTINCT with the current query. Simply a proxy to
union with the DISTINCT keyword.
*
* Usage:
* $query->unionDistinct('SELECT name FROM #__foo')
*
* @param mixed $query The JDatabaseQuery object or string to union.
* @param string $glue The glue by which to join the conditions.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @see union
*
* @since 3.0.0
* @deprecated 4.0 Use union() instead.
*/
public function unionDistinct($query, $glue = '')
{
$distinct = true;
// Apply the distinct flag to the union.
return $this->union($query, $distinct, $glue);
}
/**
* Find and replace sprintf-like tokens in a format string.
* Each token takes one of the following forms:
* %% - A literal percent character.
* %[t] - Where [t] is a type specifier.
* %[n]$[x] - Where [n] is an argument specifier and [t] is a type
specifier.
*
* Types:
* a - Numeric: Replacement text is coerced to a numeric type but not
quoted or escaped.
* e - Escape: Replacement text is passed to $this->escape().
* E - Escape (extra): Replacement text is passed to $this->escape()
with true as the second argument.
* n - Name Quote: Replacement text is passed to $this->quoteName().
* q - Quote: Replacement text is passed to $this->quote().
* Q - Quote (no escape): Replacement text is passed to $this->quote()
with false as the second argument.
* r - Raw: Replacement text is used as-is. (Be careful)
*
* Date Types:
* - Replacement text automatically quoted (use uppercase for Name Quote).
* - Replacement text should be a string in date format or name of a date
column.
* y/Y - Year
* m/M - Month
* d/D - Day
* h/H - Hour
* i/I - Minute
* s/S - Second
*
* Invariable Types:
* - Takes no argument.
* - Argument index not incremented.
* t - Replacement text is the result of $this->currentTimestamp().
* z - Replacement text is the result of $this->nullDate(false).
* Z - Replacement text is the result of $this->nullDate(true).
*
* Usage:
* $query->format('SELECT %1$n FROM %2$n WHERE %3$n = %4$a',
'foo', '#__foo', 'bar', 1);
* Returns: SELECT `foo` FROM `#__foo` WHERE `bar` = 1
*
* Notes:
* The argument specifier is optional but recommended for clarity.
* The argument index used for unspecified tokens is incremented only when
used.
*
* @param string $format The formatting string.
*
* @return string Returns a string produced according to the formatting
string.
*
* @since 3.1.4
*/
public function format($format)
{
$query = $this;
$args = array_slice(func_get_args(), 1);
array_unshift($args, null);
$i = 1;
$func = function ($match) use ($query, $args, &$i)
{
if (isset($match[6]) && $match[6] == '%')
{
return '%';
}
// No argument required, do not increment the argument index.
switch ($match[5])
{
case 't':
return $query->currentTimestamp();
break;
case 'z':
return $query->nullDate(false);
break;
case 'Z':
return $query->nullDate(true);
break;
}
// Increment the argument index only if argument specifier not provided.
$index = is_numeric($match[4]) ? (int) $match[4] : $i++;
if (!$index || !isset($args[$index]))
{
// TODO - What to do? sprintf() throws a Warning in these cases.
$replacement = '';
}
else
{
$replacement = $args[$index];
}
switch ($match[5])
{
case 'a':
return 0 + $replacement;
break;
case 'e':
return $query->escape($replacement);
break;
case 'E':
return $query->escape($replacement, true);
break;
case 'n':
return $query->quoteName($replacement);
break;
case 'q':
return $query->quote($replacement);
break;
case 'Q':
return $query->quote($replacement, false);
break;
case 'r':
return $replacement;
break;
// Dates
case 'y':
return $query->year($query->quote($replacement));
break;
case 'Y':
return $query->year($query->quoteName($replacement));
break;
case 'm':
return $query->month($query->quote($replacement));
break;
case 'M':
return $query->month($query->quoteName($replacement));
break;
case 'd':
return $query->day($query->quote($replacement));
break;
case 'D':
return $query->day($query->quoteName($replacement));
break;
case 'h':
return $query->hour($query->quote($replacement));
break;
case 'H':
return $query->hour($query->quoteName($replacement));
break;
case 'i':
return $query->minute($query->quote($replacement));
break;
case 'I':
return $query->minute($query->quoteName($replacement));
break;
case 's':
return $query->second($query->quote($replacement));
break;
case 'S':
return $query->second($query->quoteName($replacement));
break;
}
return '';
};
/**
* Regexp to find and replace all tokens.
* Matched fields:
* 0: Full token
* 1: Everything following '%'
* 2: Everything following '%' unless '%'
* 3: Argument specifier and '$'
* 4: Argument specifier
* 5: Type specifier
* 6: '%' if full token is '%%'
*/
return
preg_replace_callback('#%(((([\d]+)\$)?([aeEnqQryYmMdDhHiIsStzZ]))|(%))#',
$func, $format);
}
/**
* Add to the current date and time.
* Usage:
* $query->select($query->dateAdd());
* Prefixing the interval with a - (negative sign) will cause subtraction
to be used.
* Note: Not all drivers support all units.
*
* @param string $date The db quoted string representation of the
date to add to. May be date or datetime
* @param string $interval The string representation of the
appropriate number of units
* @param string $datePart The part of the date to perform the
addition on
*
* @return string The string with the appropriate sql for addition of
dates
*
* @link
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_date-add
* @since 3.2.0
*/
public function dateAdd($date, $interval, $datePart)
{
return 'DATE_ADD(' . $date . ', INTERVAL ' .
$interval . ' ' . $datePart . ')';
}
/**
* Add a query to UNION ALL with the current query.
* Multiple unions each require separate statements and create an array of
unions.
*
* Usage:
* $query->union('SELECT name FROM #__foo')
*
* The $query attribute as an array is deprecated and will not be
supported in 4.0.
*
* $query->union(array('SELECT name FROM
#__foo','SELECT name FROM #__bar'))
*
* @param mixed $query The JDatabaseQuery object or string to
union.
* @param boolean $distinct Not used - ignored.
* @param string $glue Not used - ignored.
*
* @return JDatabaseQuery Returns this object to allow chaining.
*
* @see union
*
* @since 3.2.0
*/
public function unionAll($query, $distinct = false, $glue = '')
{
$glue = ')' . PHP_EOL . 'UNION ALL (';
$name = 'UNION ALL ()';
if (is_array($query))
{
JLog::add('Query attribute as an array is deprecated.',
JLog::WARNING, 'deprecated');
}
// Get the JDatabaseQueryElement if it does not exist
if (is_null($this->unionAll))
{
$this->unionAll = new JDatabaseQueryElement($name, $query,
"$glue");
}
// Otherwise append the second UNION.
else
{
$this->unionAll->append($query);
}
return $this;
}
/**
* 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.
*
* @return void
*
* @since 3.7.0
* @throws RuntimeException
*/
protected function validateRowNumber($orderBy, $orderColumnAlias)
{
if ($this->selectRowNumber)
{
throw new RuntimeException("Method 'selectRowNumber' can
be called only once per instance.");
}
$this->type = 'select';
$this->selectRowNumber = array(
'orderBy' => $orderBy,
'orderColumnAlias' => $orderColumnAlias,
);
}
/**
* 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 JDatabaseQuery Returns this object to allow chaining.
*
* @since 3.7.0
* @throws RuntimeException
*/
public function selectRowNumber($orderBy, $orderColumnAlias)
{
$this->validateRowNumber($orderBy, $orderColumnAlias);
$this->select("ROW_NUMBER() OVER (ORDER BY $orderBy) AS
$orderColumnAlias");
return $this;
}
}
PK�d�[��ggdriver/pgsql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PostgreSQL PDO Database Driver
*
* @link https://www.php.net/manual/en/ref.pdo-mysql.php
* @since 3.9.0
*/
class JDatabaseDriverPgsql extends JDatabaseDriverPdo
{
/**
* The database driver name
*
* @var string
* @since 3.9.0
*/
public $name = 'pgsql';
/**
* The character(s) used to quote SQL statement names such as table names
or field names,
* etc. The child classes should define this as necessary. If a single
character string the
* same character is used for both sides of the quoted name, else the
first character will be
* used for the opening quote and the second for the closing quote.
*
* @var string
* @since 3.9.0
*/
protected $nameQuote = '"';
/**
* The null or zero representation of a timestamp for the database driver.
This should be
* defined in child classes to hold the appropriate value for the engine.
*
* @var string
* @since 3.9.0
*/
protected $nullDate = '1970-01-01 00:00:00';
/**
* The minimum supported database version.
*
* @var string
* @since 3.9.0
*/
protected static $dbMinimum = '8.3.18';
/**
* Operator used for concatenation
*
* @var string
* @since 3.9.0
*/
protected $concat_operator = '||';
/**
* Database object constructor
*
* @param array $options List of options used to configure the
connection
*
* @since 3.9.0
*/
public function __construct($options)
{
$options['driver'] = 'pgsql';
$options['host'] = isset($options['host']) ?
$options['host'] : 'localhost';
$options['user'] = isset($options['user']) ?
$options['user'] : '';
$options['password'] = isset($options['password']) ?
$options['password'] : '';
$options['database'] = isset($options['database']) ?
$options['database'] : '';
$options['port'] = isset($options['port']) ?
$options['port'] : null;
// Finalize initialization
parent::__construct($options);
}
/**
* Connects to the database if needed.
*
* @return void Returns void if the database connected successfully.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function connect()
{
if ($this->getConnection())
{
return;
}
parent::connect();
$this->setQuery('SET standard_conforming_strings =
off')->execute();
}
/**
* Drops a table from the database.
*
* @param string $tableName The name of the database table to drop.
* @param boolean $ifExists Optionally specify that the table must
exist before it is dropped.
*
* @return boolean true
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function dropTable($tableName, $ifExists = true)
{
$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS
' : '') . $this->quoteName($tableName))->execute();
return true;
}
/**
* Method to get the database collation in use by sampling a text field of
a table in the database.
*
* @return mixed The collation in use by the database or boolean false
if not supported.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getCollation()
{
$this->setQuery('SHOW LC_COLLATE');
$array = $this->loadAssocList();
return $array[0]['lc_collate'];
}
/**
* Method to get the database connection collation in use by sampling a
text field of a table in the database.
*
* @return mixed The collation in use by the database connection
(string) or boolean false if not supported.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getConnectionCollation()
{
$this->setQuery('SHOW LC_COLLATE');
$array = $this->loadAssocList();
return $array[0]['lc_collate'];
}
/**
* Internal function to get the name of the default schema for the current
PostgreSQL connection.
* That is the schema where tables are created by Joomla.
*
* @return string
*
* @since 3.9.24
*/
private function getDefaultSchema()
{
// Supported since PostgreSQL 7.3
$this->setQuery('SELECT (current_schemas(false))[1]');
return $this->loadResult();
}
/**
* Shows the table CREATE statement that creates the given tables.
*
* This is unsupported by PostgreSQL.
*
* @param mixed $tables A table name or a list of table names.
*
* @return string An empty string because this function is not supported
by PostgreSQL.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getTableCreate($tables)
{
return '';
}
/**
* Retrieves field information about a given table.
*
* @param string $table The name of the database table.
* @param boolean $typeOnly True to only return field types.
*
* @return array An array of fields for the database table.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getTableColumns($table, $typeOnly = true)
{
$this->connect();
$result = array();
$tableSub = $this->replacePrefix($table);
$defaultSchema = $this->getDefaultSchema();
$this->setQuery('
SELECT a.attname AS "column_name",
pg_catalog.format_type(a.atttypid, a.atttypmod) as "type",
CASE WHEN a.attnotnull IS TRUE
THEN \'NO\'
ELSE \'YES\'
END AS "null",
CASE WHEN pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true) IS NOT
NULL
THEN pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true)
END as "Default",
CASE WHEN pg_catalog.col_description(a.attrelid, a.attnum) IS NULL
THEN \'\'
ELSE pg_catalog.col_description(a.attrelid, a.attnum)
END AS "comments"
FROM pg_catalog.pg_attribute a
LEFT JOIN pg_catalog.pg_attrdef adef ON a.attrelid=adef.adrelid AND
a.attnum=adef.adnum
LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid
WHERE a.attrelid =
(SELECT oid FROM pg_catalog.pg_class WHERE relname=' .
$this->quote($tableSub) . '
AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
nspname = ' . $this->quote($defaultSchema) . ')
)
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum'
);
$fields = $this->loadObjectList();
if ($typeOnly)
{
foreach ($fields as $field)
{
$result[$field->column_name] = preg_replace('/[(0-9)]/',
'', $field->type);
}
}
else
{
foreach ($fields as $field)
{
if (stristr(strtolower($field->type), 'character
varying'))
{
$field->Default = '';
}
if (stristr(strtolower($field->type), 'text'))
{
$field->Default = '';
}
// Do some dirty translation to MySQL output.
// @todo: Come up with and implement a standard across databases.
$result[$field->column_name] = (object) array(
'column_name' => $field->column_name,
'type' => $field->type,
'null' => $field->null,
'Default' => $field->Default,
'comments' => '',
'Field' => $field->column_name,
'Type' => $field->type,
'Null' => $field->null,
// @todo: Improve query above to return primary key info as well
// 'Key' => ($field->PK == '1' ?
'PRI' : '')
);
}
}
// Change Postgresql's NULL::* type with PHP's null one
foreach ($fields as $field)
{
if (preg_match('/^NULL::*/', $field->Default))
{
$field->Default = null;
}
}
return $result;
}
/**
* Get the details list of keys for a table.
*
* @param string $table The name of the table.
*
* @return array An array of the column specification for the table.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getTableKeys($table)
{
$this->connect();
// To check if table exists and prevent SQL injection
$tableList = $this->getTableList();
if (in_array($table, $tableList, true))
{
// Get the details columns information.
$this->setQuery('
SELECT indexname AS "idxName", indisprimary AS
"isPrimary", indisunique AS "isUnique",
CASE WHEN indisprimary = true THEN
( SELECT \'ALTER TABLE \' || tablename || \' ADD
\' || pg_catalog.pg_get_constraintdef(const.oid, true)
FROM pg_constraint AS const WHERE const.conname=
pgClassFirst.relname )
ELSE pg_catalog.pg_get_indexdef(indexrelid, 0, true)
END AS "Query"
FROM pg_indexes
LEFT JOIN pg_class AS pgClassFirst ON indexname=pgClassFirst.relname
LEFT JOIN pg_index AS pgIndex ON pgClassFirst.oid=pgIndex.indexrelid
WHERE tablename=' . $this->quote($table) . ' ORDER BY
indkey'
);
return $this->loadObjectList();
}
return false;
}
/**
* Method to get an array of all tables in the database.
*
* @return array An array of all the tables in the database.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getTableList()
{
$query = $this->getQuery(true)
->select('table_name')
->from('information_schema.tables')
->where('table_type = ' . $this->quote('BASE
TABLE'))
->where('table_schema NOT IN (' .
$this->quote('pg_catalog') . ', ' .
$this->quote('information_schema') . ')')
->order('table_name ASC');
$this->setQuery($query);
return $this->loadColumn();
}
/**
* Get the details list of sequences for a table.
*
* @param string $table The name of the table.
*
* @return array An array of sequences specification for the table.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function getTableSequences($table)
{
// To check if table exists and prevent SQL injection
$tableList = $this->getTableList();
if (in_array($table, $tableList, true))
{
$name = array(
's.relname', 'n.nspname', 't.relname',
'a.attname', 'info.data_type',
'info.minimum_value', 'info.maximum_value',
'info.increment', 'info.cycle_option'
);
$as = array('sequence', 'schema', 'table',
'column', 'data_type', 'minimum_value',
'maximum_value', 'increment',
'cycle_option');
if (version_compare($this->getVersion(), '9.1.0') >= 0)
{
$name[] .= 'info.start_value';
$as[] .= 'start_value';
}
// Get the details columns information.
$query = $this->getQuery(true)
->select($this->quoteName($name, $as))
->from('pg_class AS s')
->leftJoin("pg_depend d ON d.objid = s.oid AND d.classid =
'pg_class'::regclass AND d.refclassid =
'pg_class'::regclass")
->leftJoin('pg_class t ON t.oid = d.refobjid')
->leftJoin('pg_namespace n ON n.oid = t.relnamespace')
->leftJoin('pg_attribute a ON a.attrelid = t.oid AND a.attnum =
d.refobjsubid')
->leftJoin('information_schema.sequences AS info ON
info.sequence_name = s.relname')
->where('s.relkind = ' . $this->quote('S') .
' AND d.deptype = ' . $this->quote('a') . ' AND
t.relname = ' . $this->quote($table));
$this->setQuery($query);
return $this->loadObjectList();
}
return false;
}
/**
* Locks a table in the database.
*
* @param string $tableName The name of the table to unlock.
*
* @return JDatabaseDriverPgsql Returns this object to support chaining.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function lockTable($tableName)
{
$this->transactionStart();
$this->setQuery('LOCK TABLE ' .
$this->quoteName($tableName) . ' IN ACCESS EXCLUSIVE
MODE')->execute();
return $this;
}
/**
* Renames a table in the database.
*
* @param string $oldTable The name of the table to be renamed
* @param string $newTable The new name for the table.
* @param string $backup Not used by PostgreSQL.
* @param string $prefix Not used by PostgreSQL.
*
* @return JDatabaseDriverPgsql Returns this object to support chaining.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function renameTable($oldTable, $newTable, $backup = null, $prefix
= null)
{
$this->connect();
// To check if table exists and prevent SQL injection
$tableList = $this->getTableList();
// Origin Table does not exist
if (!in_array($oldTable, $tableList, true))
{
// Origin Table not found
throw new \RuntimeException('Table not found in Postgresql
database.');
}
// Rename indexes
$subQuery = $this->getQuery(true)
->select('indexrelid')
->from('pg_index, pg_class')
->where('pg_class.relname = ' . $this->quote($oldTable))
->where('pg_class.oid = pg_index.indrelid');
$this->setQuery(
$this->getQuery(true)
->select('relname')
->from('pg_class')
->where('oid IN (' . (string) $subQuery . ')')
);
$oldIndexes = $this->loadColumn();
foreach ($oldIndexes as $oldIndex)
{
$changedIdxName = str_replace($oldTable, $newTable, $oldIndex);
$this->setQuery('ALTER INDEX ' .
$this->escape($oldIndex) . ' RENAME TO ' .
$this->escape($changedIdxName))->execute();
}
// Rename sequences
$subQuery = $this->getQuery(true)
->select('oid')
->from('pg_namespace')
->where('nspname NOT LIKE ' .
$this->quote('pg_%'))
->where('nspname != ' .
$this->quote('information_schema'));
$this->setQuery(
$this->getQuery(true)
->select('relname')
->from('pg_class')
->where('relkind = ' . $this->quote('S'))
->where('relnamespace IN (' . (string) $subQuery .
')')
->where('relname LIKE ' .
$this->quote("%$oldTable%"))
);
$oldSequences = $this->loadColumn();
foreach ($oldSequences as $oldSequence)
{
$changedSequenceName = str_replace($oldTable, $newTable, $oldSequence);
$this->setQuery('ALTER SEQUENCE ' .
$this->escape($oldSequence) . ' RENAME TO ' .
$this->escape($changedSequenceName))->execute();
}
// Rename table
$this->setQuery('ALTER TABLE ' . $this->escape($oldTable)
. ' RENAME TO ' . $this->escape($newTable))->execute();
return true;
}
/**
* This function return a field value as a prepared string to be used in a
SQL statement.
*
* @param array $columns Array of table's column returned by
::getTableColumns.
* @param string $fieldName The table field's name.
* @param string $fieldValue The variable value to quote and return.
*
* @return string The quoted string.
*
* @since 3.9.0
*/
public function sqlValue($columns, $fieldName, $fieldValue)
{
switch ($columns[$fieldName])
{
case 'boolean':
$val = 'NULL';
if ($fieldValue === 't' || $fieldValue === true ||
$fieldValue === 1 || $fieldValue === '1')
{
$val = 'TRUE';
}
elseif ($fieldValue === 'f' || $fieldValue === false ||
$fieldValue === 0 || $fieldValue === '0')
{
$val = 'FALSE';
}
break;
case 'bigint':
case 'bigserial':
case 'integer':
case 'money':
case 'numeric':
case 'real':
case 'smallint':
case 'serial':
case 'numeric,':
$val = $fieldValue === '' ? 'NULL' : $fieldValue;
break;
case 'date':
case 'timestamp without time zone':
if (empty($fieldValue))
{
$fieldValue = $this->getNullDate();
}
$val = $this->quote($fieldValue);
break;
default:
$val = $this->quote($fieldValue);
break;
}
return $val;
}
/**
* Method to commit a transaction.
*
* @param boolean $toSavepoint If true, commit to the last savepoint.
*
* @return void
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function transactionCommit($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('COMMIT')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$this->transactionDepth--;
}
/**
* Method to roll back a transaction.
*
* @param boolean $toSavepoint If true, rollback to the last
savepoint.
*
* @return void
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function transactionRollback($toSavepoint = false)
{
$this->connect();
if (!$toSavepoint || $this->transactionDepth <= 1)
{
if ($this->setQuery('ROLLBACK')->execute())
{
$this->transactionDepth = 0;
}
return;
}
$savepoint = 'SP_' . ($this->transactionDepth - 1);
$this->setQuery('ROLLBACK TO SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth--;
$this->setQuery('RELEASE SAVEPOINT ' .
$this->quoteName($savepoint))->execute();
}
}
/**
* Method to initialize a transaction.
*
* @param boolean $asSavepoint If true and a transaction is already
active, a savepoint will be created.
*
* @return void
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function transactionStart($asSavepoint = false)
{
$this->connect();
if (!$asSavepoint || !$this->transactionDepth)
{
if ($this->setQuery('START TRANSACTION')->execute())
{
$this->transactionDepth = 1;
}
return;
}
$savepoint = 'SP_' . $this->transactionDepth;
$this->setQuery('SAVEPOINT ' .
$this->quoteName($savepoint));
if ($this->execute())
{
$this->transactionDepth++;
}
}
/**
* Inserts a row into a table based on an object's properties.
*
* @param string $table The name of the database table to insert
into.
* @param object &$object A reference to an object whose public
properties match the table fields.
* @param string $key The name of the primary key. If provided the
object property is updated.
*
* @return boolean True on success.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function insertObject($table, &$object, $key = null)
{
$columns = $this->getTableColumns($table);
$fields = array();
$values = array();
// Iterate over the object variables to build the query fields and
values.
foreach (get_object_vars($object) as $k => $v)
{
// Skip columns that don't exist in the table.
if (!array_key_exists($k, $columns))
{
continue;
}
// Only process non-null scalars.
if (is_array($v) || is_object($v) || $v === null)
{
continue;
}
// Ignore any internal fields or primary keys with value 0.
if (($k[0] === '_') || ($k == $key && (($v === 0) ||
($v === '0'))))
{
continue;
}
// Prepare and sanitize the fields and values for the database query.
$fields[] = $this->quoteName($k);
$values[] = $this->sqlValue($columns, $k, $v);
}
// Create the base insert statement.
$query = $this->getQuery(true);
$query->insert($this->quoteName($table))
->columns($fields)
->values(implode(',', $values));
$retVal = false;
if ($key)
{
$query->returning($key);
// Set the query and execute the insert.
$this->setQuery($query);
$id = $this->loadResult();
if ($id)
{
$object->$key = $id;
$retVal = true;
}
}
else
{
// Set the query and execute the insert.
$this->setQuery($query);
if ($this->execute())
{
$retVal = true;
}
}
return $retVal;
}
/**
* Test to see if the PostgreSQL connector is available.
*
* @return boolean True on success, false otherwise.
*
* @since 3.9.0
*/
public static function isSupported()
{
return class_exists('PDO') &&
in_array('pgsql', PDO::getAvailableDrivers(), true);
}
/**
* Returns an array containing database's table list.
*
* @return array The database's table list.
*
* @since 3.9.0
*/
public function showTables()
{
$query = $this->getQuery(true)
->select('table_name')
->from('information_schema.tables')
->where('table_type=' . $this->quote('BASE
TABLE'))
->where('table_schema NOT IN (' .
$this->quote('pg_catalog') . ', ' .
$this->quote('information_schema') . ' )');
$this->setQuery($query);
return $this->loadColumn();
}
/**
* Get the substring position inside a string
*
* @param string $substring The string being sought
* @param string $string The string/column being searched
*
* @return integer The position of $substring in $string
*
* @since 3.9.0
*/
public function getStringPositionSql($substring, $string)
{
$this->setQuery("SELECT POSITION($substring IN $string)");
$position = $this->loadRow();
return $position['position'];
}
/**
* Generate a random value
*
* @return float The random generated number
*
* @since 3.9.0
*/
public function getRandom()
{
$this->setQuery('SELECT RANDOM()');
$random = $this->loadAssoc();
return $random['random'];
}
/**
* Get the query string to alter the database character set.
*
* @param string $dbName The database name
*
* @return string The query that alter the database query string
*
* @since 3.9.0
*/
public function getAlterDbCharacterSet($dbName)
{
return 'ALTER DATABASE ' . $this->quoteName($dbName) .
' SET CLIENT_ENCODING TO ' . $this->quote('UTF8');
}
/**
* Get the query string to create new Database in correct PostgreSQL
syntax.
*
* @param object $options object coming from "initialise"
function to pass user and database name to database driver.
* @param boolean $utf True if the database supports the UTF-8
character set, not used in PostgreSQL "CREATE DATABASE" query.
*
* @return string The query that creates database, owned by
$options['user']
*
* @since 3.9.0
*/
public function getCreateDbQuery($options, $utf)
{
$query = 'CREATE DATABASE ' .
$this->quoteName($options->db_name) . ' OWNER ' .
$this->quoteName($options->db_user);
if ($utf)
{
$query .= ' ENCODING ' . $this->quote('UTF-8');
}
return $query;
}
/**
* This function replaces a string identifier
<var>$prefix</var> with the string held is the
<var>tablePrefix</var> class variable.
*
* @param string $sql The SQL statement to prepare.
* @param string $prefix The common table prefix.
*
* @return string The processed SQL statement.
*
* @since 3.9.0
*/
public function replacePrefix($sql, $prefix = '#__')
{
$sql = trim($sql);
if (strpos($sql, '\''))
{
// Sequence name quoted with ' ' but need to be replaced
if (strpos($sql, 'currval'))
{
$sql = explode('currval', $sql);
for ($nIndex = 1, $nIndexMax = count($sql); $nIndex < $nIndexMax;
$nIndex += 2)
{
$sql[$nIndex] = str_replace($prefix, $this->tablePrefix,
$sql[$nIndex]);
}
$sql = implode('currval', $sql);
}
// Sequence name quoted with ' ' but need to be replaced
if (strpos($sql, 'nextval'))
{
$sql = explode('nextval', $sql);
for ($nIndex = 1, $nIndexMax = count($sql); $nIndex < $nIndexMax;
$nIndex += 2)
{
$sql[$nIndex] = str_replace($prefix, $this->tablePrefix,
$sql[$nIndex]);
}
$sql = implode('nextval', $sql);
}
// Sequence name quoted with ' ' but need to be replaced
if (strpos($sql, 'setval'))
{
$sql = explode('setval', $sql);
for ($nIndex = 1, $nIndexMax = count($sql); $nIndex < $nIndexMax;
$nIndex += 2)
{
$sql[$nIndex] = str_replace($prefix, $this->tablePrefix,
$sql[$nIndex]);
}
$sql = implode('setval', $sql);
}
$explodedQuery = explode('\'', $sql);
for ($nIndex = 0, $nIndexMax = count($explodedQuery); $nIndex <
$nIndexMax; $nIndex += 2)
{
if (strpos($explodedQuery[$nIndex], $prefix))
{
$explodedQuery[$nIndex] = str_replace($prefix, $this->tablePrefix,
$explodedQuery[$nIndex]);
}
}
$replacedQuery = implode('\'', $explodedQuery);
}
else
{
$replacedQuery = str_replace($prefix, $this->tablePrefix, $sql);
}
return $replacedQuery;
}
/**
* Unlocks tables in the database, this command does not exist in
PostgreSQL, it is automatically done on commit or rollback.
*
* @return JDatabaseDriverPgsql Returns this object to support chaining.
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function unlockTables()
{
$this->transactionCommit();
return $this;
}
/**
* Updates a row in a table based on an object's properties.
*
* @param string $table The name of the database table to update.
* @param object &$object A reference to an object whose public
properties match the table fields.
* @param array $key The name of the primary key.
* @param boolean $nulls True to update null fields or false to
ignore them.
*
* @return boolean
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function updateObject($table, &$object, $key, $nulls = false)
{
$columns = $this->getTableColumns($table);
$fields = array();
$where = array();
if (is_string($key))
{
$key = array($key);
}
if (is_object($key))
{
$key = (array) $key;
}
// Create the base update statement.
$statement = 'UPDATE ' . $this->quoteName($table) . '
SET %s WHERE %s';
// Iterate over the object variables to build the query fields/value
pairs.
foreach (get_object_vars($object) as $k => $v)
{
// Skip columns that don't exist in the table.
if (! array_key_exists($k, $columns))
{
continue;
}
// Only process scalars that are not internal fields.
if (is_array($v) || is_object($v) || $k[0] === '_')
{
continue;
}
// Set the primary key to the WHERE clause instead of a field to update.
if (in_array($k, $key, true))
{
$key_val = $this->sqlValue($columns, $k, $v);
$where[] = $this->quoteName($k) . '=' . $key_val;
continue;
}
// Prepare and sanitize the fields and values for the database query.
if ($v === null)
{
// If the value is null and we do not want to update nulls then ignore
this field.
if (!$nulls)
{
continue;
}
// If the value is null and we want to update nulls then set it.
$val = 'NULL';
}
else
// The field is not null so we prep it for update.
{
$val = $this->sqlValue($columns, $k, $v);
}
// Add the field to be updated.
$fields[] = $this->quoteName($k) . '=' . $val;
}
// We don't have any fields to update.
if (empty($fields))
{
return true;
}
// Set the query and execute the update.
$this->setQuery(sprintf($statement, implode(',', $fields),
implode(' AND ', $where)));
return $this->execute();
}
/**
* Quotes a binary string to database requirements for use in database
queries.
*
* @param mixed $data A binary string to quote.
*
* @return string The binary quoted input string.
*
* @since 3.9.12
*/
public function quoteBinary($data)
{
return "decode('" . bin2hex($data) . "',
'hex')";
}
}
PK�d�[�ۄ���exception/connecting.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Exception class defining an error connecting to the database platform
*
* @since 3.6
*/
class JDatabaseExceptionConnecting extends RuntimeException
{
}
PK�d�[>�����exception/executing.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Exception class defining an error executing a statement
*
* @since 3.6
*/
class JDatabaseExceptionExecuting extends RuntimeException
{
/**
* The SQL statement that was executed.
*
* @var string
* @since 3.6
*/
private $query;
/**
* Construct the exception
*
* @param string $query The SQL statement that was executed.
* @param string $message The Exception message to throw.
[optional]
* @param integer $code The Exception code. [optional]
* @param Exception $previous The previous exception used for the
exception chaining. [optional]
*
* @since 3.6
*/
public function __construct($query, $message = '', $code = 0,
Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->query = $query;
}
/**
* Get the SQL statement that was executed
*
* @return string
*
* @since 3.6
*/
public function getQuery()
{
return $this->query;
}
}
PK�d�[n��u��exception/unsupported.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Exception class defining an unsupported database object
*
* @since 3.6
*/
class JDatabaseExceptionUnsupported extends RuntimeException
{
}
PK�d�[+��%exporter/mysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL export driver.
*
* @since 1.7.0
* @deprecated 4.0 Use MySQLi or PDO MySQL instead
*/
class JDatabaseExporterMysql extends JDatabaseExporterMysqli
{
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseExporterMysql Method supports chaining.
*
* @since 1.7.0
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverMysql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[�{c���exporter/mysqli.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQLi export driver.
*
* @since 1.7.0
*/
class JDatabaseExporterMysqli extends JDatabaseExporter
{
/**
* Builds the XML data for the tables to export.
*
* @return string An XML string
*
* @since 1.7.0
* @throws Exception if an error occurs.
*/
protected function buildXml()
{
$buffer = array();
$buffer[] = '<?xml version="1.0"?>';
$buffer[] = '<mysqldump
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
$buffer[] = ' <database name="">';
$buffer = array_merge($buffer, $this->buildXmlStructure());
$buffer[] = ' </database>';
$buffer[] = '</mysqldump>';
return implode("\n", $buffer);
}
/**
* Builds the XML structure to export.
*
* @return array An array of XML lines (strings).
*
* @since 1.7.0
* @throws Exception if an error occurs.
*/
protected function buildXmlStructure()
{
$buffer = array();
foreach ($this->from as $table)
{
// Replace the magic prefix if found.
$table = $this->getGenericTableName($table);
// Get the details columns information.
$fields = $this->db->getTableColumns($table, false);
$keys = $this->db->getTableKeys($table);
$buffer[] = ' <table_structure name="' . $table .
'">';
foreach ($fields as $field)
{
$buffer[] = ' <field Field="' . $field->Field .
'"' . ' Type="' . $field->Type .
'"' . ' Null="' . $field->Null .
'"' . ' Key="' .
$field->Key . '"' . (isset($field->Default) ?
' Default="' . $field->Default . '"' :
'') . ' Extra="' . $field->Extra .
'"' .
' />';
}
foreach ($keys as $key)
{
$buffer[] = ' <key Table="' . $table .
'"' . ' Non_unique="' . $key->Non_unique .
'"' . ' Key_name="' . $key->Key_name .
'"' .
' Seq_in_index="' . $key->Seq_in_index .
'"' . ' Column_name="' . $key->Column_name
. '"' . ' Collation="' . $key->Collation .
'"' .
' Null="' . $key->Null . '"' . '
Index_type="' . $key->Index_type . '"' .
' Comment="' . htmlspecialchars($key->Comment,
ENT_COMPAT, 'UTF-8') . '"' . ' />';
}
$buffer[] = ' </table_structure>';
}
return $buffer;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseExporterMysqli Method supports chaining.
*
* @since 1.7.0
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverMysqli))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[�U��exporter/pdomysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL export driver for the PDO based MySQL database driver.
*
* @package Joomla.Platform
* @subpackage Database
* @since 3.4
*/
class JDatabaseExporterPdomysql extends JDatabaseExporter
{
/**
* Builds the XML data for the tables to export.
*
* @return string An XML string
*
* @since 3.4
* @throws Exception if an error occurs.
*/
protected function buildXml()
{
$buffer = array();
$buffer[] = '<?xml version="1.0"?>';
$buffer[] = '<mysqldump
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
$buffer[] = ' <database name="">';
$buffer = array_merge($buffer, $this->buildXmlStructure());
$buffer[] = ' </database>';
$buffer[] = '</mysqldump>';
return implode("\n", $buffer);
}
/**
* Builds the XML structure to export.
*
* @return array An array of XML lines (strings).
*
* @since 3.4
* @throws Exception if an error occurs.
*/
protected function buildXmlStructure()
{
$buffer = array();
foreach ($this->from as $table)
{
// Replace the magic prefix if found.
$table = $this->getGenericTableName($table);
// Get the details columns information.
$fields = $this->db->getTableColumns($table, false);
$keys = $this->db->getTableKeys($table);
$buffer[] = ' <table_structure name="' . $table .
'">';
foreach ($fields as $field)
{
$buffer[] = ' <field Field="' . $field->Field .
'"' . ' Type="' . $field->Type .
'"' . ' Null="' . $field->Null .
'"' . ' Key="' .
$field->Key . '"' . (isset($field->Default) ?
' Default="' . $field->Default . '"' :
'') . ' Extra="' . $field->Extra .
'"' .
' />';
}
foreach ($keys as $key)
{
$buffer[] = ' <key Table="' . $table .
'"' . ' Non_unique="' . $key->Non_unique .
'"' . ' Key_name="' . $key->Key_name .
'"' .
' Seq_in_index="' . $key->Seq_in_index .
'"' . ' Column_name="' . $key->Column_name
. '"' . ' Collation="' . $key->Collation .
'"' .
' Null="' . $key->Null . '"' . '
Index_type="' . $key->Index_type . '"' .
' Comment="' . htmlspecialchars($key->Comment,
ENT_COMPAT, 'UTF-8') . '"' . ' />';
}
$buffer[] = ' </table_structure>';
}
return $buffer;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseExporterPdomysql Method supports chaining.
*
* @since 3.4
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPdomysql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[THF{��exporter/pgsql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PDO PostgreSQL Database Exporter.
*
* @since 3.9.0
*/
class JDatabaseExporterPgsql extends JDatabaseExporterPostgresql
{
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseExporterPgsql Method supports chaining.
*
* @since 3.9.0
* @throws \Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPgsql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[��vexporter/postgresql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PostgreSQL export driver.
*
* @since 3.0.0
* @deprecated 4.0 Use PDO PostgreSQL instead
*
* @property-read JDatabaseDriverPostgresql $db The database connector
to use for exporting structure and/or data.
*/
class JDatabaseExporterPostgresql extends JDatabaseExporter
{
/**
* Builds the XML data for the tables to export.
*
* @return string An XML string
*
* @since 3.0.0
* @throws Exception if an error occurs.
*/
protected function buildXml()
{
$buffer = array();
$buffer[] = '<?xml version="1.0"?>';
$buffer[] = '<postgresqldump
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
$buffer[] = ' <database name="">';
$buffer = array_merge($buffer, $this->buildXmlStructure());
$buffer[] = ' </database>';
$buffer[] = '</postgresqldump>';
return implode("\n", $buffer);
}
/**
* Builds the XML structure to export.
*
* @return array An array of XML lines (strings).
*
* @since 3.0.0
* @throws Exception if an error occurs.
*/
protected function buildXmlStructure()
{
$buffer = array();
foreach ($this->from as $table)
{
// Replace the magic prefix if found.
$table = $this->getGenericTableName($table);
// Get the details columns information.
$fields = $this->db->getTableColumns($table, false);
$keys = $this->db->getTableKeys($table);
$sequences = $this->db->getTableSequences($table);
$buffer[] = ' <table_structure name="' . $table .
'">';
foreach ($sequences as $sequence)
{
if (version_compare($this->db->getVersion(), '9.1.0')
< 0)
{
$sequence->start_value = null;
}
$buffer[] = ' <sequence Name="' .
$sequence->sequence . '"' . ' Schema="' .
$sequence->schema . '"' .
' Table="' . $sequence->table . '"' .
' Column="' . $sequence->column . '"' .
' Type="' . $sequence->data_type . '"' .
' Start_Value="' . $sequence->start_value .
'"' . ' Min_Value="' .
$sequence->minimum_value . '"' .
' Max_Value="' . $sequence->maximum_value .
'"' . ' Increment="' .
$sequence->increment . '"' .
' Cycle_option="' . $sequence->cycle_option .
'"' .
' />';
}
foreach ($fields as $field)
{
$buffer[] = ' <field Field="' .
$field->column_name . '"' . ' Type="' .
$field->type . '"' . ' Null="' .
$field->null . '"' .
(isset($field->default) ? ' Default="' .
$field->default . '"' : '') . '
Comments="' . $field->comments . '"' .
' />';
}
foreach ($keys as $key)
{
$buffer[] = ' <key Index="' . $key->idxName .
'"' . ' is_primary="' . $key->isPrimary .
'"' . ' is_unique="' . $key->isUnique .
'"' .
' Query="' . $key->Query . '" />';
}
$buffer[] = ' </table_structure>';
}
return $buffer;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseExporterPostgresql Method supports chaining.
*
* @since 3.0.0
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPostgresql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[r�(��exporter.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform Database Exporter Class
*
* @since 3.0.0
*/
abstract class JDatabaseExporter
{
/**
* The type of output format (xml).
*
* @var string
* @since 3.2.0
*/
protected $asFormat = 'xml';
/**
* An array of cached data.
*
* @var array
* @since 3.2.0
*/
protected $cache = array();
/**
* The database connector to use for exporting structure and/or data.
*
* @var JDatabaseDriver
* @since 3.2.0
*/
protected $db = null;
/**
* An array input sources (table names).
*
* @var array
* @since 3.2.0
*/
protected $from = array();
/**
* An array of options for the exporter.
*
* @var object
* @since 3.2.0
*/
protected $options = null;
/**
* Constructor.
*
* Sets up the default options for the exporter.
*
* @since 3.2.0
*/
public function __construct()
{
$this->options = new stdClass;
$this->cache = array('columns' => array(),
'keys' => array());
// Set up the class defaults:
// Export with only structure
$this->withStructure();
// Export as xml.
$this->asXml();
// Default destination is a string using $output = (string) $exporter;
}
/**
* Magic function to exports the data to a string.
*
* @return string
*
* @since 3.2.0
* @throws Exception if an error is encountered.
*/
public function __toString()
{
// Check everything is ok to run first.
$this->check();
// Get the format.
switch ($this->asFormat)
{
case 'xml':
default:
$buffer = $this->buildXml();
break;
}
return $buffer;
}
/**
* Set the output option for the exporter to XML format.
*
* @return JDatabaseExporter Method supports chaining.
*
* @since 3.2.0
*/
public function asXml()
{
$this->asFormat = 'xml';
return $this;
}
/**
* Builds the XML data for the tables to export.
*
* @return string An XML string
*
* @since 3.2.0
* @throws Exception if an error occurs.
*/
abstract protected function buildXml();
/**
* Builds the XML structure to export.
*
* @return array An array of XML lines (strings).
*
* @since 3.2.0
* @throws Exception if an error occurs.
*/
abstract protected function buildXmlStructure();
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseDriver Method supports chaining.
*
* @since 3.2.0
* @throws Exception if an error is encountered.
*/
abstract public function check();
/**
* Specifies a list of table names to export.
*
* @param mixed $from The name of a single table, or an array of the
table names to export.
*
* @return JDatabaseExporter Method supports chaining.
*
* @since 3.2.0
* @throws Exception if input is not a string or array.
*/
public function from($from)
{
if (is_string($from))
{
$this->from = array($from);
}
elseif (is_array($from))
{
$this->from = $from;
}
else
{
throw new
Exception('JPLATFORM_ERROR_INPUT_REQUIRES_STRING_OR_ARRAY');
}
return $this;
}
/**
* Get the generic name of the table, converting the database prefix to
the wildcard string.
*
* @param string $table The name of the table.
*
* @return string The name of the table with the database prefix
replaced with #__.
*
* @since 3.2.0
*/
protected function getGenericTableName($table)
{
$prefix = $this->db->getPrefix();
// Replace the magic prefix if found.
$table = preg_replace("|^$prefix|", '#__', $table);
return $table;
}
/**
* Sets the database connector to use for exporting structure and/or data
from MySQL.
*
* @param JDatabaseDriver $db The database connector.
*
* @return JDatabaseExporter Method supports chaining.
*
* @since 3.2.0
*/
public function setDbo(JDatabaseDriver $db)
{
$this->db = $db;
return $this;
}
/**
* Sets an internal option to export the structure of the input table(s).
*
* @param boolean $setting True to export the structure, false to not.
*
* @return JDatabaseExporter Method supports chaining.
*
* @since 3.2.0
*/
public function withStructure($setting = true)
{
$this->options->withStructure = (boolean) $setting;
return $this;
}
}
PK�d�[�ڙimporter/mysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL import driver.
*
* @since 1.7.0
* @deprecated 4.0 Use MySQLi or PDO MySQL instead
*/
class JDatabaseImporterMysql extends JDatabaseImporterMysqli
{
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporterMysql Method supports chaining.
*
* @since 1.7.0
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverMysql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[&��;�-�-importer/mysqli.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQLi import driver.
*
* @since 1.7.0
*/
class JDatabaseImporterMysqli extends JDatabaseImporter
{
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporterMysqli Method supports chaining.
*
* @since 1.7.0
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverMysqli))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
/**
* Get the SQL syntax to add a table.
*
* @param SimpleXMLElement $table The table information.
*
* @return string
*
* @since 1.7.0
* @throws RuntimeException
*/
protected function xmlToCreate(SimpleXMLElement $table)
{
$existingTables = $this->db->getTableList();
$tableName = (string) $table['name'];
if (in_array($tableName, $existingTables))
{
throw new RuntimeException('The table you are trying to create
already exists');
}
$createTableStatement = 'CREATE TABLE ' .
$this->db->quoteName($tableName) . ' (';
foreach ($table->xpath('field') as $field)
{
$createTableStatement .= $this->getColumnSQL($field) . ',
';
}
$newLookup = $this->getKeyLookup($table->xpath('key'));
// Loop through each key in the new structure.
foreach ($newLookup as $key)
{
$createTableStatement .= $this->getKeySQL($key) . ', ';
}
// Remove the comma after the last key
$createTableStatement = rtrim($createTableStatement, ', ');
$createTableStatement .= ')';
return $createTableStatement;
}
/**
* Get the SQL syntax to add a column.
*
* @param string $table The table name.
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 1.7.0
*/
protected function getAddColumnSql($table, SimpleXMLElement $field)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' ADD COLUMN ' . $this->getColumnSql($field);
}
/**
* Get the SQL syntax to add a key.
*
* @param string $table The table name.
* @param array $keys An array of the fields pertaining to this key.
*
* @return string
*
* @since 1.7.0
*/
protected function getAddKeySql($table, $keys)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' ADD ' . $this->getKeySql($keys);
}
/**
* Get alters for table if there is a difference.
*
* @param SimpleXMLElement $structure The XML structure of the table.
*
* @return array
*
* @since 1.7.0
*/
protected function getAlterTableSql(SimpleXMLElement $structure)
{
$table = $this->getRealTableName($structure['name']);
$oldFields = $this->db->getTableColumns($table, false);
$oldKeys = $this->db->getTableKeys($table);
$alters = array();
// Get the fields and keys from the XML that we are aiming for.
$newFields = $structure->xpath('field');
$newKeys = $structure->xpath('key');
// Loop through each field in the new structure.
foreach ($newFields as $field)
{
$fName = (string) $field['Field'];
if (isset($oldFields[$fName]))
{
// The field exists, check it's the same.
$column = $oldFields[$fName];
// Test whether there is a change.
$change = ((string) $field['Type'] != $column->Type) ||
((string) $field['Null'] != $column->Null)
|| ((string) $field['Default'] != $column->Default) ||
((string) $field['Extra'] != $column->Extra);
if ($change)
{
$alters[] = $this->getChangeColumnSql($table, $field);
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldFields[$fName]);
}
else
{
// The field is new.
$alters[] = $this->getAddColumnSql($table, $field);
}
}
// Any columns left are orphans
foreach ($oldFields as $name => $column)
{
// Delete the column.
$alters[] = $this->getDropColumnSql($table, $name);
}
// Get the lookups for the old and new keys.
$oldLookup = $this->getKeyLookup($oldKeys);
$newLookup = $this->getKeyLookup($newKeys);
// Loop through each key in the new structure.
foreach ($newLookup as $name => $keys)
{
// Check if there are keys on this field in the existing table.
if (isset($oldLookup[$name]))
{
$same = true;
$newCount = count($newLookup[$name]);
$oldCount = count($oldLookup[$name]);
// There is a key on this field in the old and new tables. Are they the
same?
if ($newCount == $oldCount)
{
// Need to loop through each key and do a fine grained check.
for ($i = 0; $i < $newCount; $i++)
{
$same = (((string) $newLookup[$name][$i]['Non_unique'] ==
$oldLookup[$name][$i]->Non_unique)
&& ((string) $newLookup[$name][$i]['Column_name']
== $oldLookup[$name][$i]->Column_name)
&& ((string) $newLookup[$name][$i]['Seq_in_index']
== $oldLookup[$name][$i]->Seq_in_index)
&& ((string) $newLookup[$name][$i]['Collation'] ==
$oldLookup[$name][$i]->Collation)
&& ((string) $newLookup[$name][$i]['Index_type']
== $oldLookup[$name][$i]->Index_type));
/*
Debug.
echo '<pre>';
echo '<br />Non_unique: '.
((string) $newLookup[$name][$i]['Non_unique'] ==
$oldLookup[$name][$i]->Non_unique ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Non_unique'].' vs
'.$oldLookup[$name][$i]->Non_unique;
echo '<br />Column_name: '.
((string) $newLookup[$name][$i]['Column_name'] ==
$oldLookup[$name][$i]->Column_name ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Column_name'].' vs
'.$oldLookup[$name][$i]->Column_name;
echo '<br />Seq_in_index: '.
((string) $newLookup[$name][$i]['Seq_in_index'] ==
$oldLookup[$name][$i]->Seq_in_index ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Seq_in_index'].' vs
'.$oldLookup[$name][$i]->Seq_in_index;
echo '<br />Collation: '.
((string) $newLookup[$name][$i]['Collation'] ==
$oldLookup[$name][$i]->Collation ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Collation'].' vs
'.$oldLookup[$name][$i]->Collation;
echo '<br />Index_type: '.
((string) $newLookup[$name][$i]['Index_type'] ==
$oldLookup[$name][$i]->Index_type ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Index_type'].' vs
'.$oldLookup[$name][$i]->Index_type;
echo '<br />Same = '.($same ? 'true' :
'false');
echo '</pre>';
*/
if (!$same)
{
// Break out of the loop. No need to check further.
break;
}
}
}
else
{
// Count is different, just drop and add.
$same = false;
}
if (!$same)
{
$alters[] = $this->getDropKeySql($table, $name);
$alters[] = $this->getAddKeySql($table, $keys);
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldLookup[$name]);
}
else
{
// This is a new key.
$alters[] = $this->getAddKeySql($table, $keys);
}
}
// Any keys left are orphans.
foreach ($oldLookup as $name => $keys)
{
if (strtoupper($name) == 'PRIMARY')
{
$alters[] = $this->getDropPrimaryKeySql($table);
}
else
{
$alters[] = $this->getDropKeySql($table, $name);
}
}
return $alters;
}
/**
* Get the syntax to alter a column.
*
* @param string $table The name of the database table to
alter.
* @param SimpleXMLElement $field The XML definition for the field.
*
* @return string
*
* @since 1.7.0
*/
protected function getChangeColumnSql($table, SimpleXMLElement $field)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' CHANGE COLUMN ' . $this->db->quoteName((string)
$field['Field']) . ' '
. $this->getColumnSql($field);
}
/**
* Get the SQL syntax for a single column that would be included in a
table create or alter statement.
*
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 1.7.0
*/
protected function getColumnSql(SimpleXMLElement $field)
{
// TODO Incorporate into parent class and use $this.
$blobs = array('text', 'smalltext',
'mediumtext', 'largetext');
$fName = (string) $field['Field'];
$fType = (string) $field['Type'];
$fNull = (string) $field['Null'];
$fDefault = isset($field['Default']) ? (string)
$field['Default'] : null;
$fExtra = (string) $field['Extra'];
$query = $this->db->quoteName($fName) . ' ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$query .= ' NOT NULL';
}
else
{
// TODO Don't quote numeric values.
$query .= ' NOT NULL DEFAULT ' .
$this->db->quote($fDefault);
}
}
else
{
if ($fDefault === null)
{
$query .= ' DEFAULT NULL';
}
else
{
// TODO Don't quote numeric values.
$query .= ' DEFAULT ' . $this->db->quote($fDefault);
}
}
if ($fExtra)
{
$query .= ' ' . strtoupper($fExtra);
}
return $query;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
* @param string $name The name of the key to drop.
*
* @return string
*
* @since 1.7.0
*/
protected function getDropKeySql($table, $name)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' DROP KEY ' . $this->db->quoteName($name);
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
*
* @return string
*
* @since 1.7.0
*/
protected function getDropPrimaryKeySql($table)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' DROP PRIMARY KEY';
}
/**
* Get the details list of keys for a table.
*
* @param array $keys An array of objects that comprise the keys for
the table.
*
* @return array The lookup array. array({key name} => array(object,
...))
*
* @since 1.7.0
* @throws Exception
*/
protected function getKeyLookup($keys)
{
// First pass, create a lookup of the keys.
$lookup = array();
foreach ($keys as $key)
{
if ($key instanceof SimpleXMLElement)
{
$kName = (string) $key['Key_name'];
}
else
{
$kName = $key->Key_name;
}
if (empty($lookup[$kName]))
{
$lookup[$kName] = array();
}
$lookup[$kName][] = $key;
}
return $lookup;
}
/**
* Get the SQL syntax for a key.
*
* @param array $columns An array of SimpleXMLElement objects
comprising the key.
*
* @return string
*
* @since 1.7.0
*/
protected function getKeySql($columns)
{
// TODO Error checking on array and element types.
$kNonUnique = (string) $columns[0]['Non_unique'];
$kName = (string) $columns[0]['Key_name'];
$kColumn = (string) $columns[0]['Column_name'];
$prefix = '';
if ($kName == 'PRIMARY')
{
$prefix = 'PRIMARY ';
}
elseif ($kNonUnique == 0)
{
$prefix = 'UNIQUE ';
}
$nColumns = count($columns);
$kColumns = array();
if ($nColumns == 1)
{
$kColumns[] = $this->db->quoteName($kColumn);
}
else
{
foreach ($columns as $column)
{
$kColumns[] = (string) $column['Column_name'];
}
}
$query = $prefix . 'KEY ' . ($kName != 'PRIMARY' ?
$this->db->quoteName($kName) : '') . ' (' .
implode(',', $kColumns) . ')';
return $query;
}
}
PK�d�[;c%�
,
,importer/pdomysql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* MySQL import driver for the PDO based MySQL database driver.
*
* @package Joomla.Platform
* @subpackage Database
* @since 3.4
*/
class JDatabaseImporterPdomysql extends JDatabaseImporter
{
/**
* Get the SQL syntax to add a column.
*
* @param string $table The table name.
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.4
*/
protected function getAddColumnSql($table, SimpleXMLElement $field)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) .
' ADD COLUMN ' . $this->getColumnSql($field);
return $sql;
}
/**
* Get the SQL syntax to add a key.
*
* @param string $table The table name.
* @param array $keys An array of the fields pertaining to this key.
*
* @return string
*
* @since 3.4
*/
protected function getAddKeySql($table, $keys)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) .
' ADD ' . $this->getKeySql($keys);
return $sql;
}
/**
* Get alters for table if there is a difference.
*
* @param SimpleXMLElement $structure The XML structure of the table.
*
* @return array
*
* @since 3.4
*/
protected function getAlterTableSql(SimpleXMLElement $structure)
{
// Initialise variables.
$table = $this->getRealTableName($structure['name']);
$oldFields = $this->db->getTableColumns($table);
$oldKeys = $this->db->getTableKeys($table);
$alters = array();
// Get the fields and keys from the XML that we are aiming for.
$newFields = $structure->xpath('field');
$newKeys = $structure->xpath('key');
// Loop through each field in the new structure.
foreach ($newFields as $field)
{
$fName = (string) $field['Field'];
if (isset($oldFields[$fName]))
{
// The field exists, check it's the same.
$column = $oldFields[$fName];
// Test whether there is a change.
$change = ((string) $field['Type'] != $column->Type) ||
((string) $field['Null'] != $column->Null)
|| ((string) $field['Default'] != $column->Default) ||
((string) $field['Extra'] != $column->Extra);
if ($change)
{
$alters[] = $this->getChangeColumnSql($table, $field);
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldFields[$fName]);
}
else
{
// The field is new.
$alters[] = $this->getAddColumnSql($table, $field);
}
}
// Any columns left are orphans
foreach ($oldFields as $name => $column)
{
// Delete the column.
$alters[] = $this->getDropColumnSql($table, $name);
}
// Get the lookups for the old and new keys.
$oldLookup = $this->getKeyLookup($oldKeys);
$newLookup = $this->getKeyLookup($newKeys);
// Loop through each key in the new structure.
foreach ($newLookup as $name => $keys)
{
// Check if there are keys on this field in the existing table.
if (isset($oldLookup[$name]))
{
$same = true;
$newCount = count($newLookup[$name]);
$oldCount = count($oldLookup[$name]);
// There is a key on this field in the old and new tables. Are they the
same?
if ($newCount == $oldCount)
{
// Need to loop through each key and do a fine grained check.
for ($i = 0; $i < $newCount; $i++)
{
$same = (((string) $newLookup[$name][$i]['Non_unique'] ==
$oldLookup[$name][$i]->Non_unique)
&& ((string) $newLookup[$name][$i]['Column_name']
== $oldLookup[$name][$i]->Column_name)
&& ((string) $newLookup[$name][$i]['Seq_in_index']
== $oldLookup[$name][$i]->Seq_in_index)
&& ((string) $newLookup[$name][$i]['Collation'] ==
$oldLookup[$name][$i]->Collation)
&& ((string) $newLookup[$name][$i]['Index_type']
== $oldLookup[$name][$i]->Index_type));
/*
Debug.
echo '<pre>';
echo '<br />Non_unique: '.
((string) $newLookup[$name][$i]['Non_unique'] ==
$oldLookup[$name][$i]->Non_unique ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Non_unique'].' vs
'.$oldLookup[$name][$i]->Non_unique;
echo '<br />Column_name: '.
((string) $newLookup[$name][$i]['Column_name'] ==
$oldLookup[$name][$i]->Column_name ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Column_name'].' vs
'.$oldLookup[$name][$i]->Column_name;
echo '<br />Seq_in_index: '.
((string) $newLookup[$name][$i]['Seq_in_index'] ==
$oldLookup[$name][$i]->Seq_in_index ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Seq_in_index'].' vs
'.$oldLookup[$name][$i]->Seq_in_index;
echo '<br />Collation: '.
((string) $newLookup[$name][$i]['Collation'] ==
$oldLookup[$name][$i]->Collation ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Collation'].' vs
'.$oldLookup[$name][$i]->Collation;
echo '<br />Index_type: '.
((string) $newLookup[$name][$i]['Index_type'] ==
$oldLookup[$name][$i]->Index_type ? 'Pass' :
'Fail').' '.
(string) $newLookup[$name][$i]['Index_type'].' vs
'.$oldLookup[$name][$i]->Index_type;
echo '<br />Same = '.($same ? 'true' :
'false');
echo '</pre>';
*/
if (!$same)
{
// Break out of the loop. No need to check further.
break;
}
}
}
else
{
// Count is different, just drop and add.
$same = false;
}
if (!$same)
{
$alters[] = $this->getDropKeySql($table, $name);
$alters[] = $this->getAddKeySql($table, $keys);
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldLookup[$name]);
}
else
{
// This is a new key.
$alters[] = $this->getAddKeySql($table, $keys);
}
}
// Any keys left are orphans.
foreach ($oldLookup as $name => $keys)
{
if (strtoupper($name) == 'PRIMARY')
{
$alters[] = $this->getDropPrimaryKeySql($table);
}
else
{
$alters[] = $this->getDropKeySql($table, $name);
}
}
return $alters;
}
/**
* Get the syntax to alter a column.
*
* @param string $table The name of the database table to
alter.
* @param SimpleXMLElement $field The XML definition for the field.
*
* @return string
*
* @since 3.4
*/
protected function getChangeColumnSql($table, SimpleXMLElement $field)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) .
' CHANGE COLUMN ' . $this->db->quoteName((string)
$field['Field']) . ' '
. $this->getColumnSql($field);
return $sql;
}
/**
* Get the SQL syntax for a single column that would be included in a
table create or alter statement.
*
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.4
*/
protected function getColumnSql(SimpleXMLElement $field)
{
// Initialise variables.
// TODO Incorporate into parent class and use $this.
$blobs = array('text', 'smalltext',
'mediumtext', 'largetext');
$fName = (string) $field['Field'];
$fType = (string) $field['Type'];
$fNull = (string) $field['Null'];
$fDefault = isset($field['Default']) ? (string)
$field['Default'] : null;
$fExtra = (string) $field['Extra'];
$sql = $this->db->quoteName($fName) . ' ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$sql .= ' NOT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' NOT NULL DEFAULT ' .
$this->db->quote($fDefault);
}
}
else
{
if ($fDefault === null)
{
$sql .= ' DEFAULT NULL';
}
else
{
// TODO Don't quote numeric values.
$sql .= ' DEFAULT ' . $this->db->quote($fDefault);
}
}
if ($fExtra)
{
$sql .= ' ' . strtoupper($fExtra);
}
return $sql;
}
/**
* Get the SQL syntax to drop a column.
*
* @param string $table The table name.
* @param string $name The name of the field to drop.
*
* @return string
*
* @since 3.4
*/
protected function getDropColumnSql($table, $name)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) .
' DROP COLUMN ' . $this->db->quoteName($name);
return $sql;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
* @param string $name The name of the key to drop.
*
* @return string
*
* @since 3.4
*/
protected function getDropKeySql($table, $name)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) .
' DROP KEY ' . $this->db->quoteName($name);
return $sql;
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
*
* @return string
*
* @since 3.4
*/
protected function getDropPrimaryKeySql($table)
{
$sql = 'ALTER TABLE ' . $this->db->quoteName($table) .
' DROP PRIMARY KEY';
return $sql;
}
/**
* Get the details list of keys for a table.
*
* @param array $keys An array of objects that comprise the keys for
the table.
*
* @return array The lookup array. array({key name} => array(object,
...))
*
* @since 3.4
* @throws Exception
*/
protected function getKeyLookup($keys)
{
// First pass, create a lookup of the keys.
$lookup = array();
foreach ($keys as $key)
{
if ($key instanceof SimpleXMLElement)
{
$kName = (string) $key['Key_name'];
}
else
{
$kName = $key->Key_name;
}
if (empty($lookup[$kName]))
{
$lookup[$kName] = array();
}
$lookup[$kName][] = $key;
}
return $lookup;
}
/**
* Get the SQL syntax for a key.
*
* @param array $columns An array of SimpleXMLElement objects
comprising the key.
*
* @return string
*
* @since 3.4
*/
protected function getKeySql($columns)
{
// TODO Error checking on array and element types.
$kNonUnique = (string) $columns[0]['Non_unique'];
$kName = (string) $columns[0]['Key_name'];
$kColumn = (string) $columns[0]['Column_name'];
$prefix = '';
if ($kName == 'PRIMARY')
{
$prefix = 'PRIMARY ';
}
elseif ($kNonUnique == 0)
{
$prefix = 'UNIQUE ';
}
$nColumns = count($columns);
$kColumns = array();
if ($nColumns == 1)
{
$kColumns[] = $this->db->quoteName($kColumn);
}
else
{
foreach ($columns as $column)
{
$kColumns[] = (string) $column['Column_name'];
}
}
$sql = $prefix . 'KEY ' . ($kName != 'PRIMARY' ?
$this->db->quoteName($kName) : '') . ' (' .
implode(',', $kColumns) . ')';
return $sql;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporterPdomysql Method supports chaining.
*
* @since 3.4
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPdomysql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[� -���importer/pgsql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PDO PostgreSQL Database Importer.
*
* @since 3.9.0
*/
class JDatabaseImporterPgsql extends JDatabaseImporterPostgresql
{
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporterPgsql Method supports chaining.
*
* @since 3.9.0
* @throws \Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPgsql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
}
PK�d�[Z��38989importer/postgresql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PostgreSQL import driver.
*
* @since 3.0.0
* @deprecated 4.0 Use PDO PostgreSQL instead
*/
class JDatabaseImporterPostgresql extends JDatabaseImporter
{
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporterPostgresql Method supports chaining.
*
* @since 3.0.0
* @throws Exception if an error is encountered.
*/
public function check()
{
// Check if the db connector has been set.
if (!($this->db instanceof JDatabaseDriverPostgresql))
{
throw new
Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
}
// Check if the tables have been specified.
if (empty($this->from))
{
throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
}
return $this;
}
/**
* Get the SQL syntax to add a column.
*
* @param string $table The table name.
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.0.0
*/
protected function getAddColumnSql($table, SimpleXMLElement $field)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' ADD COLUMN ' . $this->getColumnSql($field);
}
/**
* Get the SQL syntax to add an index.
*
* @param SimpleXMLElement $field The XML index definition.
*
* @return string
*
* @since 3.0.0
*/
protected function getAddIndexSql(SimpleXMLElement $field)
{
return (string) $field['Query'];
}
/**
* Get alters for table if there is a difference.
*
* @param SimpleXMLElement $structure The XML structure of the table.
*
* @return array
*
* @since 3.0.0
*/
protected function getAlterTableSql(SimpleXMLElement $structure)
{
$table = $this->getRealTableName($structure['name']);
$oldFields = $this->db->getTableColumns($table);
$oldKeys = $this->db->getTableKeys($table);
$oldSequence = $this->db->getTableSequences($table);
$alters = array();
// Get the fields and keys from the XML that we are aiming for.
$newFields = $structure->xpath('field');
$newKeys = $structure->xpath('key');
$newSequence = $structure->xpath('sequence');
/* Sequence section */
$oldSeq = $this->getSeqLookup($oldSequence);
$newSequenceLook = $this->getSeqLookup($newSequence);
foreach ($newSequenceLook as $kSeqName => $vSeq)
{
if (isset($oldSeq[$kSeqName]))
{
// The field exists, check it's the same.
$column = $oldSeq[$kSeqName][0];
/* For older database version that doesn't support these fields
use default values */
if (version_compare($this->db->getVersion(), '9.1.0')
< 0)
{
$column->Min_Value = '1';
$column->Max_Value = '9223372036854775807';
$column->Increment = '1';
$column->Cycle_option = 'NO';
$column->Start_Value = '1';
}
// Test whether there is a change.
$change = ((string) $vSeq[0]['Type'] != $column->Type) ||
((string) $vSeq[0]['Start_Value'] != $column->Start_Value)
|| ((string) $vSeq[0]['Min_Value'] != $column->Min_Value)
|| ((string) $vSeq[0]['Max_Value'] != $column->Max_Value)
|| ((string) $vSeq[0]['Increment'] != $column->Increment)
|| ((string) $vSeq[0]['Cycle_option'] !=
$column->Cycle_option)
|| ((string) $vSeq[0]['Table'] != $column->Table) ||
((string) $vSeq[0]['Column'] != $column->Column)
|| ((string) $vSeq[0]['Schema'] != $column->Schema) ||
((string) $vSeq[0]['Name'] != $column->Name);
if ($change)
{
$alters[] = $this->getChangeSequenceSql($kSeqName, $vSeq);
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldSeq[$kSeqName]);
}
else
{
// The sequence is new
$alters[] =
$this->getAddSequenceSql($newSequenceLook[$kSeqName][0]);
}
}
// Any sequences left are orphans
foreach ($oldSeq as $name => $column)
{
// Delete the sequence.
$alters[] = $this->getDropSequenceSql($name);
}
/* Field section */
// Loop through each field in the new structure.
foreach ($newFields as $field)
{
$fName = (string) $field['Field'];
if (isset($oldFields[$fName]))
{
// The field exists, check it's the same.
$column = $oldFields[$fName];
// Test whether there is a change.
$change = ((string) $field['Type'] != $column->Type) ||
((string) $field['Null'] != $column->Null)
|| ((string) $field['Default'] != $column->Default);
if ($change)
{
$alters[] = $this->getChangeColumnSql($table, $field);
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldFields[$fName]);
}
else
{
// The field is new.
$alters[] = $this->getAddColumnSql($table, $field);
}
}
// Any columns left are orphans
foreach ($oldFields as $name => $column)
{
// Delete the column.
$alters[] = $this->getDropColumnSql($table, $name);
}
/* Index section */
// Get the lookups for the old and new keys
$oldLookup = $this->getIdxLookup($oldKeys);
$newLookup = $this->getIdxLookup($newKeys);
// Loop through each key in the new structure.
foreach ($newLookup as $name => $keys)
{
// Check if there are keys on this field in the existing table.
if (isset($oldLookup[$name]))
{
$same = true;
$newCount = count($newLookup[$name]);
$oldCount = count($oldLookup[$name]);
// There is a key on this field in the old and new tables. Are they the
same?
if ($newCount == $oldCount)
{
for ($i = 0; $i < $newCount; $i++)
{
// Check only query field -> different query means different index
$same = ((string) $newLookup[$name][$i]['Query'] ==
$oldLookup[$name][$i]->Query);
if (!$same)
{
// Break out of the loop. No need to check further.
break;
}
}
}
else
{
// Count is different, just drop and add.
$same = false;
}
if (!$same)
{
$alters[] = $this->getDropIndexSql($name);
$alters[] = (string) $newLookup[$name][0]['Query'];
}
// Unset this field so that what we have left are fields that need to
be removed.
unset($oldLookup[$name]);
}
else
{
// This is a new key.
$alters[] = (string) $newLookup[$name][0]['Query'];
}
}
// Any keys left are orphans.
foreach ($oldLookup as $name => $keys)
{
if ($oldLookup[$name][0]->is_primary == 'TRUE')
{
$alters[] = $this->getDropPrimaryKeySql($table,
$oldLookup[$name][0]->Index);
}
else
{
$alters[] = $this->getDropIndexSql($name);
}
}
return $alters;
}
/**
* Get the SQL syntax to drop a sequence.
*
* @param string $name The name of the sequence to drop.
*
* @return string
*
* @since 3.0.0
*/
protected function getDropSequenceSql($name)
{
return 'DROP SEQUENCE ' . $this->db->quoteName($name);
}
/**
* Get the syntax to add a sequence.
*
* @param SimpleXMLElement $field The XML definition for the sequence.
*
* @return string
*
* @since 3.0.0
*/
protected function getAddSequenceSql($field)
{
/* For older database version that doesn't support these fields use
default values */
if (version_compare($this->db->getVersion(), '9.1.0')
< 0)
{
$field['Min_Value'] = '1';
$field['Max_Value'] = '9223372036854775807';
$field['Increment'] = '1';
$field['Cycle_option'] = 'NO';
$field['Start_Value'] = '1';
}
return 'CREATE SEQUENCE ' . (string) $field['Name'] .
' INCREMENT BY ' . (string) $field['Increment'] .
' MINVALUE ' . $field['Min_Value'] .
' MAXVALUE ' . (string) $field['Max_Value'] . '
START ' . (string) $field['Start_Value'] .
(((string) $field['Cycle_option'] == 'NO') ? '
NO' : '') . ' CYCLE' .
' OWNED BY ' . $this->db->quoteName((string)
$field['Schema'] . '.' . (string)
$field['Table'] . '.' . (string)
$field['Column']);
}
/**
* Get the syntax to alter a sequence.
*
* @param SimpleXMLElement $field The XML definition for the sequence.
*
* @return string
*
* @since 3.0.0
*/
protected function getChangeSequenceSql($field)
{
/* For older database version that doesn't support these fields use
default values */
if (version_compare($this->db->getVersion(), '9.1.0')
< 0)
{
$field['Min_Value'] = '1';
$field['Max_Value'] = '9223372036854775807';
$field['Increment'] = '1';
$field['Cycle_option'] = 'NO';
$field['Start_Value'] = '1';
}
return 'ALTER SEQUENCE ' . (string) $field['Name'] .
' INCREMENT BY ' . (string) $field['Increment'] .
' MINVALUE ' . (string) $field['Min_Value'] .
' MAXVALUE ' . (string) $field['Max_Value'] . '
START ' . (string) $field['Start_Value'] .
' OWNED BY ' . $this->db->quoteName((string)
$field['Schema'] . '.' . (string)
$field['Table'] . '.' . (string)
$field['Column']);
}
/**
* Get the syntax to alter a column.
*
* @param string $table The name of the database table to
alter.
* @param SimpleXMLElement $field The XML definition for the field.
*
* @return string
*
* @since 3.0.0
*/
protected function getChangeColumnSql($table, SimpleXMLElement $field)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' ALTER COLUMN ' . $this->db->quoteName((string)
$field['Field']) . ' '
. $this->getAlterColumnSql($table, $field);
}
/**
* Get the SQL syntax for a single column that would be included in a
table create statement.
*
* @param string $table The name of the database table to
alter.
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.0.0
*/
protected function getAlterColumnSql($table, $field)
{
// TODO Incorporate into parent class and use $this.
$blobs = array('text', 'smalltext',
'mediumtext', 'largetext');
$fName = (string) $field['Field'];
$fType = (string) $field['Type'];
$fNull = (string) $field['Null'];
$fDefault = (isset($field['Default']) &&
$field['Default'] != 'NULL') ?
preg_match('/^[0-9]$/', $field['Default']) ?
$field['Default'] : $this->db->quote((string)
$field['Default'])
: null;
$query = ' TYPE ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$query .= ",\nALTER COLUMN " .
$this->db->quoteName($fName) . ' SET NOT NULL' .
",\nALTER COLUMN " . $this->db->quoteName($fName) .
' DROP DEFAULT';
}
else
{
$query .= ",\nALTER COLUMN " .
$this->db->quoteName($fName) . ' SET NOT NULL' .
",\nALTER COLUMN " . $this->db->quoteName($fName) .
' SET DEFAULT ' . $fDefault;
}
}
else
{
if ($fDefault !== null)
{
$query .= ",\nALTER COLUMN " .
$this->db->quoteName($fName) . ' DROP NOT NULL' .
",\nALTER COLUMN " . $this->db->quoteName($fName) .
' SET DEFAULT ' . $fDefault;
}
}
/* sequence was created in other function, here is associated a default
value but not yet owner */
if (strpos($fDefault, 'nextval') !== false)
{
$query .= ";\nALTER SEQUENCE " .
$this->db->quoteName($table . '_' . $fName .
'_seq') . ' OWNED BY ' .
$this->db->quoteName($table . '.' . $fName);
}
return $query;
}
/**
* Get the SQL syntax for a single column that would be included in a
table create statement.
*
* @param SimpleXMLElement $field The XML field definition.
*
* @return string
*
* @since 3.0.0
*/
protected function getColumnSql(SimpleXMLElement $field)
{
// TODO Incorporate into parent class and use $this.
$blobs = array('text', 'smalltext',
'mediumtext', 'largetext');
$fName = (string) $field['Field'];
$fType = (string) $field['Type'];
$fNull = (string) $field['Null'];
$fDefault = (isset($field['Default']) &&
$field['Default'] != 'NULL') ?
preg_match('/^[0-9]$/', $field['Default']) ?
$field['Default'] : $this->db->quote((string)
$field['Default'])
: null;
/* nextval() as default value means that type field is serial */
if (strpos($fDefault, 'nextval') !== false)
{
$query = $this->db->quoteName($fName) . ' SERIAL';
}
else
{
$query = $this->db->quoteName($fName) . ' ' . $fType;
if ($fNull == 'NO')
{
if (in_array($fType, $blobs) || $fDefault === null)
{
$query .= ' NOT NULL';
}
else
{
$query .= ' NOT NULL DEFAULT ' . $fDefault;
}
}
else
{
if ($fDefault !== null)
{
$query .= ' DEFAULT ' . $fDefault;
}
}
}
return $query;
}
/**
* Get the SQL syntax to drop an index.
*
* @param string $name The name of the key to drop.
*
* @return string
*
* @since 3.0.0
*/
protected function getDropIndexSql($name)
{
return 'DROP INDEX ' . $this->db->quoteName($name);
}
/**
* Get the SQL syntax to drop a key.
*
* @param string $table The table name.
* @param string $name The constraint name.
*
* @return string
*
* @since 3.0.0
*/
protected function getDropPrimaryKeySql($table, $name)
{
return 'ALTER TABLE ONLY ' . $this->db->quoteName($table)
. ' DROP CONSTRAINT ' . $this->db->quoteName($name);
}
/**
* Get the details list of keys for a table.
*
* @param array $keys An array of objects that comprise the keys for
the table.
*
* @return array The lookup array. array({key name} => array(object,
...))
*
* @since 3.0.0
* @throws Exception
*/
protected function getIdxLookup($keys)
{
// First pass, create a lookup of the keys.
$lookup = array();
foreach ($keys as $key)
{
if ($key instanceof SimpleXMLElement)
{
$kName = (string) $key['Index'];
}
else
{
$kName = $key->Index;
}
if (empty($lookup[$kName]))
{
$lookup[$kName] = array();
}
$lookup[$kName][] = $key;
}
return $lookup;
}
/**
* Get the details list of sequences for a table.
*
* @param array $sequences An array of objects that comprise the
sequences for the table.
*
* @return array The lookup array. array({key name} => array(object,
...))
*
* @since 3.0.0
* @throws Exception
*/
protected function getSeqLookup($sequences)
{
// First pass, create a lookup of the keys.
$lookup = array();
foreach ($sequences as $seq)
{
if ($seq instanceof SimpleXMLElement)
{
$sName = (string) $seq['Name'];
}
else
{
$sName = $seq->Name;
}
if (empty($lookup[$sName]))
{
$lookup[$sName] = array();
}
$lookup[$sName][] = $seq;
}
return $lookup;
}
}
PK�d�[Gu�SSimporter.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* Joomla Platform Database Importer Class
*
* @since 3.0.0
*/
abstract class JDatabaseImporter
{
/**
* @var array An array of cached data.
* @since 3.2.0
*/
protected $cache = array();
/**
* The database connector to use for exporting structure and/or data.
*
* @var JDatabaseDriver
* @since 3.2.0
*/
protected $db = null;
/**
* The input source.
*
* @var mixed
* @since 3.2.0
*/
protected $from = array();
/**
* The type of input format (XML).
*
* @var string
* @since 3.2.0
*/
protected $asFormat = 'xml';
/**
* An array of options for the exporter.
*
* @var object
* @since 3.2.0
*/
protected $options = null;
/**
* Constructor.
*
* Sets up the default options for the exporter.
*
* @since 3.2.0
*/
public function __construct()
{
$this->options = new stdClass;
$this->cache = array('columns' => array(),
'keys' => array());
// Set up the class defaults:
// Import with only structure
$this->withStructure();
// Export as XML.
$this->asXml();
// Default destination is a string using $output = (string) $exporter;
}
/**
* Set the output option for the exporter to XML format.
*
* @return JDatabaseImporter Method supports chaining.
*
* @since 3.2.0
*/
public function asXml()
{
$this->asFormat = 'xml';
return $this;
}
/**
* Checks if all data and options are in order prior to exporting.
*
* @return JDatabaseImporter Method supports chaining.
*
* @since 3.2.0
* @throws Exception if an error is encountered.
*/
abstract public function check();
/**
* Specifies the data source to import.
*
* @param mixed $from The data source to import.
*
* @return JDatabaseImporter Method supports chaining.
*
* @since 3.2.0
*/
public function from($from)
{
$this->from = $from;
return $this;
}
/**
* Get the SQL syntax to drop a column.
*
* @param string $table The table name.
* @param string $name The name of the field to drop.
*
* @return string
*
* @since 3.2.0
*/
protected function getDropColumnSql($table, $name)
{
return 'ALTER TABLE ' . $this->db->quoteName($table) .
' DROP COLUMN ' . $this->db->quoteName($name);
}
/**
* Get the real name of the table, converting the prefix wildcard string
if present.
*
* @param string $table The name of the table.
*
* @return string The real name of the table.
*
* @since 3.2.0
*/
protected function getRealTableName($table)
{
$prefix = $this->db->getPrefix();
// Replace the magic prefix if found.
$table = preg_replace('|^#__|', $prefix, $table);
return $table;
}
/**
* Merges the incoming structure definition with the existing structure.
*
* @return void
*
* @note Currently only supports XML format.
* @since 3.2.0
* @throws RuntimeException on error.
*/
public function mergeStructure()
{
$prefix = $this->db->getPrefix();
$tables = $this->db->getTableList();
if ($this->from instanceof SimpleXMLElement)
{
$xml = $this->from;
}
else
{
$xml = new SimpleXMLElement($this->from);
}
// Get all the table definitions.
$xmlTables = $xml->xpath('database/table_structure');
foreach ($xmlTables as $table)
{
// Convert the magic prefix into the real table name.
$tableName = (string) $table['name'];
$tableName = preg_replace('|^#__|', $prefix, $tableName);
if (in_array($tableName, $tables))
{
// The table already exists. Now check if there is any difference.
if ($queries = $this->getAlterTableSql($table))
{
// Run the queries to upgrade the data structure.
foreach ($queries as $query)
{
$this->db->setQuery((string) $query);
$this->db->execute();
}
}
}
else
{
// This is a new table.
$sql = $this->xmlToCreate($table);
$this->db->setQuery((string) $sql);
$this->db->execute();
}
}
}
/**
* Sets the database connector to use for exporting structure and/or data.
*
* @param JDatabaseDriver $db The database connector.
*
* @return JDatabaseImporter Method supports chaining.
*
* @since 3.2.0
*/
public function setDbo(JDatabaseDriver $db)
{
$this->db = $db;
return $this;
}
/**
* Sets an internal option to merge the structure based on the input data.
*
* @param boolean $setting True to export the structure, false to not.
*
* @return JDatabaseImporter Method supports chaining.
*
* @since 3.2.0
*/
public function withStructure($setting = true)
{
$this->options->withStructure = (boolean) $setting;
return $this;
}
}
PK�d�["y]U��iterator/pgsql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PostgreSQL database iterator for the PDO based PostgreSQL database
driver.
*
* @since 3.9.0
*/
class JDatabaseIteratorPgsql extends JDatabaseIteratorPdo
{
}
PK�d�[t�{��iterator/sqlazure.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* SQL azure database iterator.
*
* @since 3.0.0
*/
class JDatabaseIteratorSqlazure extends JDatabaseIteratorSqlsrv
{
}
PK�d�[���P}}query/pgsql.phpnu�[���<?php
/**
* @package Joomla.Platform
* @subpackage Database
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
/**
* PDO PostgreSQL Query Building Class.
*
* @since 3.9.0
*/
class JDatabaseQueryPgsql extends JDatabaseQueryPostgresql implements
JDatabaseQueryPreparable
{
/**
* Holds key / value pair of bound objects.
*
* @var mixed
* @since 3.9.0
*/
protected $bounded = array();
/**
* Method to add a variable to an internal array that will be bound to a
prepared SQL statement before query execution. Also
* removes a variable that has been bounded from the internal bounded
array when the passed in value is null.
*
* @param string|integer $key The key that will be used in
your SQL query to reference the value. Usually of
* the form ':key', but
can also be an integer.
* @param mixed &$value The value that will be
bound. The value is passed by reference to support output
* parameters such as those
possible with stored procedures.
* @param integer $dataType Constant corresponding to a
SQL datatype.
* @param integer $length The length of the variable.
Usually required for OUTPUT parameters.
* @param array $driverOptions Optional driver options to be
used.
*
* @return JDatabaseQueryPgsql
*
* @since 3.9.0
*/
public function bind($key = null, &$value = null, $dataType =
PDO::PARAM_STR, $length = 0, $driverOptions = array())
{
// Case 1: Empty Key (reset $bounded array)
if (empty($key))
{
$this->bounded = array();
return $this;
}
// Case 2: Key Provided, null value (unset key from $bounded array)
if (is_null($value))
{
if (isset($this->bounded[$key]))
{
unset($this->bounded[$key]);
}
return $this;
}
$obj = new stdClass;
$obj->value = &$value;
$obj->dataType = $dataType;
$obj->length = $length;
$obj->driverOptions = $driverOptions;
// Case 3: Simply add the Key/Value into the bounded array
$this->bounded[$key] = $obj;
return $this;
}
/**
* Retrieves the bound parameters array when key is null and returns it by
reference. If a key is provided then that item is
* returned.
*
* @param mixed $key The bounded variable key to retrieve.
*
* @return mixed
*
* @since 3.9.0
*/
public function &getBounded($key = null)
{
if (empty($key))
{
return $this->bounded;
}
if (isset($this->bounded[$key]))
{
return $this->bounded[$key];
}
}
/**
* Clear data from the query or a specific clause of the query.
*
* @param string $clause Optionally, the name of the clause to clear,
or nothing to clear the whole query.
*
* @return JDatabaseQueryPgsql Returns this object to allow chaining.
*
* @since 3.9.0
*/
public function clear($clause = null)
{
switch ($clause)
{
case null:
$this->bounded = array();
break;
}
return parent::clear($clause);
}
}
PK��[��database.phpnu�[���PK��[�Q===driver/joomla.phpnu�[���PK��[�kp0�7�7�Qdriver/mysql.phpnu�[���PK��[�'�HaHa��driver/mysqli.phpnu�[���PK ��[����=�=7�driver/oracle.phpnu�[���PK ��[:�֍�g�g
)driver/pdo.phpnu�[���PK ��[ �CQ5Q5+�driver/pdomysql.phpnu�[���PK ��[�t�֠֠��driver/postgresql.phpnu�[���PK ��[�KKXRR�gdriver/sqlazure.phpnu�[���PK ��[�s��//ojdriver/sqlite.phpnu�[���PK ��[�)�$l$l̙driver/sqlsrv.phpnu�[���PK ��[��UD�D�
1driver.phpnu�[���PK ��[::2jj��factory.phpnu�[���PK ��[��GD�[�[
T�installer.phpnu�[���PK ��[���''
QVinterface.phpnu�[���PK ��[�
�JQQ�Xiterator/azure.phpnu�[���PK ��[6
0��H[iterator/mysql.phpnu�[���PK ��[l]����{`iterator/mysqli.phpnu�[���PK ��[�V����Peiterator/oracle.phpnu�[���PK ��[c�t��giterator/pdo.phpnu�[���PK ��[g�Zmiterator/pdomysql.phpnu�[���PK ��[�����_oiterator/postgresql.phpnu�[���PK ��[Zn��otiterator/sqlite.phpnu�[���PK ��[-����<viterator/sqlsrv.phpnu�[���PK ��[h�Jh��{iterator.phpnu�[���PK ��[�D�
�
�query/element.phpnu�[���PK ��[?}P>����query/limitable.phpnu�[���PK ��[��q����query/mysql.phpnu�[���PK ��[��
����query/mysqli.phpnu�[���PK ��[�w<����query/oracle.phpnu�[���PK ��[�����
��query/pdo.phpnu�[���PK ��[h.�����query/pdomysql.phpnu�[���PK ��[�Za�BB��query/postgresql.phpnu�[���PK ��[ T����.query/preparable.phpnu�[���PK ��[L�;�887query/sqlazure.phpnu�[���PK ��[� �(�(�query/sqlite.phpnu�[���PK ��[h��{�]�]�Dquery/sqlsrv.phpnu�[���PK ��[�_����� �query.phpnu�[���PK�d�[��gg�Sdriver/pgsql.phpnu�[���PK�d�[�ۄ����exception/connecting.phpnu�[���PK�d�[>�����
�exception/executing.phpnu�[���PK�d�[n��u��.�exception/unsupported.phpnu�[���PK�d�[+��%�exporter/mysql.phpnu�[���PK�d�[�{c���o�exporter/mysqli.phpnu�[���PK�d�[�U��=�exporter/pdomysql.phpnu�[���PK�d�[THF{��v�exporter/pgsql.phpnu�[���PK�d�[��v��exporter/postgresql.phpnu�[���PK�d�[r�(����exporter.phpnu�[���PK�d�[�ڙ�importer/mysql.phpnu�[���PK�d�[&��;�-�-' importer/mysqli.phpnu�[���PK�d�[;c%�
,
,37importer/pdomysql.phpnu�[���PK�d�[�
-����cimporter/pgsql.phpnu�[���PK�d�[Z��38989�gimporter/postgresql.phpnu�[���PK�d�[Gu�SS)�importer.phpnu�[���PK�d�["y]U����iterator/pgsql.phpnu�[���PK�d�[t�{����iterator/sqlazure.phpnu�[���PK�d�[���P}}��query/pgsql.phpnu�[���PK99"G�