2010-02-11 00:02:51 +00:00
< ? php
/**
*
2014-05-27 20:18:06 +02:00
* This file is part of the phpBB Forum Software package .
2010-02-11 00:05:32 +00:00
*
2014-05-27 20:18:06 +02:00
* @ copyright ( c ) phpBB Limited < https :// www . phpbb . com >
* @ license GNU General Public License , version 2 ( GPL - 2.0 )
*
* For full copyright and license information , please see
* the docs / CREDITS . txt file .
*
*/
/**
2010-02-11 00:02:51 +00:00
* This is the MS SQL Server Native database abstraction layer .
* PHP mssql native driver required .
* @ author Chris Pucci
*
*/
2013-09-10 14:01:09 +02:00
namespace phpbb\db\driver ;
class mssqlnative extends \phpbb\db\driver\mssql_base
2010-02-11 00:02:51 +00:00
{
2013-10-28 22:27:25 +01:00
var $m_insert_id = null ;
2010-02-11 00:02:51 +00:00
var $last_query_text = '' ;
2010-10-25 03:27:38 +02:00
var $query_options = array ();
2012-12-04 16:12:31 -05:00
var $connect_error = '' ;
2010-02-11 00:02:51 +00:00
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
function sql_connect ( $sqlserver , $sqluser , $sqlpassword , $database , $port = false , $persistency = false , $new_link = false )
{
2012-12-04 16:12:31 -05:00
// Test for driver support, to avoid suppressed fatal error
2010-02-11 00:02:51 +00:00
if ( ! function_exists ( 'sqlsrv_connect' ))
{
2012-12-04 16:12:31 -05:00
$this -> connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx' ;
return $this -> sql_error ( '' );
2010-02-11 00:02:51 +00:00
}
//set up connection variables
$this -> persistency = $persistency ;
$this -> user = $sqluser ;
$this -> dbname = $database ;
$port_delimiter = ( defined ( 'PHP_OS' ) && substr ( PHP_OS , 0 , 3 ) === 'WIN' ) ? ',' : ':' ;
$this -> server = $sqlserver . (( $port ) ? $port_delimiter . $port : '' );
//connect to database
$this -> db_connect_id = sqlsrv_connect ( $this -> server , array (
'Database' => $this -> dbname ,
'UID' => $this -> user ,
'PWD' => $sqlpassword
));
return ( $this -> db_connect_id ) ? $this -> db_connect_id : $this -> sql_error ( '' );
}
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
2010-06-06 08:42:27 -05:00
function sql_server_info ( $raw = false , $use_cache = true )
2010-02-11 00:02:51 +00:00
{
global $cache ;
2010-06-06 08:42:27 -05:00
if ( ! $use_cache || empty ( $cache ) || ( $this -> sql_server_version = $cache -> get ( 'mssql_version' )) === false )
2010-02-11 00:02:51 +00:00
{
$arr_server_info = sqlsrv_server_info ( $this -> db_connect_id );
$this -> sql_server_version = $arr_server_info [ 'SQLServerVersion' ];
2010-06-06 08:42:27 -05:00
if ( ! empty ( $cache ) && $use_cache )
2010-02-11 00:02:51 +00:00
{
$cache -> put ( 'mssql_version' , $this -> sql_server_version );
}
}
if ( $raw )
{
return $this -> sql_server_version ;
}
return ( $this -> sql_server_version ) ? 'MSSQL<br />' . $this -> sql_server_version : 'MSSQL' ;
}
2011-03-12 16:49:25 +01:00
/**
* { @ inheritDoc }
*/
2011-06-02 01:45:12 +02:00
function sql_buffer_nested_transactions ()
2011-03-12 16:49:25 +01:00
{
return true ;
}
2010-02-11 00:02:51 +00:00
/**
* SQL Transaction
* @ access private
*/
function _sql_transaction ( $status = 'begin' )
{
switch ( $status )
{
case 'begin' :
return sqlsrv_begin_transaction ( $this -> db_connect_id );
break ;
case 'commit' :
return sqlsrv_commit ( $this -> db_connect_id );
break ;
case 'rollback' :
return sqlsrv_rollback ( $this -> db_connect_id );
break ;
}
return true ;
}
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
function sql_query ( $query = '' , $cache_ttl = 0 )
{
if ( $query != '' )
{
global $cache ;
// EXPLAIN only in extra debug mode
2012-11-12 11:10:25 +01:00
if ( defined ( 'DEBUG' ))
2010-02-11 00:02:51 +00:00
{
$this -> sql_report ( 'start' , $query );
}
$this -> last_query_text = $query ;
2013-01-02 14:36:14 -05:00
$this -> query_result = ( $cache && $cache_ttl ) ? $cache -> sql_load ( $query ) : false ;
2010-02-11 00:02:51 +00:00
$this -> sql_add_num_queries ( $this -> query_result );
if ( $this -> query_result === false )
{
2010-10-25 03:27:38 +02:00
if (( $this -> query_result = @ sqlsrv_query ( $this -> db_connect_id , $query , array (), $this -> query_options )) === false )
2010-02-11 00:02:51 +00:00
{
$this -> sql_error ( $query );
}
2010-10-25 03:27:38 +02:00
// reset options for next query
$this -> query_options = array ();
2010-02-11 00:02:51 +00:00
2012-11-12 11:10:25 +01:00
if ( defined ( 'DEBUG' ))
2010-02-11 00:02:51 +00:00
{
$this -> sql_report ( 'stop' , $query );
}
2013-06-20 19:16:21 +05:30
if ( $cache && $cache_ttl )
2010-02-11 00:02:51 +00:00
{
$this -> open_queries [( int ) $this -> query_result ] = $this -> query_result ;
2012-12-20 04:35:30 -05:00
$this -> query_result = $cache -> sql_save ( $this , $query , $this -> query_result , $cache_ttl );
2010-02-11 00:02:51 +00:00
}
else if ( strpos ( $query , 'SELECT' ) === 0 && $this -> query_result )
{
$this -> open_queries [( int ) $this -> query_result ] = $this -> query_result ;
}
}
2012-11-12 11:10:25 +01:00
else if ( defined ( 'DEBUG' ))
2010-02-11 00:02:51 +00:00
{
$this -> sql_report ( 'fromcache' , $query );
}
}
else
{
return false ;
}
return $this -> query_result ;
}
/**
* Build LIMIT query
*/
function _sql_query_limit ( $query , $total , $offset = 0 , $cache_ttl = 0 )
{
$this -> query_result = false ;
2010-10-25 15:50:09 +02:00
// total == 0 means all results - not zero results
if ( $offset == 0 && $total !== 0 )
2010-02-11 00:02:51 +00:00
{
if ( strpos ( $query , " SELECT " ) === false )
{
$query = " TOP { $total } " . $query ;
}
else
{
$query = preg_replace ( '/SELECT(\s*DISTINCT)?/Dsi' , 'SELECT$1 TOP ' . $total , $query );
}
}
2010-10-25 15:50:09 +02:00
else if ( $offset > 0 )
2010-02-11 00:02:51 +00:00
{
$query = preg_replace ( '/SELECT(\s*DISTINCT)?/Dsi' , 'SELECT$1 TOP(10000000) ' , $query );
$query = ' SELECT *
FROM ( SELECT sub2 .* , ROW_NUMBER () OVER ( ORDER BY sub2 . line2 ) AS line3
2010-10-25 15:50:09 +02:00
FROM ( SELECT 1 AS line2 , sub1 .* FROM ( ' . $query . ' ) AS sub1 ) as sub2 ) AS sub3 ' ;
if ( $total > 0 )
{
$query .= ' WHERE line3 BETWEEN ' . ( $offset + 1 ) . ' AND ' . ( $offset + $total );
}
else
{
$query .= ' WHERE line3 > ' . $offset ;
}
2010-02-11 00:02:51 +00:00
}
$result = $this -> sql_query ( $query , $cache_ttl );
return $result ;
}
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
function sql_affectedrows ()
{
2013-06-20 19:16:21 +05:30
return ( $this -> db_connect_id ) ? @ sqlsrv_rows_affected ( $this -> query_result ) : false ;
2010-02-11 00:02:51 +00:00
}
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
function sql_fetchrow ( $query_id = false )
{
global $cache ;
if ( $query_id === false )
{
$query_id = $this -> query_result ;
}
2013-06-20 19:16:21 +05:30
if ( $cache && $cache -> sql_exists ( $query_id ))
2010-02-11 00:02:51 +00:00
{
return $cache -> sql_fetchrow ( $query_id );
}
if ( $query_id === false )
{
return false ;
}
$row = @ sqlsrv_fetch_array ( $query_id , SQLSRV_FETCH_ASSOC );
if ( $row )
{
foreach ( $row as $key => $value )
{
2013-10-28 22:27:25 +01:00
$row [ $key ] = ( $value === ' ' || $value === null ) ? '' : $value ;
2010-02-11 00:02:51 +00:00
}
2010-10-25 19:22:57 +02:00
// remove helper values from LIMIT queries
if ( isset ( $row [ 'line2' ]))
{
unset ( $row [ 'line2' ], $row [ 'line3' ]);
}
2010-02-11 00:02:51 +00:00
}
2012-07-17 12:08:13 -05:00
return ( sizeof ( $row )) ? $row : false ;
2010-02-11 00:02:51 +00:00
}
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
function sql_nextid ()
{
$result_id = @ sqlsrv_query ( $this -> db_connect_id , 'SELECT @@IDENTITY' );
if ( $result_id !== false )
{
$row = @ sqlsrv_fetch_array ( $result_id );
$id = $row [ 0 ];
@ sqlsrv_free_stmt ( $result_id );
return $id ;
}
else
{
return false ;
}
}
/**
2014-03-17 13:18:05 +01:00
* { @ inheritDoc }
2010-02-11 00:02:51 +00:00
*/
function sql_freeresult ( $query_id = false )
{
global $cache ;
if ( $query_id === false )
{
$query_id = $this -> query_result ;
}
2013-10-14 16:37:23 -05:00
if ( $cache && ! is_object ( $query_id ) && $cache -> sql_exists ( $query_id ))
2010-02-11 00:02:51 +00:00
{
return $cache -> sql_freeresult ( $query_id );
}
2013-06-20 19:16:21 +05:30
if ( isset ( $this -> open_queries [( int ) $query_id ]))
2010-02-11 00:02:51 +00:00
{
2013-06-20 19:16:21 +05:30
unset ( $this -> open_queries [( int ) $query_id ]);
2010-02-11 00:02:51 +00:00
return @ sqlsrv_free_stmt ( $query_id );
}
2013-10-14 16:37:23 -05:00
2010-02-11 00:02:51 +00:00
return false ;
}
/**
* return sql error array
* @ access private
*/
function _sql_error ()
{
2012-12-04 16:12:31 -05:00
if ( function_exists ( 'sqlsrv_errors' ))
2010-02-11 00:02:51 +00:00
{
2012-12-04 16:12:31 -05:00
$errors = @ sqlsrv_errors ( SQLSRV_ERR_ERRORS );
$error_message = '' ;
$code = 0 ;
if ( $errors != null )
2010-02-11 00:02:51 +00:00
{
2012-12-04 16:12:31 -05:00
foreach ( $errors as $error )
{
2012-12-04 21:22:33 -05:00
$error_message .= " SQLSTATE: " . $error [ 'SQLSTATE' ] . " \n " ;
$error_message .= " code: " . $error [ 'code' ] . " \n " ;
2012-12-04 16:12:31 -05:00
$code = $error [ 'code' ];
2012-12-04 21:22:33 -05:00
$error_message .= " message: " . $error [ 'message' ] . " \n " ;
2012-12-04 16:12:31 -05:00
}
$this -> last_error_result = $error_message ;
$error = $this -> last_error_result ;
2010-02-11 00:02:51 +00:00
}
2012-12-04 16:12:31 -05:00
else
2010-02-11 00:02:51 +00:00
{
2012-12-04 16:12:31 -05:00
$error = ( isset ( $this -> last_error_result ) && $this -> last_error_result ) ? $this -> last_error_result : array ();
2010-02-11 00:02:51 +00:00
}
2012-12-04 16:12:31 -05:00
2012-12-04 21:32:02 -05:00
$error = array (
2012-12-04 16:12:31 -05:00
'message' => $error ,
'code' => $code ,
);
2010-02-11 00:02:51 +00:00
}
else
{
2012-12-04 21:32:02 -05:00
$error = array (
2012-12-04 16:12:31 -05:00
'message' => $this -> connect_error ,
'code' => '' ,
);
2010-02-11 00:02:51 +00:00
}
2010-04-08 00:04:47 +02:00
2012-12-04 21:32:02 -05:00
return $error ;
2010-02-11 00:02:51 +00:00
}
/**
* Close sql connection
* @ access private
*/
function _sql_close ()
{
return @ sqlsrv_close ( $this -> db_connect_id );
}
/**
* Build db - specific report
* @ access private
*/
function _sql_report ( $mode , $query = '' )
{
switch ( $mode )
{
case 'start' :
$html_table = false ;
@ sqlsrv_query ( $this -> db_connect_id , 'SET SHOWPLAN_TEXT ON;' );
if ( $result = @ sqlsrv_query ( $this -> db_connect_id , $query ))
{
@ sqlsrv_next_result ( $result );
while ( $row = @ sqlsrv_fetch_array ( $result ))
{
$html_table = $this -> sql_report ( 'add_select_row' , $query , $html_table , $row );
}
}
@ sqlsrv_query ( $this -> db_connect_id , 'SET SHOWPLAN_TEXT OFF;' );
@ sqlsrv_free_stmt ( $result );
if ( $html_table )
{
$this -> html_hold .= '</table>' ;
}
break ;
case 'fromcache' :
$endtime = explode ( ' ' , microtime ());
$endtime = $endtime [ 0 ] + $endtime [ 1 ];
$result = @ sqlsrv_query ( $this -> db_connect_id , $query );
while ( $void = @ sqlsrv_fetch_array ( $result ))
{
// Take the time spent on parsing rows into account
}
@ sqlsrv_free_stmt ( $result );
$splittime = explode ( ' ' , microtime ());
$splittime = $splittime [ 0 ] + $splittime [ 1 ];
$this -> sql_report ( 'record_fromcache' , $query , $endtime , $splittime );
break ;
}
}
/**
* Utility method used to retrieve number of rows
* Emulates mysql_num_rows
* Used in acp_database . php -> write_data_mssqlnative ()
2010-10-25 03:27:38 +02:00
* Requires a static or keyset cursor to be definde via
* mssqlnative_set_query_options ()
2010-02-11 00:02:51 +00:00
*/
function mssqlnative_num_rows ( $res )
{
if ( $res !== false )
{
2010-10-25 03:27:38 +02:00
return sqlsrv_num_rows ( $res );
2010-02-11 00:02:51 +00:00
}
else
{
return false ;
}
}
2011-03-12 16:49:25 +01:00
2010-10-25 03:27:38 +02:00
/**
* Allows setting mssqlnative specific query options passed to sqlsrv_query as 4 th parameter .
*/
function mssqlnative_set_query_options ( $options )
{
$this -> query_options = $options ;
}
2010-02-11 00:02:51 +00:00
}