|  | <?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; | 
|  | } |  | } | 
|  |   |  |   |