Augmentation vers version 3.3.0
This commit is contained in:
1220
install/update/old/phpbb/db/driver/driver.php
Normal file
1220
install/update/old/phpbb/db/driver/driver.php
Normal file
File diff suppressed because it is too large
Load Diff
453
install/update/old/phpbb/db/driver/driver_interface.php
Normal file
453
install/update/old/phpbb/db/driver/driver_interface.php
Normal file
@@ -0,0 +1,453 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
interface driver_interface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the sql layer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_sql_layer();
|
||||
|
||||
/**
|
||||
* Gets the name of the database.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_db_name();
|
||||
|
||||
/**
|
||||
* Wildcards for matching any (%) character within LIKE expressions
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_any_char();
|
||||
|
||||
/**
|
||||
* Wildcards for matching exactly one (_) character within LIKE expressions
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_one_char();
|
||||
|
||||
/**
|
||||
* Gets the time spent into the queries
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_sql_time();
|
||||
|
||||
/**
|
||||
* Gets the connect ID.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_db_connect_id();
|
||||
|
||||
/**
|
||||
* Indicates if an error was triggered.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_sql_error_triggered();
|
||||
|
||||
/**
|
||||
* Gets the last faulty query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_sql_error_sql();
|
||||
|
||||
/**
|
||||
* Indicates if we are in a transaction.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_transaction();
|
||||
|
||||
/**
|
||||
* Gets the returned error.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_sql_error_returned();
|
||||
|
||||
/**
|
||||
* Indicates if multiple insertion can be used
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_multi_insert();
|
||||
|
||||
/**
|
||||
* Set if multiple insertion can be used
|
||||
*
|
||||
* @param bool $multi_insert
|
||||
*/
|
||||
public function set_multi_insert($multi_insert);
|
||||
|
||||
/**
|
||||
* Gets the exact number of rows in a specified table.
|
||||
*
|
||||
* @param string $table_name Table name
|
||||
* @return string Exact number of rows in $table_name.
|
||||
*/
|
||||
public function get_row_count($table_name);
|
||||
|
||||
/**
|
||||
* Gets the estimated number of rows in a specified table.
|
||||
*
|
||||
* @param string $table_name Table name
|
||||
* @return string Number of rows in $table_name.
|
||||
* Prefixed with ~ if estimated (otherwise exact).
|
||||
*/
|
||||
public function get_estimated_row_count($table_name);
|
||||
|
||||
/**
|
||||
* Run LOWER() on DB column of type text (i.e. neither varchar nor char).
|
||||
*
|
||||
* @param string $column_name The column name to use
|
||||
* @return string A SQL statement like "LOWER($column_name)"
|
||||
*/
|
||||
public function sql_lower_text($column_name);
|
||||
|
||||
/**
|
||||
* Display sql error page
|
||||
*
|
||||
* @param string $sql The SQL query causing the error
|
||||
* @return mixed Returns the full error message, if $this->return_on_error
|
||||
* is set, null otherwise
|
||||
*/
|
||||
public function sql_error($sql = '');
|
||||
|
||||
/**
|
||||
* Returns whether results of a query need to be buffered to run a
|
||||
* transaction while iterating over them.
|
||||
*
|
||||
* @return bool Whether buffering is required.
|
||||
*/
|
||||
public function sql_buffer_nested_transactions();
|
||||
|
||||
/**
|
||||
* Run binary OR operator on DB column.
|
||||
*
|
||||
* @param string $column_name The column name to use
|
||||
* @param int $bit The value to use for the OR operator,
|
||||
* will be converted to (1 << $bit). Is used by options,
|
||||
* using the number schema... 0, 1, 2...29
|
||||
* @param string $compare Any custom SQL code after the check (e.g. "= 0")
|
||||
* @return string A SQL statement like "$column | (1 << $bit) {$compare}"
|
||||
*/
|
||||
public function sql_bit_or($column_name, $bit, $compare = '');
|
||||
|
||||
/**
|
||||
* Version information about used database
|
||||
*
|
||||
* @param bool $raw Only return the fetched sql_server_version
|
||||
* @param bool $use_cache Is it safe to retrieve the value from the cache
|
||||
* @return string sql server version
|
||||
*/
|
||||
public function sql_server_info($raw = false, $use_cache = true);
|
||||
|
||||
/**
|
||||
* Return on error or display error message
|
||||
*
|
||||
* @param bool $fail Should we return on errors, or stop
|
||||
* @return null
|
||||
*/
|
||||
public function sql_return_on_error($fail = false);
|
||||
|
||||
/**
|
||||
* Build sql statement from an array
|
||||
*
|
||||
* @param string $query Should be on of the following strings:
|
||||
* INSERT, INSERT_SELECT, UPDATE, SELECT, DELETE
|
||||
* @param array $assoc_ary Array with "column => value" pairs
|
||||
* @return string A SQL statement like "c1 = 'a' AND c2 = 'b'"
|
||||
*/
|
||||
public function sql_build_array($query, $assoc_ary = array());
|
||||
|
||||
/**
|
||||
* Fetch all rows
|
||||
*
|
||||
* @param mixed $query_id Already executed query to get the rows from,
|
||||
* if false, the last query will be used.
|
||||
* @return mixed Nested array if the query had rows, false otherwise
|
||||
*/
|
||||
public function sql_fetchrowset($query_id = false);
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
*
|
||||
* @param string $status Should be one of the following strings:
|
||||
* begin, commit, rollback
|
||||
* @return mixed Buffered, seekable result handle, false on error
|
||||
*/
|
||||
public function sql_transaction($status = 'begin');
|
||||
|
||||
/**
|
||||
* Build a concatenated expression
|
||||
*
|
||||
* @param string $expr1 Base SQL expression where we append the second one
|
||||
* @param string $expr2 SQL expression that is appended to the first expression
|
||||
* @return string Concatenated string
|
||||
*/
|
||||
public function sql_concatenate($expr1, $expr2);
|
||||
|
||||
/**
|
||||
* Build a case expression
|
||||
*
|
||||
* Note: The two statements action_true and action_false must have the same
|
||||
* data type (int, vchar, ...) in the database!
|
||||
*
|
||||
* @param string $condition The condition which must be true,
|
||||
* to use action_true rather then action_else
|
||||
* @param string $action_true SQL expression that is used, if the condition is true
|
||||
* @param mixed $action_false SQL expression that is used, if the condition is false
|
||||
* @return string CASE expression including the condition and statements
|
||||
*/
|
||||
public function sql_case($condition, $action_true, $action_false = false);
|
||||
|
||||
/**
|
||||
* Build sql statement from array for select and select distinct statements
|
||||
*
|
||||
* Possible query values: SELECT, SELECT_DISTINCT
|
||||
*
|
||||
* @param string $query Should be one of: SELECT, SELECT_DISTINCT
|
||||
* @param array $array Array with the query data:
|
||||
* SELECT A comma imploded list of columns to select
|
||||
* FROM Array with "table => alias" pairs,
|
||||
* (alias can also be an array)
|
||||
* Optional: LEFT_JOIN Array of join entries:
|
||||
* FROM Table that should be joined
|
||||
* ON Condition for the join
|
||||
* Optional: WHERE Where SQL statement
|
||||
* Optional: GROUP_BY Group by SQL statement
|
||||
* Optional: ORDER_BY Order by SQL statement
|
||||
* @return string A SQL statement ready for execution
|
||||
*/
|
||||
public function sql_build_query($query, $array);
|
||||
|
||||
/**
|
||||
* Fetch field
|
||||
* if rownum is false, the current row is used, else it is pointing to the row (zero-based)
|
||||
*
|
||||
* @param string $field Name of the column
|
||||
* @param mixed $rownum Row number, if false the current row will be used
|
||||
* and the row curser will point to the next row
|
||||
* Note: $rownum is 0 based
|
||||
* @param mixed $query_id Already executed query to get the rows from,
|
||||
* if false, the last query will be used.
|
||||
* @return mixed String value of the field in the selected row,
|
||||
* false, if the row does not exist
|
||||
*/
|
||||
public function sql_fetchfield($field, $rownum = false, $query_id = false);
|
||||
|
||||
/**
|
||||
* Fetch current row
|
||||
*
|
||||
* @param mixed $query_id Already executed query to get the rows from,
|
||||
* if false, the last query will be used.
|
||||
* @return mixed Array with the current row,
|
||||
* false, if the row does not exist
|
||||
*/
|
||||
public function sql_fetchrow($query_id = false);
|
||||
|
||||
/**
|
||||
* Returns SQL string to cast a string expression to an int.
|
||||
*
|
||||
* @param string $expression An expression evaluating to string
|
||||
* @return string Expression returning an int
|
||||
*/
|
||||
public function cast_expr_to_bigint($expression);
|
||||
|
||||
/**
|
||||
* Get last inserted id after insert statement
|
||||
*
|
||||
* @return string Autoincrement value of the last inserted row
|
||||
*/
|
||||
public function sql_nextid();
|
||||
|
||||
/**
|
||||
* Add to query count
|
||||
*
|
||||
* @param bool $cached Is this query cached?
|
||||
* @return null
|
||||
*/
|
||||
public function sql_add_num_queries($cached = false);
|
||||
|
||||
/**
|
||||
* Build LIMIT query
|
||||
*
|
||||
* @param string $query The SQL query to execute
|
||||
* @param int $total The number of rows to select
|
||||
* @param int $offset
|
||||
* @param int $cache_ttl Either 0 to avoid caching or
|
||||
* the time in seconds which the result shall be kept in cache
|
||||
* @return mixed Buffered, seekable result handle, false on error
|
||||
*/
|
||||
public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0);
|
||||
|
||||
/**
|
||||
* Base query method
|
||||
*
|
||||
* @param string $query The SQL query to execute
|
||||
* @param int $cache_ttl Either 0 to avoid caching or
|
||||
* the time in seconds which the result shall be kept in cache
|
||||
* @return mixed Buffered, seekable result handle, false on error
|
||||
*/
|
||||
public function sql_query($query = '', $cache_ttl = 0);
|
||||
|
||||
/**
|
||||
* Returns SQL string to cast an integer expression to a string.
|
||||
*
|
||||
* @param string $expression An expression evaluating to int
|
||||
* @return string Expression returning a string
|
||||
*/
|
||||
public function cast_expr_to_string($expression);
|
||||
|
||||
/**
|
||||
* Connect to server
|
||||
*
|
||||
* @param string $sqlserver Address of the database server
|
||||
* @param string $sqluser User name of the SQL user
|
||||
* @param string $sqlpassword Password of the SQL user
|
||||
* @param string $database Name of the database
|
||||
* @param mixed $port Port of the database server
|
||||
* @param bool $persistency
|
||||
* @param bool $new_link Should a new connection be established
|
||||
* @return mixed Connection ID on success, string error message otherwise
|
||||
*/
|
||||
public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false);
|
||||
|
||||
/**
|
||||
* Run binary AND operator on DB column.
|
||||
* Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}"
|
||||
*
|
||||
* @param string $column_name The column name to use
|
||||
* @param int $bit The value to use for the AND operator,
|
||||
* will be converted to (1 << $bit). Is used by
|
||||
* options, using the number schema: 0, 1, 2...29
|
||||
* @param string $compare Any custom SQL code after the check (for example "= 0")
|
||||
* @return string A SQL statement like: "{$column} & (1 << {$bit}) {$compare}"
|
||||
*/
|
||||
public function sql_bit_and($column_name, $bit, $compare = '');
|
||||
|
||||
/**
|
||||
* Free sql result
|
||||
*
|
||||
* @param mixed $query_id Already executed query result,
|
||||
* if false, the last query will be used.
|
||||
* @return null
|
||||
*/
|
||||
public function sql_freeresult($query_id = false);
|
||||
|
||||
/**
|
||||
* Return number of sql queries and cached sql queries used
|
||||
*
|
||||
* @param bool $cached Should we return the number of cached or normal queries?
|
||||
* @return int Number of queries that have been executed
|
||||
*/
|
||||
public function sql_num_queries($cached = false);
|
||||
|
||||
/**
|
||||
* Run more than one insert statement.
|
||||
*
|
||||
* @param string $table Table name to run the statements on
|
||||
* @param array $sql_ary Multi-dimensional array holding the statement data
|
||||
* @return bool false if no statements were executed.
|
||||
*/
|
||||
public function sql_multi_insert($table, $sql_ary);
|
||||
|
||||
/**
|
||||
* Return number of affected rows
|
||||
*
|
||||
* @return mixed Number of the affected rows by the last query
|
||||
* false if no query has been run before
|
||||
*/
|
||||
public function sql_affectedrows();
|
||||
|
||||
/**
|
||||
* DBAL garbage collection, close SQL connection
|
||||
*
|
||||
* @return mixed False if no connection was opened before,
|
||||
* Server response otherwise
|
||||
*/
|
||||
public function sql_close();
|
||||
|
||||
/**
|
||||
* Seek to given row number
|
||||
*
|
||||
* @param mixed $rownum Row number the curser should point to
|
||||
* Note: $rownum is 0 based
|
||||
* @param mixed $query_id ID of the query to set the row cursor on
|
||||
* if false, the last query will be used.
|
||||
* $query_id will then be set correctly
|
||||
* @return bool False if something went wrong
|
||||
*/
|
||||
public function sql_rowseek($rownum, &$query_id);
|
||||
|
||||
/**
|
||||
* Escape string used in sql query
|
||||
*
|
||||
* @param string $msg String to be escaped
|
||||
* @return string Escaped version of $msg
|
||||
*/
|
||||
public function sql_escape($msg);
|
||||
|
||||
/**
|
||||
* Correctly adjust LIKE expression for special characters
|
||||
* Some DBMS are handling them in a different way
|
||||
*
|
||||
* @param string $expression The expression to use. Every wildcard is
|
||||
* escaped, except $this->any_char and $this->one_char
|
||||
* @return string A SQL statement like: "LIKE 'bertie_%'"
|
||||
*/
|
||||
public function sql_like_expression($expression);
|
||||
|
||||
/**
|
||||
* Correctly adjust NOT LIKE expression for special characters
|
||||
* Some DBMS are handling them in a different way
|
||||
*
|
||||
* @param string $expression The expression to use. Every wildcard is
|
||||
* escaped, except $this->any_char and $this->one_char
|
||||
* @return string A SQL statement like: "NOT LIKE 'bertie_%'"
|
||||
*/
|
||||
public function sql_not_like_expression($expression);
|
||||
|
||||
/**
|
||||
* Explain queries
|
||||
*
|
||||
* @param string $mode Available modes: display, start, stop,
|
||||
* add_select_row, fromcache, record_fromcache
|
||||
* @param string $query The Query that should be explained
|
||||
* @return mixed Either a full HTML page, boolean or null
|
||||
*/
|
||||
public function sql_report($mode, $query = '');
|
||||
|
||||
/**
|
||||
* Build IN or NOT IN sql comparison string, uses <> or = on single element
|
||||
* arrays to improve comparison speed
|
||||
*
|
||||
* @param string $field Name of the sql column that shall be compared
|
||||
* @param array $array Array of values that are (not) allowed
|
||||
* @param bool $negate true for NOT IN (), false for IN ()
|
||||
* @param bool $allow_empty_set If true, allow $array to be empty,
|
||||
* this function will return 1=1 or 1=0 then.
|
||||
* @return string A SQL statement like: "IN (1, 2, 3, 4)" or "= 1"
|
||||
*/
|
||||
public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false);
|
||||
}
|
||||
443
install/update/old/phpbb/db/driver/factory.php
Normal file
443
install/update/old/phpbb/db/driver/factory.php
Normal file
@@ -0,0 +1,443 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
use \Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Database Abstraction Layer
|
||||
*/
|
||||
class factory implements driver_interface
|
||||
{
|
||||
/**
|
||||
* @var driver_interface
|
||||
*/
|
||||
protected $driver = null;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ContainerInterface $container A ContainerInterface instance
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current driver (and retrieved it from the container if necessary)
|
||||
*
|
||||
* @return driver_interface
|
||||
*/
|
||||
protected function get_driver()
|
||||
{
|
||||
if ($this->driver === null)
|
||||
{
|
||||
$this->driver = $this->container->get('dbal.conn.driver');
|
||||
}
|
||||
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current driver
|
||||
*
|
||||
* @param driver_interface $driver
|
||||
*/
|
||||
public function set_driver(driver_interface $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_sql_layer()
|
||||
{
|
||||
return $this->get_driver()->get_sql_layer();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_db_name()
|
||||
{
|
||||
return $this->get_driver()->get_db_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_any_char()
|
||||
{
|
||||
return $this->get_driver()->get_any_char();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_one_char()
|
||||
{
|
||||
return $this->get_driver()->get_one_char();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_db_connect_id()
|
||||
{
|
||||
return $this->get_driver()->get_db_connect_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_sql_error_triggered()
|
||||
{
|
||||
return $this->get_driver()->get_sql_error_triggered();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_sql_error_sql()
|
||||
{
|
||||
return $this->get_driver()->get_sql_error_sql();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_transaction()
|
||||
{
|
||||
return $this->get_driver()->get_transaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_sql_time()
|
||||
{
|
||||
return $this->get_driver()->get_sql_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_sql_error_returned()
|
||||
{
|
||||
return $this->get_driver()->get_sql_error_returned();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_multi_insert()
|
||||
{
|
||||
return $this->get_driver()->get_multi_insert();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set_multi_insert($multi_insert)
|
||||
{
|
||||
$this->get_driver()->set_multi_insert($multi_insert);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_row_count($table_name)
|
||||
{
|
||||
return $this->get_driver()->get_row_count($table_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_estimated_row_count($table_name)
|
||||
{
|
||||
return $this->get_driver()->get_estimated_row_count($table_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_lower_text($column_name)
|
||||
{
|
||||
return $this->get_driver()->sql_lower_text($column_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_error($sql = '')
|
||||
{
|
||||
return $this->get_driver()->sql_error($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_buffer_nested_transactions()
|
||||
{
|
||||
return $this->get_driver()->sql_buffer_nested_transactions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_bit_or($column_name, $bit, $compare = '')
|
||||
{
|
||||
return $this->get_driver()->sql_bit_or($column_name, $bit, $compare);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
return $this->get_driver()->sql_server_info($raw, $use_cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_return_on_error($fail = false)
|
||||
{
|
||||
return $this->get_driver()->sql_return_on_error($fail);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_build_array($query, $assoc_ary = array())
|
||||
{
|
||||
return $this->get_driver()->sql_build_array($query, $assoc_ary);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_fetchrowset($query_id = false)
|
||||
{
|
||||
return $this->get_driver()->sql_fetchrowset($query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_transaction($status = 'begin')
|
||||
{
|
||||
return $this->get_driver()->sql_transaction($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_concatenate($expr1, $expr2)
|
||||
{
|
||||
return $this->get_driver()->sql_concatenate($expr1, $expr2);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_case($condition, $action_true, $action_false = false)
|
||||
{
|
||||
return $this->get_driver()->sql_case($condition, $action_true, $action_false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_build_query($query, $array)
|
||||
{
|
||||
return $this->get_driver()->sql_build_query($query, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_fetchfield($field, $rownum = false, $query_id = false)
|
||||
{
|
||||
return $this->get_driver()->sql_fetchfield($field, $rownum, $query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_fetchrow($query_id = false)
|
||||
{
|
||||
return $this->get_driver()->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cast_expr_to_bigint($expression)
|
||||
{
|
||||
return $this->get_driver()->cast_expr_to_bigint($expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_nextid()
|
||||
{
|
||||
return $this->get_driver()->sql_nextid();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_add_num_queries($cached = false)
|
||||
{
|
||||
return $this->get_driver()->sql_add_num_queries($cached);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
|
||||
{
|
||||
return $this->get_driver()->sql_query_limit($query, $total, $offset, $cache_ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
return $this->get_driver()->sql_query($query, $cache_ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cast_expr_to_string($expression)
|
||||
{
|
||||
return $this->get_driver()->cast_expr_to_string($expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
throw new \Exception('Disabled method.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_bit_and($column_name, $bit, $compare = '')
|
||||
{
|
||||
return $this->get_driver()->sql_bit_and($column_name, $bit, $compare);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_freeresult($query_id = false)
|
||||
{
|
||||
return $this->get_driver()->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_num_queries($cached = false)
|
||||
{
|
||||
return $this->get_driver()->sql_num_queries($cached);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_multi_insert($table, $sql_ary)
|
||||
{
|
||||
return $this->get_driver()->sql_multi_insert($table, $sql_ary);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_affectedrows()
|
||||
{
|
||||
return $this->get_driver()->sql_affectedrows();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_close()
|
||||
{
|
||||
return $this->get_driver()->sql_close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_rowseek($rownum, &$query_id)
|
||||
{
|
||||
return $this->get_driver()->sql_rowseek($rownum, $query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_escape($msg)
|
||||
{
|
||||
return $this->get_driver()->sql_escape($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_like_expression($expression)
|
||||
{
|
||||
return $this->get_driver()->sql_like_expression($expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_not_like_expression($expression)
|
||||
{
|
||||
return $this->get_driver()->sql_not_like_expression($expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_report($mode, $query = '')
|
||||
{
|
||||
return $this->get_driver()->sql_report($mode, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
|
||||
{
|
||||
return $this->get_driver()->sql_in_set($field, $array, $negate, $allow_empty_set);
|
||||
}
|
||||
}
|
||||
385
install/update/old/phpbb/db/driver/mssql_odbc.php
Normal file
385
install/update/old/phpbb/db/driver/mssql_odbc.php
Normal file
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
/**
|
||||
* Unified ODBC functions
|
||||
* Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere...
|
||||
* Here we only support MSSQL Server 2000+ because of the provided schema
|
||||
*
|
||||
* @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting.
|
||||
* If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example.
|
||||
* @note odbc.defaultbinmode may affect UTF8 characters
|
||||
*/
|
||||
class mssql_odbc extends \phpbb\db\driver\mssql_base
|
||||
{
|
||||
var $last_query_text = '';
|
||||
var $connect_error = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
$this->persistency = $persistency;
|
||||
$this->user = $sqluser;
|
||||
$this->dbname = $database;
|
||||
|
||||
$port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
|
||||
$this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
|
||||
|
||||
$max_size = @ini_get('odbc.defaultlrl');
|
||||
if (!empty($max_size))
|
||||
{
|
||||
$unit = strtolower(substr($max_size, -1, 1));
|
||||
$max_size = (int) $max_size;
|
||||
|
||||
if ($unit == 'k')
|
||||
{
|
||||
$max_size = floor($max_size / 1024);
|
||||
}
|
||||
else if ($unit == 'g')
|
||||
{
|
||||
$max_size *= 1024;
|
||||
}
|
||||
else if (is_numeric($unit))
|
||||
{
|
||||
$max_size = floor((int) ($max_size . $unit) / 1048576);
|
||||
}
|
||||
$max_size = max(8, $max_size) . 'M';
|
||||
|
||||
@ini_set('odbc.defaultlrl', $max_size);
|
||||
}
|
||||
|
||||
if ($this->persistency)
|
||||
{
|
||||
if (!function_exists('odbc_pconnect'))
|
||||
{
|
||||
$this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!function_exists('odbc_connect'))
|
||||
{
|
||||
$this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword);
|
||||
}
|
||||
|
||||
return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssqlodbc_version')) === false)
|
||||
{
|
||||
$result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')");
|
||||
|
||||
$row = false;
|
||||
if ($result_id)
|
||||
{
|
||||
$row = odbc_fetch_array($result_id);
|
||||
odbc_free_result($result_id);
|
||||
}
|
||||
|
||||
$this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
|
||||
|
||||
if (!empty($cache) && $use_cache)
|
||||
{
|
||||
$cache->put('mssqlodbc_version', $this->sql_server_version);
|
||||
}
|
||||
}
|
||||
|
||||
if ($raw)
|
||||
{
|
||||
return $this->sql_server_version;
|
||||
}
|
||||
|
||||
return ($this->sql_server_version) ? 'MSSQL (ODBC)<br />' . $this->sql_server_version : 'MSSQL (ODBC)';
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
* @access private
|
||||
*/
|
||||
function _sql_transaction($status = 'begin')
|
||||
{
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION');
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION');
|
||||
break;
|
||||
|
||||
case 'rollback':
|
||||
return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION');
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
if ($query != '')
|
||||
{
|
||||
global $cache;
|
||||
|
||||
// EXPLAIN only in extra debug mode
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('start', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->curtime = microtime(true);
|
||||
}
|
||||
|
||||
$this->last_query_text = $query;
|
||||
$this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
|
||||
$this->sql_add_num_queries($this->query_result);
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
if (($this->query_result = @odbc_exec($this->db_connect_id, $query)) === false)
|
||||
{
|
||||
$this->sql_error($query);
|
||||
}
|
||||
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('stop', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->sql_time += microtime(true) - $this->curtime;
|
||||
}
|
||||
|
||||
if (!$this->query_result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cache && $cache_ttl)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
|
||||
}
|
||||
else if (strpos($query, 'SELECT') === 0)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
}
|
||||
}
|
||||
else if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('fromcache', $query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIMIT query
|
||||
*/
|
||||
function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
|
||||
{
|
||||
$this->query_result = false;
|
||||
|
||||
// Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
|
||||
if ($total)
|
||||
{
|
||||
// We need to grab the total number of rows + the offset number of rows to get the correct result
|
||||
if (strpos($query, 'SELECT DISTINCT') === 0)
|
||||
{
|
||||
$query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->sql_query($query, $cache_ttl);
|
||||
|
||||
// Seek by $offset rows
|
||||
if ($offset)
|
||||
{
|
||||
$this->sql_rowseek($offset, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_affectedrows()
|
||||
{
|
||||
return ($this->db_connect_id) ? @odbc_num_rows($this->query_result) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
return ($query_id) ? odbc_fetch_array($query_id) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_nextid()
|
||||
{
|
||||
$result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY');
|
||||
|
||||
if ($result_id)
|
||||
{
|
||||
if (odbc_fetch_array($result_id))
|
||||
{
|
||||
$id = odbc_result($result_id, 1);
|
||||
odbc_free_result($result_id);
|
||||
return $id;
|
||||
}
|
||||
odbc_free_result($result_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
if (isset($this->open_queries[(int) $query_id]))
|
||||
{
|
||||
unset($this->open_queries[(int) $query_id]);
|
||||
return odbc_free_result($query_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* return sql error array
|
||||
* @access private
|
||||
*/
|
||||
function _sql_error()
|
||||
{
|
||||
if (function_exists('odbc_errormsg'))
|
||||
{
|
||||
$error = array(
|
||||
'message' => @odbc_errormsg(),
|
||||
'code' => @odbc_error(),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = array(
|
||||
'message' => $this->connect_error,
|
||||
'code' => '',
|
||||
);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close sql connection
|
||||
* @access private
|
||||
*/
|
||||
function _sql_close()
|
||||
{
|
||||
return @odbc_close($this->db_connect_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific report
|
||||
* @access private
|
||||
*/
|
||||
function _sql_report($mode, $query = '')
|
||||
{
|
||||
switch ($mode)
|
||||
{
|
||||
case 'start':
|
||||
break;
|
||||
|
||||
case 'fromcache':
|
||||
$endtime = explode(' ', microtime());
|
||||
$endtime = $endtime[0] + $endtime[1];
|
||||
|
||||
$result = @odbc_exec($this->db_connect_id, $query);
|
||||
if ($result)
|
||||
{
|
||||
while ($void = odbc_fetch_array($result))
|
||||
{
|
||||
// Take the time spent on parsing rows into account
|
||||
}
|
||||
odbc_free_result($result);
|
||||
}
|
||||
|
||||
$splittime = explode(' ', microtime());
|
||||
$splittime = $splittime[0] + $splittime[1];
|
||||
|
||||
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
451
install/update/old/phpbb/db/driver/mssqlnative.php
Normal file
451
install/update/old/phpbb/db/driver/mssqlnative.php
Normal file
@@ -0,0 +1,451 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the MS SQL Server Native database abstraction layer.
|
||||
* PHP mssql native driver required.
|
||||
* @author Chris Pucci
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
class mssqlnative extends \phpbb\db\driver\mssql_base
|
||||
{
|
||||
var $m_insert_id = null;
|
||||
var $last_query_text = '';
|
||||
var $query_options = array();
|
||||
var $connect_error = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
// Test for driver support, to avoid suppressed fatal error
|
||||
if (!function_exists('sqlsrv_connect'))
|
||||
{
|
||||
$this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
|
||||
//set up connection variables
|
||||
$this->persistency = $persistency;
|
||||
$this->user = $sqluser;
|
||||
$this->dbname = $database;
|
||||
$port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
|
||||
$this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
|
||||
|
||||
//connect to database
|
||||
$this->db_connect_id = sqlsrv_connect($this->server, array(
|
||||
'Database' => $this->dbname,
|
||||
'UID' => $this->user,
|
||||
'PWD' => $sqlpassword,
|
||||
'CharacterSet' => 'UTF-8'
|
||||
));
|
||||
|
||||
return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false)
|
||||
{
|
||||
$arr_server_info = sqlsrv_server_info($this->db_connect_id);
|
||||
$this->sql_server_version = $arr_server_info['SQLServerVersion'];
|
||||
|
||||
if (!empty($cache) && $use_cache)
|
||||
{
|
||||
$cache->put('mssql_version', $this->sql_server_version);
|
||||
}
|
||||
}
|
||||
|
||||
if ($raw)
|
||||
{
|
||||
return $this->sql_server_version;
|
||||
}
|
||||
|
||||
return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_buffer_nested_transactions()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
* @access private
|
||||
*/
|
||||
function _sql_transaction($status = 'begin')
|
||||
{
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return sqlsrv_begin_transaction($this->db_connect_id);
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
return sqlsrv_commit($this->db_connect_id);
|
||||
break;
|
||||
|
||||
case 'rollback':
|
||||
return sqlsrv_rollback($this->db_connect_id);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
if ($query != '')
|
||||
{
|
||||
global $cache;
|
||||
|
||||
// EXPLAIN only in extra debug mode
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('start', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->curtime = microtime(true);
|
||||
}
|
||||
|
||||
$this->last_query_text = $query;
|
||||
$this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
|
||||
$this->sql_add_num_queries($this->query_result);
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false)
|
||||
{
|
||||
$this->sql_error($query);
|
||||
}
|
||||
// reset options for next query
|
||||
$this->query_options = array();
|
||||
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('stop', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->sql_time += microtime(true) - $this->curtime;
|
||||
}
|
||||
|
||||
if (!$this->query_result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cache && $cache_ttl)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
|
||||
}
|
||||
else if (strpos($query, 'SELECT') === 0)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
}
|
||||
}
|
||||
else if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('fromcache', $query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return $this->query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIMIT query
|
||||
*/
|
||||
function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
|
||||
{
|
||||
$this->query_result = false;
|
||||
|
||||
// total == 0 means all results - not zero results
|
||||
if ($offset == 0 && $total !== 0)
|
||||
{
|
||||
if (strpos($query, "SELECT") === false)
|
||||
{
|
||||
$query = "TOP {$total} " . $query;
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query);
|
||||
}
|
||||
}
|
||||
else if ($offset > 0)
|
||||
{
|
||||
$query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query);
|
||||
$query = 'SELECT *
|
||||
FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3
|
||||
FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3';
|
||||
|
||||
if ($total > 0)
|
||||
{
|
||||
$query .= ' WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total);
|
||||
}
|
||||
else
|
||||
{
|
||||
$query .= ' WHERE line3 > ' . $offset;
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->sql_query($query, $cache_ttl);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_affectedrows()
|
||||
{
|
||||
return ($this->db_connect_id) ? @sqlsrv_rows_affected($this->query_result) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
if (!$query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($row)
|
||||
{
|
||||
foreach ($row as $key => $value)
|
||||
{
|
||||
$row[$key] = ($value === ' ' || $value === null) ? '' : $value;
|
||||
}
|
||||
|
||||
// remove helper values from LIMIT queries
|
||||
if (isset($row['line2']))
|
||||
{
|
||||
unset($row['line2'], $row['line3']);
|
||||
}
|
||||
}
|
||||
return ($row !== null) ? $row : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_nextid()
|
||||
{
|
||||
$result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY');
|
||||
|
||||
if ($result_id)
|
||||
{
|
||||
$row = sqlsrv_fetch_array($result_id);
|
||||
$id = $row[0];
|
||||
sqlsrv_free_stmt($result_id);
|
||||
return $id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
if (isset($this->open_queries[(int) $query_id]))
|
||||
{
|
||||
unset($this->open_queries[(int) $query_id]);
|
||||
return sqlsrv_free_stmt($query_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* return sql error array
|
||||
* @access private
|
||||
*/
|
||||
function _sql_error()
|
||||
{
|
||||
if (function_exists('sqlsrv_errors'))
|
||||
{
|
||||
$errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS);
|
||||
$error_message = '';
|
||||
$code = 0;
|
||||
|
||||
if ($errors != null)
|
||||
{
|
||||
foreach ($errors as $error)
|
||||
{
|
||||
$error_message .= "SQLSTATE: " . $error['SQLSTATE'] . "\n";
|
||||
$error_message .= "code: " . $error['code'] . "\n";
|
||||
$code = $error['code'];
|
||||
$error_message .= "message: " . $error['message'] . "\n";
|
||||
}
|
||||
$this->last_error_result = $error_message;
|
||||
$error = $this->last_error_result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
|
||||
}
|
||||
|
||||
$error = array(
|
||||
'message' => $error,
|
||||
'code' => $code,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = array(
|
||||
'message' => $this->connect_error,
|
||||
'code' => '',
|
||||
);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close sql connection
|
||||
* @access private
|
||||
*/
|
||||
function _sql_close()
|
||||
{
|
||||
return @sqlsrv_close($this->db_connect_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific report
|
||||
* @access private
|
||||
*/
|
||||
function _sql_report($mode, $query = '')
|
||||
{
|
||||
switch ($mode)
|
||||
{
|
||||
case 'start':
|
||||
$html_table = false;
|
||||
@sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;');
|
||||
if ($result = @sqlsrv_query($this->db_connect_id, $query))
|
||||
{
|
||||
sqlsrv_next_result($result);
|
||||
while ($row = sqlsrv_fetch_array($result))
|
||||
{
|
||||
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
|
||||
}
|
||||
sqlsrv_free_stmt($result);
|
||||
}
|
||||
@sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;');
|
||||
|
||||
if ($html_table)
|
||||
{
|
||||
$this->html_hold .= '</table>';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'fromcache':
|
||||
$endtime = explode(' ', microtime());
|
||||
$endtime = $endtime[0] + $endtime[1];
|
||||
|
||||
$result = @sqlsrv_query($this->db_connect_id, $query);
|
||||
if ($result)
|
||||
{
|
||||
while ($void = sqlsrv_fetch_array($result))
|
||||
{
|
||||
// Take the time spent on parsing rows into account
|
||||
}
|
||||
sqlsrv_free_stmt($result);
|
||||
}
|
||||
|
||||
$splittime = explode(' ', microtime());
|
||||
$splittime = $splittime[0] + $splittime[1];
|
||||
|
||||
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to retrieve number of rows
|
||||
* Emulates mysql_num_rows
|
||||
* Used in acp_database.php -> write_data_mssqlnative()
|
||||
* Requires a static or keyset cursor to be definde via
|
||||
* mssqlnative_set_query_options()
|
||||
*/
|
||||
function mssqlnative_num_rows($res)
|
||||
{
|
||||
if ($res !== false)
|
||||
{
|
||||
return sqlsrv_num_rows($res);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter.
|
||||
*/
|
||||
function mssqlnative_set_query_options($options)
|
||||
{
|
||||
$this->query_options = $options;
|
||||
}
|
||||
}
|
||||
490
install/update/old/phpbb/db/driver/mysqli.php
Normal file
490
install/update/old/phpbb/db/driver/mysqli.php
Normal file
@@ -0,0 +1,490 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
/**
|
||||
* MySQLi Database Abstraction Layer
|
||||
* mysqli-extension has to be compiled with:
|
||||
* MySQL 4.1+ or MySQL 5.0+
|
||||
*/
|
||||
class mysqli extends \phpbb\db\driver\mysql_base
|
||||
{
|
||||
var $multi_insert = true;
|
||||
var $connect_error = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
if (!function_exists('mysqli_connect'))
|
||||
{
|
||||
$this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
|
||||
$this->persistency = $persistency;
|
||||
$this->user = $sqluser;
|
||||
|
||||
// If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix
|
||||
$this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver;
|
||||
|
||||
$this->dbname = $database;
|
||||
$port = (!$port) ? null : $port;
|
||||
|
||||
// If port is set and it is not numeric, most likely mysqli socket is set.
|
||||
// Try to map it to the $socket parameter.
|
||||
$socket = null;
|
||||
if ($port)
|
||||
{
|
||||
if (is_numeric($port))
|
||||
{
|
||||
$port = (int) $port;
|
||||
}
|
||||
else
|
||||
{
|
||||
$socket = $port;
|
||||
$port = null;
|
||||
}
|
||||
}
|
||||
|
||||
$this->db_connect_id = mysqli_init();
|
||||
|
||||
if (!@mysqli_real_connect($this->db_connect_id, $this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket, MYSQLI_CLIENT_FOUND_ROWS))
|
||||
{
|
||||
$this->db_connect_id = '';
|
||||
}
|
||||
|
||||
if ($this->db_connect_id && $this->dbname != '')
|
||||
{
|
||||
@mysqli_query($this->db_connect_id, "SET NAMES 'utf8'");
|
||||
|
||||
// enforce strict mode on databases that support it
|
||||
if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
|
||||
{
|
||||
$result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode');
|
||||
if ($result)
|
||||
{
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
mysqli_free_result($result);
|
||||
|
||||
$modes = array_map('trim', explode(',', $row['sql_mode']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$modes = array();
|
||||
}
|
||||
|
||||
// TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
|
||||
if (!in_array('TRADITIONAL', $modes))
|
||||
{
|
||||
if (!in_array('STRICT_ALL_TABLES', $modes))
|
||||
{
|
||||
$modes[] = 'STRICT_ALL_TABLES';
|
||||
}
|
||||
|
||||
if (!in_array('STRICT_TRANS_TABLES', $modes))
|
||||
{
|
||||
$modes[] = 'STRICT_TRANS_TABLES';
|
||||
}
|
||||
}
|
||||
|
||||
$mode = implode(',', $modes);
|
||||
@mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'");
|
||||
}
|
||||
return $this->db_connect_id;
|
||||
}
|
||||
|
||||
return $this->sql_error('');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false)
|
||||
{
|
||||
$result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version');
|
||||
if ($result)
|
||||
{
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
mysqli_free_result($result);
|
||||
|
||||
$this->sql_server_version = $row['version'];
|
||||
|
||||
if (!empty($cache) && $use_cache)
|
||||
{
|
||||
$cache->put('mysqli_version', $this->sql_server_version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
* @access private
|
||||
*/
|
||||
function _sql_transaction($status = 'begin')
|
||||
{
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return @mysqli_autocommit($this->db_connect_id, false);
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
$result = @mysqli_commit($this->db_connect_id);
|
||||
@mysqli_autocommit($this->db_connect_id, true);
|
||||
return $result;
|
||||
break;
|
||||
|
||||
case 'rollback':
|
||||
$result = @mysqli_rollback($this->db_connect_id);
|
||||
@mysqli_autocommit($this->db_connect_id, true);
|
||||
return $result;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
if ($query != '')
|
||||
{
|
||||
global $cache;
|
||||
|
||||
// EXPLAIN only in extra debug mode
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('start', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->curtime = microtime(true);
|
||||
}
|
||||
|
||||
$this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
|
||||
$this->sql_add_num_queries($this->query_result);
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false)
|
||||
{
|
||||
$this->sql_error($query);
|
||||
}
|
||||
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('stop', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->sql_time += microtime(true) - $this->curtime;
|
||||
}
|
||||
|
||||
if (!$this->query_result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cache && $cache_ttl)
|
||||
{
|
||||
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
|
||||
}
|
||||
}
|
||||
else if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('fromcache', $query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_affectedrows()
|
||||
{
|
||||
return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
if ($query_id)
|
||||
{
|
||||
$result = mysqli_fetch_assoc($query_id);
|
||||
return $result !== null ? $result : false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_rowseek($rownum, &$query_id)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_rowseek($rownum, $query_id);
|
||||
}
|
||||
|
||||
return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_nextid()
|
||||
{
|
||||
return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
if (!$query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($query_id === true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return mysqli_free_result($query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_escape($msg)
|
||||
{
|
||||
return @mysqli_real_escape_string($this->db_connect_id, $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* return sql error array
|
||||
* @access private
|
||||
*/
|
||||
function _sql_error()
|
||||
{
|
||||
if ($this->db_connect_id)
|
||||
{
|
||||
$error = array(
|
||||
'message' => @mysqli_error($this->db_connect_id),
|
||||
'code' => @mysqli_errno($this->db_connect_id)
|
||||
);
|
||||
}
|
||||
else if (function_exists('mysqli_connect_error'))
|
||||
{
|
||||
$error = array(
|
||||
'message' => @mysqli_connect_error(),
|
||||
'code' => @mysqli_connect_errno(),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = array(
|
||||
'message' => $this->connect_error,
|
||||
'code' => '',
|
||||
);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close sql connection
|
||||
* @access private
|
||||
*/
|
||||
function _sql_close()
|
||||
{
|
||||
return @mysqli_close($this->db_connect_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific report
|
||||
* @access private
|
||||
*/
|
||||
function _sql_report($mode, $query = '')
|
||||
{
|
||||
static $test_prof;
|
||||
|
||||
// current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING
|
||||
if ($test_prof === null)
|
||||
{
|
||||
$test_prof = false;
|
||||
if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false)
|
||||
{
|
||||
$ver = mysqli_get_server_version($this->db_connect_id);
|
||||
if ($ver >= 50037 && $ver < 50100)
|
||||
{
|
||||
$test_prof = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ($mode)
|
||||
{
|
||||
case 'start':
|
||||
|
||||
$explain_query = $query;
|
||||
if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
|
||||
{
|
||||
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
|
||||
}
|
||||
else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
|
||||
{
|
||||
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
|
||||
}
|
||||
|
||||
if (preg_match('/^SELECT/', $explain_query))
|
||||
{
|
||||
$html_table = false;
|
||||
|
||||
// begin profiling
|
||||
if ($test_prof)
|
||||
{
|
||||
@mysqli_query($this->db_connect_id, 'SET profiling = 1;');
|
||||
}
|
||||
|
||||
if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query"))
|
||||
{
|
||||
while ($row = mysqli_fetch_assoc($result))
|
||||
{
|
||||
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
}
|
||||
|
||||
if ($html_table)
|
||||
{
|
||||
$this->html_hold .= '</table>';
|
||||
}
|
||||
|
||||
if ($test_prof)
|
||||
{
|
||||
$html_table = false;
|
||||
|
||||
// get the last profile
|
||||
if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;'))
|
||||
{
|
||||
$this->html_hold .= '<br />';
|
||||
while ($row = mysqli_fetch_assoc($result))
|
||||
{
|
||||
// make <unknown> HTML safe
|
||||
if (!empty($row['Source_function']))
|
||||
{
|
||||
$row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']);
|
||||
}
|
||||
|
||||
// remove unsupported features
|
||||
foreach ($row as $key => $val)
|
||||
{
|
||||
if ($val === null)
|
||||
{
|
||||
unset($row[$key]);
|
||||
}
|
||||
}
|
||||
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
}
|
||||
|
||||
if ($html_table)
|
||||
{
|
||||
$this->html_hold .= '</table>';
|
||||
}
|
||||
|
||||
@mysqli_query($this->db_connect_id, 'SET profiling = 0;');
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'fromcache':
|
||||
$endtime = explode(' ', microtime());
|
||||
$endtime = $endtime[0] + $endtime[1];
|
||||
|
||||
$result = @mysqli_query($this->db_connect_id, $query);
|
||||
if ($result)
|
||||
{
|
||||
while ($void = mysqli_fetch_assoc($result))
|
||||
{
|
||||
// Take the time spent on parsing rows into account
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
}
|
||||
|
||||
$splittime = explode(' ', microtime());
|
||||
$splittime = $splittime[0] + $splittime[1];
|
||||
|
||||
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
822
install/update/old/phpbb/db/driver/oracle.php
Normal file
822
install/update/old/phpbb/db/driver/oracle.php
Normal file
@@ -0,0 +1,822 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
/**
|
||||
* Oracle Database Abstraction Layer
|
||||
*/
|
||||
class oracle extends \phpbb\db\driver\driver
|
||||
{
|
||||
var $last_query_text = '';
|
||||
var $connect_error = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
$this->persistency = $persistency;
|
||||
$this->user = $sqluser;
|
||||
$this->server = $sqlserver . (($port) ? ':' . $port : '');
|
||||
$this->dbname = $database;
|
||||
|
||||
$connect = $database;
|
||||
|
||||
// support for "easy connect naming"
|
||||
if ($sqlserver !== '' && $sqlserver !== '/')
|
||||
{
|
||||
if (substr($sqlserver, -1, 1) == '/')
|
||||
{
|
||||
$sqlserver == substr($sqlserver, 0, -1);
|
||||
}
|
||||
$connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database;
|
||||
}
|
||||
|
||||
if ($new_link)
|
||||
{
|
||||
if (!function_exists('ocinlogon'))
|
||||
{
|
||||
$this->connect_error = 'ocinlogon function does not exist, is oci extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8');
|
||||
}
|
||||
else if ($this->persistency)
|
||||
{
|
||||
if (!function_exists('ociplogon'))
|
||||
{
|
||||
$this->connect_error = 'ociplogon function does not exist, is oci extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!function_exists('ocilogon'))
|
||||
{
|
||||
$this->connect_error = 'ocilogon function does not exist, is oci extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8');
|
||||
}
|
||||
|
||||
return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
/**
|
||||
* force $use_cache false. I didn't research why the caching code below is commented out
|
||||
* but I assume its because the Oracle extension provides a direct method to access it
|
||||
* without a query.
|
||||
*/
|
||||
/*
|
||||
global $cache;
|
||||
|
||||
if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false)
|
||||
{
|
||||
$result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\'');
|
||||
@ociexecute($result, OCI_DEFAULT);
|
||||
@ocicommit($this->db_connect_id);
|
||||
|
||||
$row = array();
|
||||
@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS);
|
||||
@ocifreestatement($result);
|
||||
$this->sql_server_version = trim($row['BANNER']);
|
||||
|
||||
$cache->put('oracle_version', $this->sql_server_version);
|
||||
}
|
||||
*/
|
||||
$this->sql_server_version = @ociserverversion($this->db_connect_id);
|
||||
|
||||
return $this->sql_server_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
* @access private
|
||||
*/
|
||||
function _sql_transaction($status = 'begin')
|
||||
{
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
return @ocicommit($this->db_connect_id);
|
||||
break;
|
||||
|
||||
case 'rollback':
|
||||
return @ocirollback($this->db_connect_id);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle specific code to handle the fact that it does not compare columns properly
|
||||
* @access private
|
||||
*/
|
||||
function _rewrite_col_compare($args)
|
||||
{
|
||||
if (count($args) == 4)
|
||||
{
|
||||
if ($args[2] == '=')
|
||||
{
|
||||
return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))';
|
||||
}
|
||||
else if ($args[2] == '<>')
|
||||
{
|
||||
// really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
|
||||
return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->_rewrite_where($args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle specific code to handle it's lack of sanity
|
||||
* @access private
|
||||
*/
|
||||
function _rewrite_where($where_clause)
|
||||
{
|
||||
preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER);
|
||||
$out = '';
|
||||
foreach ($result as $val)
|
||||
{
|
||||
if (!isset($val[5]))
|
||||
{
|
||||
if ($val[4] !== "''")
|
||||
{
|
||||
$out .= $val[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$out .= ' ' . $val[1] . ' ' . $val[2];
|
||||
if ($val[3] == '=')
|
||||
{
|
||||
$out .= ' is NULL';
|
||||
}
|
||||
else if ($val[3] == '<>')
|
||||
{
|
||||
$out .= ' is NOT NULL';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$in_clause = array();
|
||||
$sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1);
|
||||
$extra = false;
|
||||
preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER);
|
||||
$i = 0;
|
||||
foreach ($sub_vals[0] as $sub_val)
|
||||
{
|
||||
// two things:
|
||||
// 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
|
||||
// 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
|
||||
if ($sub_val !== "''")
|
||||
{
|
||||
$in_clause[(int) $i++/1000][] = $sub_val;
|
||||
}
|
||||
else
|
||||
{
|
||||
$extra = true;
|
||||
}
|
||||
}
|
||||
if (!$extra && $i < 1000)
|
||||
{
|
||||
$out .= $val[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$out .= ' ' . $val[1] . '(';
|
||||
$in_array = array();
|
||||
|
||||
// constuct each IN() clause
|
||||
foreach ($in_clause as $in_values)
|
||||
{
|
||||
$in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
|
||||
}
|
||||
|
||||
// Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
|
||||
$out .= implode(' OR ', $in_array);
|
||||
|
||||
// handle the empty string case
|
||||
if ($extra)
|
||||
{
|
||||
$out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL';
|
||||
}
|
||||
$out .= ')';
|
||||
|
||||
unset($in_array, $in_clause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
if ($query != '')
|
||||
{
|
||||
global $cache;
|
||||
|
||||
// EXPLAIN only in extra debug mode
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('start', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->curtime = microtime(true);
|
||||
}
|
||||
|
||||
$this->last_query_text = $query;
|
||||
$this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
|
||||
$this->sql_add_num_queries($this->query_result);
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
$in_transaction = false;
|
||||
if (!$this->transaction)
|
||||
{
|
||||
$this->sql_transaction('begin');
|
||||
}
|
||||
else
|
||||
{
|
||||
$in_transaction = true;
|
||||
}
|
||||
|
||||
$array = array();
|
||||
|
||||
// We overcome Oracle's 4000 char limit by binding vars
|
||||
if (strlen($query) > 4000)
|
||||
{
|
||||
if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs))
|
||||
{
|
||||
if (strlen($regs[3]) > 4000)
|
||||
{
|
||||
$cols = explode(', ', $regs[2]);
|
||||
|
||||
preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
|
||||
|
||||
/* The code inside this comment block breaks clob handling, but does allow the
|
||||
database restore script to work. If you want to allow no posts longer than 4KB
|
||||
and/or need the db restore script, uncomment this.
|
||||
|
||||
|
||||
if (count($cols) !== count($vals))
|
||||
{
|
||||
// Try to replace some common data we know is from our restore script or from other sources
|
||||
$regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]);
|
||||
$_vals = explode(', ', $regs[3]);
|
||||
|
||||
$vals = array();
|
||||
$is_in_val = false;
|
||||
$i = 0;
|
||||
$string = '';
|
||||
|
||||
foreach ($_vals as $value)
|
||||
{
|
||||
if (strpos($value, "'") === false && !$is_in_val)
|
||||
{
|
||||
$vals[$i++] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (substr($value, -1) === "'")
|
||||
{
|
||||
$vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value;
|
||||
$string = '';
|
||||
$is_in_val = false;
|
||||
|
||||
if ($vals[$i][0] !== "'")
|
||||
{
|
||||
$vals[$i] = "''" . $vals[$i];
|
||||
}
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$string .= (($is_in_val) ? ', ' : '') . $value;
|
||||
$is_in_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($string)
|
||||
{
|
||||
// New value if cols != value
|
||||
$vals[(count($cols) !== count($vals)) ? $i : $i - 1] .= $string;
|
||||
}
|
||||
|
||||
$vals = array(0 => $vals);
|
||||
}
|
||||
*/
|
||||
|
||||
$inserts = $vals[0];
|
||||
unset($vals);
|
||||
|
||||
foreach ($inserts as $key => $value)
|
||||
{
|
||||
if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
|
||||
{
|
||||
$inserts[$key] = ':' . strtoupper($cols[$key]);
|
||||
$array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1));
|
||||
}
|
||||
}
|
||||
|
||||
$query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
|
||||
}
|
||||
}
|
||||
else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER))
|
||||
{
|
||||
if (strlen($data[0][2]) > 4000)
|
||||
{
|
||||
$update = $data[0][1];
|
||||
$where = $data[0][3];
|
||||
preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER);
|
||||
unset($data);
|
||||
|
||||
$cols = array();
|
||||
foreach ($temp as $value)
|
||||
{
|
||||
if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2
|
||||
{
|
||||
$cols[] = $value[1] . '=:' . strtoupper($value[1]);
|
||||
$array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
$cols[] = $value[1] . '=' . $value[2];
|
||||
}
|
||||
}
|
||||
|
||||
$query = $update . implode(', ', $cols) . ' ' . $where;
|
||||
unset($cols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (substr($query, 0, 6))
|
||||
{
|
||||
case 'DELETE':
|
||||
if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs))
|
||||
{
|
||||
$query = $regs[1] . $this->_rewrite_where($regs[2]);
|
||||
unset($regs);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UPDATE':
|
||||
if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs))
|
||||
{
|
||||
$query = $regs[1] . $this->_rewrite_where($regs[2]);
|
||||
unset($regs);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SELECT':
|
||||
$query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->query_result = @ociparse($this->db_connect_id, $query);
|
||||
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
@ocibindbyname($this->query_result, $key, $array[$key], -1);
|
||||
}
|
||||
|
||||
$success = @ociexecute($this->query_result, OCI_DEFAULT);
|
||||
|
||||
if (!$success)
|
||||
{
|
||||
$this->sql_error($query);
|
||||
$this->query_result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$in_transaction)
|
||||
{
|
||||
$this->sql_transaction('commit');
|
||||
}
|
||||
}
|
||||
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('stop', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->sql_time += microtime(true) - $this->curtime;
|
||||
}
|
||||
|
||||
if (!$this->query_result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cache && $cache_ttl)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
|
||||
}
|
||||
else if (strpos($query, 'SELECT') === 0)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
}
|
||||
}
|
||||
else if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('fromcache', $query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIMIT query
|
||||
*/
|
||||
function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
|
||||
{
|
||||
$this->query_result = false;
|
||||
|
||||
$query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
|
||||
|
||||
return $this->sql_query($query, $cache_ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_affectedrows()
|
||||
{
|
||||
return ($this->query_result) ? @ocirowcount($this->query_result) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
if ($query_id)
|
||||
{
|
||||
$row = array();
|
||||
$result = ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
|
||||
|
||||
if (!$result || !$row)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$result_row = array();
|
||||
foreach ($row as $key => $value)
|
||||
{
|
||||
// Oracle treats empty strings as null
|
||||
if (is_null($value))
|
||||
{
|
||||
$value = '';
|
||||
}
|
||||
|
||||
// OCI->CLOB?
|
||||
if (is_object($value))
|
||||
{
|
||||
$value = $value->load();
|
||||
}
|
||||
|
||||
$result_row[strtolower($key)] = $value;
|
||||
}
|
||||
|
||||
return $result_row;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_rowseek($rownum, &$query_id)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_rowseek($rownum, $query_id);
|
||||
}
|
||||
|
||||
if (!$query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset internal pointer
|
||||
@ociexecute($query_id, OCI_DEFAULT);
|
||||
|
||||
// We do not fetch the row for rownum == 0 because then the next resultset would be the second row
|
||||
for ($i = 0; $i < $rownum; $i++)
|
||||
{
|
||||
if (!$this->sql_fetchrow($query_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_nextid()
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
|
||||
if ($query_id !== false && $this->last_query_text != '')
|
||||
{
|
||||
if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
|
||||
{
|
||||
$query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
|
||||
$stmt = @ociparse($this->db_connect_id, $query);
|
||||
if ($stmt)
|
||||
{
|
||||
$success = @ociexecute($stmt, OCI_DEFAULT);
|
||||
|
||||
if ($success)
|
||||
{
|
||||
$temp_result = ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
|
||||
ocifreestatement($stmt);
|
||||
|
||||
if ($temp_result)
|
||||
{
|
||||
return $temp_array['CURRVAL'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
if (isset($this->open_queries[(int) $query_id]))
|
||||
{
|
||||
unset($this->open_queries[(int) $query_id]);
|
||||
return ocifreestatement($query_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_escape($msg)
|
||||
{
|
||||
return str_replace(array("'", "\0"), array("''", ''), $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIKE expression
|
||||
* @access private
|
||||
*/
|
||||
function _sql_like_expression($expression)
|
||||
{
|
||||
return $expression . " ESCAPE '\\'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Build NOT LIKE expression
|
||||
* @access private
|
||||
*/
|
||||
function _sql_not_like_expression($expression)
|
||||
{
|
||||
return $expression . " ESCAPE '\\'";
|
||||
}
|
||||
|
||||
function _sql_custom_build($stage, $data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
function _sql_bit_and($column_name, $bit, $compare = '')
|
||||
{
|
||||
return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
|
||||
}
|
||||
|
||||
function _sql_bit_or($column_name, $bit, $compare = '')
|
||||
{
|
||||
return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* return sql error array
|
||||
* @access private
|
||||
*/
|
||||
function _sql_error()
|
||||
{
|
||||
if (function_exists('ocierror'))
|
||||
{
|
||||
$error = @ocierror();
|
||||
$error = (!$error) ? @ocierror($this->query_result) : $error;
|
||||
$error = (!$error) ? @ocierror($this->db_connect_id) : $error;
|
||||
|
||||
if ($error)
|
||||
{
|
||||
$this->last_error_result = $error;
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = array(
|
||||
'message' => $this->connect_error,
|
||||
'code' => '',
|
||||
);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close sql connection
|
||||
* @access private
|
||||
*/
|
||||
function _sql_close()
|
||||
{
|
||||
return @ocilogoff($this->db_connect_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific report
|
||||
* @access private
|
||||
*/
|
||||
function _sql_report($mode, $query = '')
|
||||
{
|
||||
switch ($mode)
|
||||
{
|
||||
case 'start':
|
||||
|
||||
$html_table = false;
|
||||
|
||||
// Grab a plan table, any will do
|
||||
$sql = "SELECT table_name
|
||||
FROM USER_TABLES
|
||||
WHERE table_name LIKE '%PLAN_TABLE%'";
|
||||
$stmt = ociparse($this->db_connect_id, $sql);
|
||||
ociexecute($stmt);
|
||||
$result = array();
|
||||
|
||||
if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS))
|
||||
{
|
||||
$table = $result['TABLE_NAME'];
|
||||
|
||||
// This is the statement_id that will allow us to track the plan
|
||||
$statement_id = substr(md5($query), 0, 30);
|
||||
|
||||
// Remove any stale plans
|
||||
$stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
|
||||
ociexecute($stmt2);
|
||||
ocifreestatement($stmt2);
|
||||
|
||||
// Explain the plan
|
||||
$sql = "EXPLAIN PLAN
|
||||
SET STATEMENT_ID = '$statement_id'
|
||||
FOR $query";
|
||||
$stmt2 = ociparse($this->db_connect_id, $sql);
|
||||
ociexecute($stmt2);
|
||||
ocifreestatement($stmt2);
|
||||
|
||||
// Get the data from the plan
|
||||
$sql = "SELECT operation, options, object_name, object_type, cardinality, cost
|
||||
FROM plan_table
|
||||
START WITH id = 0 AND statement_id = '$statement_id'
|
||||
CONNECT BY PRIOR id = parent_id
|
||||
AND statement_id = '$statement_id'";
|
||||
$stmt2 = ociparse($this->db_connect_id, $sql);
|
||||
ociexecute($stmt2);
|
||||
|
||||
$row = array();
|
||||
while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS))
|
||||
{
|
||||
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
|
||||
}
|
||||
|
||||
ocifreestatement($stmt2);
|
||||
|
||||
// Remove the plan we just made, we delete them on request anyway
|
||||
$stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
|
||||
ociexecute($stmt2);
|
||||
ocifreestatement($stmt2);
|
||||
}
|
||||
|
||||
ocifreestatement($stmt);
|
||||
|
||||
if ($html_table)
|
||||
{
|
||||
$this->html_hold .= '</table>';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'fromcache':
|
||||
$endtime = explode(' ', microtime());
|
||||
$endtime = $endtime[0] + $endtime[1];
|
||||
|
||||
$result = @ociparse($this->db_connect_id, $query);
|
||||
if ($result)
|
||||
{
|
||||
$success = @ociexecute($result, OCI_DEFAULT);
|
||||
if ($success)
|
||||
{
|
||||
$row = array();
|
||||
|
||||
while (ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
|
||||
{
|
||||
// Take the time spent on parsing rows into account
|
||||
}
|
||||
@ocifreestatement($result);
|
||||
}
|
||||
}
|
||||
|
||||
$splittime = explode(' ', microtime());
|
||||
$splittime = $splittime[0] + $splittime[1];
|
||||
|
||||
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
501
install/update/old/phpbb/db/driver/postgres.php
Normal file
501
install/update/old/phpbb/db/driver/postgres.php
Normal file
@@ -0,0 +1,501 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
/**
|
||||
* PostgreSQL Database Abstraction Layer
|
||||
* Minimum Requirement is Version 8.3+
|
||||
*/
|
||||
class postgres extends \phpbb\db\driver\driver
|
||||
{
|
||||
var $multi_insert = true;
|
||||
var $last_query_text = '';
|
||||
var $connect_error = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
$connect_string = '';
|
||||
|
||||
if ($sqluser)
|
||||
{
|
||||
$connect_string .= "user=$sqluser ";
|
||||
}
|
||||
|
||||
if ($sqlpassword)
|
||||
{
|
||||
$connect_string .= "password=$sqlpassword ";
|
||||
}
|
||||
|
||||
if ($sqlserver)
|
||||
{
|
||||
// $sqlserver can carry a port separated by : for compatibility reasons
|
||||
// If $sqlserver has more than one : it's probably an IPv6 address.
|
||||
// In this case we only allow passing a port via the $port variable.
|
||||
if (substr_count($sqlserver, ':') === 1)
|
||||
{
|
||||
list($sqlserver, $port) = explode(':', $sqlserver);
|
||||
}
|
||||
|
||||
if ($sqlserver !== 'localhost')
|
||||
{
|
||||
$connect_string .= "host=$sqlserver ";
|
||||
}
|
||||
|
||||
if ($port)
|
||||
{
|
||||
$connect_string .= "port=$port ";
|
||||
}
|
||||
}
|
||||
|
||||
$schema = '';
|
||||
|
||||
if ($database)
|
||||
{
|
||||
$this->dbname = $database;
|
||||
if (strpos($database, '.') !== false)
|
||||
{
|
||||
list($database, $schema) = explode('.', $database);
|
||||
}
|
||||
$connect_string .= "dbname=$database";
|
||||
}
|
||||
|
||||
$this->persistency = $persistency;
|
||||
|
||||
if ($this->persistency)
|
||||
{
|
||||
if (!function_exists('pg_pconnect'))
|
||||
{
|
||||
$this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$collector = new \phpbb\error_collector;
|
||||
$collector->install();
|
||||
$this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!function_exists('pg_connect'))
|
||||
{
|
||||
$this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
$collector = new \phpbb\error_collector;
|
||||
$collector->install();
|
||||
$this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW);
|
||||
}
|
||||
|
||||
$collector->uninstall();
|
||||
|
||||
if ($this->db_connect_id)
|
||||
{
|
||||
if ($schema !== '')
|
||||
{
|
||||
@pg_query($this->db_connect_id, 'SET search_path TO ' . $schema);
|
||||
}
|
||||
return $this->db_connect_id;
|
||||
}
|
||||
|
||||
$this->connect_error = $collector->format_errors();
|
||||
return $this->sql_error('');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false)
|
||||
{
|
||||
$query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version');
|
||||
if ($query_id)
|
||||
{
|
||||
$row = pg_fetch_assoc($query_id, null);
|
||||
pg_free_result($query_id);
|
||||
|
||||
$this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0;
|
||||
|
||||
if (!empty($cache) && $use_cache)
|
||||
{
|
||||
$cache->put('pgsql_version', $this->sql_server_version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ($raw) ? $this->sql_server_version : 'PostgreSQL ' . $this->sql_server_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
* @access private
|
||||
*/
|
||||
function _sql_transaction($status = 'begin')
|
||||
{
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return @pg_query($this->db_connect_id, 'BEGIN');
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
return @pg_query($this->db_connect_id, 'COMMIT');
|
||||
break;
|
||||
|
||||
case 'rollback':
|
||||
return @pg_query($this->db_connect_id, 'ROLLBACK');
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
if ($query != '')
|
||||
{
|
||||
global $cache;
|
||||
|
||||
// EXPLAIN only in extra debug mode
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('start', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->curtime = microtime(true);
|
||||
}
|
||||
|
||||
$this->last_query_text = $query;
|
||||
$this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
|
||||
$this->sql_add_num_queries($this->query_result);
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
if (($this->query_result = @pg_query($this->db_connect_id, $query)) === false)
|
||||
{
|
||||
$this->sql_error($query);
|
||||
}
|
||||
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('stop', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->sql_time += microtime(true) - $this->curtime;
|
||||
}
|
||||
|
||||
if (!$this->query_result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cache && $cache_ttl)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
|
||||
}
|
||||
else if (strpos($query, 'SELECT') === 0)
|
||||
{
|
||||
$this->open_queries[(int) $this->query_result] = $this->query_result;
|
||||
}
|
||||
}
|
||||
else if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('fromcache', $query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific query data
|
||||
* @access private
|
||||
*/
|
||||
function _sql_custom_build($stage, $data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIMIT query
|
||||
*/
|
||||
function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
|
||||
{
|
||||
$this->query_result = false;
|
||||
|
||||
// if $total is set to 0 we do not want to limit the number of rows
|
||||
if ($total == 0)
|
||||
{
|
||||
$total = 'ALL';
|
||||
}
|
||||
|
||||
$query .= "\n LIMIT $total OFFSET $offset";
|
||||
|
||||
return $this->sql_query($query, $cache_ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_affectedrows()
|
||||
{
|
||||
return ($this->query_result) ? @pg_affected_rows($this->query_result) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
return ($query_id) ? pg_fetch_assoc($query_id, null) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_rowseek($rownum, &$query_id)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_rowseek($rownum, $query_id);
|
||||
}
|
||||
|
||||
return ($query_id) ? @pg_result_seek($query_id, $rownum) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_nextid()
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
|
||||
if ($query_id !== false && $this->last_query_text != '')
|
||||
{
|
||||
if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename))
|
||||
{
|
||||
$query = "SELECT currval('" . $tablename[1] . "_seq') AS last_value";
|
||||
$temp_q_id = @pg_query($this->db_connect_id, $query);
|
||||
|
||||
if (!$temp_q_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$temp_result = pg_fetch_assoc($temp_q_id, null);
|
||||
pg_free_result($query_id);
|
||||
|
||||
return ($temp_result) ? $temp_result['last_value'] : false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
if (isset($this->open_queries[(int) $query_id]))
|
||||
{
|
||||
unset($this->open_queries[(int) $query_id]);
|
||||
return pg_free_result($query_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_escape($msg)
|
||||
{
|
||||
return @pg_escape_string($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIKE expression
|
||||
* @access private
|
||||
*/
|
||||
function _sql_like_expression($expression)
|
||||
{
|
||||
return $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build NOT LIKE expression
|
||||
* @access private
|
||||
*/
|
||||
function _sql_not_like_expression($expression)
|
||||
{
|
||||
return $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function cast_expr_to_bigint($expression)
|
||||
{
|
||||
return 'CAST(' . $expression . ' as DECIMAL(255, 0))';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function cast_expr_to_string($expression)
|
||||
{
|
||||
return 'CAST(' . $expression . ' as VARCHAR(255))';
|
||||
}
|
||||
|
||||
/**
|
||||
* return sql error array
|
||||
* @access private
|
||||
*/
|
||||
function _sql_error()
|
||||
{
|
||||
// pg_last_error only works when there is an established connection.
|
||||
// Connection errors have to be tracked by us manually.
|
||||
if ($this->db_connect_id)
|
||||
{
|
||||
$message = @pg_last_error($this->db_connect_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = $this->connect_error;
|
||||
}
|
||||
|
||||
return array(
|
||||
'message' => $message,
|
||||
'code' => ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close sql connection
|
||||
* @access private
|
||||
*/
|
||||
function _sql_close()
|
||||
{
|
||||
return @pg_close($this->db_connect_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific report
|
||||
* @access private
|
||||
*/
|
||||
function _sql_report($mode, $query = '')
|
||||
{
|
||||
switch ($mode)
|
||||
{
|
||||
case 'start':
|
||||
|
||||
$explain_query = $query;
|
||||
if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
|
||||
{
|
||||
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
|
||||
}
|
||||
else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
|
||||
{
|
||||
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
|
||||
}
|
||||
|
||||
if (preg_match('/^SELECT/', $explain_query))
|
||||
{
|
||||
$html_table = false;
|
||||
|
||||
if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query"))
|
||||
{
|
||||
while ($row = pg_fetch_assoc($result, null))
|
||||
{
|
||||
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
|
||||
}
|
||||
pg_free_result($result);
|
||||
}
|
||||
|
||||
if ($html_table)
|
||||
{
|
||||
$this->html_hold .= '</table>';
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'fromcache':
|
||||
$endtime = explode(' ', microtime());
|
||||
$endtime = $endtime[0] + $endtime[1];
|
||||
|
||||
$result = @pg_query($this->db_connect_id, $query);
|
||||
if ($result)
|
||||
{
|
||||
while ($void = pg_fetch_assoc($result, null))
|
||||
{
|
||||
// Take the time spent on parsing rows into account
|
||||
}
|
||||
pg_free_result($result);
|
||||
}
|
||||
|
||||
$splittime = explode(' ', microtime());
|
||||
$splittime = $splittime[0] + $splittime[1];
|
||||
|
||||
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
431
install/update/old/phpbb/db/driver/sqlite3.php
Normal file
431
install/update/old/phpbb/db/driver/sqlite3.php
Normal file
@@ -0,0 +1,431 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\driver;
|
||||
|
||||
/**
|
||||
* SQLite3 Database Abstraction Layer
|
||||
* Minimum Requirement: 3.6.15+
|
||||
*/
|
||||
class sqlite3 extends \phpbb\db\driver\driver
|
||||
{
|
||||
/**
|
||||
* @var string Stores errors during connection setup in case the driver is not available
|
||||
*/
|
||||
protected $connect_error = '';
|
||||
|
||||
/**
|
||||
* @var \SQLite3 The SQLite3 database object to operate against
|
||||
*/
|
||||
protected $dbo = null;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
|
||||
{
|
||||
$this->persistency = false;
|
||||
$this->user = $sqluser;
|
||||
$this->server = $sqlserver . (($port) ? ':' . $port : '');
|
||||
$this->dbname = $database;
|
||||
|
||||
if (!class_exists('SQLite3', false))
|
||||
{
|
||||
$this->connect_error = 'SQLite3 not found, is the extension installed?';
|
||||
return $this->sql_error('');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
|
||||
$this->dbo->busyTimeout(60000);
|
||||
$this->db_connect_id = true;
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$this->connect_error = $e->getMessage();
|
||||
return array('message' => $this->connect_error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_server_info($raw = false, $use_cache = true)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false)
|
||||
{
|
||||
$version = \SQLite3::version();
|
||||
|
||||
$this->sql_server_version = $version['versionString'];
|
||||
|
||||
if (!empty($cache) && $use_cache)
|
||||
{
|
||||
$cache->put('sqlite_version', $this->sql_server_version);
|
||||
}
|
||||
}
|
||||
|
||||
return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Transaction
|
||||
*
|
||||
* @param string $status Should be one of the following strings:
|
||||
* begin, commit, rollback
|
||||
* @return bool Success/failure of the transaction query
|
||||
*/
|
||||
protected function _sql_transaction($status = 'begin')
|
||||
{
|
||||
switch ($status)
|
||||
{
|
||||
case 'begin':
|
||||
return $this->dbo->exec('BEGIN IMMEDIATE');
|
||||
break;
|
||||
|
||||
case 'commit':
|
||||
return $this->dbo->exec('COMMIT');
|
||||
break;
|
||||
|
||||
case 'rollback':
|
||||
return @$this->dbo->exec('ROLLBACK');
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_query($query = '', $cache_ttl = 0)
|
||||
{
|
||||
if ($query != '')
|
||||
{
|
||||
global $cache;
|
||||
|
||||
// EXPLAIN only in extra debug mode
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('start', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->curtime = microtime(true);
|
||||
}
|
||||
|
||||
$this->last_query_text = $query;
|
||||
$this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
|
||||
$this->sql_add_num_queries($this->query_result);
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
if ($this->transaction === true && strpos($query, 'INSERT') === 0)
|
||||
{
|
||||
$query = preg_replace('/^INSERT INTO/', 'INSERT OR ROLLBACK INTO', $query);
|
||||
}
|
||||
|
||||
if (($this->query_result = @$this->dbo->query($query)) === false)
|
||||
{
|
||||
// Try to recover a lost database connection
|
||||
if ($this->dbo && !@$this->dbo->lastErrorMsg())
|
||||
{
|
||||
if ($this->sql_connect($this->server, $this->user, '', $this->dbname))
|
||||
{
|
||||
$this->query_result = @$this->dbo->query($query);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->query_result === false)
|
||||
{
|
||||
$this->sql_error($query);
|
||||
}
|
||||
}
|
||||
|
||||
if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('stop', $query);
|
||||
}
|
||||
else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
|
||||
{
|
||||
$this->sql_time += microtime(true) - $this->curtime;
|
||||
}
|
||||
|
||||
if (!$this->query_result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cache && $cache_ttl)
|
||||
{
|
||||
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
|
||||
}
|
||||
}
|
||||
else if (defined('DEBUG'))
|
||||
{
|
||||
$this->sql_report('fromcache', $query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIMIT query
|
||||
*
|
||||
* @param string $query The SQL query to execute
|
||||
* @param int $total The number of rows to select
|
||||
* @param int $offset
|
||||
* @param int $cache_ttl Either 0 to avoid caching or
|
||||
* the time in seconds which the result shall be kept in cache
|
||||
* @return mixed Buffered, seekable result handle, false on error
|
||||
*/
|
||||
protected function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
|
||||
{
|
||||
$this->query_result = false;
|
||||
|
||||
// if $total is set to 0 we do not want to limit the number of rows
|
||||
if ($total == 0)
|
||||
{
|
||||
$total = -1;
|
||||
}
|
||||
|
||||
$query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
|
||||
|
||||
return $this->sql_query($query, $cache_ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_affectedrows()
|
||||
{
|
||||
return ($this->db_connect_id) ? $this->dbo->changes() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_fetchrow($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
/** @var \SQLite3Result $query_id */
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_fetchrow($query_id);
|
||||
}
|
||||
|
||||
return is_object($query_id) ? @$query_id->fetchArray(SQLITE3_ASSOC) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_nextid()
|
||||
{
|
||||
return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_freeresult($query_id = false)
|
||||
{
|
||||
global $cache;
|
||||
|
||||
if ($query_id === false)
|
||||
{
|
||||
$query_id = $this->query_result;
|
||||
}
|
||||
|
||||
if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
|
||||
{
|
||||
return $cache->sql_freeresult($query_id);
|
||||
}
|
||||
|
||||
if ($query_id)
|
||||
{
|
||||
return @$query_id->finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sql_escape($msg)
|
||||
{
|
||||
return \SQLite3::escapeString($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* For SQLite an underscore is an unknown character.
|
||||
*/
|
||||
public function sql_like_expression($expression)
|
||||
{
|
||||
// Unlike LIKE, GLOB is unfortunately case sensitive.
|
||||
// We only catch * and ? here, not the character map possible on file globbing.
|
||||
$expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
|
||||
|
||||
$expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
|
||||
$expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
|
||||
|
||||
return 'GLOB \'' . $this->sql_escape($expression) . '\'';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* For SQLite an underscore is an unknown character.
|
||||
*/
|
||||
public function sql_not_like_expression($expression)
|
||||
{
|
||||
// Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive
|
||||
// We only catch * and ? here, not the character map possible on file globbing.
|
||||
$expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
|
||||
|
||||
$expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
|
||||
$expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
|
||||
|
||||
return 'NOT GLOB \'' . $this->sql_escape($expression) . '\'';
|
||||
}
|
||||
|
||||
/**
|
||||
* return sql error array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _sql_error()
|
||||
{
|
||||
if (class_exists('SQLite3', false) && isset($this->dbo))
|
||||
{
|
||||
$error = array(
|
||||
'message' => $this->dbo->lastErrorMsg(),
|
||||
'code' => $this->dbo->lastErrorCode(),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = array(
|
||||
'message' => $this->connect_error,
|
||||
'code' => '',
|
||||
);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific query data
|
||||
*
|
||||
* @param string $stage Available stages: FROM, WHERE
|
||||
* @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses
|
||||
*
|
||||
* @return string The db-specific query fragment
|
||||
*/
|
||||
protected function _sql_custom_build($stage, $data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close sql connection
|
||||
*
|
||||
* @return bool False if failure
|
||||
*/
|
||||
protected function _sql_close()
|
||||
{
|
||||
return $this->dbo->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build db-specific report
|
||||
*
|
||||
* @param string $mode Available modes: display, start, stop,
|
||||
* add_select_row, fromcache, record_fromcache
|
||||
* @param string $query The Query that should be explained
|
||||
* @return mixed Either a full HTML page, boolean or null
|
||||
*/
|
||||
protected function _sql_report($mode, $query = '')
|
||||
{
|
||||
switch ($mode)
|
||||
{
|
||||
case 'start':
|
||||
|
||||
$explain_query = $query;
|
||||
if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
|
||||
{
|
||||
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
|
||||
}
|
||||
else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
|
||||
{
|
||||
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
|
||||
}
|
||||
|
||||
if (preg_match('/^SELECT/', $explain_query))
|
||||
{
|
||||
$html_table = false;
|
||||
|
||||
if ($result = $this->dbo->query("EXPLAIN QUERY PLAN $explain_query"))
|
||||
{
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
|
||||
}
|
||||
}
|
||||
|
||||
if ($html_table)
|
||||
{
|
||||
$this->html_hold .= '</table>';
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'fromcache':
|
||||
$endtime = explode(' ', microtime());
|
||||
$endtime = $endtime[0] + $endtime[1];
|
||||
|
||||
$result = $this->dbo->query($query);
|
||||
if ($result)
|
||||
{
|
||||
while ($void = $result->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
// Take the time spent on parsing rows into account
|
||||
}
|
||||
}
|
||||
|
||||
$splittime = explode(' ', microtime());
|
||||
$splittime = $splittime[0] + $splittime[1];
|
||||
|
||||
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
403
install/update/old/phpbb/db/extractor/mysql_extractor.php
Normal file
403
install/update/old/phpbb/db/extractor/mysql_extractor.php
Normal file
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\extractor;
|
||||
|
||||
use phpbb\db\extractor\exception\extractor_not_initialized_exception;
|
||||
|
||||
class mysql_extractor extends base_extractor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write_start($table_prefix)
|
||||
{
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
$sql_data = "#\n";
|
||||
$sql_data .= "# phpBB Backup Script\n";
|
||||
$sql_data .= "# Dump of tables for $table_prefix\n";
|
||||
$sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
|
||||
$sql_data .= "#\n";
|
||||
$this->flush($sql_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write_table($table_name)
|
||||
{
|
||||
static $new_extract;
|
||||
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
if ($new_extract === null)
|
||||
{
|
||||
if ($this->db->get_sql_layer() === 'mysqli' || version_compare($this->db->sql_server_info(true), '3.23.20', '>='))
|
||||
{
|
||||
$new_extract = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_extract = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($new_extract)
|
||||
{
|
||||
$this->new_write_table($table_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->old_write_table($table_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write_data($table_name)
|
||||
{
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
if ($this->db->get_sql_layer() === 'mysqli')
|
||||
{
|
||||
$this->write_data_mysqli($table_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->write_data_mysql($table_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts data from database table (for MySQLi driver)
|
||||
*
|
||||
* @param string $table_name name of the database table
|
||||
* @return null
|
||||
* @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
|
||||
*/
|
||||
protected function write_data_mysqli($table_name)
|
||||
{
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
$sql = "SELECT *
|
||||
FROM $table_name";
|
||||
$result = mysqli_query($this->db->get_db_connect_id(), $sql, MYSQLI_USE_RESULT);
|
||||
if ($result != false)
|
||||
{
|
||||
$fields_cnt = mysqli_num_fields($result);
|
||||
|
||||
// Get field information
|
||||
$field = mysqli_fetch_fields($result);
|
||||
$field_set = array();
|
||||
|
||||
for ($j = 0; $j < $fields_cnt; $j++)
|
||||
{
|
||||
$field_set[] = $field[$j]->name;
|
||||
}
|
||||
|
||||
$search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
|
||||
$replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
|
||||
$fields = implode(', ', $field_set);
|
||||
$sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
|
||||
$first_set = true;
|
||||
$query_len = 0;
|
||||
$max_len = get_usable_memory();
|
||||
|
||||
while ($row = mysqli_fetch_row($result))
|
||||
{
|
||||
$values = array();
|
||||
if ($first_set)
|
||||
{
|
||||
$query = $sql_data . '(';
|
||||
}
|
||||
else
|
||||
{
|
||||
$query .= ',(';
|
||||
}
|
||||
|
||||
for ($j = 0; $j < $fields_cnt; $j++)
|
||||
{
|
||||
if (!isset($row[$j]) || is_null($row[$j]))
|
||||
{
|
||||
$values[$j] = 'NULL';
|
||||
}
|
||||
else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024))
|
||||
{
|
||||
$values[$j] = $row[$j];
|
||||
}
|
||||
else
|
||||
{
|
||||
$values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
|
||||
}
|
||||
}
|
||||
$query .= implode(', ', $values) . ')';
|
||||
|
||||
$query_len += strlen($query);
|
||||
if ($query_len > $max_len)
|
||||
{
|
||||
$this->flush($query . ";\n\n");
|
||||
$query = '';
|
||||
$query_len = 0;
|
||||
$first_set = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$first_set = false;
|
||||
}
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
|
||||
// check to make sure we have nothing left to flush
|
||||
if (!$first_set && $query)
|
||||
{
|
||||
$this->flush($query . ";\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts data from database table (for MySQL driver)
|
||||
*
|
||||
* @param string $table_name name of the database table
|
||||
* @return null
|
||||
* @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
|
||||
*/
|
||||
protected function write_data_mysql($table_name)
|
||||
{
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
$sql = "SELECT *
|
||||
FROM $table_name";
|
||||
$result = mysql_unbuffered_query($sql, $this->db->get_db_connect_id());
|
||||
|
||||
if ($result != false)
|
||||
{
|
||||
$fields_cnt = mysql_num_fields($result);
|
||||
|
||||
// Get field information
|
||||
$field = array();
|
||||
for ($i = 0; $i < $fields_cnt; $i++)
|
||||
{
|
||||
$field[] = mysql_fetch_field($result, $i);
|
||||
}
|
||||
$field_set = array();
|
||||
|
||||
for ($j = 0; $j < $fields_cnt; $j++)
|
||||
{
|
||||
$field_set[] = $field[$j]->name;
|
||||
}
|
||||
|
||||
$search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
|
||||
$replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
|
||||
$fields = implode(', ', $field_set);
|
||||
$sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
|
||||
$first_set = true;
|
||||
$query_len = 0;
|
||||
$max_len = get_usable_memory();
|
||||
|
||||
while ($row = mysql_fetch_row($result))
|
||||
{
|
||||
$values = array();
|
||||
if ($first_set)
|
||||
{
|
||||
$query = $sql_data . '(';
|
||||
}
|
||||
else
|
||||
{
|
||||
$query .= ',(';
|
||||
}
|
||||
|
||||
for ($j = 0; $j < $fields_cnt; $j++)
|
||||
{
|
||||
if (!isset($row[$j]) || is_null($row[$j]))
|
||||
{
|
||||
$values[$j] = 'NULL';
|
||||
}
|
||||
else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp'))
|
||||
{
|
||||
$values[$j] = $row[$j];
|
||||
}
|
||||
else
|
||||
{
|
||||
$values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
|
||||
}
|
||||
}
|
||||
$query .= implode(', ', $values) . ')';
|
||||
|
||||
$query_len += strlen($query);
|
||||
if ($query_len > $max_len)
|
||||
{
|
||||
$this->flush($query . ";\n\n");
|
||||
$query = '';
|
||||
$query_len = 0;
|
||||
$first_set = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$first_set = false;
|
||||
}
|
||||
}
|
||||
mysql_free_result($result);
|
||||
|
||||
// check to make sure we have nothing left to flush
|
||||
if (!$first_set && $query)
|
||||
{
|
||||
$this->flush($query . ";\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts database table structure (for MySQLi or MySQL 3.23.20+)
|
||||
*
|
||||
* @param string $table_name name of the database table
|
||||
* @return null
|
||||
* @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
|
||||
*/
|
||||
protected function new_write_table($table_name)
|
||||
{
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
$sql = 'SHOW CREATE TABLE ' . $table_name;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
|
||||
$sql_data = '# Table: ' . $table_name . "\n";
|
||||
$sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
|
||||
$this->flush($sql_data . $row['Create Table'] . ";\n\n");
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts database table structure (for MySQL verisons older than 3.23.20)
|
||||
*
|
||||
* @param string $table_name name of the database table
|
||||
* @return null
|
||||
* @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
|
||||
*/
|
||||
protected function old_write_table($table_name)
|
||||
{
|
||||
if (!$this->is_initialized)
|
||||
{
|
||||
throw new extractor_not_initialized_exception();
|
||||
}
|
||||
|
||||
$sql_data = '# Table: ' . $table_name . "\n";
|
||||
$sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
|
||||
$sql_data .= "CREATE TABLE $table_name(\n";
|
||||
$rows = array();
|
||||
|
||||
$sql = "SHOW FIELDS
|
||||
FROM $table_name";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$line = ' ' . $row['Field'] . ' ' . $row['Type'];
|
||||
|
||||
if (!is_null($row['Default']))
|
||||
{
|
||||
$line .= " DEFAULT '{$row['Default']}'";
|
||||
}
|
||||
|
||||
if ($row['Null'] != 'YES')
|
||||
{
|
||||
$line .= ' NOT NULL';
|
||||
}
|
||||
|
||||
if ($row['Extra'] != '')
|
||||
{
|
||||
$line .= ' ' . $row['Extra'];
|
||||
}
|
||||
|
||||
$rows[] = $line;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$sql = "SHOW KEYS
|
||||
FROM $table_name";
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$index = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$kname = $row['Key_name'];
|
||||
|
||||
if ($kname != 'PRIMARY')
|
||||
{
|
||||
if ($row['Non_unique'] == 0)
|
||||
{
|
||||
$kname = "UNIQUE|$kname";
|
||||
}
|
||||
}
|
||||
|
||||
if ($row['Sub_part'])
|
||||
{
|
||||
$row['Column_name'] .= '(' . $row['Sub_part'] . ')';
|
||||
}
|
||||
$index[$kname][] = $row['Column_name'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
foreach ($index as $key => $columns)
|
||||
{
|
||||
$line = ' ';
|
||||
|
||||
if ($key == 'PRIMARY')
|
||||
{
|
||||
$line .= 'PRIMARY KEY (' . implode(', ', $columns) . ')';
|
||||
}
|
||||
else if (strpos($key, 'UNIQUE') === 0)
|
||||
{
|
||||
$line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')';
|
||||
}
|
||||
else if (strpos($key, 'FULLTEXT') === 0)
|
||||
{
|
||||
$line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$line .= "KEY $key (" . implode(', ', $columns) . ')';
|
||||
}
|
||||
|
||||
$rows[] = $line;
|
||||
}
|
||||
|
||||
$sql_data .= implode(",\n", $rows);
|
||||
$sql_data .= "\n);\n\n";
|
||||
|
||||
$this->flush($sql_data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v30x;
|
||||
|
||||
class release_3_0_4_rc1 extends \phpbb\db\migration\migration
|
||||
{
|
||||
public function effectively_installed()
|
||||
{
|
||||
return phpbb_version_compare($this->config['version'], '3.0.4-RC1', '>=');
|
||||
}
|
||||
|
||||
static public function depends_on()
|
||||
{
|
||||
return array('\phpbb\db\migration\data\v30x\release_3_0_3');
|
||||
}
|
||||
|
||||
public function update_schema()
|
||||
{
|
||||
return array(
|
||||
'add_columns' => array(
|
||||
$this->table_prefix . 'profile_fields' => array(
|
||||
'field_show_profile' => array('BOOL', 0),
|
||||
),
|
||||
),
|
||||
'change_columns' => array(
|
||||
$this->table_prefix . 'styles' => array(
|
||||
'style_id' => array('UINT', NULL, 'auto_increment'),
|
||||
'template_id' => array('UINT', 0),
|
||||
'theme_id' => array('UINT', 0),
|
||||
'imageset_id' => array('UINT', 0),
|
||||
),
|
||||
$this->table_prefix . 'styles_imageset' => array(
|
||||
'imageset_id' => array('UINT', NULL, 'auto_increment'),
|
||||
),
|
||||
$this->table_prefix . 'styles_imageset_data' => array(
|
||||
'image_id' => array('UINT', NULL, 'auto_increment'),
|
||||
'imageset_id' => array('UINT', 0),
|
||||
),
|
||||
$this->table_prefix . 'styles_theme' => array(
|
||||
'theme_id' => array('UINT', NULL, 'auto_increment'),
|
||||
),
|
||||
$this->table_prefix . 'styles_template' => array(
|
||||
'template_id' => array('UINT', NULL, 'auto_increment'),
|
||||
),
|
||||
$this->table_prefix . 'styles_template_data' => array(
|
||||
'template_id' => array('UINT', 0),
|
||||
),
|
||||
$this->table_prefix . 'forums' => array(
|
||||
'forum_style' => array('UINT', 0),
|
||||
),
|
||||
$this->table_prefix . 'users' => array(
|
||||
'user_style' => array('UINT', 0),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function revert_schema()
|
||||
{
|
||||
return array(
|
||||
'drop_columns' => array(
|
||||
$this->table_prefix . 'profile_fields' => array(
|
||||
'field_show_profile',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function update_data()
|
||||
{
|
||||
return array(
|
||||
array('custom', array(array(&$this, 'update_custom_profile_fields'))),
|
||||
|
||||
array('config.update', array('version', '3.0.4-RC1')),
|
||||
);
|
||||
}
|
||||
|
||||
public function update_custom_profile_fields()
|
||||
{
|
||||
// Update the Custom Profile Fields based on previous settings to the new \format
|
||||
$sql = 'SELECT field_id, field_required, field_show_on_reg, field_hide
|
||||
FROM ' . PROFILE_FIELDS_TABLE;
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$sql_ary = array(
|
||||
'field_required' => 0,
|
||||
'field_show_on_reg' => 0,
|
||||
'field_hide' => 0,
|
||||
'field_show_profile'=> 0,
|
||||
);
|
||||
|
||||
if ($row['field_required'])
|
||||
{
|
||||
$sql_ary['field_required'] = $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1;
|
||||
}
|
||||
else if ($row['field_show_on_reg'])
|
||||
{
|
||||
$sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1;
|
||||
}
|
||||
else if ($row['field_hide'])
|
||||
{
|
||||
// Only administrators and moderators can see this CPF, if the view is enabled, they can see it, otherwise just admins in the acp_users module
|
||||
$sql_ary['field_hide'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// equivelant to "none", which is the "Display in user control panel" option
|
||||
$sql_ary['field_show_profile'] = 1;
|
||||
}
|
||||
|
||||
$this->sql_query('UPDATE ' . $this->table_prefix . 'profile_fields SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE field_id = ' . $row['field_id'], $errored, $error_ary);
|
||||
}
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v310;
|
||||
|
||||
class softdelete_p1 extends \phpbb\db\migration\migration
|
||||
{
|
||||
public function effectively_installed()
|
||||
{
|
||||
return $this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_visibility');
|
||||
}
|
||||
|
||||
static public function depends_on()
|
||||
{
|
||||
return array('\phpbb\db\migration\data\v310\dev');
|
||||
}
|
||||
|
||||
public function update_schema()
|
||||
{
|
||||
return array(
|
||||
'add_columns' => array(
|
||||
$this->table_prefix . 'forums' => array(
|
||||
'forum_posts_approved' => array('UINT', 0),
|
||||
'forum_posts_unapproved' => array('UINT', 0),
|
||||
'forum_posts_softdeleted' => array('UINT', 0),
|
||||
'forum_topics_approved' => array('UINT', 0),
|
||||
'forum_topics_unapproved' => array('UINT', 0),
|
||||
'forum_topics_softdeleted' => array('UINT', 0),
|
||||
),
|
||||
$this->table_prefix . 'posts' => array(
|
||||
'post_visibility' => array('TINT:3', 0),
|
||||
'post_delete_time' => array('TIMESTAMP', 0),
|
||||
'post_delete_reason' => array('STEXT_UNI', ''),
|
||||
'post_delete_user' => array('UINT', 0),
|
||||
),
|
||||
$this->table_prefix . 'topics' => array(
|
||||
'topic_visibility' => array('TINT:3', 0),
|
||||
'topic_delete_time' => array('TIMESTAMP', 0),
|
||||
'topic_delete_reason' => array('STEXT_UNI', ''),
|
||||
'topic_delete_user' => array('UINT', 0),
|
||||
'topic_posts_approved' => array('UINT', 0),
|
||||
'topic_posts_unapproved' => array('UINT', 0),
|
||||
'topic_posts_softdeleted' => array('UINT', 0),
|
||||
),
|
||||
),
|
||||
'add_index' => array(
|
||||
$this->table_prefix . 'posts' => array(
|
||||
'post_visibility' => array('post_visibility'),
|
||||
),
|
||||
$this->table_prefix . 'topics' => array(
|
||||
'topic_visibility' => array('topic_visibility'),
|
||||
'forum_vis_last' => array('forum_id', 'topic_visibility', 'topic_last_post_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function revert_schema()
|
||||
{
|
||||
return array(
|
||||
'drop_columns' => array(
|
||||
$this->table_prefix . 'forums' => array(
|
||||
'forum_posts_approved',
|
||||
'forum_posts_unapproved',
|
||||
'forum_posts_softdeleted',
|
||||
'forum_topics_approved',
|
||||
'forum_topics_unapproved',
|
||||
'forum_topics_softdeleted',
|
||||
),
|
||||
$this->table_prefix . 'posts' => array(
|
||||
'post_visibility',
|
||||
'post_delete_time',
|
||||
'post_delete_reason',
|
||||
'post_delete_user',
|
||||
),
|
||||
$this->table_prefix . 'topics' => array(
|
||||
'topic_visibility',
|
||||
'topic_delete_time',
|
||||
'topic_delete_reason',
|
||||
'topic_delete_user',
|
||||
'topic_posts_approved',
|
||||
'topic_posts_unapproved',
|
||||
'topic_posts_softdeleted',
|
||||
),
|
||||
),
|
||||
'drop_keys' => array(
|
||||
$this->table_prefix . 'posts' => array('post_visibility'),
|
||||
$this->table_prefix . 'topics' => array('topic_visibility', 'forum_vis_last'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function update_data()
|
||||
{
|
||||
return array(
|
||||
array('custom', array(array($this, 'update_post_visibility'))),
|
||||
array('custom', array(array($this, 'update_topic_visibility'))),
|
||||
array('custom', array(array($this, 'update_topics_post_counts'))),
|
||||
array('custom', array(array($this, 'update_forums_topic_and_post_counts'))),
|
||||
|
||||
array('permission.add', array('f_softdelete', false)),
|
||||
array('permission.add', array('m_softdelete', false)),
|
||||
);
|
||||
}
|
||||
|
||||
public function update_post_visibility()
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->table_prefix . 'posts
|
||||
SET post_visibility = post_approved';
|
||||
$this->sql_query($sql);
|
||||
}
|
||||
|
||||
public function update_topic_visibility()
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->table_prefix . 'topics
|
||||
SET topic_visibility = topic_approved';
|
||||
$this->sql_query($sql);
|
||||
}
|
||||
|
||||
public function update_topics_post_counts()
|
||||
{
|
||||
/*
|
||||
* Using sql_case here to avoid "BIGINT UNSIGNED value is out of range" errors.
|
||||
* As we update all topics in 2 queries, one broken topic would stop the conversion
|
||||
* for all topics and the surpressed error will cause the admin to not even notice it.
|
||||
*/
|
||||
$sql = 'UPDATE ' . $this->table_prefix . 'topics
|
||||
SET topic_posts_approved = topic_replies + 1,
|
||||
topic_posts_unapproved = ' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . '
|
||||
WHERE topic_visibility = ' . ITEM_APPROVED;
|
||||
$this->sql_query($sql);
|
||||
|
||||
$sql = 'UPDATE ' . $this->table_prefix . 'topics
|
||||
SET topic_posts_approved = 0,
|
||||
topic_posts_unapproved = (' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ') + 1
|
||||
WHERE topic_visibility = ' . ITEM_UNAPPROVED;
|
||||
$this->sql_query($sql);
|
||||
}
|
||||
|
||||
public function update_forums_topic_and_post_counts($start)
|
||||
{
|
||||
$start = (int) $start;
|
||||
$limit = 10;
|
||||
$converted_forums = 0;
|
||||
|
||||
if (!$start)
|
||||
{
|
||||
// Preserve the forum_posts value for link forums as it represents redirects.
|
||||
$sql = 'UPDATE ' . $this->table_prefix . 'forums
|
||||
SET forum_posts_approved = forum_posts
|
||||
WHERE forum_type = ' . FORUM_LINK;
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
$sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS sum_topics, SUM(topic_posts_approved) AS sum_posts_approved, SUM(topic_posts_unapproved) AS sum_posts_unapproved
|
||||
FROM ' . $this->table_prefix . 'topics
|
||||
GROUP BY forum_id, topic_visibility
|
||||
ORDER BY forum_id, topic_visibility';
|
||||
$result = $this->db->sql_query_limit($sql, $limit, $start);
|
||||
|
||||
$update_forums = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$converted_forums++;
|
||||
|
||||
$forum_id = (int) $row['forum_id'];
|
||||
if (!isset($update_forums[$forum_id]))
|
||||
{
|
||||
$update_forums[$forum_id] = array(
|
||||
'forum_posts_approved' => 0,
|
||||
'forum_posts_unapproved' => 0,
|
||||
'forum_topics_approved' => 0,
|
||||
'forum_topics_unapproved' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$update_forums[$forum_id]['forum_posts_approved'] += (int) $row['sum_posts_approved'];
|
||||
$update_forums[$forum_id]['forum_posts_unapproved'] += (int) $row['sum_posts_unapproved'];
|
||||
|
||||
$update_forums[$forum_id][(($row['topic_visibility'] == ITEM_APPROVED) ? 'forum_topics_approved' : 'forum_topics_unapproved')] += (int) $row['sum_topics'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
foreach ($update_forums as $forum_id => $forum_data)
|
||||
{
|
||||
$sql = 'UPDATE ' . FORUMS_TABLE . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', $forum_data) . '
|
||||
WHERE forum_id = ' . $forum_id;
|
||||
$this->sql_query($sql);
|
||||
}
|
||||
|
||||
if ($converted_forums < $limit)
|
||||
{
|
||||
// There are no more topics, we are done
|
||||
return;
|
||||
}
|
||||
|
||||
// There are still more topics to query, return the next start value
|
||||
return $start + $limit;
|
||||
}
|
||||
}
|
||||
556
install/update/old/phpbb/db/migration/tool/module.php
Normal file
556
install/update/old/phpbb/db/migration/tool/module.php
Normal file
@@ -0,0 +1,556 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\tool;
|
||||
|
||||
use phpbb\module\exception\module_exception;
|
||||
|
||||
/**
|
||||
* Migration module management tool
|
||||
*/
|
||||
class module implements \phpbb\db\migration\tool\tool_interface
|
||||
{
|
||||
/** @var \phpbb\cache\service */
|
||||
protected $cache;
|
||||
|
||||
/** @var \phpbb\db\driver\driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var \phpbb\user */
|
||||
protected $user;
|
||||
|
||||
/** @var \phpbb\module\module_manager */
|
||||
protected $module_manager;
|
||||
|
||||
/** @var string */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var string */
|
||||
protected $php_ext;
|
||||
|
||||
/** @var string */
|
||||
protected $modules_table;
|
||||
|
||||
/** @var array */
|
||||
protected $module_categories = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db
|
||||
* @param \phpbb\cache\service $cache
|
||||
* @param \phpbb\user $user
|
||||
* @param \phpbb\module\module_manager $module_manager
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
* @param string $modules_table
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, \phpbb\module\module_manager $module_manager, $phpbb_root_path, $php_ext, $modules_table)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->cache = $cache;
|
||||
$this->user = $user;
|
||||
$this->module_manager = $module_manager;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
$this->modules_table = $modules_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_name()
|
||||
{
|
||||
return 'module';
|
||||
}
|
||||
|
||||
/**
|
||||
* Module Exists
|
||||
*
|
||||
* Check if a module exists
|
||||
*
|
||||
* @param string $class The module class(acp|mcp|ucp)
|
||||
* @param int|string|bool $parent The parent module_id|module_langname (0 for no parent).
|
||||
* Use false to ignore the parent check and check class wide.
|
||||
* @param int|string $module The module_id|module_langname you would like to
|
||||
* check for to see if it exists
|
||||
* @param bool $lazy Checks lazily if the module exists. Returns true if it exists in at
|
||||
* least one given parent.
|
||||
* @return bool true if module exists in *all* given parents, false if not in any given parent;
|
||||
* true if ignoring parent check and module exists class wide, false if not found at all.
|
||||
*/
|
||||
public function exists($class, $parent, $module, $lazy = false)
|
||||
{
|
||||
// the main root directory should return true
|
||||
if (!$module)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$parent_sqls = [];
|
||||
if ($parent !== false)
|
||||
{
|
||||
$parents = $this->get_parent_module_id($parent, $module, false);
|
||||
if ($parents === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ((array) $parents as $parent_id)
|
||||
{
|
||||
$parent_sqls[] = 'AND parent_id = ' . (int) $parent_id;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$parent_sqls[] = '';
|
||||
}
|
||||
|
||||
foreach ($parent_sqls as $parent_sql)
|
||||
{
|
||||
$sql = 'SELECT module_id
|
||||
FROM ' . $this->modules_table . "
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
$parent_sql
|
||||
AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'");
|
||||
$result = $this->db->sql_query($sql);
|
||||
$module_id = $this->db->sql_fetchfield('module_id');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$lazy && !$module_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($lazy && $module_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true, if modules exist in all parents and false otherwise
|
||||
return !$lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Module Add
|
||||
*
|
||||
* Add a new module
|
||||
*
|
||||
* @param string $class The module class(acp|mcp|ucp)
|
||||
* @param int|string $parent The parent module_id|module_langname (0 for no parent)
|
||||
* @param array $data an array of the data on the new \module.
|
||||
* This can be setup in two different ways.
|
||||
* 1. The "manual" way. For inserting a category or one at a time.
|
||||
* It will be merged with the base array shown a bit below,
|
||||
* but at the least requires 'module_langname' to be sent, and,
|
||||
* if you want to create a module (instead of just a category) you must
|
||||
* send module_basename and module_mode.
|
||||
* array(
|
||||
* 'module_enabled' => 1,
|
||||
* 'module_display' => 1,
|
||||
* 'module_basename' => '',
|
||||
* 'module_class' => $class,
|
||||
* 'parent_id' => (int) $parent,
|
||||
* 'module_langname' => '',
|
||||
* 'module_mode' => '',
|
||||
* 'module_auth' => '',
|
||||
* )
|
||||
* 2. The "automatic" way. For inserting multiple at a time based on the
|
||||
* specs in the info file for the module(s). For this to work the
|
||||
* modules must be correctly setup in the info file.
|
||||
* An example follows (this would insert the settings, log, and flag
|
||||
* modes from the includes/acp/info/acp_asacp.php file):
|
||||
* array(
|
||||
* 'module_basename' => 'asacp',
|
||||
* 'modes' => array('settings', 'log', 'flag'),
|
||||
* )
|
||||
* Optionally you may not send 'modes' and it will insert all of the
|
||||
* modules in that info file.
|
||||
* path, specify that here
|
||||
* @return null
|
||||
* @throws \phpbb\db\migration\exception
|
||||
*/
|
||||
public function add($class, $parent = 0, $data = array())
|
||||
{
|
||||
global $user, $phpbb_log;
|
||||
|
||||
// allow sending the name as a string in $data to create a category
|
||||
if (!is_array($data))
|
||||
{
|
||||
$data = array('module_langname' => $data);
|
||||
}
|
||||
|
||||
$parents = (array) $this->get_parent_module_id($parent, $data);
|
||||
|
||||
if (!isset($data['module_langname']))
|
||||
{
|
||||
// The "automatic" way
|
||||
$basename = (isset($data['module_basename'])) ? $data['module_basename'] : '';
|
||||
$module = $this->get_module_info($class, $basename);
|
||||
|
||||
foreach ($module['modes'] as $mode => $module_info)
|
||||
{
|
||||
if (!isset($data['modes']) || in_array($mode, $data['modes']))
|
||||
{
|
||||
$new_module = array(
|
||||
'module_basename' => $basename,
|
||||
'module_langname' => $module_info['title'],
|
||||
'module_mode' => $mode,
|
||||
'module_auth' => $module_info['auth'],
|
||||
'module_display' => (isset($module_info['display'])) ? $module_info['display'] : true,
|
||||
'before' => (isset($module_info['before'])) ? $module_info['before'] : false,
|
||||
'after' => (isset($module_info['after'])) ? $module_info['after'] : false,
|
||||
);
|
||||
|
||||
// Run the "manual" way with the data we've collected.
|
||||
foreach ($parents as $parent)
|
||||
{
|
||||
$this->add($class, $parent, $new_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($parents as $parent)
|
||||
{
|
||||
$data['parent_id'] = $parent;
|
||||
|
||||
// The "manual" way
|
||||
if (!$this->exists($class, false, $parent))
|
||||
{
|
||||
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
|
||||
}
|
||||
|
||||
if ($this->exists($class, $parent, $data['module_langname']))
|
||||
{
|
||||
throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']);
|
||||
}
|
||||
|
||||
$module_data = array(
|
||||
'module_enabled' => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1,
|
||||
'module_display' => (isset($data['module_display'])) ? $data['module_display'] : 1,
|
||||
'module_basename' => (isset($data['module_basename'])) ? $data['module_basename'] : '',
|
||||
'module_class' => $class,
|
||||
'parent_id' => (int) $parent,
|
||||
'module_langname' => (isset($data['module_langname'])) ? $data['module_langname'] : '',
|
||||
'module_mode' => (isset($data['module_mode'])) ? $data['module_mode'] : '',
|
||||
'module_auth' => (isset($data['module_auth'])) ? $data['module_auth'] : '',
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
$this->module_manager->update_module_data($module_data);
|
||||
|
||||
// Success
|
||||
$module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']);
|
||||
$phpbb_log->add('admin', (isset($user->data['user_id'])) ? $user->data['user_id'] : ANONYMOUS, $user->ip, 'LOG_MODULE_ADD', false, array($module_log_name));
|
||||
|
||||
// Move the module if requested above/below an existing one
|
||||
if (isset($data['before']) && $data['before'])
|
||||
{
|
||||
$before_mode = $before_langname = '';
|
||||
if (is_array($data['before']))
|
||||
{
|
||||
// Restore legacy-legacy behaviour from phpBB 3.0
|
||||
list($before_mode, $before_langname) = $data['before'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Legacy behaviour from phpBB 3.1+
|
||||
$before_langname = $data['before'];
|
||||
}
|
||||
|
||||
$sql = 'SELECT left_id
|
||||
FROM ' . $this->modules_table . "
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
AND parent_id = " . (int) $parent . "
|
||||
AND module_langname = '" . $this->db->sql_escape($before_langname) . "'"
|
||||
. (($before_mode) ? " AND module_mode = '" . $this->db->sql_escape($before_mode) . "'" : '');
|
||||
$result = $this->db->sql_query($sql);
|
||||
$to_left = (int) $this->db->sql_fetchfield('left_id');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$sql = 'UPDATE ' . $this->modules_table . "
|
||||
SET left_id = left_id + 2, right_id = right_id + 2
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
AND left_id >= $to_left
|
||||
AND left_id < {$module_data['left_id']}";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
$sql = 'UPDATE ' . $this->modules_table . "
|
||||
SET left_id = $to_left, right_id = " . ($to_left + 1) . "
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
AND module_id = {$module_data['module_id']}";
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
else if (isset($data['after']) && $data['after'])
|
||||
{
|
||||
$after_mode = $after_langname = '';
|
||||
if (is_array($data['after']))
|
||||
{
|
||||
// Restore legacy-legacy behaviour from phpBB 3.0
|
||||
list($after_mode, $after_langname) = $data['after'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Legacy behaviour from phpBB 3.1+
|
||||
$after_langname = $data['after'];
|
||||
}
|
||||
|
||||
$sql = 'SELECT right_id
|
||||
FROM ' . $this->modules_table . "
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
AND parent_id = " . (int) $parent . "
|
||||
AND module_langname = '" . $this->db->sql_escape($after_langname) . "'"
|
||||
. (($after_mode) ? " AND module_mode = '" . $this->db->sql_escape($after_mode) . "'" : '');
|
||||
$result = $this->db->sql_query($sql);
|
||||
$to_right = (int) $this->db->sql_fetchfield('right_id');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$sql = 'UPDATE ' . $this->modules_table . "
|
||||
SET left_id = left_id + 2, right_id = right_id + 2
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
AND left_id >= $to_right
|
||||
AND left_id < {$module_data['left_id']}";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
$sql = 'UPDATE ' . $this->modules_table . '
|
||||
SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . "
|
||||
WHERE module_class = '" . $this->db->sql_escape($class) . "'
|
||||
AND module_id = {$module_data['module_id']}";
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
catch (module_exception $e)
|
||||
{
|
||||
// Error
|
||||
throw new \phpbb\db\migration\exception('MODULE_ERROR', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the Modules Cache
|
||||
$this->module_manager->remove_cache_file($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Module Remove
|
||||
*
|
||||
* Remove a module
|
||||
*
|
||||
* @param string $class The module class(acp|mcp|ucp)
|
||||
* @param int|string|bool $parent The parent module_id|module_langname(0 for no parent).
|
||||
* Use false to ignore the parent check and check class wide.
|
||||
* @param int|string $module The module id|module_langname
|
||||
* specify that here
|
||||
* @return null
|
||||
* @throws \phpbb\db\migration\exception
|
||||
*/
|
||||
public function remove($class, $parent = 0, $module = '')
|
||||
{
|
||||
// Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto
|
||||
if (is_array($module))
|
||||
{
|
||||
if (isset($module['module_langname']))
|
||||
{
|
||||
// Manual Method
|
||||
return $this->remove($class, $parent, $module['module_langname']);
|
||||
}
|
||||
|
||||
// Failed.
|
||||
if (!isset($module['module_basename']))
|
||||
{
|
||||
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST');
|
||||
}
|
||||
|
||||
// Automatic method
|
||||
$basename = $module['module_basename'];
|
||||
$module_info = $this->get_module_info($class, $basename);
|
||||
|
||||
foreach ($module_info['modes'] as $mode => $info)
|
||||
{
|
||||
if (!isset($module['modes']) || in_array($mode, $module['modes']))
|
||||
{
|
||||
$this->remove($class, $parent, $info['title']);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$this->exists($class, $parent, $module, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$parent_sql = '';
|
||||
if ($parent !== false)
|
||||
{
|
||||
$parents = (array) $this->get_parent_module_id($parent, $module);
|
||||
$parent_sql = 'AND ' . $this->db->sql_in_set('parent_id', $parents);
|
||||
}
|
||||
|
||||
$module_ids = array();
|
||||
if (!is_numeric($module))
|
||||
{
|
||||
$sql = 'SELECT module_id
|
||||
FROM ' . $this->modules_table . "
|
||||
WHERE module_langname = '" . $this->db->sql_escape($module) . "'
|
||||
AND module_class = '" . $this->db->sql_escape($class) . "'
|
||||
$parent_sql";
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($module_id = $this->db->sql_fetchfield('module_id'))
|
||||
{
|
||||
$module_ids[] = (int) $module_id;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
$module_ids[] = (int) $module;
|
||||
}
|
||||
|
||||
foreach ($module_ids as $module_id)
|
||||
{
|
||||
$this->module_manager->delete_module($module_id, $class);
|
||||
}
|
||||
|
||||
$this->module_manager->remove_cache_file($class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reverse()
|
||||
{
|
||||
$arguments = func_get_args();
|
||||
$original_call = array_shift($arguments);
|
||||
|
||||
$call = false;
|
||||
switch ($original_call)
|
||||
{
|
||||
case 'add':
|
||||
$call = 'remove';
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
$call = 'add';
|
||||
break;
|
||||
|
||||
case 'reverse':
|
||||
// Reversing a reverse is just the call itself
|
||||
$call = array_shift($arguments);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($call)
|
||||
{
|
||||
return call_user_func_array(array(&$this, $call), $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for \acp_modules::get_module_infos()
|
||||
*
|
||||
* @param string $class Module Class
|
||||
* @param string $basename Module Basename
|
||||
* @return array Module Information
|
||||
* @throws \phpbb\db\migration\exception
|
||||
*/
|
||||
protected function get_module_info($class, $basename)
|
||||
{
|
||||
$module = $this->module_manager->get_module_infos($class, $basename, true);
|
||||
|
||||
if (empty($module))
|
||||
{
|
||||
throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename);
|
||||
}
|
||||
|
||||
return array_pop($module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of installed module categories
|
||||
* key - module_id
|
||||
* value - module_langname
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function get_categories_list()
|
||||
{
|
||||
// Select the top level categories
|
||||
// and 2nd level [sub]categories
|
||||
$sql = 'SELECT m2.module_id, m2.module_langname
|
||||
FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
|
||||
WHERE m1.parent_id = 0
|
||||
AND (m1.module_id = m2.module_id OR m2.parent_id = m1.module_id)
|
||||
ORDER BY m1.module_id, m2.module_id ASC";
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$this->module_categories[(int) $row['module_id']] = $row['module_langname'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent module id
|
||||
*
|
||||
* @param string|int $parent_id The parent module_id|module_langname
|
||||
* @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding
|
||||
* @param bool $throw_exception The flag indicating if exception should be thrown on error
|
||||
* @return mixed The int parent module_id, an array of int parent module_id values or false
|
||||
* @throws \phpbb\db\migration\exception
|
||||
*/
|
||||
public function get_parent_module_id($parent_id, $data = '', $throw_exception = true)
|
||||
{
|
||||
// Allow '' to be sent as 0
|
||||
$parent_id = $parent_id ?: 0;
|
||||
|
||||
if (!is_numeric($parent_id))
|
||||
{
|
||||
// Refresh the $module_categories array
|
||||
$this->get_categories_list();
|
||||
|
||||
// Search for the parent module_langname
|
||||
$ids = array_keys($this->module_categories, $parent_id);
|
||||
|
||||
switch (count($ids))
|
||||
{
|
||||
// No parent with the given module_langname exist
|
||||
case 0:
|
||||
if ($throw_exception)
|
||||
{
|
||||
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Return the module id
|
||||
case 1:
|
||||
return (int) $ids[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
// This represents the old behaviour of phpBB 3.0
|
||||
return $ids;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $parent_id;
|
||||
}
|
||||
}
|
||||
1037
install/update/old/phpbb/db/migrator.php
Normal file
1037
install/update/old/phpbb/db/migrator.php
Normal file
File diff suppressed because it is too large
Load Diff
880
install/update/old/phpbb/db/tools/mssql.php
Normal file
880
install/update/old/phpbb/db/tools/mssql.php
Normal file
@@ -0,0 +1,880 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\tools;
|
||||
|
||||
/**
|
||||
* Database Tools for handling cross-db actions such as altering columns, etc.
|
||||
* Currently not supported is returning SQL for creating tables.
|
||||
*/
|
||||
class mssql extends tools
|
||||
{
|
||||
/**
|
||||
* Is the used MS SQL Server a SQL Server 2000?
|
||||
* @var bool
|
||||
*/
|
||||
protected $is_sql_server_2000;
|
||||
|
||||
/**
|
||||
* Get the column types for mssql based databases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_dbms_type_map()
|
||||
{
|
||||
return array(
|
||||
'mssql' => array(
|
||||
'INT:' => '[int]',
|
||||
'BINT' => '[float]',
|
||||
'ULINT' => '[int]',
|
||||
'UINT' => '[int]',
|
||||
'UINT:' => '[int]',
|
||||
'TINT:' => '[int]',
|
||||
'USINT' => '[int]',
|
||||
'BOOL' => '[int]',
|
||||
'VCHAR' => '[varchar] (255)',
|
||||
'VCHAR:' => '[varchar] (%d)',
|
||||
'CHAR:' => '[char] (%d)',
|
||||
'XSTEXT' => '[varchar] (1000)',
|
||||
'STEXT' => '[varchar] (3000)',
|
||||
'TEXT' => '[varchar] (8000)',
|
||||
'MTEXT' => '[text]',
|
||||
'XSTEXT_UNI'=> '[nvarchar] (100)',
|
||||
'STEXT_UNI' => '[nvarchar] (255)',
|
||||
'TEXT_UNI' => '[nvarchar] (4000)',
|
||||
'MTEXT_UNI' => '[ntext]',
|
||||
'TIMESTAMP' => '[int]',
|
||||
'DECIMAL' => '[float]',
|
||||
'DECIMAL:' => '[float]',
|
||||
'PDECIMAL' => '[float]',
|
||||
'PDECIMAL:' => '[float]',
|
||||
'VCHAR_UNI' => '[nvarchar] (255)',
|
||||
'VCHAR_UNI:'=> '[nvarchar] (%d)',
|
||||
'VCHAR_CI' => '[nvarchar] (255)',
|
||||
'VARBINARY' => '[varchar] (255)',
|
||||
),
|
||||
|
||||
'mssqlnative' => array(
|
||||
'INT:' => '[int]',
|
||||
'BINT' => '[float]',
|
||||
'ULINT' => '[int]',
|
||||
'UINT' => '[int]',
|
||||
'UINT:' => '[int]',
|
||||
'TINT:' => '[int]',
|
||||
'USINT' => '[int]',
|
||||
'BOOL' => '[int]',
|
||||
'VCHAR' => '[varchar] (255)',
|
||||
'VCHAR:' => '[varchar] (%d)',
|
||||
'CHAR:' => '[char] (%d)',
|
||||
'XSTEXT' => '[varchar] (1000)',
|
||||
'STEXT' => '[varchar] (3000)',
|
||||
'TEXT' => '[varchar] (8000)',
|
||||
'MTEXT' => '[text]',
|
||||
'XSTEXT_UNI'=> '[nvarchar] (100)',
|
||||
'STEXT_UNI' => '[nvarchar] (255)',
|
||||
'TEXT_UNI' => '[nvarchar] (4000)',
|
||||
'MTEXT_UNI' => '[ntext]',
|
||||
'TIMESTAMP' => '[int]',
|
||||
'DECIMAL' => '[float]',
|
||||
'DECIMAL:' => '[float]',
|
||||
'PDECIMAL' => '[float]',
|
||||
'PDECIMAL:' => '[float]',
|
||||
'VCHAR_UNI' => '[nvarchar] (255)',
|
||||
'VCHAR_UNI:'=> '[nvarchar] (%d)',
|
||||
'VCHAR_CI' => '[nvarchar] (255)',
|
||||
'VARBINARY' => '[varchar] (255)',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Set DB Object and set {@link $return_statements return_statements}.
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param bool $return_statements True if only statements should be returned and no SQL being executed
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
|
||||
{
|
||||
parent::__construct($db, $return_statements);
|
||||
|
||||
// Determine mapping database type
|
||||
switch ($this->db->get_sql_layer())
|
||||
{
|
||||
case 'mssql_odbc':
|
||||
$this->sql_layer = 'mssql';
|
||||
break;
|
||||
|
||||
case 'mssqlnative':
|
||||
$this->sql_layer = 'mssqlnative';
|
||||
break;
|
||||
}
|
||||
|
||||
$this->dbms_type_map = self::get_dbms_type_map();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_list_tables()
|
||||
{
|
||||
$sql = "SELECT name
|
||||
FROM sysobjects
|
||||
WHERE type='U'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$tables = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$name = current($row);
|
||||
$tables[$name] = $name;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_table($table_name, $table_data)
|
||||
{
|
||||
// holds the DDL for a column
|
||||
$columns = $statements = array();
|
||||
|
||||
if ($this->sql_table_exists($table_name))
|
||||
{
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
// Begin transaction
|
||||
$statements[] = 'begin';
|
||||
|
||||
// Determine if we have created a PRIMARY KEY in the earliest
|
||||
$primary_key_gen = false;
|
||||
|
||||
// Determine if the table requires a sequence
|
||||
$create_sequence = false;
|
||||
|
||||
// Begin table sql statement
|
||||
$table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n";
|
||||
|
||||
if (!isset($table_data['PRIMARY_KEY']))
|
||||
{
|
||||
$table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment');
|
||||
$table_data['PRIMARY_KEY'] = 'mssqlindex';
|
||||
}
|
||||
|
||||
// Iterate through the columns to create a table
|
||||
foreach ($table_data['COLUMNS'] as $column_name => $column_data)
|
||||
{
|
||||
// here lies an array, filled with information compiled on the column's data
|
||||
$prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
|
||||
|
||||
if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
|
||||
{
|
||||
trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
|
||||
}
|
||||
|
||||
// here we add the definition of the new column to the list of columns
|
||||
$columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default'];
|
||||
|
||||
// see if we have found a primary key set due to a column definition if we have found it, we can stop looking
|
||||
if (!$primary_key_gen)
|
||||
{
|
||||
$primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
|
||||
}
|
||||
|
||||
// create sequence DDL based off of the existance of auto incrementing columns
|
||||
if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
|
||||
{
|
||||
$create_sequence = $column_name;
|
||||
}
|
||||
}
|
||||
|
||||
// this makes up all the columns in the create table statement
|
||||
$table_sql .= implode(",\n", $columns);
|
||||
|
||||
// Close the table for two DBMS and add to the statements
|
||||
$table_sql .= "\n);";
|
||||
$statements[] = $table_sql;
|
||||
|
||||
// we have yet to create a primary key for this table,
|
||||
// this means that we can add the one we really wanted instead
|
||||
if (!$primary_key_gen)
|
||||
{
|
||||
// Write primary key
|
||||
if (isset($table_data['PRIMARY_KEY']))
|
||||
{
|
||||
if (!is_array($table_data['PRIMARY_KEY']))
|
||||
{
|
||||
$table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
|
||||
}
|
||||
|
||||
// We need the data here
|
||||
$old_return_statements = $this->return_statements;
|
||||
$this->return_statements = true;
|
||||
|
||||
$primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']);
|
||||
foreach ($primary_key_stmts as $pk_stmt)
|
||||
{
|
||||
$statements[] = $pk_stmt;
|
||||
}
|
||||
|
||||
$this->return_statements = $old_return_statements;
|
||||
}
|
||||
}
|
||||
|
||||
// Write Keys
|
||||
if (isset($table_data['KEYS']))
|
||||
{
|
||||
foreach ($table_data['KEYS'] as $key_name => $key_data)
|
||||
{
|
||||
if (!is_array($key_data[1]))
|
||||
{
|
||||
$key_data[1] = array($key_data[1]);
|
||||
}
|
||||
|
||||
$old_return_statements = $this->return_statements;
|
||||
$this->return_statements = true;
|
||||
|
||||
$key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
|
||||
|
||||
foreach ($key_stmts as $key_stmt)
|
||||
{
|
||||
$statements[] = $key_stmt;
|
||||
}
|
||||
|
||||
$this->return_statements = $old_return_statements;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit Transaction
|
||||
$statements[] = 'commit';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_list_columns($table_name)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
$sql = "SELECT c.name
|
||||
FROM syscolumns c
|
||||
LEFT JOIN sysobjects o ON c.id = o.id
|
||||
WHERE o.name = '{$table_name}'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$column = strtolower(current($row));
|
||||
$columns[$column] = $column;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_index_exists($table_name, $index_name)
|
||||
{
|
||||
$sql = "EXEC sp_statistics '$table_name'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if ($row['TYPE'] == 3)
|
||||
{
|
||||
if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
|
||||
{
|
||||
$this->db->sql_freeresult($result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_unique_index_exists($table_name, $index_name)
|
||||
{
|
||||
$sql = "EXEC sp_statistics '$table_name'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
// Usually NON_UNIQUE is the column we want to check, but we allow for both
|
||||
if ($row['TYPE'] == 3)
|
||||
{
|
||||
if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
|
||||
{
|
||||
$this->db->sql_freeresult($result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_prepare_column_data($table_name, $column_name, $column_data)
|
||||
{
|
||||
if (strlen($column_name) > 30)
|
||||
{
|
||||
trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
|
||||
}
|
||||
|
||||
// Get type
|
||||
list($column_type, ) = $this->get_column_type($column_data[0]);
|
||||
|
||||
// Adjust default value if db-dependent specified
|
||||
if (is_array($column_data[1]))
|
||||
{
|
||||
$column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
|
||||
}
|
||||
|
||||
$sql = '';
|
||||
|
||||
$return_array = array();
|
||||
|
||||
$sql .= " {$column_type} ";
|
||||
$sql_default = " {$column_type} ";
|
||||
|
||||
// For adding columns we need the default definition
|
||||
if (!is_null($column_data[1]))
|
||||
{
|
||||
// For hexadecimal values do not use single quotes
|
||||
if (strpos($column_data[1], '0x') === 0)
|
||||
{
|
||||
$return_array['default'] = 'DEFAULT (' . $column_data[1] . ') ';
|
||||
$sql_default .= $return_array['default'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
|
||||
$sql_default .= $return_array['default'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
|
||||
{
|
||||
// $sql .= 'IDENTITY (1, 1) ';
|
||||
$sql_default .= 'IDENTITY (1, 1) ';
|
||||
}
|
||||
|
||||
$return_array['textimage'] = $column_type === '[text]';
|
||||
|
||||
if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment'))
|
||||
{
|
||||
$sql .= 'NOT NULL';
|
||||
$sql_default .= 'NOT NULL';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql .= 'NULL';
|
||||
$sql_default .= 'NULL';
|
||||
}
|
||||
|
||||
$return_array['column_type_sql_default'] = $sql_default;
|
||||
|
||||
$return_array['column_type_sql'] = $sql;
|
||||
|
||||
return $return_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_column_add($table_name, $column_name, $column_data, $inline = false)
|
||||
{
|
||||
$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
|
||||
$statements = array();
|
||||
|
||||
// Does not support AFTER, only through temporary table
|
||||
$statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_column_remove($table_name, $column_name, $inline = false)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
// We need the data here
|
||||
$old_return_statements = $this->return_statements;
|
||||
$this->return_statements = true;
|
||||
|
||||
$indexes = $this->get_existing_indexes($table_name, $column_name);
|
||||
$indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true));
|
||||
|
||||
// Drop any indexes
|
||||
$recreate_indexes = array();
|
||||
if (!empty($indexes))
|
||||
{
|
||||
foreach ($indexes as $index_name => $index_data)
|
||||
{
|
||||
$result = $this->sql_index_drop($table_name, $index_name);
|
||||
$statements = array_merge($statements, $result);
|
||||
if (count($index_data) > 1)
|
||||
{
|
||||
// Remove this column from the index and recreate it
|
||||
$recreate_indexes[$index_name] = array_diff($index_data, array($column_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop primary keys depending on this column
|
||||
$result = $this->mssql_get_drop_default_primary_key_queries($table_name, $column_name);
|
||||
$statements = array_merge($statements, $result);
|
||||
|
||||
// Drop default value constraint
|
||||
$result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
|
||||
$statements = array_merge($statements, $result);
|
||||
|
||||
// Remove the column
|
||||
$statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
|
||||
|
||||
if (!empty($recreate_indexes))
|
||||
{
|
||||
// Recreate indexes after we removed the column
|
||||
foreach ($recreate_indexes as $index_name => $index_data)
|
||||
{
|
||||
$result = $this->sql_create_index($table_name, $index_name, $index_data);
|
||||
$statements = array_merge($statements, $result);
|
||||
}
|
||||
}
|
||||
|
||||
$this->return_statements = $old_return_statements;
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_index_drop($table_name, $index_name)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$statements[] = 'DROP INDEX [' . $table_name . '].[' . $index_name . ']';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_table_drop($table_name)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
if (!$this->sql_table_exists($table_name))
|
||||
{
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
// the most basic operation, get rid of the table
|
||||
$statements[] = 'DROP TABLE ' . $table_name;
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_primary_key($table_name, $column, $inline = false)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
|
||||
$sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED (";
|
||||
$sql .= '[' . implode("],\n\t\t[", $column) . ']';
|
||||
$sql .= ')';
|
||||
|
||||
$statements[] = $sql;
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_unique_index($table_name, $index_name, $column)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
if ($this->mssql_is_sql_server_2000())
|
||||
{
|
||||
$this->check_index_name_length($table_name, $index_name);
|
||||
}
|
||||
|
||||
$statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_index($table_name, $index_name, $column)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$this->check_index_name_length($table_name, $index_name);
|
||||
|
||||
// remove index length
|
||||
$column = preg_replace('#:.*$#', '', $column);
|
||||
|
||||
$statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function get_max_index_name_length()
|
||||
{
|
||||
if ($this->mssql_is_sql_server_2000())
|
||||
{
|
||||
return parent::get_max_index_name_length();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_list_index($table_name)
|
||||
{
|
||||
$index_array = array();
|
||||
$sql = "EXEC sp_statistics '$table_name'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if ($row['TYPE'] == 3)
|
||||
{
|
||||
$index_array[] = strtolower($row['INDEX_NAME']);
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $index_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_column_change($table_name, $column_name, $column_data, $inline = false)
|
||||
{
|
||||
$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
|
||||
$statements = array();
|
||||
|
||||
// We need the data here
|
||||
$old_return_statements = $this->return_statements;
|
||||
$this->return_statements = true;
|
||||
|
||||
$indexes = $this->get_existing_indexes($table_name, $column_name);
|
||||
$unique_indexes = $this->get_existing_indexes($table_name, $column_name, true);
|
||||
|
||||
// Drop any indexes
|
||||
if (!empty($indexes) || !empty($unique_indexes))
|
||||
{
|
||||
$drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes));
|
||||
foreach ($drop_indexes as $index_name)
|
||||
{
|
||||
$result = $this->sql_index_drop($table_name, $index_name);
|
||||
$statements = array_merge($statements, $result);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop default value constraint
|
||||
$result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
|
||||
$statements = array_merge($statements, $result);
|
||||
|
||||
// Change the column
|
||||
$statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
|
||||
|
||||
if (!empty($column_data['default']) && !$this->mssql_is_column_identity($table_name, $column_name))
|
||||
{
|
||||
// Add new default value constraint
|
||||
$statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $column_data['default'] . ' FOR [' . $column_name . ']';
|
||||
}
|
||||
|
||||
if (!empty($indexes))
|
||||
{
|
||||
// Recreate indexes after we changed the column
|
||||
foreach ($indexes as $index_name => $index_data)
|
||||
{
|
||||
$result = $this->sql_create_index($table_name, $index_name, $index_data);
|
||||
$statements = array_merge($statements, $result);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($unique_indexes))
|
||||
{
|
||||
// Recreate unique indexes after we changed the column
|
||||
foreach ($unique_indexes as $index_name => $index_data)
|
||||
{
|
||||
$result = $this->sql_create_unique_index($table_name, $index_name, $index_data);
|
||||
$statements = array_merge($statements, $result);
|
||||
}
|
||||
}
|
||||
|
||||
$this->return_statements = $old_return_statements;
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get queries to drop the default constraints of a column
|
||||
*
|
||||
* We need to drop the default constraints of a column,
|
||||
* before being able to change their type or deleting them.
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param string $column_name
|
||||
* @return array Array with SQL statements
|
||||
*/
|
||||
protected function mssql_get_drop_default_constraints_queries($table_name, $column_name)
|
||||
{
|
||||
$statements = array();
|
||||
if ($this->mssql_is_sql_server_2000())
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
|
||||
// Deprecated in SQL Server 2005
|
||||
$sql = "SELECT so.name AS def_name
|
||||
FROM sysobjects so
|
||||
JOIN sysconstraints sc ON so.id = sc.constid
|
||||
WHERE object_name(so.parent_obj) = '{$table_name}'
|
||||
AND so.xtype = 'D'
|
||||
AND sc.colid = (SELECT colid FROM syscolumns
|
||||
WHERE id = object_id('{$table_name}')
|
||||
AND name = '{$column_name}')";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "SELECT dobj.name AS def_name
|
||||
FROM sys.columns col
|
||||
LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D')
|
||||
WHERE col.object_id = object_id('{$table_name}')
|
||||
AND col.name = '{$column_name}'
|
||||
AND dobj.name IS NOT NULL";
|
||||
}
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']';
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get queries to drop the primary keys depending on the specified column
|
||||
*
|
||||
* We need to drop primary keys depending on this column before being able
|
||||
* to delete them.
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param string $column_name
|
||||
* @return array Array with SQL statements
|
||||
*/
|
||||
protected function mssql_get_drop_default_primary_key_queries($table_name, $column_name)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$sql = "SELECT ccu.CONSTRAINT_NAME, ccu.COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
|
||||
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu ON tc.CONSTRAINT_NAME = ccu.Constraint_name
|
||||
WHERE tc.TABLE_NAME = '{$table_name}'
|
||||
AND tc.CONSTRAINT_TYPE = 'Primary Key'
|
||||
AND ccu.COLUMN_NAME = '{$column_name}'";
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($primary_key = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $primary_key['CONSTRAINT_NAME'] . ']';
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if column is an identity column
|
||||
*
|
||||
* Identity columns cannot have defaults set for them.
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param string $column_name
|
||||
* @return bool true if identity, false if not
|
||||
*/
|
||||
protected function mssql_is_column_identity($table_name, $column_name)
|
||||
{
|
||||
if ($this->mssql_is_sql_server_2000())
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
|
||||
// Deprecated in SQL Server 2005
|
||||
$sql = "SELECT COLUMNPROPERTY(object_id('{$table_name}'), '{$column_name}', 'IsIdentity') AS is_identity";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "SELECT is_identity FROM sys.columns
|
||||
WHERE object_id = object_id('{$table_name}')
|
||||
AND name = '{$column_name}'";
|
||||
}
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
$is_identity = $this->db->sql_fetchfield('is_identity');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return (bool) $is_identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list with existing indexes for the column
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param string $column_name
|
||||
* @param bool $unique Should we get unique indexes or normal ones
|
||||
* @return array Array with Index name => columns
|
||||
*/
|
||||
public function get_existing_indexes($table_name, $column_name, $unique = false)
|
||||
{
|
||||
$existing_indexes = array();
|
||||
if ($this->mssql_is_sql_server_2000())
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
|
||||
// Deprecated in SQL Server 2005
|
||||
$sql = "SELECT DISTINCT ix.name AS phpbb_index_name
|
||||
FROM sysindexes ix
|
||||
INNER JOIN sysindexkeys ixc
|
||||
ON ixc.id = ix.id
|
||||
AND ixc.indid = ix.indid
|
||||
INNER JOIN syscolumns cols
|
||||
ON cols.colid = ixc.colid
|
||||
AND cols.id = ix.id
|
||||
WHERE ix.id = object_id('{$table_name}')
|
||||
AND cols.name = '{$column_name}'
|
||||
AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "SELECT DISTINCT ix.name AS phpbb_index_name
|
||||
FROM sys.indexes ix
|
||||
INNER JOIN sys.index_columns ixc
|
||||
ON ixc.object_id = ix.object_id
|
||||
AND ixc.index_id = ix.index_id
|
||||
INNER JOIN sys.columns cols
|
||||
ON cols.column_id = ixc.column_id
|
||||
AND cols.object_id = ix.object_id
|
||||
WHERE ix.object_id = object_id('{$table_name}')
|
||||
AND cols.name = '{$column_name}'
|
||||
AND ix.is_primary_key = 0
|
||||
AND ix.is_unique = " . ($unique ? '1' : '0');
|
||||
}
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE'))
|
||||
{
|
||||
$existing_indexes[$row['phpbb_index_name']] = array();
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (empty($existing_indexes))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($this->mssql_is_sql_server_2000())
|
||||
{
|
||||
$sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
|
||||
FROM sysindexes ix
|
||||
INNER JOIN sysindexkeys ixc
|
||||
ON ixc.id = ix.id
|
||||
AND ixc.indid = ix.indid
|
||||
INNER JOIN syscolumns cols
|
||||
ON cols.colid = ixc.colid
|
||||
AND cols.id = ix.id
|
||||
WHERE ix.id = object_id('{$table_name}')
|
||||
AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
|
||||
FROM sys.indexes ix
|
||||
INNER JOIN sys.index_columns ixc
|
||||
ON ixc.object_id = ix.object_id
|
||||
AND ixc.index_id = ix.index_id
|
||||
INNER JOIN sys.columns cols
|
||||
ON cols.column_id = ixc.column_id
|
||||
AND cols.object_id = ix.object_id
|
||||
WHERE ix.object_id = object_id('{$table_name}')
|
||||
AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
|
||||
}
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $existing_indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the used MS SQL Server a SQL Server 2000?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function mssql_is_sql_server_2000()
|
||||
{
|
||||
if ($this->is_sql_server_2000 === null)
|
||||
{
|
||||
$sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$properties = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
$this->is_sql_server_2000 = $properties['mssql_version'][0] == '8';
|
||||
}
|
||||
|
||||
return $this->is_sql_server_2000;
|
||||
}
|
||||
|
||||
}
|
||||
614
install/update/old/phpbb/db/tools/postgres.php
Normal file
614
install/update/old/phpbb/db/tools/postgres.php
Normal file
@@ -0,0 +1,614 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\tools;
|
||||
|
||||
/**
|
||||
* Database Tools for handling cross-db actions such as altering columns, etc.
|
||||
* Currently not supported is returning SQL for creating tables.
|
||||
*/
|
||||
class postgres extends tools
|
||||
{
|
||||
/**
|
||||
* Get the column types for postgres only
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_dbms_type_map()
|
||||
{
|
||||
return array(
|
||||
'postgres' => array(
|
||||
'INT:' => 'INT4',
|
||||
'BINT' => 'INT8',
|
||||
'ULINT' => 'INT4', // unsigned
|
||||
'UINT' => 'INT4', // unsigned
|
||||
'UINT:' => 'INT4', // unsigned
|
||||
'USINT' => 'INT2', // unsigned
|
||||
'BOOL' => 'INT2', // unsigned
|
||||
'TINT:' => 'INT2',
|
||||
'VCHAR' => 'varchar(255)',
|
||||
'VCHAR:' => 'varchar(%d)',
|
||||
'CHAR:' => 'char(%d)',
|
||||
'XSTEXT' => 'varchar(1000)',
|
||||
'STEXT' => 'varchar(3000)',
|
||||
'TEXT' => 'varchar(8000)',
|
||||
'MTEXT' => 'TEXT',
|
||||
'XSTEXT_UNI'=> 'varchar(100)',
|
||||
'STEXT_UNI' => 'varchar(255)',
|
||||
'TEXT_UNI' => 'varchar(4000)',
|
||||
'MTEXT_UNI' => 'TEXT',
|
||||
'TIMESTAMP' => 'INT4', // unsigned
|
||||
'DECIMAL' => 'decimal(5,2)',
|
||||
'DECIMAL:' => 'decimal(%d,2)',
|
||||
'PDECIMAL' => 'decimal(6,3)',
|
||||
'PDECIMAL:' => 'decimal(%d,3)',
|
||||
'VCHAR_UNI' => 'varchar(255)',
|
||||
'VCHAR_UNI:'=> 'varchar(%d)',
|
||||
'VCHAR_CI' => 'varchar_ci',
|
||||
'VARBINARY' => 'bytea',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Set DB Object and set {@link $return_statements return_statements}.
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param bool $return_statements True if only statements should be returned and no SQL being executed
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
|
||||
{
|
||||
parent::__construct($db, $return_statements);
|
||||
|
||||
// Determine mapping database type
|
||||
$this->sql_layer = 'postgres';
|
||||
|
||||
$this->dbms_type_map = self::get_dbms_type_map();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_list_tables()
|
||||
{
|
||||
$sql = 'SELECT relname
|
||||
FROM pg_stat_user_tables';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$tables = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$name = current($row);
|
||||
$tables[$name] = $name;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_table($table_name, $table_data)
|
||||
{
|
||||
// holds the DDL for a column
|
||||
$columns = $statements = array();
|
||||
|
||||
if ($this->sql_table_exists($table_name))
|
||||
{
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
// Begin transaction
|
||||
$statements[] = 'begin';
|
||||
|
||||
// Determine if we have created a PRIMARY KEY in the earliest
|
||||
$primary_key_gen = false;
|
||||
|
||||
// Determine if the table requires a sequence
|
||||
$create_sequence = false;
|
||||
|
||||
// Begin table sql statement
|
||||
$table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";
|
||||
|
||||
// Iterate through the columns to create a table
|
||||
foreach ($table_data['COLUMNS'] as $column_name => $column_data)
|
||||
{
|
||||
// here lies an array, filled with information compiled on the column's data
|
||||
$prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
|
||||
|
||||
if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
|
||||
{
|
||||
trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
|
||||
}
|
||||
|
||||
// here we add the definition of the new column to the list of columns
|
||||
$columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];
|
||||
|
||||
// see if we have found a primary key set due to a column definition if we have found it, we can stop looking
|
||||
if (!$primary_key_gen)
|
||||
{
|
||||
$primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
|
||||
}
|
||||
|
||||
// create sequence DDL based off of the existance of auto incrementing columns
|
||||
if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
|
||||
{
|
||||
$create_sequence = $column_name;
|
||||
}
|
||||
}
|
||||
|
||||
// this makes up all the columns in the create table statement
|
||||
$table_sql .= implode(",\n", $columns);
|
||||
|
||||
// we have yet to create a primary key for this table,
|
||||
// this means that we can add the one we really wanted instead
|
||||
if (!$primary_key_gen)
|
||||
{
|
||||
// Write primary key
|
||||
if (isset($table_data['PRIMARY_KEY']))
|
||||
{
|
||||
if (!is_array($table_data['PRIMARY_KEY']))
|
||||
{
|
||||
$table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
|
||||
}
|
||||
|
||||
$table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
// do we need to add a sequence for auto incrementing columns?
|
||||
if ($create_sequence)
|
||||
{
|
||||
$statements[] = "CREATE SEQUENCE {$table_name}_seq;";
|
||||
}
|
||||
|
||||
// close the table
|
||||
$table_sql .= "\n);";
|
||||
$statements[] = $table_sql;
|
||||
|
||||
// Write Keys
|
||||
if (isset($table_data['KEYS']))
|
||||
{
|
||||
foreach ($table_data['KEYS'] as $key_name => $key_data)
|
||||
{
|
||||
if (!is_array($key_data[1]))
|
||||
{
|
||||
$key_data[1] = array($key_data[1]);
|
||||
}
|
||||
|
||||
$old_return_statements = $this->return_statements;
|
||||
$this->return_statements = true;
|
||||
|
||||
$key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
|
||||
|
||||
foreach ($key_stmts as $key_stmt)
|
||||
{
|
||||
$statements[] = $key_stmt;
|
||||
}
|
||||
|
||||
$this->return_statements = $old_return_statements;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit Transaction
|
||||
$statements[] = 'commit';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_list_columns($table_name)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
$sql = "SELECT a.attname
|
||||
FROM pg_class c, pg_attribute a
|
||||
WHERE c.relname = '{$table_name}'
|
||||
AND a.attnum > 0
|
||||
AND a.attrelid = c.oid";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$column = strtolower(current($row));
|
||||
$columns[$column] = $column;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_index_exists($table_name, $index_name)
|
||||
{
|
||||
$sql = "SELECT ic.relname as index_name
|
||||
FROM pg_class bc, pg_class ic, pg_index i
|
||||
WHERE (bc.oid = i.indrelid)
|
||||
AND (ic.oid = i.indexrelid)
|
||||
AND (bc.relname = '" . $table_name . "')
|
||||
AND (i.indisunique != 't')
|
||||
AND (i.indisprimary != 't')";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
// This DBMS prefixes index names with the table name
|
||||
$row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
|
||||
|
||||
if (strtolower($row['index_name']) == strtolower($index_name))
|
||||
{
|
||||
$this->db->sql_freeresult($result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_unique_index_exists($table_name, $index_name)
|
||||
{
|
||||
$sql = "SELECT ic.relname as index_name, i.indisunique
|
||||
FROM pg_class bc, pg_class ic, pg_index i
|
||||
WHERE (bc.oid = i.indrelid)
|
||||
AND (ic.oid = i.indexrelid)
|
||||
AND (bc.relname = '" . $table_name . "')
|
||||
AND (i.indisprimary != 't')";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if ($row['indisunique'] != 't')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// This DBMS prefixes index names with the table name
|
||||
$row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
|
||||
|
||||
if (strtolower($row['index_name']) == strtolower($index_name))
|
||||
{
|
||||
$this->db->sql_freeresult($result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to prepare some column information for better usage
|
||||
* @access private
|
||||
*/
|
||||
function sql_prepare_column_data($table_name, $column_name, $column_data)
|
||||
{
|
||||
if (strlen($column_name) > 30)
|
||||
{
|
||||
trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
|
||||
}
|
||||
|
||||
// Get type
|
||||
list($column_type, $orig_column_type) = $this->get_column_type($column_data[0]);
|
||||
|
||||
// Adjust default value if db-dependent specified
|
||||
if (is_array($column_data[1]))
|
||||
{
|
||||
$column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
|
||||
}
|
||||
|
||||
$sql = " {$column_type} ";
|
||||
|
||||
$return_array = array(
|
||||
'column_type' => $column_type,
|
||||
'auto_increment' => false,
|
||||
);
|
||||
|
||||
if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
|
||||
{
|
||||
$default_val = "nextval('{$table_name}_seq')";
|
||||
$return_array['auto_increment'] = true;
|
||||
}
|
||||
else if (!is_null($column_data[1]))
|
||||
{
|
||||
$default_val = "'" . $column_data[1] . "'";
|
||||
$return_array['null'] = 'NOT NULL';
|
||||
$sql .= 'NOT NULL ';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Integers need to have 0 instead of empty string as default
|
||||
if (strpos($column_type, 'INT') === 0)
|
||||
{
|
||||
$default_val = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
$default_val = "'" . $column_data[1] . "'";
|
||||
}
|
||||
$return_array['null'] = 'NULL';
|
||||
$sql .= 'NULL ';
|
||||
}
|
||||
|
||||
$return_array['default'] = $default_val;
|
||||
|
||||
$sql .= "DEFAULT {$default_val}";
|
||||
|
||||
// Unsigned? Then add a CHECK contraint
|
||||
if (in_array($orig_column_type, $this->unsigned_types))
|
||||
{
|
||||
$return_array['constraint'] = "CHECK ({$column_name} >= 0)";
|
||||
$sql .= " CHECK ({$column_name} >= 0)";
|
||||
}
|
||||
|
||||
$return_array['column_type_sql'] = $sql;
|
||||
|
||||
return $return_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_column_add($table_name, $column_name, $column_data, $inline = false)
|
||||
{
|
||||
$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
|
||||
$statements = array();
|
||||
|
||||
// Does not support AFTER, only through temporary table
|
||||
if (version_compare($this->db->sql_server_info(true), '8.0', '>='))
|
||||
{
|
||||
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// old versions cannot add columns with default and null information
|
||||
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint'];
|
||||
|
||||
if (isset($column_data['null']))
|
||||
{
|
||||
if ($column_data['null'] == 'NOT NULL')
|
||||
{
|
||||
$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($column_data['default']))
|
||||
{
|
||||
$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_column_remove($table_name, $column_name, $inline = false)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_index_drop($table_name, $index_name)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name;
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_table_drop($table_name)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
if (!$this->sql_table_exists($table_name))
|
||||
{
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
// the most basic operation, get rid of the table
|
||||
$statements[] = 'DROP TABLE ' . $table_name;
|
||||
|
||||
// PGSQL does not "tightly" bind sequences and tables, we must guess...
|
||||
$sql = "SELECT relname
|
||||
FROM pg_class
|
||||
WHERE relkind = 'S'
|
||||
AND relname = '{$table_name}_seq'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
// We don't even care about storing the results. We already know the answer if we get rows back.
|
||||
if ($this->db->sql_fetchrow($result))
|
||||
{
|
||||
$statements[] = "DROP SEQUENCE IF EXISTS {$table_name}_seq;\n";
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_primary_key($table_name, $column, $inline = false)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_unique_index($table_name, $index_name, $column)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$this->check_index_name_length($table_name, $index_name);
|
||||
|
||||
$statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_create_index($table_name, $index_name, $column)
|
||||
{
|
||||
$statements = array();
|
||||
|
||||
$this->check_index_name_length($table_name, $index_name);
|
||||
|
||||
// remove index length
|
||||
$column = preg_replace('#:.*$#', '', $column);
|
||||
|
||||
$statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_list_index($table_name)
|
||||
{
|
||||
$index_array = array();
|
||||
|
||||
$sql = "SELECT ic.relname as index_name
|
||||
FROM pg_class bc, pg_class ic, pg_index i
|
||||
WHERE (bc.oid = i.indrelid)
|
||||
AND (ic.oid = i.indexrelid)
|
||||
AND (bc.relname = '" . $table_name . "')
|
||||
AND (i.indisunique != 't')
|
||||
AND (i.indisprimary != 't')";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
|
||||
|
||||
$index_array[] = $row['index_name'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return array_map('strtolower', $index_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_column_change($table_name, $column_name, $column_data, $inline = false)
|
||||
{
|
||||
$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
|
||||
$statements = array();
|
||||
|
||||
$sql = 'ALTER TABLE ' . $table_name . ' ';
|
||||
|
||||
$sql_array = array();
|
||||
$sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
|
||||
|
||||
if (isset($column_data['null']))
|
||||
{
|
||||
if ($column_data['null'] == 'NOT NULL')
|
||||
{
|
||||
$sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
|
||||
}
|
||||
else if ($column_data['null'] == 'NULL')
|
||||
{
|
||||
$sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($column_data['default']))
|
||||
{
|
||||
$sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
|
||||
}
|
||||
|
||||
// we don't want to double up on constraints if we change different number data types
|
||||
if (isset($column_data['constraint']))
|
||||
{
|
||||
$constraint_sql = "SELECT consrc as constraint_data
|
||||
FROM pg_constraint, pg_class bc
|
||||
WHERE conrelid = bc.oid
|
||||
AND bc.relname = '{$table_name}'
|
||||
AND NOT EXISTS (
|
||||
SELECT *
|
||||
FROM pg_constraint as c, pg_inherits as i
|
||||
WHERE i.inhrelid = pg_constraint.conrelid
|
||||
AND c.conname = pg_constraint.conname
|
||||
AND c.consrc = pg_constraint.consrc
|
||||
AND c.conrelid = i.inhparent
|
||||
)";
|
||||
|
||||
$constraint_exists = false;
|
||||
|
||||
$result = $this->db->sql_query($constraint_sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if (trim($row['constraint_data']) == trim($column_data['constraint']))
|
||||
{
|
||||
$constraint_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$constraint_exists)
|
||||
{
|
||||
$sql_array[] = 'ADD ' . $column_data['constraint'];
|
||||
}
|
||||
}
|
||||
|
||||
$sql .= implode(', ', $sql_array);
|
||||
|
||||
$statements[] = $sql;
|
||||
|
||||
return $this->_sql_run_sql($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list with existing indexes for the column
|
||||
*
|
||||
* @param string $table_name
|
||||
* @param string $column_name
|
||||
* @param bool $unique Should we get unique indexes or normal ones
|
||||
* @return array Array with Index name => columns
|
||||
*/
|
||||
public function get_existing_indexes($table_name, $column_name, $unique = false)
|
||||
{
|
||||
// Not supported
|
||||
throw new \Exception('DBMS is not supported');
|
||||
}
|
||||
}
|
||||
1956
install/update/old/phpbb/db/tools/tools.php
Normal file
1956
install/update/old/phpbb/db/tools/tools.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user