| <?php |
| <?php |
| # MantisBT - A PHP based bugtracking system |
| # MantisBT - A PHP based bugtracking system |
| |
| |
| # MantisBT is free software: you can redistribute it and/or modify |
| # MantisBT is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 2 of the License, or |
| # the Free Software Foundation, either version 2 of the License, or |
| # (at your option) any later version. |
| # (at your option) any later version. |
| # |
| # |
| # MantisBT is distributed in the hope that it will be useful, |
| # MantisBT is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # GNU General Public License for more details. |
| # |
| # |
| # You should have received a copy of the GNU General Public License |
| # You should have received a copy of the GNU General Public License |
| # along with MantisBT. If not, see <http://www.gnu.org/licenses/>. |
| # along with MantisBT. If not, see <http://www.gnu.org/licenses/>. |
| |
| |
| /** |
| /** |
| * Database API |
| * Database API |
| * |
| * |
| * @package CoreAPI |
| * @package CoreAPI |
| * @subpackage DatabaseAPI |
| * @subpackage DatabaseAPI |
| * @copyright Copyright 2000 - 2002 Kenzaburo Ito - kenito@300baud.org |
| * @copyright Copyright 2000 - 2002 Kenzaburo Ito - kenito@300baud.org |
| * @copyright Copyright 2002 MantisBT Team - mantisbt-dev@lists.sourceforge.net |
| * @copyright Copyright 2002 MantisBT Team - mantisbt-dev@lists.sourceforge.net |
| * @link http://www.mantisbt.org |
| * @link http://www.mantisbt.org |
| * |
| * |
| * @uses config_api.php |
| * @uses config_api.php |
| * @uses constant_inc.php |
| * @uses constant_inc.php |
| * @uses error_api.php |
| * @uses error_api.php |
| * @uses logging_api.php |
| * @uses logging_api.php |
| * @uses utility_api.php |
| * @uses utility_api.php |
| * @uses adodb/adodb.inc.php |
| * @uses adodb/adodb.inc.php |
| */ |
| */ |
| |
| |
| require_api( 'config_api.php' ); |
| require_api( 'config_api.php' ); |
| require_api( 'constant_inc.php' ); |
| require_api( 'constant_inc.php' ); |
| require_api( 'error_api.php' ); |
| require_api( 'error_api.php' ); |
| require_api( 'logging_api.php' ); |
| require_api( 'logging_api.php' ); |
| require_api( 'utility_api.php' ); |
| require_api( 'utility_api.php' ); |
| |
| |
| # An array in which all executed queries are stored. This is used for profiling |
| # An array in which all executed queries are stored. This is used for profiling |
| # @global array $g_queries_array |
| # @global array $g_queries_array |
| $g_queries_array = array(); |
| $g_queries_array = array(); |
| |
| |
| |
| |
| # Stores whether a database connection was successfully opened. |
| # Stores whether a database connection was successfully opened. |
| # @global bool $g_db_connected |
| # @global bool $g_db_connected |
| $g_db_connected = false; |
| $g_db_connected = false; |
| |
| |
| # Store whether to log queries ( used for show_queries_count/query list) |
| # Store whether to log queries ( used for show_queries_count/query list) |
| # @global bool $g_db_log_queries |
| # @global bool $g_db_log_queries |
| $g_db_log_queries = ( 0 != ( config_get_global( 'log_level' ) & LOG_DATABASE ) ); |
| $g_db_log_queries = ( 0 != ( config_get_global( 'log_level' ) & LOG_DATABASE ) ); |
| |
| |
| # set adodb to associative fetch mode with lowercase column names |
| # set adodb to associative fetch mode with lowercase column names |
| # @global bool $ADODB_FETCH_MODE |
| # @global bool $ADODB_FETCH_MODE |
| global $ADODB_FETCH_MODE; |
| global $ADODB_FETCH_MODE; |
| $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; |
| $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; |
| define( 'ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_LOWER ); |
| define( 'ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_LOWER ); |
| |
| |
| # Stores the functional database type based on db driver |
| # Stores the functional database type based on db driver |
| $g_db_functional_type = db_get_type( config_get_global( 'db_type' ) ); |
| $g_db_functional_type = db_get_type( config_get_global( 'db_type' ) ); |
| |
| |
| /** |
| /** |
| * Mantis Database Parameters Count class |
| * Mantis Database Parameters Count class |
| * Stores the current parameter count, provides method to generate parameters |
| * Stores the current parameter count, provides method to generate parameters |
| * and a simple stack mechanism to enable the caller to build multiple queries |
| * and a simple stack mechanism to enable the caller to build multiple queries |
| * concurrently on RDBMS using positional parameters (e.g. PostgreSQL) |
| * concurrently on RDBMS using positional parameters (e.g. PostgreSQL) |
| */ |
| */ |
| class MantisDbParam { |
| class MantisDbParam { |
| /** |
| /** |
| * Current parameter count |
| * Current parameter count |
| */ |
| */ |
| public $count = 0; |
| public $count = 0; |
| |
| |
| /** |
| /** |
| * Parameter count stack |
| * Parameter count stack |
| */ |
| */ |
| private $stack = array(); |
| private $stack = array(); |
| |
| |
| /** |
| /** |
| * Generate a string to insert a parameter into a database query string |
| * Generate a string to insert a parameter into a database query string |
| * @return string 'wildcard' matching a parameter in correct ordered format for the current database. |
| * @return string 'wildcard' matching a parameter in correct ordered format for the current database. |
| */ |
| */ |
| public function assign() { |
| public function assign() { |
| global $g_db; |
| global $g_db; |
| return $g_db->Param( $this->count++ ); |
| return $g_db->Param( $this->count++ ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Pushes current parameter count onto stack and resets its value to 0 |
| * Pushes current parameter count onto stack and resets its value to 0 |
| * @return void |
| * @return void |
| */ |
| */ |
| public function push() { |
| public function push() { |
| $this->stack[] = $this->count; |
| $this->stack[] = $this->count; |
| $this->count = 0; |
| $this->count = 0; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Pops the previous value of param count from the stack |
| * Pops the previous value of param count from the stack |
| * This function is called by {@see db_query()} and should not need |
| * This function is called by {@see db_query()} and should not need |
| * to be executed directly |
| * to be executed directly |
| * @return void |
| * @return void |
| */ |
| */ |
| public function pop() { |
| public function pop() { |
| global $g_db; |
| global $g_db; |
| |
| |
| $this->count = (int)array_pop( $this->stack ); |
| $this->count = (int)array_pop( $this->stack ); |
| if( db_is_pgsql() ) { |
| if( db_is_pgsql() ) { |
| # Manually reset the ADOdb param number to the value we just popped |
| # Manually reset the ADOdb param number to the value we just popped |
| $g_db->_pnum = $this->count; |
| $g_db->_pnum = $this->count; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| # Tracks the query parameter count |
| # Tracks the query parameter count |
| # @global object $g_db_param |
| # @global object $g_db_param |
| $g_db_param = new MantisDbParam(); |
| $g_db_param = new MantisDbParam(); |
| |
| |
| /** |
| /** |
| * Open a connection to the database. |
| * Open a connection to the database. |
| * @param string $p_dsn Database connection string ( specified instead of other params). |
| * @param string $p_dsn Database connection string ( specified instead of other params). |
| * @param string $p_hostname Database server hostname. |
| * @param string $p_hostname Database server hostname. |
| * @param string $p_username Database server username. |
| * @param string $p_username Database server username. |
| * @param string $p_password Database server password. |
| * @param string $p_password Database server password. |
| * @param string $p_database_name Database name. |
| * @param string $p_database_name Database name. |
| * @param boolean $p_pconnect Use a Persistent connection to database. |
| * @param boolean $p_pconnect Use a Persistent connection to database. |
| * @return boolean indicating if the connection was successful |
| * @return boolean indicating if the connection was successful |
| */ |
| */ |
| function db_connect( $p_dsn, $p_hostname = null, $p_username = null, $p_password = null, $p_database_name = null, $p_pconnect = false ) { |
| function db_connect( $p_dsn, $p_hostname = null, $p_username = null, $p_password = null, $p_database_name = null, $p_pconnect = false ) { |
| global $g_db_connected, $g_db, $g_db_functional_type; |
| global $g_db_connected, $g_db, $g_db_functional_type; |
| $t_db_type = config_get_global( 'db_type' ); |
| $t_db_type = config_get_global( 'db_type' ); |
| $g_db_functional_type = db_get_type( $t_db_type ); |
| $g_db_functional_type = db_get_type( $t_db_type ); |
| |
| |
| if( $g_db_functional_type == DB_TYPE_UNDEFINED ) { |
| if( $g_db_functional_type == DB_TYPE_UNDEFINED ) { |
| error_parameters( 0, 'Database type is not supported by MantisBT, check $g_db_type in config_inc.php' ); |
| error_parameters( 0, 'Database type is not supported by MantisBT, check $g_db_type in config_inc.php' ); |
| trigger_error( ERROR_DB_CONNECT_FAILED, ERROR ); |
| trigger_error( ERROR_DB_CONNECT_FAILED, ERROR ); |
| } |
| } |
| |
| |
| if( !db_check_database_support( $t_db_type ) ) { |
| if( !db_check_database_support( $t_db_type ) ) { |
| error_parameters( 0, 'PHP Support for database is not enabled' ); |
| error_parameters( 0, 'PHP Support for database is not enabled' ); |
| trigger_error( ERROR_DB_CONNECT_FAILED, ERROR ); |
| trigger_error( ERROR_DB_CONNECT_FAILED, ERROR ); |
| } |
| } |
| |
| |
| if( empty( $p_dsn ) ) { |
| if( empty( $p_dsn ) ) { |
| $g_db = ADONewConnection( $t_db_type ); |
| $g_db = ADONewConnection( $t_db_type ); |
| |
| |
| |
| if(db_is_mssql())
|
| |
| { |
| |
| $g_db->setConnectionParameter('characterSet','UTF-8');
|
| |
| } |
| |
| |
| if( $p_pconnect ) { |
| if( $p_pconnect ) { |
| $t_result = $g_db->PConnect( $p_hostname, $p_username, $p_password, $p_database_name ); |
| $t_result = $g_db->PConnect( $p_hostname, $p_username, $p_password, $p_database_name ); |
| } else { |
| } else { |
| $t_result = $g_db->Connect( $p_hostname, $p_username, $p_password, $p_database_name ); |
| $t_result = $g_db->Connect( $p_hostname, $p_username, $p_password, $p_database_name ); |
| } |
| } |
| } else { |
| } else { |
| $g_db = ADONewConnection( $p_dsn ); |
| $g_db = ADONewConnection( $p_dsn ); |
| $t_result = $g_db->IsConnected(); |
| $t_result = $g_db->IsConnected(); |
| } |
| } |
| |
| |
| if( $t_result ) { |
| if( $t_result ) { |
| # For MySQL, the charset for the connection needs to be specified. |
| # For MySQL, the charset for the connection needs to be specified. |
| if( db_is_mysql() ) { |
| if( db_is_mysql() ) { |
| # @todo Is there a way to translate any charset name to MySQL format? e.g. remote the dashes? |
| # @todo Is there a way to translate any charset name to MySQL format? e.g. remote the dashes? |
| # @todo Is this needed for other databases? |
| # @todo Is this needed for other databases? |
| db_query( 'SET NAMES UTF8' ); |
| db_query( 'SET NAMES UTF8' ); |
| } |
| } |
| } else { |
| } else { |
| db_error(); |
| db_error(); |
| trigger_error( ERROR_DB_CONNECT_FAILED, ERROR ); |
| trigger_error( ERROR_DB_CONNECT_FAILED, ERROR ); |
| return false; |
| return false; |
| } |
| } |
| |
| |
| $g_db_connected = true; |
| $g_db_connected = true; |
| |
| |
| return true; |
| return true; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Returns whether a connection to the database exists |
| * Returns whether a connection to the database exists |
| * @global stores database connection state |
| * @global stores database connection state |
| * @return boolean indicating if the a database connection has been made |
| * @return boolean indicating if the a database connection has been made |
| */ |
| */ |
| function db_is_connected() { |
| function db_is_connected() { |
| global $g_db_connected; |
| global $g_db_connected; |
| |
| |
| return $g_db_connected; |
| return $g_db_connected; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Returns whether php support for a database is enabled |
| * Returns whether php support for a database is enabled |
| * @param string $p_db_type Database type. |
| * @param string $p_db_type Database type. |
| * @return boolean indicating if php current supports the given database type |
| * @return boolean indicating if php current supports the given database type |
| */ |
| */ |
| function db_check_database_support( $p_db_type ) { |
| function db_check_database_support( $p_db_type ) { |
| switch( $p_db_type ) { |
| switch( $p_db_type ) { |
| case 'mysqli': |
| case 'mysqli': |
| $t_support = function_exists( 'mysqli_connect' ); |
| $t_support = function_exists( 'mysqli_connect' ); |
| break; |
| break; |
| case 'pgsql': |
| case 'pgsql': |
| $t_support = function_exists( 'pg_connect' ); |
| $t_support = function_exists( 'pg_connect' ); |
| break; |
| break; |
| case 'mssqlnative': |
| case 'mssqlnative': |
| $t_support = function_exists( 'sqlsrv_connect' ); |
| $t_support = function_exists( 'sqlsrv_connect' ); |
| break; |
| break; |
| case 'oci8': |
| case 'oci8': |
| $t_support = function_exists( 'OCILogon' ); |
| $t_support = function_exists( 'OCILogon' ); |
| break; |
| break; |
| case 'odbc_mssql': |
| case 'odbc_mssql': |
| $t_support = function_exists( 'odbc_connect' ); |
| $t_support = function_exists( 'odbc_connect' ); |
| break; |
| break; |
| default: |
| default: |
| $t_support = false; |
| $t_support = false; |
| } |
| } |
| return $t_support; |
| return $t_support; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Maps a db driver type to the functional databse type |
| * Maps a db driver type to the functional databse type |
| * @param string $p_driver_type Database driver name |
| * @param string $p_driver_type Database driver name |
| * @return int Database type |
| * @return int Database type |
| */ |
| */ |
| function db_get_type( $p_driver_type ) { |
| function db_get_type( $p_driver_type ) { |
| switch( $p_driver_type ) { |
| switch( $p_driver_type ) { |
| case 'mysqli': |
| case 'mysqli': |
| return DB_TYPE_MYSQL; |
| return DB_TYPE_MYSQL; |
| case 'pgsql': |
| case 'pgsql': |
| return DB_TYPE_PGSQL; |
| return DB_TYPE_PGSQL; |
| case 'mssqlnative': |
| case 'mssqlnative': |
| case 'odbc_mssql': |
| case 'odbc_mssql': |
| return DB_TYPE_MSSQL; |
| return DB_TYPE_MSSQL; |
| case 'oci8': |
| case 'oci8': |
| return DB_TYPE_ORACLE; |
| return DB_TYPE_ORACLE; |
| default: |
| default: |
| return DB_TYPE_UNDEFINED; |
| return DB_TYPE_UNDEFINED; |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * Checks if the database driver is MySQL |
| * Checks if the database driver is MySQL |
| * @return boolean true if mysql |
| * @return boolean true if mysql |
| */ |
| */ |
| function db_is_mysql() { |
| function db_is_mysql() { |
| global $g_db_functional_type; |
| global $g_db_functional_type; |
| return( DB_TYPE_MYSQL == $g_db_functional_type ); |
| return( DB_TYPE_MYSQL == $g_db_functional_type ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Checks if the database driver is PostgreSQL |
| * Checks if the database driver is PostgreSQL |
| * @return boolean true if postgres |
| * @return boolean true if postgres |
| */ |
| */ |
| function db_is_pgsql() { |
| function db_is_pgsql() { |
| global $g_db_functional_type; |
| global $g_db_functional_type; |
| return( DB_TYPE_PGSQL == $g_db_functional_type ); |
| return( DB_TYPE_PGSQL == $g_db_functional_type ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Checks if the database driver is MS SQL |
| * Checks if the database driver is MS SQL |
| * @return boolean true if mssql |
| * @return boolean true if mssql |
| */ |
| */ |
| function db_is_mssql() { |
| function db_is_mssql() { |
| global $g_db_functional_type; |
| global $g_db_functional_type; |
| return( DB_TYPE_MSSQL == $g_db_functional_type ); |
| return( DB_TYPE_MSSQL == $g_db_functional_type ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Checks if the database driver is Oracle (oci8) |
| * Checks if the database driver is Oracle (oci8) |
| * @return boolean true if oracle |
| * @return boolean true if oracle |
| */ |
| */ |
| function db_is_oracle() { |
| function db_is_oracle() { |
| global $g_db_functional_type; |
| global $g_db_functional_type; |
| return( DB_TYPE_ORACLE == $g_db_functional_type ); |
| return( DB_TYPE_ORACLE == $g_db_functional_type ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Validates that the given identifier's length is OK for the database platform |
| * Validates that the given identifier's length is OK for the database platform |
| * Triggers an error if the identifier is too long |
| * Triggers an error if the identifier is too long |
| * @param string $p_identifier Identifier to check. |
| * @param string $p_identifier Identifier to check. |
| * @return void |
| * @return void |
| */ |
| */ |
| function db_check_identifier_size( $p_identifier ) { |
| function db_check_identifier_size( $p_identifier ) { |
| # Oracle does not support long object names (30 chars max) |
| # Oracle does not support long object names (30 chars max) |
| if( db_is_oracle() && 30 < strlen( $p_identifier ) ) { |
| if( db_is_oracle() && 30 < strlen( $p_identifier ) ) { |
| error_parameters( $p_identifier ); |
| error_parameters( $p_identifier ); |
| trigger_error( ERROR_DB_IDENTIFIER_TOO_LONG, ERROR ); |
| trigger_error( ERROR_DB_IDENTIFIER_TOO_LONG, ERROR ); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * function alias for db_query() for legacy support of plugins |
| * function alias for db_query() for legacy support of plugins |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 2.0 |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 2.0 |
| */ |
| */ |
| function db_query_bound() { |
| function db_query_bound() { |
| error_parameters( __FUNCTION__ . '()', 'db_query()' ); |
| error_parameters( __FUNCTION__ . '()', 'db_query()' ); |
| trigger_error( ERROR_DEPRECATED_SUPERSEDED, DEPRECATED ); |
| trigger_error( ERROR_DEPRECATED_SUPERSEDED, DEPRECATED ); |
| |
| |
| return call_user_func_array( 'db_query', func_get_args() ); |
| return call_user_func_array( 'db_query', func_get_args() ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * execute query, requires connection to be opened |
| * execute query, requires connection to be opened |
| * An error will be triggered if there is a problem executing the query. |
| * An error will be triggered if there is a problem executing the query. |
| * This will pop the database parameter stack {@see MantisDbParam} after a |
| * This will pop the database parameter stack {@see MantisDbParam} after a |
| * successful execution, unless specified otherwise |
| * successful execution, unless specified otherwise |
| * |
| * |
| * @global array of previous executed queries for profiling |
| * @global array of previous executed queries for profiling |
| * @global adodb database connection object |
| * @global adodb database connection object |
| * @global boolean indicating whether queries array is populated |
| * @global boolean indicating whether queries array is populated |
| * @param string $p_query Parameterlised Query string to execute. |
| * @param string $p_query Parameterlised Query string to execute. |
| * @param array $p_arr_parms Array of parameters matching $p_query. |
| * @param array $p_arr_parms Array of parameters matching $p_query. |
| * @param integer $p_limit Number of results to return. |
| * @param integer $p_limit Number of results to return. |
| * @param integer $p_offset Offset query results for paging. |
| * @param integer $p_offset Offset query results for paging. |
| * @param boolean $p_pop_param Set to false to leave the parameters on the stack |
| * @param boolean $p_pop_param Set to false to leave the parameters on the stack |
| * @return IteratorAggregate|boolean adodb result set or false if the query failed. |
| * @return IteratorAggregate|boolean adodb result set or false if the query failed. |
| */ |
| */ |
| function db_query( $p_query, array $p_arr_parms = null, $p_limit = -1, $p_offset = -1, $p_pop_param = true ) { |
| function db_query( $p_query, array $p_arr_parms = null, $p_limit = -1, $p_offset = -1, $p_pop_param = true ) { |
| global $g_queries_array, $g_db, $g_db_log_queries, $g_db_param; |
| global $g_queries_array, $g_db, $g_db_log_queries, $g_db_param; |
| |
| |
| $t_db_type = config_get_global( 'db_type' ); |
| $t_db_type = config_get_global( 'db_type' ); |
| |
| |
| static $s_check_params; |
| static $s_check_params; |
| if( $s_check_params === null ) { |
| if( $s_check_params === null ) { |
| $s_check_params = ( db_is_pgsql() || $t_db_type == 'odbc_mssql' || $t_db_type == 'mssqlnative' ); |
| $s_check_params = ( db_is_pgsql() || $t_db_type == 'odbc_mssql' || $t_db_type == 'mssqlnative' ); |
| } |
| } |
| |
| |
| $t_start = microtime( true ); |
| $t_start = microtime( true ); |
| |
| |
| # This ensures that we don't get an error from ADOdb if $p_arr_parms == null, |
| # This ensures that we don't get an error from ADOdb if $p_arr_parms == null, |
| # as Execute() expects either an array or false if there are no parameters - |
| # as Execute() expects either an array or false if there are no parameters - |
| # null actually gets treated as array( 0 => null ) |
| # null actually gets treated as array( 0 => null ) |
| if( is_null( $p_arr_parms ) ) { |
| if( is_null( $p_arr_parms ) ) { |
| $p_arr_parms = array(); |
| $p_arr_parms = array(); |
| } |
| } |
| |
| |
| if( !empty( $p_arr_parms ) && $s_check_params ) { |
| if( !empty( $p_arr_parms ) && $s_check_params ) { |
| $t_params = count( $p_arr_parms ); |
| $t_params = count( $p_arr_parms ); |
| for( $i = 0;$i < $t_params;$i++ ) { |
| for( $i = 0;$i < $t_params;$i++ ) { |
| if( $p_arr_parms[$i] === false ) { |
| if( $p_arr_parms[$i] === false ) { |
| $p_arr_parms[$i] = 0; |
| $p_arr_parms[$i] = 0; |
| } elseif( $p_arr_parms[$i] === true && $t_db_type == 'mssqlnative' ) { |
| } elseif( $p_arr_parms[$i] === true && $t_db_type == 'mssqlnative' ) { |
| $p_arr_parms[$i] = 1; |
| $p_arr_parms[$i] = 1; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| static $s_prefix; |
| static $s_prefix; |
| static $s_suffix; |
| static $s_suffix; |
| if( $s_prefix === null ) { |
| if( $s_prefix === null ) { |
| # Determine table prefix and suffixes including trailing and leading '_' |
| # Determine table prefix and suffixes including trailing and leading '_' |
| $s_prefix = trim( config_get_global( 'db_table_prefix' ) ); |
| $s_prefix = trim( config_get_global( 'db_table_prefix' ) ); |
| $s_suffix = trim( config_get_global( 'db_table_suffix' ) ); |
| $s_suffix = trim( config_get_global( 'db_table_suffix' ) ); |
| |
| |
| if( !empty( $s_prefix ) && '_' != substr( $s_prefix, -1 ) ) { |
| if( !empty( $s_prefix ) && '_' != substr( $s_prefix, -1 ) ) { |
| $s_prefix .= '_'; |
| $s_prefix .= '_'; |
| } |
| } |
| if( !empty( $s_suffix ) && '_' != substr( $s_suffix, 0, 1 ) ) { |
| if( !empty( $s_suffix ) && '_' != substr( $s_suffix, 0, 1 ) ) { |
| $s_suffix = '_' . $s_suffix; |
| $s_suffix = '_' . $s_suffix; |
| } |
| } |
| } |
| } |
| |
| |
| $p_query = strtr($p_query, array( |
| $p_query = strtr($p_query, array( |
| '{' => $s_prefix, |
| '{' => $s_prefix, |
| '}' => $s_suffix, |
| '}' => $s_suffix, |
| ) ); |
| ) ); |
| |
| |
| # Pushing params to safeguard the ADOdb parameter count (required for pgsql) |
| # Pushing params to safeguard the ADOdb parameter count (required for pgsql) |
| $g_db_param->push(); |
| $g_db_param->push(); |
| |
| |
| if( db_is_oracle() ) { |
| if( db_is_oracle() ) { |
| $p_query = db_oracle_adapt_query_syntax( $p_query, $p_arr_parms ); |
| $p_query = db_oracle_adapt_query_syntax( $p_query, $p_arr_parms ); |
| } |
| } |
| |
| |
| if( ( $p_limit != -1 ) || ( $p_offset != -1 ) ) { |
| if( ( $p_limit != -1 ) || ( $p_offset != -1 ) ) { |
| $t_result = $g_db->SelectLimit( $p_query, $p_limit, $p_offset, $p_arr_parms ); |
| $t_result = $g_db->SelectLimit( $p_query, $p_limit, $p_offset, $p_arr_parms ); |
| } else { |
| } else { |
| $t_result = $g_db->Execute( $p_query, $p_arr_parms ); |
| $t_result = $g_db->Execute( $p_query, $p_arr_parms ); |
| } |
| } |
| |
| |
| # Restore ADOdb parameter count |
| # Restore ADOdb parameter count |
| $g_db_param->pop(); |
| $g_db_param->pop(); |
| |
| |
| $t_elapsed = number_format( microtime( true ) - $t_start, 4 ); |
| $t_elapsed = number_format( microtime( true ) - $t_start, 4 ); |
| |
| |
| if( ON == $g_db_log_queries ) { |
| if( ON == $g_db_log_queries ) { |
| $t_query_text = db_format_query_log_msg( $p_query, $p_arr_parms ); |
| $t_query_text = db_format_query_log_msg( $p_query, $p_arr_parms ); |
| log_event( LOG_DATABASE, array( $t_query_text, $t_elapsed ) ); |
| log_event( LOG_DATABASE, array( $t_query_text, $t_elapsed ) ); |
| } else { |
| } else { |
| # If not logging the queries the actual text is not needed |
| # If not logging the queries the actual text is not needed |
| $t_query_text = ''; |
| $t_query_text = ''; |
| } |
| } |
| array_push( $g_queries_array, array( $t_query_text, $t_elapsed ) ); |
| array_push( $g_queries_array, array( $t_query_text, $t_elapsed ) ); |
| |
| |
| # Restore param stack: only pop if asked to AND the query has params |
| # Restore param stack: only pop if asked to AND the query has params |
| if( $p_pop_param && !empty( $p_arr_parms ) ) { |
| if( $p_pop_param && !empty( $p_arr_parms ) ) { |
| $g_db_param->pop(); |
| $g_db_param->pop(); |
| } |
| } |
| |
| |
| if( !$t_result ) { |
| if( !$t_result ) { |
| db_error( $p_query ); |
| db_error( $p_query ); |
| trigger_error( ERROR_DB_QUERY_FAILED, ERROR ); |
| trigger_error( ERROR_DB_QUERY_FAILED, ERROR ); |
| return false; |
| return false; |
| } else { |
| } else { |
| return $t_result; |
| return $t_result; |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * Generate a string to insert a parameter into a database query string |
| * Generate a string to insert a parameter into a database query string |
| * @return string 'wildcard' matching a parameter in correct ordered format for the current database. |
| * @return string 'wildcard' matching a parameter in correct ordered format for the current database. |
| */ |
| */ |
| function db_param() { |
| function db_param() { |
| global $g_db_param; |
| global $g_db_param; |
| return $g_db_param->assign(); |
| return $g_db_param->assign(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Pushes current parameter count onto stack and resets its value |
| * Pushes current parameter count onto stack and resets its value |
| * Allows the caller to build multiple queries concurrently on RDBMS using |
| * Allows the caller to build multiple queries concurrently on RDBMS using |
| * positional parameters (e.g. PostgreSQL) |
| * positional parameters (e.g. PostgreSQL) |
| * @return void |
| * @return void |
| */ |
| */ |
| function db_param_push() { |
| function db_param_push() { |
| global $g_db_param; |
| global $g_db_param; |
| $g_db_param->push(); |
| $g_db_param->push(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Pops the previous parameter count from the stack |
| * Pops the previous parameter count from the stack |
| * It is generally not necessary to call this, because the param count is popped |
| * It is generally not necessary to call this, because the param count is popped |
| * automatically whenever a query is executed via db_query(). There are some |
| * automatically whenever a query is executed via db_query(). There are some |
| * corner cases when doing it manually makes sense, e.g. when a query is built |
| * corner cases when doing it manually makes sense, e.g. when a query is built |
| * but not executed. |
| * but not executed. |
| * @return void |
| * @return void |
| */ |
| */ |
| function db_param_pop() { |
| function db_param_pop() { |
| global $g_db_param; |
| global $g_db_param; |
| $g_db_param->pop(); |
| $g_db_param->pop(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Retrieve number of rows returned for a specific database query |
| * Retrieve number of rows returned for a specific database query |
| * @param IteratorAggregate $p_result Database Query Record Set to retrieve record count for. |
| * @param IteratorAggregate $p_result Database Query Record Set to retrieve record count for. |
| * @return integer Record Count |
| * @return integer Record Count |
| */ |
| */ |
| function db_num_rows( IteratorAggregate $p_result ) { |
| function db_num_rows( IteratorAggregate $p_result ) { |
| return $p_result->RecordCount(); |
| return $p_result->RecordCount(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Retrieve number of rows affected by a specific database query |
| * Retrieve number of rows affected by a specific database query |
| * @return integer Affected Rows |
| * @return integer Affected Rows |
| */ |
| */ |
| function db_affected_rows() { |
| function db_affected_rows() { |
| global $g_db; |
| global $g_db; |
| |
| |
| return $g_db->Affected_Rows(); |
| return $g_db->Affected_Rows(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Retrieve the next row returned from a specific database query |
| * Retrieve the next row returned from a specific database query |
| * @param IteratorAggregate &$p_result Database Query Record Set to retrieve next result for. |
| * @param IteratorAggregate &$p_result Database Query Record Set to retrieve next result for. |
| * @return array Database result |
| * @return array Database result |
| */ |
| */ |
| function db_fetch_array( IteratorAggregate &$p_result ) { |
| function db_fetch_array( IteratorAggregate &$p_result ) { |
| global $g_db_functional_type; |
| global $g_db_functional_type; |
| |
| |
| if( $p_result->EOF ) { |
| if( $p_result->EOF ) { |
| return false; |
| return false; |
| } |
| } |
| |
| |
| # Retrieve the fields from the recordset |
| # Retrieve the fields from the recordset |
| $t_row = $p_result->fields; |
| $t_row = $p_result->fields; |
| |
| |
| # Additional handling for specific RDBMS |
| # Additional handling for specific RDBMS |
| switch( $g_db_functional_type ) { |
| switch( $g_db_functional_type ) { |
| |
| |
| case DB_TYPE_PGSQL: |
| case DB_TYPE_PGSQL: |
| # pgsql's boolean fields are stored as 't' or 'f' and must be converted |
| # pgsql's boolean fields are stored as 't' or 'f' and must be converted |
| static $s_current_result = null, $s_convert_needed; |
| static $s_current_result = null, $s_convert_needed; |
| |
| |
| if( $s_current_result != $p_result ) { |
| if( $s_current_result != $p_result ) { |
| # Processing a new query |
| # Processing a new query |
| $s_current_result = $p_result; |
| $s_current_result = $p_result; |
| $s_convert_needed = false; |
| $s_convert_needed = false; |
| } elseif( !$s_convert_needed ) { |
| } elseif( !$s_convert_needed ) { |
| # No conversion needed, return the row as-is |
| # No conversion needed, return the row as-is |
| $p_result->MoveNext(); |
| $p_result->MoveNext(); |
| return $t_row; |
| return $t_row; |
| } |
| } |
| |
| |
| foreach( $p_result->FieldTypesArray() as $t_field ) { |
| foreach( $p_result->FieldTypesArray() as $t_field ) { |
| switch( $t_field->type ) { |
| switch( $t_field->type ) { |
| case 'bool': |
| case 'bool': |
| switch( $t_row[$t_field->name] ) { |
| switch( $t_row[$t_field->name] ) { |
| case 'f': |
| case 'f': |
| $t_row[$t_field->name] = false; |
| $t_row[$t_field->name] = false; |
| break; |
| break; |
| case 't': |
| case 't': |
| $t_row[$t_field->name] = true; |
| $t_row[$t_field->name] = true; |
| break; |
| break; |
| } |
| } |
| $s_convert_needed = true; |
| $s_convert_needed = true; |
| break; |
| break; |
| } |
| } |
| } |
| } |
| break; |
| break; |
| |
| |
| case DB_TYPE_ORACLE: |
| case DB_TYPE_ORACLE: |
| # oci8 returns null values for empty strings, convert them back |
| # oci8 returns null values for empty strings, convert them back |
| foreach( $t_row as &$t_value ) { |
| foreach( $t_row as &$t_value ) { |
| if( !isset( $t_value ) ) { |
| if( !isset( $t_value ) ) { |
| $t_value = ''; |
| $t_value = ''; |
| } |
| } |
| } |
| } |
| break; |
| break; |
| } |
| } |
| |
| |
| $p_result->MoveNext(); |
| $p_result->MoveNext(); |
| return $t_row; |
| return $t_row; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Retrieve a specific field from a database query result |
| * Retrieve a specific field from a database query result |
| * @param boolean|IteratorAggregate $p_result Database Query Record Set to retrieve the field from. |
| * @param boolean|IteratorAggregate $p_result Database Query Record Set to retrieve the field from. |
| * @param integer $p_row_index Row to retrieve, zero-based (optional). |
| * @param integer $p_row_index Row to retrieve, zero-based (optional). |
| * @param integer $p_col_index Column to retrieve, zero-based (optional). |
| * @param integer $p_col_index Column to retrieve, zero-based (optional). |
| * @return mixed Database result |
| * @return mixed Database result |
| */ |
| */ |
| function db_result( $p_result, $p_row_index = 0, $p_col_index = 0 ) { |
| function db_result( $p_result, $p_row_index = 0, $p_col_index = 0 ) { |
| if( $p_result && ( db_num_rows( $p_result ) > 0 ) ) { |
| if( $p_result && ( db_num_rows( $p_result ) > 0 ) ) { |
| $p_result->Move( $p_row_index ); |
| $p_result->Move( $p_row_index ); |
| $t_row = db_fetch_array( $p_result ); |
| $t_row = db_fetch_array( $p_result ); |
| |
| |
| # Make the array numerically indexed. This is required to retrieve the |
| # Make the array numerically indexed. This is required to retrieve the |
| # column ($p_index2), since we use ADODB_FETCH_ASSOC fetch mode. |
| # column ($p_index2), since we use ADODB_FETCH_ASSOC fetch mode. |
| $t_result = array_values( $t_row ); |
| $t_result = array_values( $t_row ); |
| |
| |
| return $t_result[$p_col_index]; |
| return $t_result[$p_col_index]; |
| } |
| } |
| |
| |
| return false; |
| return false; |
| } |
| } |
| |
| |
| /** |
| /** |
| * return the last inserted id for a specific database table |
| * return the last inserted id for a specific database table |
| * @param string $p_table A valid database table name. |
| * @param string $p_table A valid database table name. |
| * @param string $p_field A valid field name (default 'id'). |
| * @param string $p_field A valid field name (default 'id'). |
| * @return integer last successful insert id |
| * @return integer last successful insert id |
| */ |
| */ |
| function db_insert_id( $p_table = null, $p_field = 'id' ) { |
| function db_insert_id( $p_table = null, $p_field = 'id' ) { |
| global $g_db, $g_db_functional_type; |
| global $g_db, $g_db_functional_type; |
| |
| |
| if( isset( $p_table ) ) { |
| if( isset( $p_table ) ) { |
| switch( $g_db_functional_type ) { |
| switch( $g_db_functional_type ) { |
| case DB_TYPE_ORACLE: |
| case DB_TYPE_ORACLE: |
| $t_query = 'SELECT seq_' . $p_table . '.CURRVAL FROM DUAL'; |
| $t_query = 'SELECT seq_' . $p_table . '.CURRVAL FROM DUAL'; |
| break; |
| break; |
| case DB_TYPE_PGSQL: |
| case DB_TYPE_PGSQL: |
| $t_query = 'SELECT currval(\'' . $p_table . '_' . $p_field . '_seq\')'; |
| $t_query = 'SELECT currval(\'' . $p_table . '_' . $p_field . '_seq\')'; |
| break; |
| break; |
| case DB_TYPE_MSSQL: |
| case DB_TYPE_MSSQL: |
| $t_query = 'SELECT IDENT_CURRENT(\'' . $p_table . '\')'; |
| $t_query = 'SELECT IDENT_CURRENT(\'' . $p_table . '\')'; |
| break; |
| break; |
| } |
| } |
| if( isset( $t_query ) ) { |
| if( isset( $t_query ) ) { |
| $t_result = db_query( $t_query ); |
| $t_result = db_query( $t_query ); |
| return (int)db_result( $t_result ); |
| return (int)db_result( $t_result ); |
| } |
| } |
| } |
| } |
| return $g_db->Insert_ID(); |
| return $g_db->Insert_ID(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Check if the specified table exists. |
| * Check if the specified table exists. |
| * @param string $p_table_name A valid database table name. |
| * @param string $p_table_name A valid database table name. |
| * @return boolean indicating whether the table exists |
| * @return boolean indicating whether the table exists |
| */ |
| */ |
| function db_table_exists( $p_table_name ) { |
| function db_table_exists( $p_table_name ) { |
| if( is_blank( $p_table_name ) ) { |
| if( is_blank( $p_table_name ) ) { |
| return false; |
| return false; |
| } |
| } |
| |
| |
| $t_tables = db_get_table_list(); |
| $t_tables = db_get_table_list(); |
| if( !is_array( $t_tables ) ) { |
| if( !is_array( $t_tables ) ) { |
| return false; |
| return false; |
| } |
| } |
| |
| |
| # Can't use in_array() since it is case sensitive |
| # Can't use in_array() since it is case sensitive |
| $t_table_name = utf8_strtolower( $p_table_name ); |
| $t_table_name = utf8_strtolower( $p_table_name ); |
| foreach( $t_tables as $t_current_table ) { |
| foreach( $t_tables as $t_current_table ) { |
| if( utf8_strtolower( $t_current_table ) == $t_table_name ) { |
| if( utf8_strtolower( $t_current_table ) == $t_table_name ) { |
| return true; |
| return true; |
| } |
| } |
| } |
| } |
| |
| |
| return false; |
| return false; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Check if the specified table index exists. |
| * Check if the specified table index exists. |
| * @param string $p_table_name A valid database table name. |
| * @param string $p_table_name A valid database table name. |
| * @param string $p_index_name A valid database index name. |
| * @param string $p_index_name A valid database index name. |
| * @return boolean indicating whether the index exists |
| * @return boolean indicating whether the index exists |
| */ |
| */ |
| function db_index_exists( $p_table_name, $p_index_name ) { |
| function db_index_exists( $p_table_name, $p_index_name ) { |
| global $g_db; |
| global $g_db; |
| |
| |
| if( is_blank( $p_index_name ) || is_blank( $p_table_name ) ) { |
| if( is_blank( $p_index_name ) || is_blank( $p_table_name ) ) { |
| return false; |
| return false; |
| } |
| } |
| |
| |
| $t_indexes = $g_db->MetaIndexes( $p_table_name ); |
| $t_indexes = $g_db->MetaIndexes( $p_table_name ); |
| if( $t_indexes === false ) { |
| if( $t_indexes === false ) { |
| # no index found |
| # no index found |
| return false; |
| return false; |
| } |
| } |
| |
| |
| if( !empty( $t_indexes ) ) { |
| if( !empty( $t_indexes ) ) { |
| # Can't use in_array() since it is case sensitive |
| # Can't use in_array() since it is case sensitive |
| $t_index_name = utf8_strtolower( $p_index_name ); |
| $t_index_name = utf8_strtolower( $p_index_name ); |
| foreach( $t_indexes as $t_current_index_name => $t_current_index_obj ) { |
| foreach( $t_indexes as $t_current_index_name => $t_current_index_obj ) { |
| if( utf8_strtolower( $t_current_index_name ) == $t_index_name ) { |
| if( utf8_strtolower( $t_current_index_name ) == $t_index_name ) { |
| return true; |
| return true; |
| } |
| } |
| } |
| } |
| } |
| } |
| return false; |
| return false; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Check if the specified field exists in a given table |
| * Check if the specified field exists in a given table |
| * @param string $p_field_name A database field name. |
| * @param string $p_field_name A database field name. |
| * @param string $p_table_name A valid database table name. |
| * @param string $p_table_name A valid database table name. |
| * @return boolean indicating whether the field exists |
| * @return boolean indicating whether the field exists |
| */ |
| */ |
| function db_field_exists( $p_field_name, $p_table_name ) { |
| function db_field_exists( $p_field_name, $p_table_name ) { |
| $t_columns = db_field_names( $p_table_name ); |
| $t_columns = db_field_names( $p_table_name ); |
| |
| |
| # ADOdb oci8 driver works with uppercase column names, and as of 5.19 does |
| # ADOdb oci8 driver works with uppercase column names, and as of 5.19 does |
| # not provide a way to force them to lowercase |
| # not provide a way to force them to lowercase |
| if( db_is_oracle() ) { |
| if( db_is_oracle() ) { |
| $p_field_name = strtoupper( $p_field_name ); |
| $p_field_name = strtoupper( $p_field_name ); |
| } |
| } |
| |
| |
| return in_array( $p_field_name, $t_columns ); |
| return in_array( $p_field_name, $t_columns ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Retrieve list of fields for a given table |
| * Retrieve list of fields for a given table |
| * @param string $p_table_name A valid database table name. |
| * @param string $p_table_name A valid database table name. |
| * @return array array of fields on table |
| * @return array array of fields on table |
| */ |
| */ |
| function db_field_names( $p_table_name ) { |
| function db_field_names( $p_table_name ) { |
| global $g_db; |
| global $g_db; |
| $t_columns = $g_db->MetaColumnNames( $p_table_name ); |
| $t_columns = $g_db->MetaColumnNames( $p_table_name ); |
| return is_array( $t_columns ) ? $t_columns : array(); |
| return is_array( $t_columns ) ? $t_columns : array(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Returns the last error number. The error number is reset after every call to Execute(). If 0 is returned, no error occurred. |
| * Returns the last error number. The error number is reset after every call to Execute(). If 0 is returned, no error occurred. |
| * @return int last error number |
| * @return int last error number |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| */ |
| */ |
| function db_error_num() { |
| function db_error_num() { |
| global $g_db; |
| global $g_db; |
| |
| |
| return $g_db->ErrorNo(); |
| return $g_db->ErrorNo(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Returns the last status or error message. Returns the last status or error message. The error message is reset when Execute() is called. |
| * Returns the last status or error message. Returns the last status or error message. The error message is reset when Execute() is called. |
| * This can return a string even if no error occurs. In general you do not need to call this function unless an ADOdb function returns false on an error. |
| * This can return a string even if no error occurs. In general you do not need to call this function unless an ADOdb function returns false on an error. |
| * @return string last error string |
| * @return string last error string |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| */ |
| */ |
| function db_error_msg() { |
| function db_error_msg() { |
| global $g_db; |
| global $g_db; |
| |
| |
| return $g_db->ErrorMsg(); |
| return $g_db->ErrorMsg(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * send both the error number and error message and query (optional) as parameters for a triggered error |
| * send both the error number and error message and query (optional) as parameters for a triggered error |
| * @param string $p_query Query that generated the error. |
| * @param string $p_query Query that generated the error. |
| * @return void |
| * @return void |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| */ |
| */ |
| function db_error( $p_query = null ) { |
| function db_error( $p_query = null ) { |
| if( null !== $p_query ) { |
| if( null !== $p_query ) { |
| error_parameters( db_error_num(), db_error_msg(), $p_query ); |
| error_parameters( db_error_num(), db_error_msg(), $p_query ); |
| } else { |
| } else { |
| error_parameters( db_error_num(), db_error_msg() ); |
| error_parameters( db_error_num(), db_error_msg() ); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * close the connection. |
| * close the connection. |
| * Not really necessary most of the time since a connection is automatically closed when a page finishes loading. |
| * Not really necessary most of the time since a connection is automatically closed when a page finishes loading. |
| * @return void |
| * @return void |
| */ |
| */ |
| function db_close() { |
| function db_close() { |
| global $g_db; |
| global $g_db; |
| |
| |
| $t_result = $g_db->Close(); |
| $t_result = $g_db->Close(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * prepare a string before DB insertion |
| * prepare a string before DB insertion |
| * @param string $p_string Unprepared string. |
| * @param string $p_string Unprepared string. |
| * @return string prepared database query string |
| * @return string prepared database query string |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| */ |
| */ |
| function db_prepare_string( $p_string ) { |
| function db_prepare_string( $p_string ) { |
| global $g_db; |
| global $g_db; |
| $t_db_type = config_get_global( 'db_type' ); |
| $t_db_type = config_get_global( 'db_type' ); |
| |
| |
| switch( $t_db_type ) { |
| switch( $t_db_type ) { |
| case 'mssqlnative': |
| case 'mssqlnative': |
| case 'odbc_mssql': |
| case 'odbc_mssql': |
| return addslashes( $p_string ); |
| return addslashes( $p_string ); |
| case 'mysqli': |
| case 'mysqli': |
| $t_escaped = $g_db->qstr( $p_string, false ); |
| $t_escaped = $g_db->qstr( $p_string, false ); |
| return utf8_substr( $t_escaped, 1, utf8_strlen( $t_escaped ) - 2 ); |
| return utf8_substr( $t_escaped, 1, utf8_strlen( $t_escaped ) - 2 ); |
| case 'pgsql': |
| case 'pgsql': |
| return pg_escape_string( $p_string ); |
| return pg_escape_string( $p_string ); |
| case 'oci8': |
| case 'oci8': |
| return $p_string; |
| return $p_string; |
| default: |
| default: |
| error_parameters( 'db_type', $t_db_type ); |
| error_parameters( 'db_type', $t_db_type ); |
| trigger_error( ERROR_CONFIG_OPT_INVALID, ERROR ); |
| trigger_error( ERROR_CONFIG_OPT_INVALID, ERROR ); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * Prepare a binary string before DB insertion |
| * Prepare a binary string before DB insertion |
| * Use of this function is required for some DB types, to properly encode |
| * Use of this function is required for some DB types, to properly encode |
| * BLOB fields prior to calling db_query() |
| * BLOB fields prior to calling db_query() |
| * @param string $p_string Raw binary data. |
| * @param string $p_string Raw binary data. |
| * @return string prepared database query string |
| * @return string prepared database query string |
| */ |
| */ |
| function db_prepare_binary_string( $p_string ) { |
| function db_prepare_binary_string( $p_string ) { |
| global $g_db; |
| global $g_db; |
| $t_db_type = config_get_global( 'db_type' ); |
| $t_db_type = config_get_global( 'db_type' ); |
| |
| |
| switch( $t_db_type ) { |
| switch( $t_db_type ) { |
| case 'odbc_mssql': |
| case 'odbc_mssql': |
| $t_content = unpack( 'H*hex', $p_string ); |
| $t_content = unpack( 'H*hex', $p_string ); |
| return '0x' . $t_content['hex']; |
| return '0x' . $t_content['hex']; |
| break; |
| break; |
| case 'pgsql': |
| case 'pgsql': |
| return $g_db->BlobEncode( $p_string ); |
| return $g_db->BlobEncode( $p_string ); |
| break; |
| break; |
| case 'mssqlnative': |
| case 'mssqlnative': |
| case 'oci8': |
| case 'oci8': |
| # Fall through, mssqlnative, oci8 store raw data in BLOB |
| # Fall through, mssqlnative, oci8 store raw data in BLOB |
| default: |
| default: |
| return $p_string; |
| return $p_string; |
| break; |
| break; |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * prepare a int for database insertion. |
| * prepare a int for database insertion. |
| * @param integer $p_int Integer. |
| * @param integer $p_int Integer. |
| * @return integer integer |
| * @return integer integer |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| */ |
| */ |
| function db_prepare_int( $p_int ) { |
| function db_prepare_int( $p_int ) { |
| return (int)$p_int; |
| return (int)$p_int; |
| } |
| } |
| |
| |
| /** |
| /** |
| * prepare a double for database insertion. |
| * prepare a double for database insertion. |
| * @param float $p_double Double. |
| * @param float $p_double Double. |
| * @return double double |
| * @return double double |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| */ |
| */ |
| function db_prepare_double( $p_double ) { |
| function db_prepare_double( $p_double ) { |
| return (double)$p_double; |
| return (double)$p_double; |
| } |
| } |
| |
| |
| /** |
| /** |
| * prepare a boolean for database insertion. |
| * prepare a boolean for database insertion. |
| * @param boolean $p_bool Boolean value. |
| * @param boolean $p_bool Boolean value. |
| * @return integer integer representing boolean |
| * @return integer integer representing boolean |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @deprecated db_query should be used in preference to this function. This function may be removed in 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final |
| */ |
| */ |
| function db_prepare_bool( $p_bool ) { |
| function db_prepare_bool( $p_bool ) { |
| global $g_db; |
| global $g_db; |
| if( db_is_pgsql() ) { |
| if( db_is_pgsql() ) { |
| return $g_db->qstr( $p_bool ); |
| return $g_db->qstr( $p_bool ); |
| } else { |
| } else { |
| return (int)(bool)$p_bool; |
| return (int)(bool)$p_bool; |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * return current time as Unix timestamp |
| * return current time as Unix timestamp |
| * @return integer Unix timestamp of the current date and time |
| * @return integer Unix timestamp of the current date and time |
| */ |
| */ |
| function db_now() { |
| function db_now() { |
| return time(); |
| return time(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * convert minutes to a time format [h]h:mm |
| * convert minutes to a time format [h]h:mm |
| * @param integer $p_min Integer representing number of minutes. |
| * @param integer $p_min Integer representing number of minutes. |
| * @return string representing formatted duration string in hh:mm format. |
| * @return string representing formatted duration string in hh:mm format. |
| */ |
| */ |
| function db_minutes_to_hhmm( $p_min = 0 ) { |
| function db_minutes_to_hhmm( $p_min = 0 ) { |
| return sprintf( '%02d:%02d', $p_min / 60, $p_min % 60 ); |
| return sprintf( '%02d:%02d', $p_min / 60, $p_min % 60 ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * A helper function that generates a case-sensitive or case-insensitive like phrase based on the current db type. |
| * A helper function that generates a case-sensitive or case-insensitive like phrase based on the current db type. |
| * The field name and value are assumed to be safe to insert in a query (i.e. already cleaned). |
| * The field name and value are assumed to be safe to insert in a query (i.e. already cleaned). |
| * @param string $p_field_name The name of the field to filter on. |
| * @param string $p_field_name The name of the field to filter on. |
| * @param boolean $p_case_sensitive True: case sensitive, false: case insensitive. |
| * @param boolean $p_case_sensitive True: case sensitive, false: case insensitive. |
| * @return string returns (field LIKE 'value') OR (field ILIKE 'value') |
| * @return string returns (field LIKE 'value') OR (field ILIKE 'value') |
| */ |
| */ |
| function db_helper_like( $p_field_name, $p_case_sensitive = false ) { |
| function db_helper_like( $p_field_name, $p_case_sensitive = false ) { |
| $t_like_keyword = ' LIKE '; |
| $t_like_keyword = ' LIKE '; |
| |
| |
| if( $p_case_sensitive === false ) { |
| if( $p_case_sensitive === false ) { |
| if( db_is_pgsql() ) { |
| if( db_is_pgsql() ) { |
| $t_like_keyword = ' ILIKE '; |
| $t_like_keyword = ' ILIKE '; |
| } |
| } |
| } |
| } |
| |
| |
| return '(' . $p_field_name . $t_like_keyword . db_param() . ')'; |
| return '(' . $p_field_name . $t_like_keyword . db_param() . ')'; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Compare two dates against a certain number of days |
| * Compare two dates against a certain number of days |
| * 'val_or_col' parameters will be used "as is" in the query component, |
| * 'val_or_col' parameters will be used "as is" in the query component, |
| * allowing use of a column name. To compare against a specific date, |
| * allowing use of a column name. To compare against a specific date, |
| * it is recommended to pass db_param() instead of a date constant. |
| * it is recommended to pass db_param() instead of a date constant. |
| * @param string $p_val_or_col_1 Value or Column to compare. |
| * @param string $p_val_or_col_1 Value or Column to compare. |
| * @param string $p_operator SQL comparison operator. |
| * @param string $p_operator SQL comparison operator. |
| * @param string $p_val_or_col_2 Value or Column to compare. |
| * @param string $p_val_or_col_2 Value or Column to compare. |
| * @param integer $p_num_secs Number of seconds to compare against |
| * @param integer $p_num_secs Number of seconds to compare against |
| * @return string Database query component to compare dates |
| * @return string Database query component to compare dates |
| * @todo Check if there is a way to do that using ADODB rather than implementing it here. |
| * @todo Check if there is a way to do that using ADODB rather than implementing it here. |
| */ |
| */ |
| function db_helper_compare_time( $p_val_or_col_1, $p_operator, $p_val_or_col_2, $p_num_secs ) { |
| function db_helper_compare_time( $p_val_or_col_1, $p_operator, $p_val_or_col_2, $p_num_secs ) { |
| if( $p_num_secs == 0 ) { |
| if( $p_num_secs == 0 ) { |
| return "($p_val_or_col_1 $p_operator $p_val_or_col_2)"; |
| return "($p_val_or_col_1 $p_operator $p_val_or_col_2)"; |
| } elseif( $p_num_secs > 0 ) { |
| } elseif( $p_num_secs > 0 ) { |
| return "($p_val_or_col_1 $p_operator $p_val_or_col_2 + $p_num_secs)"; |
| return "($p_val_or_col_1 $p_operator $p_val_or_col_2 + $p_num_secs)"; |
| } else { |
| } else { |
| # Invert comparison to avoid issues with unsigned integers on MySQL |
| # Invert comparison to avoid issues with unsigned integers on MySQL |
| return "($p_val_or_col_1 - $p_num_secs $p_operator $p_val_or_col_2)"; |
| return "($p_val_or_col_1 - $p_num_secs $p_operator $p_val_or_col_2)"; |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| /** |
| * count queries |
| * count queries |
| * @return integer |
| * @return integer |
| */ |
| */ |
| function db_count_queries() { |
| function db_count_queries() { |
| global $g_queries_array; |
| global $g_queries_array; |
| |
| |
| return count( $g_queries_array ); |
| return count( $g_queries_array ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * count unique queries |
| * count unique queries |
| * @return integer |
| * @return integer |
| */ |
| */ |
| function db_count_unique_queries() { |
| function db_count_unique_queries() { |
| global $g_queries_array; |
| global $g_queries_array; |
| |
| |
| $t_unique_queries = 0; |
| $t_unique_queries = 0; |
| $t_shown_queries = array(); |
| $t_shown_queries = array(); |
| foreach( $g_queries_array as $t_val_array ) { |
| foreach( $g_queries_array as $t_val_array ) { |
| if( !in_array( $t_val_array[0], $t_shown_queries ) ) { |
| if( !in_array( $t_val_array[0], $t_shown_queries ) ) { |
| $t_unique_queries++; |
| $t_unique_queries++; |
| array_push( $t_shown_queries, $t_val_array[0] ); |
| array_push( $t_shown_queries, $t_val_array[0] ); |
| } |
| } |
| } |
| } |
| return $t_unique_queries; |
| return $t_unique_queries; |
| } |
| } |
| |
| |
| /** |
| /** |
| * get total time for queries |
| * get total time for queries |
| * @return integer |
| * @return integer |
| */ |
| */ |
| function db_time_queries() { |
| function db_time_queries() { |
| global $g_queries_array; |
| global $g_queries_array; |
| $t_count = count( $g_queries_array ); |
| $t_count = count( $g_queries_array ); |
| $t_total = 0; |
| $t_total = 0; |
| for( $i = 0;$i < $t_count;$i++ ) { |
| for( $i = 0;$i < $t_count;$i++ ) { |
| $t_total += $g_queries_array[$i][1]; |
| $t_total += $g_queries_array[$i][1]; |
| } |
| } |
| return $t_total; |
| return $t_total; |
| } |
| } |
| |
| |
| /** |
| /** |
| * get database table name |
| * get database table name |
| * |
| * |
| * @param string $p_name Can either be specified as 'XXX' (e.g. 'bug'), or |
| * @param string $p_name Can either be specified as 'XXX' (e.g. 'bug'), or |
| * using the legacy style 'mantis_XXX_table'; in the |
| * using the legacy style 'mantis_XXX_table'; in the |
| * latter case, a deprecation warning will be issued. |
| * latter case, a deprecation warning will be issued. |
| * @return string containing full database table name (with prefix and suffix) |
| * @return string containing full database table name (with prefix and suffix) |
| */ |
| */ |
| function db_get_table( $p_name ) { |
| function db_get_table( $p_name ) { |
| if( preg_match( '/^mantis_(.*)_table$/', $p_name, $t_matches ) ) { |
| if( preg_match( '/^mantis_(.*)_table$/', $p_name, $t_matches ) ) { |
| $t_table = $t_matches[1]; |
| $t_table = $t_matches[1]; |
| error_parameters( |
| error_parameters( |
| __FUNCTION__ . "( '$p_name' )", |
| __FUNCTION__ . "( '$p_name' )", |
| __FUNCTION__ . "( '$t_table' )" |
| __FUNCTION__ . "( '$t_table' )" |
| ); |
| ); |
| trigger_error( ERROR_DEPRECATED_SUPERSEDED, DEPRECATED ); |
| trigger_error( ERROR_DEPRECATED_SUPERSEDED, DEPRECATED ); |
| } else { |
| } else { |
| $t_table = $p_name; |
| $t_table = $p_name; |
| } |
| } |
| |
| |
| # Determine table prefix including trailing '_' |
| # Determine table prefix including trailing '_' |
| $t_prefix = trim( config_get_global( 'db_table_prefix' ) ); |
| $t_prefix = trim( config_get_global( 'db_table_prefix' ) ); |
| if( !empty( $t_prefix ) && '_' != substr( $t_prefix, -1 ) ) { |
| if( !empty( $t_prefix ) && '_' != substr( $t_prefix, -1 ) ) { |
| $t_prefix .= '_'; |
| $t_prefix .= '_'; |
| } |
| } |
| # Determine table suffix including leading '_' |
| # Determine table suffix including leading '_' |
| $t_suffix = trim( config_get_global( 'db_table_suffix' ) ); |
| $t_suffix = trim( config_get_global( 'db_table_suffix' ) ); |
| if( !empty( $t_suffix ) && '_' != substr( $t_suffix, 0, 1 ) ) { |
| if( !empty( $t_suffix ) && '_' != substr( $t_suffix, 0, 1 ) ) { |
| $t_suffix = '_' . $t_suffix; |
| $t_suffix = '_' . $t_suffix; |
| } |
| } |
| |
| |
| # Physical table name |
| # Physical table name |
| $t_table = $t_prefix . $t_table . $t_suffix; |
| $t_table = $t_prefix . $t_table . $t_suffix; |
| db_check_identifier_size( $t_table ); |
| db_check_identifier_size( $t_table ); |
| return $t_table; |
| return $t_table; |
| } |
| } |
| |
| |
| /** |
| /** |
| * get list database tables |
| * get list database tables |
| * @return array containing table names |
| * @return array containing table names |
| */ |
| */ |
| function db_get_table_list() { |
| function db_get_table_list() { |
| global $g_db; |
| global $g_db; |
| |
| |
| $t_tables = $g_db->MetaTables( 'TABLE' ); |
| $t_tables = $g_db->MetaTables( 'TABLE' ); |
| return $t_tables; |
| return $t_tables; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Updates a BLOB column |
| * Updates a BLOB column |
| * |
| * |
| * This function is only needed for oci8; it will do nothing and return |
| * This function is only needed for oci8; it will do nothing and return |
| * false if used with another RDBMS. |
| * false if used with another RDBMS. |
| * |
| * |
| * @param string $p_table Table name. |
| * @param string $p_table Table name. |
| * @param string $p_column The BLOB column to update. |
| * @param string $p_column The BLOB column to update. |
| * @param string $p_val Data to store into the BLOB. |
| * @param string $p_val Data to store into the BLOB. |
| * @param string $p_where Where clause to identify which record to update |
| * @param string $p_where Where clause to identify which record to update |
| * if null, defaults to the last record inserted in $p_table. |
| * if null, defaults to the last record inserted in $p_table. |
| * @return boolean |
| * @return boolean |
| */ |
| */ |
| function db_update_blob( $p_table, $p_column, $p_val, $p_where = null ) { |
| function db_update_blob( $p_table, $p_column, $p_val, $p_where = null ) { |
| global $g_db, $g_db_log_queries, $g_queries_array; |
| global $g_db, $g_db_log_queries, $g_queries_array; |
| |
| |
| if( !db_is_oracle() ) { |
| if( !db_is_oracle() ) { |
| return false; |
| return false; |
| } |
| } |
| |
| |
| if( null == $p_where ) { |
| if( null == $p_where ) { |
| $p_where = 'id=' . db_insert_id( $p_table ); |
| $p_where = 'id=' . db_insert_id( $p_table ); |
| } |
| } |
| |
| |
| if( ON == $g_db_log_queries ) { |
| if( ON == $g_db_log_queries ) { |
| $t_start = microtime( true ); |
| $t_start = microtime( true ); |
| |
| |
| $t_backtrace = debug_backtrace(); |
| $t_backtrace = debug_backtrace(); |
| $t_caller = basename( $t_backtrace[0]['file'] ); |
| $t_caller = basename( $t_backtrace[0]['file'] ); |
| $t_caller .= ':' . $t_backtrace[0]['line']; |
| $t_caller .= ':' . $t_backtrace[0]['line']; |
| |
| |
| # Is this called from another function? |
| # Is this called from another function? |
| if( isset( $t_backtrace[1] ) ) { |
| if( isset( $t_backtrace[1] ) ) { |
| $t_caller .= ' ' . $t_backtrace[1]['function'] . '()'; |
| $t_caller .= ' ' . $t_backtrace[1]['function'] . '()'; |
| } else { |
| } else { |
| # or from a script directly? |
| # or from a script directly? |
| $t_caller .= ' ' . $_SERVER['SCRIPT_NAME']; |
| $t_caller .= ' ' . $_SERVER['SCRIPT_NAME']; |
| } |
| } |
| } |
| } |
| |
| |
| $t_result = $g_db->UpdateBlob( $p_table, $p_column, $p_val, $p_where ); |
| $t_result = $g_db->UpdateBlob( $p_table, $p_column, $p_val, $p_where ); |
| |
| |
| if( $g_db_log_queries ) { |
| if( $g_db_log_queries ) { |
| $t_elapsed = number_format( microtime( true ) - $t_start, 4 ); |
| $t_elapsed = number_format( microtime( true ) - $t_start, 4 ); |
| $t_log_data = array( |
| $t_log_data = array( |
| 'Update BLOB in ' . $p_table . '.' . $p_column . ' where ' . $p_where, |
| 'Update BLOB in ' . $p_table . '.' . $p_column . ' where ' . $p_where, |
| $t_elapsed, |
| $t_elapsed, |
| $t_caller |
| $t_caller |
| ); |
| ); |
| log_event( LOG_DATABASE, var_export( $t_log_data, true ) ); |
| log_event( LOG_DATABASE, var_export( $t_log_data, true ) ); |
| array_push( $g_queries_array, $t_log_data ); |
| array_push( $g_queries_array, $t_log_data ); |
| } |
| } |
| |
| |
| if( !$t_result ) { |
| if( !$t_result ) { |
| db_error(); |
| db_error(); |
| trigger_error( ERROR_DB_QUERY_FAILED, ERROR ); |
| trigger_error( ERROR_DB_QUERY_FAILED, ERROR ); |
| return false; |
| return false; |
| } |
| } |
| |
| |
| return $t_result; |
| return $t_result; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Sorts bind variable numbers and puts them in sequential order |
| * Sorts bind variable numbers and puts them in sequential order |
| * e.g. input: "... WHERE F1=:12 and F2=:97 ", |
| * e.g. input: "... WHERE F1=:12 and F2=:97 ", |
| * output: "... WHERE F1=:0 and F2=:1 ". |
| * output: "... WHERE F1=:0 and F2=:1 ". |
| * Used in db_oracle_adapt_query_syntax(). |
| * Used in db_oracle_adapt_query_syntax(). |
| * @param string $p_query Query string to sort. |
| * @param string $p_query Query string to sort. |
| * @return string Query string with sorted bind variable numbers. |
| * @return string Query string with sorted bind variable numbers. |
| */ |
| */ |
| function db_oracle_order_binds_sequentially( $p_query ) { |
| function db_oracle_order_binds_sequentially( $p_query ) { |
| $t_new_query= ''; |
| $t_new_query= ''; |
| $t_is_odd = true; |
| $t_is_odd = true; |
| $t_after_quote = false; |
| $t_after_quote = false; |
| $t_iter = 0; |
| $t_iter = 0; |
| |
| |
| # Divide statement to skip processing string literals |
| # Divide statement to skip processing string literals |
| $t_p_query_arr = explode( '\'', $p_query ); |
| $t_p_query_arr = explode( '\'', $p_query ); |
| foreach( $t_p_query_arr as $t_p_query_part ) { |
| foreach( $t_p_query_arr as $t_p_query_part ) { |
| if( $t_new_query != '' ) { |
| if( $t_new_query != '' ) { |
| $t_new_query .= '\''; |
| $t_new_query .= '\''; |
| } |
| } |
| if( $t_is_odd ) { |
| if( $t_is_odd ) { |
| # Divide to process all bindvars |
| # Divide to process all bindvars |
| $t_p_query_subpart_arr = explode( ':', $t_p_query_part ); |
| $t_p_query_subpart_arr = explode( ':', $t_p_query_part ); |
| if( count( $t_p_query_subpart_arr ) > 1 ) { |
| if( count( $t_p_query_subpart_arr ) > 1 ) { |
| foreach( $t_p_query_subpart_arr as $t_p_query_subpart ) { |
| foreach( $t_p_query_subpart_arr as $t_p_query_subpart ) { |
| if( ( !$t_after_quote ) && ( $t_new_query != '' ) ) { |
| if( ( !$t_after_quote ) && ( $t_new_query != '' ) ) { |
| $t_new_query .= ':' . preg_replace( '/^(\d+?)/U', strval( $t_iter ), $t_p_query_subpart ); |
| $t_new_query .= ':' . preg_replace( '/^(\d+?)/U', strval( $t_iter ), $t_p_query_subpart ); |
| $t_iter++; |
| $t_iter++; |
| } else { |
| } else { |
| $t_new_query .= $t_p_query_subpart; |
| $t_new_query .= $t_p_query_subpart; |
| } |
| } |
| $t_after_quote = false; |
| $t_after_quote = false; |
| } |
| } |
| } else { |
| } else { |
| $t_new_query .= $t_p_query_part; |
| $t_new_query .= $t_p_query_part; |
| } |
| } |
| $t_is_odd = false; |
| $t_is_odd = false; |
| } else { |
| } else { |
| $t_after_quote = true; |
| $t_after_quote = true; |
| $t_new_query .= $t_p_query_part; |
| $t_new_query .= $t_p_query_part; |
| $t_is_odd = true; |
| $t_is_odd = true; |
| } |
| } |
| } |
| } |
| return $t_new_query; |
| return $t_new_query; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Adapt input query string and bindvars array to Oracle DB syntax: |
| * Adapt input query string and bindvars array to Oracle DB syntax: |
| * 1. Change bind vars id's to sequence beginning with 0 |
| * 1. Change bind vars id's to sequence beginning with 0 |
| * (calls db_oracle_order_binds_sequentially() ) |
| * (calls db_oracle_order_binds_sequentially() ) |
| * 2. Remove "AS" keyword, because it is not supported with table aliasing |
| * 2. Remove "AS" keyword, because it is not supported with table aliasing |
| * 3. Remove null bind variables in insert statements for default values support |
| * 3. Remove null bind variables in insert statements for default values support |
| * 4. Replace "tab.column=:bind" to "tab.column IS NULL" when :bind is empty string |
| * 4. Replace "tab.column=:bind" to "tab.column IS NULL" when :bind is empty string |
| * 5. Replace "SET tab.column=:bind" to "SET tab.column=DEFAULT" when :bind is empty string |
| * 5. Replace "SET tab.column=:bind" to "SET tab.column=DEFAULT" when :bind is empty string |
| * @param string $p_query Query string to sort. |
| * @param string $p_query Query string to sort. |
| * @param array &$p_arr_parms Array of parameters matching $p_query, function sorts array keys. |
| * @param array &$p_arr_parms Array of parameters matching $p_query, function sorts array keys. |
| * @return string Query string with sorted bind variable numbers. |
| * @return string Query string with sorted bind variable numbers. |
| */ |
| */ |
| function db_oracle_adapt_query_syntax( $p_query, array &$p_arr_parms = null ) { |
| function db_oracle_adapt_query_syntax( $p_query, array &$p_arr_parms = null ) { |
| # Remove "AS" keyword, because not supported with table aliasing |
| # Remove "AS" keyword, because not supported with table aliasing |
| # - Do not remove text literal within "'" quotes |
| # - Do not remove text literal within "'" quotes |
| # - Will remove all "AS", except when it's part of a "CAST(x AS y)" expression |
| # - Will remove all "AS", except when it's part of a "CAST(x AS y)" expression |
| # To do so, we will assume that the "AS" following a "CAST", is safe to be kept. |
| # To do so, we will assume that the "AS" following a "CAST", is safe to be kept. |
| # Using a counter for "CAST" appearances to allow nesting: CAST(CAST(x AS y) AS z) |
| # Using a counter for "CAST" appearances to allow nesting: CAST(CAST(x AS y) AS z) |
| |
| |
| # split the string by the relevant delimiters. The delimiters will be part of the splitted array |
| # split the string by the relevant delimiters. The delimiters will be part of the splitted array |
| $t_parts = preg_split("/(')|( AS )|(CAST\s*\()/mi", $p_query, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); |
| $t_parts = preg_split("/(')|( AS )|(CAST\s*\()/mi", $p_query, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); |
| $t_is_literal = false; |
| $t_is_literal = false; |
| $t_cast = 0; |
| $t_cast = 0; |
| $t_query = ''; |
| $t_query = ''; |
| foreach( $t_parts as $t_part ) { |
| foreach( $t_parts as $t_part ) { |
| # if quotes, switch literal flag |
| # if quotes, switch literal flag |
| if( $t_part == '\'' ) { |
| if( $t_part == '\'' ) { |
| $t_is_literal = !$t_is_literal; |
| $t_is_literal = !$t_is_literal; |
| $t_query .= $t_part; |
| $t_query .= $t_part; |
| continue; |
| continue; |
| } |
| } |
| # if this part is litereal, do not change |
| # if this part is litereal, do not change |
| if( $t_is_literal ) { |
| if( $t_is_literal ) { |
| $t_query .= $t_part; |
| $t_query .= $t_part; |
| continue; |
| continue; |
| } else { |
| } else { |
| # if there is "CAST" delimiter, flag the counter |
| # if there is "CAST" delimiter, flag the counter |
| if( preg_match( '/^CAST\s*\($/i', $t_part ) ) { |
| if( preg_match( '/^CAST\s*\($/i', $t_part ) ) { |
| $t_cast++; |
| $t_cast++; |
| $t_query .= $t_part; |
| $t_query .= $t_part; |
| continue; |
| continue; |
| } |
| } |
| # if there is "AS" |
| # if there is "AS" |
| if( strcasecmp( $t_part, ' AS ' ) == 0 ) { |
| if( strcasecmp( $t_part, ' AS ' ) == 0 ) { |
| # if there's a previous CAST, keep the AS |
| # if there's a previous CAST, keep the AS |
| if( $t_cast > 0 ) { |
| if( $t_cast > 0 ) { |
| $t_cast--; |
| $t_cast--; |
| $t_query .= $t_part; |
| $t_query .= $t_part; |
| } else { |
| } else { |
| # otherwise, remove the " AS ", replace by a space |
| # otherwise, remove the " AS ", replace by a space |
| $t_query .= ' '; |
| $t_query .= ' '; |
| } |
| } |
| continue; |
| continue; |
| } |
| } |
| $t_query .= $t_part; |
| $t_query .= $t_part; |
| continue; |
| continue; |
| } |
| } |
| } |
| } |
| $p_query = $t_query; |
| $p_query = $t_query; |
| |
| |
| # Remove null bind variables in insert statements for default values support |
| # Remove null bind variables in insert statements for default values support |
| if( is_array( $p_arr_parms ) ) { |
| if( is_array( $p_arr_parms ) ) { |
| preg_match( '/^[\s\n\r]*insert[\s\n\r]+(into){0,1}[\s\n\r]+(?P<table>[a-z0-9_]+)[\s\n\r]*\([\s\n\r]*[\s\n\r]*(?P<fields>[a-z0-9_,\s\n\r]+)[\s\n\r]*\)[\s\n\r]*values[\s\n\r]*\([\s\n\r]*(?P<values>[:a-z0-9_,\s\n\r]+)\)/i', $p_query, $t_matches ); |
| preg_match( '/^[\s\n\r]*insert[\s\n\r]+(into){0,1}[\s\n\r]+(?P<table>[a-z0-9_]+)[\s\n\r]*\([\s\n\r]*[\s\n\r]*(?P<fields>[a-z0-9_,\s\n\r]+)[\s\n\r]*\)[\s\n\r]*values[\s\n\r]*\([\s\n\r]*(?P<values>[:a-z0-9_,\s\n\r]+)\)/i', $p_query, $t_matches ); |
| |
| |
| if( isset( $t_matches['values'] ) ) { #if statement is a INSERT INTO ... (...) VALUES(...) |
| if( isset( $t_matches['values'] ) ) { #if statement is a INSERT INTO ... (...) VALUES(...) |
| # iterates non-empty bind variables |
| # iterates non-empty bind variables |
| $i = 0; |
| $i = 0; |
| $t_fields_left = $t_matches['fields']; |
| $t_fields_left = $t_matches['fields']; |
| $t_values_left = $t_matches['values']; |
| $t_values_left = $t_matches['values']; |
| |
| |
| for( $t_arr_index = 0; $t_arr_index < count( $p_arr_parms ); $t_arr_index++ ) { |
| for( $t_arr_index = 0; $t_arr_index < count( $p_arr_parms ); $t_arr_index++ ) { |
| # inserting fieldname search |
| # inserting fieldname search |
| if( preg_match( '/^[\s\n\r]*([a-z0-9_]+)[\s\n\r]*,{0,1}([\d\D]*)\z/i', $t_fields_left, $t_fieldmatch ) ) { |
| if( preg_match( '/^[\s\n\r]*([a-z0-9_]+)[\s\n\r]*,{0,1}([\d\D]*)\z/i', $t_fields_left, $t_fieldmatch ) ) { |
| $t_fields_left = $t_fieldmatch[2]; |
| $t_fields_left = $t_fieldmatch[2]; |
| $t_fields_arr[$i] = $t_fieldmatch[1]; |
| $t_fields_arr[$i] = $t_fieldmatch[1]; |
| } |
| } |
| # inserting bindvar name search |
| # inserting bindvar name search |
| if( preg_match( '/^[\s\n\r]*(:[a-z0-9_]+)[\s\n\r]*,{0,1}([\d\D]*)\z/i', $t_values_left, $t_valuematch ) ) { |
| if( preg_match( '/^[\s\n\r]*(:[a-z0-9_]+)[\s\n\r]*,{0,1}([\d\D]*)\z/i', $t_values_left, $t_valuematch ) ) { |
| $t_values_left = $t_valuematch[2]; |
| $t_values_left = $t_valuematch[2]; |
| $t_values_arr[$i] = $t_valuematch[1]; |
| $t_values_arr[$i] = $t_valuematch[1]; |
| } |
| } |
| # skip unsetting if bind array value not empty |
| # skip unsetting if bind array value not empty |
| if( $p_arr_parms[$t_arr_index] !== '' ) { |
| if( $p_arr_parms[$t_arr_index] !== '' ) { |
| $i++; |
| $i++; |
| } else { |
| } else { |
| $t_arr_index--; |
| $t_arr_index--; |
| # Shift array and unset bind array element |
| # Shift array and unset bind array element |
| for( $n = $i + 1; $n < count( $p_arr_parms ); $n++ ) { |
| for( $n = $i + 1; $n < count( $p_arr_parms ); $n++ ) { |
| $p_arr_parms[$n-1] = $p_arr_parms[$n]; |
| $p_arr_parms[$n-1] = $p_arr_parms[$n]; |
| } |
| } |
| unset( $t_fields_arr[$i] ); |
| unset( $t_fields_arr[$i] ); |
| unset( $t_values_arr[$i] ); |
| unset( $t_values_arr[$i] ); |
| unset( $p_arr_parms[count( $p_arr_parms ) - 1] ); |
| unset( $p_arr_parms[count( $p_arr_parms ) - 1] ); |
| } |
| } |
| } |
| } |
| |
| |
| # Combine statement from arrays |
| # Combine statement from arrays |
| $p_query = 'INSERT INTO ' . $t_matches['table'] . ' (' . $t_fields_arr[0]; |
| $p_query = 'INSERT INTO ' . $t_matches['table'] . ' (' . $t_fields_arr[0]; |
| for( $i = 1; $i < count( $p_arr_parms ); $i++ ) { |
| for( $i = 1; $i < count( $p_arr_parms ); $i++ ) { |
| $p_query = $p_query . ', ' . $t_fields_arr[$i]; |
| $p_query = $p_query . ', ' . $t_fields_arr[$i]; |
| } |
| } |
| $p_query = $p_query . ') values (' . $t_values_arr[0]; |
| $p_query = $p_query . ') values (' . $t_values_arr[0]; |
| for( $i = 1; $i < count( $p_arr_parms ); $i++ ) { |
| for( $i = 1; $i < count( $p_arr_parms ); $i++ ) { |
| $p_query = $p_query . ', ' . $t_values_arr[$i]; |
| $p_query = $p_query . ', ' . $t_values_arr[$i]; |
| } |
| } |
| $p_query = $p_query . ')'; |
| $p_query = $p_query . ')'; |
| } else { |
| } else { |
| # if input statement is NOT a INSERT INTO (...) VALUES(...) |
| # if input statement is NOT a INSERT INTO (...) VALUES(...) |
| |
| |
| # "IS NULL" adoptation here |
| # "IS NULL" adoptation here |
| $t_set_where_template_str = substr( md5( uniqid( rand(), true ) ), 0, 50 ); |
| $t_set_where_template_str = substr( md5( uniqid( rand(), true ) ), 0, 50 ); |
| $t_removed_set_where = ''; |
| $t_removed_set_where = ''; |
| |
| |
| # Need to order parameter array element correctly |
| # Need to order parameter array element correctly |
| $p_query = db_oracle_order_binds_sequentially( $p_query ); |
| $p_query = db_oracle_order_binds_sequentially( $p_query ); |
| |
| |
| # Find and remove temporarily "SET var1=:bind1, var2=:bind2 WHERE" part |
| # Find and remove temporarily "SET var1=:bind1, var2=:bind2 WHERE" part |
| preg_match( '/^(?P<before_set_where>.*)(?P<set_where>[\s\n\r]*set[\s\n\r]+[\s\n\ra-z0-9_\.=,:\']+)(?P<after_set_where>where[\d\D]*)$/i', $p_query, $t_matches ); |
| preg_match( '/^(?P<before_set_where>.*)(?P<set_where>[\s\n\r]*set[\s\n\r]+[\s\n\ra-z0-9_\.=,:\']+)(?P<after_set_where>where[\d\D]*)$/i', $p_query, $t_matches ); |
| $t_set_where_stmt = isset( $t_matches['after_set_where'] ); |
| $t_set_where_stmt = isset( $t_matches['after_set_where'] ); |
| |
| |
| if( $t_set_where_stmt ) { |
| if( $t_set_where_stmt ) { |
| $t_removed_set_where = $t_matches['set_where']; |
| $t_removed_set_where = $t_matches['set_where']; |
| # Now work with statement without "SET ... WHERE" part |
| # Now work with statement without "SET ... WHERE" part |
| $t_templated_query = $t_matches['before_set_where'] . $t_set_where_template_str . $t_matches['after_set_where']; |
| $t_templated_query = $t_matches['before_set_where'] . $t_set_where_template_str . $t_matches['after_set_where']; |
| } else { |
| } else { |
| $t_templated_query = $p_query; |
| $t_templated_query = $p_query; |
| } |
| } |
| |
| |
| # Replace "var1=''" by "var1 IS NULL" |
| # Replace "var1=''" by "var1 IS NULL" |
| while( preg_match( '/^(?P<before_empty_literal>[\d\D]*[\s\n\r(]+([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)[\s\n\r]*=[\s\n\r]*\'\'(?P<after_empty_literal>[\s\n\r]*[\d\D]*\z)/i', $t_templated_query, $t_matches ) > 0 ) { |
| while( preg_match( '/^(?P<before_empty_literal>[\d\D]*[\s\n\r(]+([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)[\s\n\r]*=[\s\n\r]*\'\'(?P<after_empty_literal>[\s\n\r]*[\d\D]*\z)/i', $t_templated_query, $t_matches ) > 0 ) { |
| $t_templated_query = $t_matches['before_empty_literal'] . ' IS NULL ' . $t_matches['after_empty_literal']; |
| $t_templated_query = $t_matches['before_empty_literal'] . ' IS NULL ' . $t_matches['after_empty_literal']; |
| } |
| } |
| # Replace "var1!=''" and "var1<>''" by "var1 IS NOT NULL" |
| # Replace "var1!=''" and "var1<>''" by "var1 IS NOT NULL" |
| while( preg_match( '/^(?P<before_empty_literal>[\d\D]*[\s\n\r(]+([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)[\s\n\r]*(![\s\n\r]*=|<[\s\n\r]*>)[\s\n\r]*\'\'(?P<after_empty_literal>[\s\n\r]*[\d\D]*\z)/i', $t_templated_query, $t_matches ) > 0 ) { |
| while( preg_match( '/^(?P<before_empty_literal>[\d\D]*[\s\n\r(]+([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)[\s\n\r]*(![\s\n\r]*=|<[\s\n\r]*>)[\s\n\r]*\'\'(?P<after_empty_literal>[\s\n\r]*[\d\D]*\z)/i', $t_templated_query, $t_matches ) > 0 ) { |
| $t_templated_query = $t_matches['before_empty_literal'] . ' IS NOT NULL ' . $t_matches['after_empty_literal']; |
| $t_templated_query = $t_matches['before_empty_literal'] . ' IS NOT NULL ' . $t_matches['after_empty_literal']; |
| } |
| } |
| |
| |
| $p_query = $t_templated_query; |
| $p_query = $t_templated_query; |
| # Process input bind variable array to replace "WHERE fld=:12" |
| # Process input bind variable array to replace "WHERE fld=:12" |
| # by "WHERE fld IS NULL" if :12 is empty |
| # by "WHERE fld IS NULL" if :12 is empty |
| while( preg_match( '/^(?P<before_var>[\d\D]*[\s\n\r(]+)(?P<var_name>([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)(?P<dividers>[\s\n\r]*=[\s\n\r]*:)(?P<bind_name>[0-9]+)(?P<after_var>[\s\n\r]*[\d\D]*\z)/i', $t_templated_query, $t_matches ) > 0 ) { |
| while( preg_match( '/^(?P<before_var>[\d\D]*[\s\n\r(]+)(?P<var_name>([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)(?P<dividers>[\s\n\r]*=[\s\n\r]*:)(?P<bind_name>[0-9]+)(?P<after_var>[\s\n\r]*[\d\D]*\z)/i', $t_templated_query, $t_matches ) > 0 ) { |
| $t_bind_num = $t_matches['bind_name']; |
| $t_bind_num = $t_matches['bind_name']; |
| |
| |
| $t_search_substr = $t_matches['before_var'] . $t_matches['var_name'] . $t_matches['dividers'] . $t_matches['bind_name'] . $t_matches['after_var']; |
| $t_search_substr = $t_matches['before_var'] . $t_matches['var_name'] . $t_matches['dividers'] . $t_matches['bind_name'] . $t_matches['after_var']; |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . '=:' . $t_matches['bind_name']. $t_matches['after_var']; |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . '=:' . $t_matches['bind_name']. $t_matches['after_var']; |
| |
| |
| if( $p_arr_parms[$t_bind_num] === '' ) { |
| if( $p_arr_parms[$t_bind_num] === '' ) { |
| for( $n = $t_bind_num + 1; $n < count( $p_arr_parms ); $n++ ) { |
| for( $n = $t_bind_num + 1; $n < count( $p_arr_parms ); $n++ ) { |
| $p_arr_parms[$n - 1] = $p_arr_parms[$n]; |
| $p_arr_parms[$n - 1] = $p_arr_parms[$n]; |
| } |
| } |
| unset( $p_arr_parms[count( $p_arr_parms ) - 1] ); |
| unset( $p_arr_parms[count( $p_arr_parms ) - 1] ); |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . ' IS NULL ' . $t_matches['after_var']; |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . ' IS NULL ' . $t_matches['after_var']; |
| } |
| } |
| $p_query = str_replace( $t_search_substr, $t_replace_substr, $p_query ); |
| $p_query = str_replace( $t_search_substr, $t_replace_substr, $p_query ); |
| |
| |
| $t_templated_query = $t_matches['before_var'] . $t_matches['after_var']; |
| $t_templated_query = $t_matches['before_var'] . $t_matches['after_var']; |
| } |
| } |
| |
| |
| if( $t_set_where_stmt ) { |
| if( $t_set_where_stmt ) { |
| # Put temporarily removed "SET ... WHERE" part back |
| # Put temporarily removed "SET ... WHERE" part back |
| $p_query = str_replace( $t_set_where_template_str, $t_removed_set_where, $p_query ); |
| $p_query = str_replace( $t_set_where_template_str, $t_removed_set_where, $p_query ); |
| # Need to order parameter array element correctly |
| # Need to order parameter array element correctly |
| $p_query = db_oracle_order_binds_sequentially( $p_query ); |
| $p_query = db_oracle_order_binds_sequentially( $p_query ); |
| # Find and remove temporary "SET var1=:bind1, var2=:bind2 WHERE" part again |
| # Find and remove temporary "SET var1=:bind1, var2=:bind2 WHERE" part again |
| preg_match( '/^(?P<before_set_where>.*)(?P<set_where>[\s\n\r]*set[\s\n\r]+[\s\n\ra-z0-9_\.=,:\']+)(?P<after_set_where>where[\d\D]*)$/i', $p_query, $t_matches ); |
| preg_match( '/^(?P<before_set_where>.*)(?P<set_where>[\s\n\r]*set[\s\n\r]+[\s\n\ra-z0-9_\.=,:\']+)(?P<after_set_where>where[\d\D]*)$/i', $p_query, $t_matches ); |
| $t_removed_set_where = $t_matches['set_where']; |
| $t_removed_set_where = $t_matches['set_where']; |
| $p_query = $t_matches['before_set_where'] . $t_set_where_template_str . $t_matches['after_set_where']; |
| $p_query = $t_matches['before_set_where'] . $t_set_where_template_str . $t_matches['after_set_where']; |
| |
| |
| #Replace "SET fld1=:1" to "SET fld1=DEFAULT" if bind array value is empty |
| #Replace "SET fld1=:1" to "SET fld1=DEFAULT" if bind array value is empty |
| $t_removed_set_where_parsing = $t_removed_set_where; |
| $t_removed_set_where_parsing = $t_removed_set_where; |
| |
| |
| while( preg_match( '/^(?P<before_var>[\d\D]*[\s\n\r,]+)(?P<var_name>([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)(?P<dividers>[\s\n\r]*=[\s\n\r]*:)(?P<bind_name>[0-9]+)(?P<after_var>[,\s\n\r]*[\d\D]*\z)/i', $t_removed_set_where_parsing, $t_matches ) > 0 ) { |
| while( preg_match( '/^(?P<before_var>[\d\D]*[\s\n\r,]+)(?P<var_name>([a-z0-9_]*[\s\n\r]*\.){0,1}[\s\n\r]*[a-z0-9_]+)(?P<dividers>[\s\n\r]*=[\s\n\r]*:)(?P<bind_name>[0-9]+)(?P<after_var>[,\s\n\r]*[\d\D]*\z)/i', $t_removed_set_where_parsing, $t_matches ) > 0 ) { |
| $t_bind_num = $t_matches['bind_name']; |
| $t_bind_num = $t_matches['bind_name']; |
| $t_search_substr = $t_matches['before_var'] . $t_matches['var_name'] . $t_matches['dividers'] . $t_matches['bind_name'] ; |
| $t_search_substr = $t_matches['before_var'] . $t_matches['var_name'] . $t_matches['dividers'] . $t_matches['bind_name'] ; |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . $t_matches['dividers'] . $t_matches['bind_name'] ; |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . $t_matches['dividers'] . $t_matches['bind_name'] ; |
| |
| |
| if( $p_arr_parms[$t_bind_num] === '' ) { |
| if( $p_arr_parms[$t_bind_num] === '' ) { |
| for( $n = $t_bind_num + 1; $n < count( $p_arr_parms ); $n++ ) { |
| for( $n = $t_bind_num + 1; $n < count( $p_arr_parms ); $n++ ) { |
| $p_arr_parms[$n - 1] = $p_arr_parms[$n]; |
| $p_arr_parms[$n - 1] = $p_arr_parms[$n]; |
| } |
| } |
| unset( $p_arr_parms[count( $p_arr_parms ) - 1] ); |
| unset( $p_arr_parms[count( $p_arr_parms ) - 1] ); |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . '=DEFAULT '; |
| $t_replace_substr = $t_matches['before_var'] . $t_matches['var_name'] . '=DEFAULT '; |
| } |
| } |
| $t_removed_set_where = str_replace( $t_search_substr, $t_replace_substr, $t_removed_set_where ); |
| $t_removed_set_where = str_replace( $t_search_substr, $t_replace_substr, $t_removed_set_where ); |
| $t_removed_set_where_parsing = $t_matches['before_var'] . $t_matches['after_var']; |
| $t_removed_set_where_parsing = $t_matches['before_var'] . $t_matches['after_var']; |
| } |
| } |
| $p_query = str_replace( $t_set_where_template_str, $t_removed_set_where, $p_query ); |
| $p_query = str_replace( $t_set_where_template_str, $t_removed_set_where, $p_query ); |
| } |
| } |
| } |
| } |
| } |
| } |
| $p_query = db_oracle_order_binds_sequentially( $p_query ); |
| $p_query = db_oracle_order_binds_sequentially( $p_query ); |
| return $p_query; |
| return $p_query; |
| } |
| } |
| |
| |
| /** |
| /** |
| * Replace 4-byte UTF-8 chars |
| * Replace 4-byte UTF-8 chars |
| * This is a workaround to avoid data getting truncated on MySQL databases |
| * This is a workaround to avoid data getting truncated on MySQL databases |
| * using native utf8 encoding, which only supports 3 bytes chars (see #20431) |
| * using native utf8 encoding, which only supports 3 bytes chars (see #20431) |
| * @param string $p_string |
| * @param string $p_string |
| * @return string |
| * @return string |
| */ |
| */ |
| function db_mysql_fix_utf8( $p_string ) { |
| function db_mysql_fix_utf8( $p_string ) { |
| if( !db_is_mysql() ) { |
| if( !db_is_mysql() ) { |
| return $p_string; |
| return $p_string; |
| } |
| } |
| return preg_replace( |
| return preg_replace( |
| # 4-byte UTF8 chars always start with bytes 0xF0-0xF7 (0b11110xxx) |
| # 4-byte UTF8 chars always start with bytes 0xF0-0xF7 (0b11110xxx) |
| '/[\xF0-\xF7].../s', |
| '/[\xF0-\xF7].../s', |
| # replace with U+FFFD to avoid potential Unicode XSS attacks, |
| # replace with U+FFFD to avoid potential Unicode XSS attacks, |
| # see http://unicode.org/reports/tr36/#Deletion_of_Noncharacters |
| # see http://unicode.org/reports/tr36/#Deletion_of_Noncharacters |
| "\xEF\xBF\xBD", |
| "\xEF\xBF\xBD", |
| $p_string |
| $p_string |
| ); |
| ); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Creates an empty record set, compatible with db_query() result |
| * Creates an empty record set, compatible with db_query() result |
| * This object can be used when a query can't be performed, or is not needed, |
| * This object can be used when a query can't be performed, or is not needed, |
| * and still want to return an empty result as a transparent return value. |
| * and still want to return an empty result as a transparent return value. |
| * @return \ADORecordSet_empty |
| * @return \ADORecordSet_empty |
| */ |
| */ |
| function db_empty_result() { |
| function db_empty_result() { |
| return new ADORecordSet_empty(); |
| return new ADORecordSet_empty(); |
| } |
| } |
| |
| |
| /** |
| /** |
| * Process a query string by replacing token parameters by their bound values |
| * Process a query string by replacing token parameters by their bound values |
| * @param string $p_query Query string |
| * @param string $p_query Query string |
| * @param array $p_arr_parms Parameter array |
| * @param array $p_arr_parms Parameter array |
| * @return string Processed query string |
| * @return string Processed query string |
| */ |
| */ |
| function db_format_query_log_msg( $p_query, array $p_arr_parms ) { |
| function db_format_query_log_msg( $p_query, array $p_arr_parms ) { |
| global $g_db; |
| global $g_db; |
| |
| |
| $t_lastoffset = 0; |
| $t_lastoffset = 0; |
| $i = 0; |
| $i = 0; |
| if( !empty( $p_arr_parms ) ) { |
| if( !empty( $p_arr_parms ) ) { |
| # For mysql, tokens are '?', and parameters are bound sequentially |
| # For mysql, tokens are '?', and parameters are bound sequentially |
| # For pgsql, tokens are '$number', and parameters are bound by the denoted |
| # For pgsql, tokens are '$number', and parameters are bound by the denoted |
| # index (1-based) in the parameter array |
| # index (1-based) in the parameter array |
| # For oracle, tokens are ':string', but mantis rewrites them as sequentially |
| # For oracle, tokens are ':string', but mantis rewrites them as sequentially |
| # ordered, so they behave like mysql. See db_oracle_order_binds_sequentially() |
| # ordered, so they behave like mysql. See db_oracle_order_binds_sequentially() |
| $t_regex = '/(?<token>\?|\$|:)(?<index>[0-9]*)/'; |
| $t_regex = '/(?<token>\?|\$|:)(?<index>[0-9]*)/'; |
| while( preg_match( $t_regex , $p_query, $t_matches, PREG_OFFSET_CAPTURE, $t_lastoffset ) ) { |
| while( preg_match( $t_regex , $p_query, $t_matches, PREG_OFFSET_CAPTURE, $t_lastoffset ) ) { |
| $t_match_param = $t_matches[0]; |
| $t_match_param = $t_matches[0]; |
| # Realign the offset returned by preg_match as it is byte-based, |
| # Realign the offset returned by preg_match as it is byte-based, |
| # which causes issues with UTF-8 characters in the query string |
| # which causes issues with UTF-8 characters in the query string |
| # (e.g. from custom fields names) |
| # (e.g. from custom fields names) |
| $t_utf8_offset = utf8_strlen( substr( $p_query, 0, $t_match_param[1] ), mb_internal_encoding() ); |
| $t_utf8_offset = utf8_strlen( substr( $p_query, 0, $t_match_param[1] ), mb_internal_encoding() ); |
| if( $i <= count( $p_arr_parms ) ) { |
| if( $i <= count( $p_arr_parms ) ) { |
| if( db_is_pgsql() ) { |
| if( db_is_pgsql() ) { |
| # For pgsql, the bound value is indexed by the parameter name |
| # For pgsql, the bound value is indexed by the parameter name |
| $t_index = (int)$t_matches['index'][0]; |
| $t_index = (int)$t_matches['index'][0]; |
| $t_value = $p_arr_parms[$t_index-1]; |
| $t_value = $p_arr_parms[$t_index-1]; |
| } else { |
| } else { |
| $t_value = $p_arr_parms[$i]; |
| $t_value = $p_arr_parms[$i]; |
| } |
| } |
| if( is_null( $t_value ) ) { |
| if( is_null( $t_value ) ) { |
| $t_replace = 'NULL'; |
| $t_replace = 'NULL'; |
| } else if( is_string( $t_value ) ) { |
| } else if( is_string( $t_value ) ) { |
| $t_replace = "'" . $t_value . "'"; |
| $t_replace = "'" . $t_value . "'"; |
| } else if( is_integer( $t_value ) || is_float( $t_value ) ) { |
| } else if( is_integer( $t_value ) || is_float( $t_value ) ) { |
| $t_replace = (float)$t_value; |
| $t_replace = (float)$t_value; |
| } else if( is_bool( $t_value ) ) { |
| } else if( is_bool( $t_value ) ) { |
| # use the actual literal from db driver |
| # use the actual literal from db driver |
| $t_replace = $t_value ? $g_db->true : $g_db->false; |
| $t_replace = $t_value ? $g_db->true : $g_db->false; |
| } else { |
| } else { |
| # Could not find a supported type for this parameter value. |
| # Could not find a supported type for this parameter value. |
| # Skip this token, so replacing it with itself. |
| # Skip this token, so replacing it with itself. |
| $t_replace = $t_match_param[0]; |
| $t_replace = $t_match_param[0]; |
| } |
| } |
| $p_query = utf8_substr( $p_query, 0, $t_utf8_offset ) |
| $p_query = utf8_substr( $p_query, 0, $t_utf8_offset ) |
| . $t_replace |
| . $t_replace |
| . utf8_substr( $p_query, $t_utf8_offset + utf8_strlen( $t_match_param[0] ) ); |
| . utf8_substr( $p_query, $t_utf8_offset + utf8_strlen( $t_match_param[0] ) ); |
| $t_lastoffset = $t_match_param[1] + strlen( $t_replace ) + 1; |
| $t_lastoffset = $t_match_param[1] + strlen( $t_replace ) + 1; |
| } else { |
| } else { |
| $t_lastoffset = $t_match_param[1] + 1; |
| $t_lastoffset = $t_match_param[1] + 1; |
| } |
| } |
| $i++; |
| $i++; |
| } |
| } |
| } |
| } |
| return $p_query; |
| return $p_query; |
| } |
| } |
| |
| |