Skip to content

Commit

Permalink
Improve db_fetch_array performance
Browse files Browse the repository at this point in the history
Improve db_fetch_array performance by caching the result from:
- db_is_pgsql()
- db_is_oracle()

Based on profiling, the repeated calls were using up to 20% of total
time for the db_fetch_array execution.

Fixes #21871, PR #1105
  • Loading branch information
dregad committed May 15, 2017
2 parents b0b56c8 + db1996c commit 06e7677
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 75 deletions.
7 changes: 7 additions & 0 deletions core/constant_inc.php
Expand Up @@ -693,3 +693,10 @@
define( 'MANAGE_CONFIG_ACTION_CREATE', 'create' );
define( 'MANAGE_CONFIG_ACTION_CLONE', 'clone' );
define( 'MANAGE_CONFIG_ACTION_EDIT', 'edit' );

# Databse functional type identifiers.
define( 'DB_TYPE_UNDEFINED', 0 );
define( 'DB_TYPE_MYSQL', 1 );
define( 'DB_TYPE_PGSQL', 2 );
define( 'DB_TYPE_MSSQL', 3 );
define( 'DB_TYPE_ORACLE', 4 );
159 changes: 84 additions & 75 deletions core/database_api.php
Expand Up @@ -59,6 +59,9 @@
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
define( 'ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_LOWER );

# Stores the functional database type based on db driver
$g_db_functional_type = db_get_type( config_get_global( 'db_type' ) );

/**
* Mantis Database Parameters Count class
* Stores the current parameter count, provides method to generate parameters
Expand Down Expand Up @@ -126,8 +129,9 @@ public function pop() {
* @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 ) {
global $g_db_connected, $g_db;
global $g_db_connected, $g_db, $g_db_functional_type;
$t_db_type = config_get_global( 'db_type' );
$g_db_functional_type = db_get_type( $t_db_type );

if( !db_check_database_support( $t_db_type ) ) {
error_parameters( 0, 'PHP Support for database is not enabled' );
Expand Down Expand Up @@ -211,63 +215,64 @@ function db_check_database_support( $p_db_type ) {
}

/**
* Checks if the database driver is MySQL
* @return boolean true if mysql
* Maps a db driver type to the functional databse type
* @param string $p_driver_type Database driver name
* @return int Database type
*/
function db_is_mysql() {
$t_db_type = config_get_global( 'db_type' );

switch( $t_db_type ) {
function db_get_type( $p_driver_type ) {
switch( $p_driver_type ) {
case 'mysql':
case 'mysqli':
return true;
return DB_TYPE_MYSQL;
case 'postgres':
case 'postgres7':
case 'pgsql':
return DB_TYPE_PGSQL;
case 'mssql':
case 'mssqlnative':
case 'odbc_mssql':
return DB_TYPE_MSSQL;
case 'oci8':
return DB_TYPE_ORACLE;
default:
return DB_TYPE_UNDEFINED;
}
}

return false;
/**
* Checks if the database driver is MySQL
* @return boolean true if mysql
*/
function db_is_mysql() {
global $g_db_functional_type;
return( DB_TYPE_MYSQL == $g_db_functional_type );
}

/**
* Checks if the database driver is PostgreSQL
* @return boolean true if postgres
*/
function db_is_pgsql() {
$t_db_type = config_get_global( 'db_type' );

switch( $t_db_type ) {
case 'postgres':
case 'postgres7':
case 'pgsql':
return true;
}

return false;
global $g_db_functional_type;
return( DB_TYPE_PGSQL == $g_db_functional_type );
}

/**
* Checks if the database driver is MS SQL
* @return boolean true if mssql
*/
function db_is_mssql() {
$t_db_type = config_get_global( 'db_type' );

switch( $t_db_type ) {
case 'mssql':
case 'mssqlnative':
case 'odbc_mssql':
return true;
}

return false;
global $g_db_functional_type;
return( DB_TYPE_MSSQL == $g_db_functional_type );
}

/**
* Checks if the database driver is Oracle (oci8)
* @return boolean true if oracle
*/
function db_is_oracle() {
$t_db_type = config_get_global( 'db_type' );

return ( $t_db_type == 'oci8' );
global $g_db_functional_type;
return( DB_TYPE_ORACLE == $g_db_functional_type );
}

/**
Expand Down Expand Up @@ -460,7 +465,7 @@ function db_affected_rows() {
* @return array Database result
*/
function db_fetch_array( IteratorAggregate &$p_result ) {
global $g_db, $g_db_type;
global $g_db_functional_type;

if( $p_result->EOF ) {
return false;
Expand All @@ -470,66 +475,70 @@ function db_fetch_array( IteratorAggregate &$p_result ) {
$t_row = $p_result->fields;

# Additional handling for specific RDBMS
if( db_is_pgsql() ) {
# pgsql's boolean fields are stored as 't' or 'f' and must be converted
static $s_current_result = null, $s_convert_needed;

if( $s_current_result != $p_result ) {
# Processing a new query
$s_current_result = $p_result;
$s_convert_needed = false;
} elseif( !$s_convert_needed ) {
# No conversion needed, return the row as-is
$p_result->MoveNext();
return $t_row;
}
switch( $g_db_functional_type ) {

case DB_TYPE_PGSQL:
# pgsql's boolean fields are stored as 't' or 'f' and must be converted
static $s_current_result = null, $s_convert_needed;

if( $s_current_result != $p_result ) {
# Processing a new query
$s_current_result = $p_result;
$s_convert_needed = false;
} elseif( !$s_convert_needed ) {
# No conversion needed, return the row as-is
$p_result->MoveNext();
return $t_row;
}

foreach( $p_result->FieldTypesArray() as $t_field ) {
switch( $t_field->type ) {
case 'bool':
switch( $t_row[$t_field->name] ) {
case 'f':
$t_row[$t_field->name] = false;
break;
case 't':
$t_row[$t_field->name] = true;
break;
}
$s_convert_needed = true;
break;
foreach( $p_result->FieldTypesArray() as $t_field ) {
switch( $t_field->type ) {
case 'bool':
switch( $t_row[$t_field->name] ) {
case 'f':
$t_row[$t_field->name] = false;
break;
case 't':
$t_row[$t_field->name] = true;
break;
}
$s_convert_needed = true;
break;
}
}
}
break;

} elseif( db_is_oracle() ) {
# oci8 returns null values for empty strings, convert them back
foreach( $t_row as &$t_value ) {
if( !isset( $t_value ) ) {
$t_value = '';
case DB_TYPE_ORACLE:
# oci8 returns null values for empty strings, convert them back
foreach( $t_row as &$t_value ) {
if( !isset( $t_value ) ) {
$t_value = '';
}
}
}
break;
}

$p_result->MoveNext();
return $t_row;
}

/**
* Retrieve a result returned from a specific database query
* @param boolean|IteratorAggregate $p_result Database Query Record Set to retrieve next result for.
* @param integer $p_index1 Row to retrieve (optional).
* @param integer $p_index2 Column to retrieve (optional).
* Retrieve a specific field from a database query result
* @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_col_index Column to retrieve, zero-based (optional).
* @return mixed Database result
*/
function db_result( $p_result, $p_index1 = 0, $p_index2 = 0 ) {
function db_result( $p_result, $p_row_index = 0, $p_col_index = 0 ) {
if( $p_result && ( db_num_rows( $p_result ) > 0 ) ) {
$p_result->Move( $p_index1 );
$t_result = $p_result->GetArray();
$p_result->Move( $p_row_index );
$t_row = db_fetch_array( $p_result );

# Make the array numerically indexed. This is required to retrieve the
# column ($p_index2), since we use ADODB_FETCH_ASSOC fetch mode.
$t_result = array_values( $t_result[0] );
$t_result = array_values( $t_row );

return $t_result[$p_index2];
return $t_result[$p_col_index];
}

return false;
Expand Down

0 comments on commit 06e7677

Please sign in to comment.