2006-04-24 16:24:57 +00:00
< ? php
/* SVN FILE: $Id$ */
/**
* MS SQL layer for DBO
*
* Long description for file
*
* PHP versions 4 and 5
*
2007-02-02 10:39:45 +00:00
* CakePHP ( tm ) : Rapid Development Framework < http :// www . cakephp . org />
2008-01-01 22:18:17 +00:00
* Copyright 2005 - 2008 , Cake Software Foundation , Inc .
2006-05-26 05:29:17 +00:00
* 1785 E . Sahara Avenue , Suite 490 - 204
* Las Vegas , Nevada 89104
2006-04-24 16:24:57 +00:00
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
*
* @ filesource
2008-01-01 22:18:17 +00:00
* @ copyright Copyright 2005 - 2008 , Cake Software Foundation , Inc .
2007-02-02 10:39:45 +00:00
* @ link http :// www . cakefoundation . org / projects / info / cakephp CakePHP ( tm ) Project
2006-05-26 05:29:17 +00:00
* @ package cake
2006-12-01 02:34:56 +00:00
* @ subpackage cake . cake . libs . model . datasources . dbo
2007-02-02 10:39:45 +00:00
* @ since CakePHP ( tm ) v 0.10 . 5.1790
2006-05-26 05:29:17 +00:00
* @ version $Revision $
* @ modifiedby $LastChangedBy $
* @ lastmodified $Date $
* @ license http :// www . opensource . org / licenses / mit - license . php The MIT License
2006-04-24 16:24:57 +00:00
*/
/**
* Short description for class .
*
* Long description for class
*
2006-05-26 05:29:17 +00:00
* @ package cake
2006-12-01 02:34:56 +00:00
* @ subpackage cake . cake . libs . model . datasources . dbo
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
class DboMssql extends DboSource {
2006-04-24 16:24:57 +00:00
/**
2007-03-28 16:39:15 +00:00
* Driver description
2006-04-24 16:24:57 +00:00
*
2007-03-28 16:39:15 +00:00
* @ var string
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
var $description = " MS SQL DBO Driver " ;
2006-04-24 16:24:57 +00:00
/**
2007-03-28 16:39:15 +00:00
* Starting quote character for quoted identifiers
2006-04-24 16:24:57 +00:00
*
2007-03-28 16:39:15 +00:00
* @ var string
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
var $startQuote = " [ " ;
2006-04-24 16:24:57 +00:00
/**
2007-03-28 16:39:15 +00:00
* Ending quote character for quoted identifiers
2006-04-24 16:24:57 +00:00
*
2007-03-28 16:39:15 +00:00
* @ var string
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
var $endQuote = " ] " ;
2008-05-03 14:15:47 +00:00
/**
2006-10-20 02:32:50 +00:00
* Creates a map between field aliases and numeric indexes . Workaround for the
* SQL Server driver ' s 30 - character column name limitation .
*
* @ var array
*/
var $__fieldMappings = array ();
2006-04-24 16:24:57 +00:00
/**
* Base configuration settings for MS SQL driver
*
* @ var array
*/
2006-10-20 02:32:50 +00:00
var $_baseConfig = array (
'persistent' => true ,
'host' => 'localhost' ,
'login' => 'root' ,
'password' => '' ,
'database' => 'cake' ,
'port' => '1433' ,
);
2006-04-24 16:24:57 +00:00
/**
* MS SQL column definition
*
* @ var array
*/
2006-10-20 02:32:50 +00:00
var $columns = array (
2008-01-10 07:02:33 +00:00
'primary_key' => array ( 'name' => 'IDENTITY (1, 1) NOT NULL' ),
2007-03-28 16:39:15 +00:00
'string' => array ( 'name' => 'varchar' , 'limit' => '255' ),
2006-10-20 02:32:50 +00:00
'text' => array ( 'name' => 'text' ),
2007-03-29 02:21:50 +00:00
'integer' => array ( 'name' => 'int' , 'formatter' => 'intval' ),
2008-01-10 07:02:33 +00:00
'float' => array ( 'name' => 'numeric' , 'formatter' => 'floatval' ),
2007-03-28 16:39:15 +00:00
'datetime' => array ( 'name' => 'datetime' , 'format' => 'Y-m-d H:i:s' , 'formatter' => 'date' ),
'timestamp' => array ( 'name' => 'timestamp' , 'format' => 'Y-m-d H:i:s' , 'formatter' => 'date' ),
'time' => array ( 'name' => 'datetime' , 'format' => 'H:i:s' , 'formatter' => 'date' ),
'date' => array ( 'name' => 'datetime' , 'format' => 'Y-m-d' , 'formatter' => 'date' ),
2006-10-20 02:32:50 +00:00
'binary' => array ( 'name' => 'image' ),
'boolean' => array ( 'name' => 'bit' )
);
2006-04-24 16:24:57 +00:00
/**
* MS SQL DBO driver constructor ; sets SQL Server error reporting defaults
*
* @ param array $config Configuration data from app / config / databases . php
2007-10-22 16:09:35 +00:00
* @ return boolean True if connected successfully , false on error
2006-04-24 16:24:57 +00:00
*/
2007-10-04 05:04:44 +00:00
function __construct ( $config , $autoConnect = true ) {
if ( $autoConnect ) {
if ( ! function_exists ( 'mssql_min_message_severity' )) {
trigger_error ( " PHP SQL Server interface is not installed, cannot continue. For troubleshooting information, see http://php.net/mssql/ " , E_USER_WARNING );
}
mssql_min_message_severity ( 15 );
mssql_min_error_severity ( 2 );
2007-03-28 16:39:15 +00:00
}
2007-10-04 05:04:44 +00:00
return parent :: __construct ( $config , $autoConnect );
2006-05-26 05:29:17 +00:00
}
2006-04-24 16:24:57 +00:00
/**
* Connects to the database using options in the given configuration array .
*
2007-10-22 16:09:35 +00:00
* @ return boolean True if the database could be connected , else false
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
function connect () {
$config = $this -> config ;
2006-08-06 22:51:59 +00:00
$os = env ( 'OS' );
if ( ! empty ( $os ) && strpos ( $os , 'Windows' ) !== false ) {
$sep = ',' ;
} else {
$sep = ':' ;
}
2006-05-26 05:29:17 +00:00
$this -> connected = false ;
if ( is_numeric ( $config [ 'port' ])) {
2006-08-06 22:51:59 +00:00
$port = $sep . $config [ 'port' ]; // Port number
2006-07-13 14:55:48 +00:00
} elseif ( $config [ 'port' ] === null ) {
$port = '' ; // No port - SQL Server 2005
2006-05-26 05:29:17 +00:00
} else {
2006-07-13 14:55:48 +00:00
$port = '\\' . $config [ 'port' ]; // Named pipe
2006-05-26 05:29:17 +00:00
}
2007-11-30 22:23:57 +00:00
2008-01-10 07:02:33 +00:00
if ( ! $config [ 'persistent' ]) {
$this -> connection = mssql_connect ( $config [ 'host' ] . $port , $config [ 'login' ], $config [ 'password' ], true );
2007-11-30 22:23:57 +00:00
} else {
2008-01-10 07:02:33 +00:00
$this -> connection = mssql_pconnect ( $config [ 'host' ] . $port , $config [ 'login' ], $config [ 'password' ]);
2007-11-30 22:23:57 +00:00
}
2006-05-26 05:29:17 +00:00
if ( mssql_select_db ( $config [ 'database' ], $this -> connection )) {
2008-05-03 14:15:47 +00:00
$this -> _execute ( " SET DATEFORMAT ymd " );
2006-05-26 05:29:17 +00:00
$this -> connected = true ;
}
2008-01-10 07:02:33 +00:00
return $this -> connected ;
2006-05-26 05:29:17 +00:00
}
2006-04-24 16:24:57 +00:00
/**
* Disconnects from database .
*
2007-10-22 16:09:35 +00:00
* @ return boolean True if the database could be disconnected , else false
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
function disconnect () {
2007-02-18 13:17:28 +00:00
@ mssql_free_result ( $this -> results );
$this -> connected = !@ mssql_close ( $this -> connection );
return ! $this -> connected ;
2006-05-26 05:29:17 +00:00
}
2006-04-24 16:24:57 +00:00
/**
* Executes given SQL statement .
*
* @ param string $sql SQL statement
* @ return resource Result resource identifier
* @ access protected
*/
2006-05-26 05:29:17 +00:00
function _execute ( $sql ) {
return mssql_query ( $sql , $this -> connection );
}
2006-04-24 16:24:57 +00:00
/**
* Returns an array of sources ( tables ) in the database .
*
* @ return array Array of tablenames in the database
*/
2006-05-26 05:29:17 +00:00
function listSources () {
2007-03-28 16:39:15 +00:00
$cache = parent :: listSources ();
2006-05-26 05:29:17 +00:00
if ( $cache != null ) {
return $cache ;
}
$result = $this -> fetchAll ( 'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES' );
if ( ! $result || empty ( $result )) {
return array ();
} else {
2007-03-28 16:39:15 +00:00
$tables = array ();
2006-05-26 05:29:17 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $result as $table ) {
2006-05-26 05:29:17 +00:00
$tables [] = $table [ 0 ][ 'TABLE_NAME' ];
}
parent :: listSources ( $tables );
return $tables ;
}
}
2006-04-24 16:24:57 +00:00
/**
* Returns an array of the fields in given table name .
*
2006-04-27 10:04:08 +00:00
* @ param Model $model Model object to describe
2006-04-24 16:24:57 +00:00
* @ return array Fields in table . Keys are name and type
*/
2006-05-26 05:29:17 +00:00
function describe ( & $model ) {
$cache = parent :: describe ( $model );
if ( $cache != null ) {
return $cache ;
}
$fields = false ;
2006-09-28 22:41:50 +00:00
$cols = $this -> fetchAll ( " SELECT COLUMN_NAME as Field, DATA_TYPE as Type, COL_LENGTH(' " . $this -> fullTableName ( $model , false ) . " ', COLUMN_NAME) as Length, IS_NULLABLE As [Null], COLUMN_DEFAULT as [Default], COLUMNPROPERTY(OBJECT_ID(' " . $this -> fullTableName ( $model , false ) . " '), COLUMN_NAME, 'IsIdentity') as [Key], NUMERIC_SCALE as Size FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ' " . $this -> fullTableName ( $model , false ) . " ' " , false );
2006-05-26 05:29:17 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $cols as $column ) {
2008-05-11 18:53:54 +00:00
$field = $column [ 0 ][ 'Field' ];
$fields [ $field ] = array (
2006-12-28 03:41:33 +00:00
'type' => $this -> column ( $column [ 0 ][ 'Type' ]),
2007-12-08 06:08:03 +00:00
'null' => ( strtoupper ( $column [ 0 ][ 'Null' ]) == 'YES' ),
2008-05-11 18:53:54 +00:00
'default' => preg_replace ( " /^ \ ('?([^']*)?'? \ ) $ / " , " $ 1 " , $column [ 0 ][ 'Default' ]),
2007-12-26 22:44:41 +00:00
'length' => intval ( $column [ 0 ][ 'Length' ]),
2008-05-11 18:53:54 +00:00
'key' => ( $column [ 0 ][ 'Key' ] == '1' )
2006-07-07 19:49:13 +00:00
);
2008-05-11 18:53:54 +00:00
if ( in_array ( $fields [ $field ][ 'default' ], array ( 'null' , '(null)' ))) {
$fields [ $field ][ 'default' ] = null ;
}
if ( $fields [ $field ][ 'key' ] && $fields [ $field ][ 'type' ] == 'integer' ) {
$fields [ $field ][ 'length' ] = 11 ;
} elseif ( ! $fields [ $field ][ 'key' ]) {
unset ( $fields [ $field ][ 'key' ]);
}
if ( in_array ( $fields [ $field ][ 'type' ], array ( 'date' , 'time' , 'datetime' , 'timestamp' ))) {
$fields [ $field ][ 'length' ] = null ;
2008-04-18 06:27:58 +00:00
}
2006-05-26 05:29:17 +00:00
}
2006-09-28 22:41:50 +00:00
$this -> __cacheDescription ( $this -> fullTableName ( $model , false ), $fields );
2006-05-26 05:29:17 +00:00
return $fields ;
}
2006-04-24 16:24:57 +00:00
/**
* Returns a quoted and escaped string of $data for use in an SQL statement .
*
* @ param string $data String to be prepared for use in an SQL statement
* @ param string $column The column into which this data will be inserted
2007-10-22 16:54:36 +00:00
* @ param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
2006-04-24 16:24:57 +00:00
* @ return string Quoted and escaped data
*/
2006-05-26 05:29:17 +00:00
function value ( $data , $column = null , $safe = false ) {
$parent = parent :: value ( $data , $column , $safe );
if ( $parent != null ) {
return $parent ;
}
if ( $data === null ) {
return 'NULL' ;
}
2006-07-13 14:55:48 +00:00
if ( $data === '' ) {
2006-05-26 05:29:17 +00:00
return " '' " ;
}
switch ( $column ) {
case 'boolean' :
$data = $this -> boolean (( bool ) $data );
break ;
default :
2007-02-01 03:38:27 +00:00
if ( get_magic_quotes_gpc ()) {
2007-12-08 06:08:03 +00:00
$data = stripslashes ( str_replace ( " ' " , " '' " , $data ));
2007-02-01 03:38:27 +00:00
} else {
2007-12-08 06:08:03 +00:00
$data = str_replace ( " ' " , " '' " , $data );
2007-02-01 03:38:27 +00:00
}
2006-05-26 05:29:17 +00:00
break ;
}
2007-10-04 05:04:44 +00:00
if ( in_array ( $column , array ( 'integer' , 'float' )) && is_numeric ( $data )) {
return $data ;
}
2006-05-26 05:29:17 +00:00
return " ' " . $data . " ' " ;
}
2006-04-24 16:24:57 +00:00
/**
* Generates the fields list of an SQL query .
*
* @ param Model $model
* @ param string $alias Alias tablename
* @ param mixed $fields
* @ return array
*/
2007-03-28 16:39:15 +00:00
function fields ( & $model , $alias = null , $fields = array (), $quote = true ) {
if ( empty ( $alias )) {
2007-10-27 01:32:17 +00:00
$alias = $model -> alias ;
2006-05-26 05:29:17 +00:00
}
2007-03-28 16:39:15 +00:00
$fields = parent :: fields ( $model , $alias , $fields , false );
2006-05-26 05:29:17 +00:00
$count = count ( $fields );
if ( $count >= 1 && $fields [ 0 ] != '*' && strpos ( $fields [ 0 ], 'COUNT(*)' ) === false ) {
2007-06-20 06:15:35 +00:00
for ( $i = 0 ; $i < $count ; $i ++ ) {
2008-04-18 06:27:58 +00:00
$prepend = '' ;
if ( strpos ( $fields [ $i ], 'DISTINCT' ) !== false ) {
$prepend = 'DISTINCT ' ;
$fields [ $i ] = trim ( str_replace ( 'DISTINCT' , '' , $fields [ $i ]));
}
2006-10-20 02:32:50 +00:00
$fieldAlias = count ( $this -> __fieldMappings );
2006-05-26 05:29:17 +00:00
2008-05-03 14:15:47 +00:00
if ( ! preg_match ( '/\s+AS\s+/i' , $fields [ $i ])) {
if ( strpos ( $fields [ $i ], '.' ) === false ) {
$this -> __fieldMappings [ $alias . '__' . $fieldAlias ] = $alias . '.' . $fields [ $i ];
$fieldName = $this -> name ( $alias . '.' . $fields [ $i ]);
$fieldAlias = $this -> name ( $alias . '__' . $fieldAlias );
} else {
$build = explode ( '.' , $fields [ $i ]);
$this -> __fieldMappings [ $build [ 0 ] . '__' . $fieldAlias ] = $fields [ $i ];
$fieldName = $this -> name ( $build [ 0 ] . '.' . $build [ 1 ]);
$fieldAlias = $this -> name ( preg_replace ( " /^ \ [(.+) \ ] $ / " , " $ 1 " , $build [ 0 ]) . '__' . $fieldAlias );
}
if ( $model -> getColumnType ( $fields [ $i ]) == 'datetime' ) {
$fieldName = " CONVERT(VARCHAR(20), { $fieldName } , 20) " ;
}
$fields [ $i ] = " { $fieldName } AS { $fieldAlias } " ;
2006-05-26 05:29:17 +00:00
}
2008-04-18 06:27:58 +00:00
$fields [ $i ] = $prepend . $fields [ $i ];
2006-05-26 05:29:17 +00:00
}
}
return $fields ;
}
2006-04-24 16:24:57 +00:00
/**
* Begin a transaction
*
* @ param unknown_type $model
2007-10-22 16:09:35 +00:00
* @ return boolean True on success , false on fail
2006-04-24 16:24:57 +00:00
* ( i . e . if the database / model does not support transactions ) .
*/
2006-05-26 05:29:17 +00:00
function begin ( & $model ) {
2008-03-11 02:44:33 +00:00
if ( parent :: begin ( $model ) && $this -> execute ( 'BEGIN TRANSACTION' )) {
$this -> _transactionStarted = true ;
return true ;
2006-05-26 05:29:17 +00:00
}
return false ;
}
2008-05-11 18:53:54 +00:00
/**
* Generates and executes an SQL INSERT statement for given model , fields , and values .
* Removes Identity ( primary key ) column from update data before returning to parent , if
* value is empty .
*
* @ param Model $model
* @ param array $fields
* @ param array $values
* @ param mixed $conditions
* @ return array
*/
function create ( & $model , $fields = null , $values = null ) {
if ( ! empty ( $values )) {
$fields = array_combine ( $fields , $values );
}
if ( array_key_exists ( $model -> primaryKey , $fields )) {
if ( empty ( $fields [ $model -> primaryKey ])) {
unset ( $fields [ $model -> primaryKey ]);
} else {
$this -> _execute ( " SET IDENTITY_INSERT " . $this -> fullTableName ( $model ) . " ON " );
}
}
$result = parent :: create ( $model , array_keys ( $fields ), array_values ( $fields ));
if ( array_key_exists ( $model -> primaryKey , $fields ) && ! empty ( $fields [ $model -> primaryKey ])) {
$this -> _execute ( " SET IDENTITY_INSERT " . $this -> fullTableName ( $model ) . " OFF " );
}
return $result ;
}
2006-04-27 10:04:08 +00:00
/**
2008-01-11 06:45:00 +00:00
* Generates and executes an SQL UPDATE statement for given model , fields , and values .
* Removes Identity ( primary key ) column from update data before returning to parent .
2006-04-27 10:04:08 +00:00
*
* @ param Model $model
* @ param array $fields
* @ param array $values
2008-01-11 06:45:00 +00:00
* @ param mixed $conditions
2006-04-27 10:04:08 +00:00
* @ return array
*/
2008-01-11 06:45:00 +00:00
function update ( & $model , $fields = array (), $values = null , $conditions = null ) {
2008-05-11 18:53:54 +00:00
if ( ! empty ( $values )) {
$fields = array_combine ( $fields , $values );
}
if ( isset ( $fields [ $model -> primaryKey ])) {
unset ( $fields [ $model -> primaryKey ]);
2006-05-26 05:29:17 +00:00
}
2008-05-11 18:53:54 +00:00
return parent :: update ( $model , array_keys ( $fields ), array_values ( $fields ), $conditions );
2006-05-26 05:29:17 +00:00
}
2006-04-24 16:24:57 +00:00
/**
* Returns a formatted error message from previous database operation .
*
* @ return string Error message with error number
*/
2006-05-26 05:29:17 +00:00
function lastError () {
$error = mssql_get_last_message ( $this -> connection );
if ( $error ) {
2007-12-08 06:08:03 +00:00
if ( strpos ( strtolower ( $error ), 'changed database' ) === false ) {
2006-05-26 05:29:17 +00:00
return $error ;
}
}
return null ;
}
2006-04-24 16:24:57 +00:00
/**
* Returns number of affected rows in previous database operation . If no previous operation exists ,
* this returns false .
*
2007-10-22 16:54:36 +00:00
* @ return integer Number of affected rows
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
function lastAffected () {
if ( $this -> _result ) {
return mssql_rows_affected ( $this -> connection );
}
return null ;
}
2006-04-24 16:24:57 +00:00
/**
* Returns number of rows in previous resultset . If no previous resultset exists ,
* this returns false .
*
2007-10-22 16:54:36 +00:00
* @ return integer Number of rows in resultset
2006-04-24 16:24:57 +00:00
*/
2006-05-26 05:29:17 +00:00
function lastNumRows () {
if ( $this -> _result ) {
return @ mssql_num_rows ( $this -> _result );
}
return null ;
}
2006-04-24 16:24:57 +00:00
/**
* Returns the ID generated from the previous INSERT operation .
*
* @ param unknown_type $source
* @ return in
*/
2006-05-26 05:29:17 +00:00
function lastInsertId ( $source = null ) {
2007-05-24 05:33:55 +00:00
$id = $this -> fetchRow ( 'SELECT SCOPE_IDENTITY() AS insertID' , false );
return $id [ 0 ][ 'insertID' ];
2006-05-26 05:29:17 +00:00
}
2006-04-24 16:24:57 +00:00
/**
* Returns a limit statement in the correct format for the particular database .
*
2007-10-22 16:11:12 +00:00
* @ param integer $limit Limit of results returned
* @ param integer $offset Offset from which to start results
2006-04-24 16:24:57 +00:00
* @ return string SQL limit / offset statement
*/
2006-05-26 05:29:17 +00:00
function limit ( $limit , $offset = null ) {
if ( $limit ) {
$rt = '' ;
if ( ! strpos ( strtolower ( $limit ), 'top' ) || strpos ( strtolower ( $limit ), 'top' ) === 0 ) {
$rt = ' TOP' ;
}
$rt .= ' ' . $limit ;
2007-03-28 16:39:15 +00:00
if ( is_int ( $offset ) && $offset > 0 ) {
$rt .= ' OFFSET ' . $offset ;
}
2006-05-26 05:29:17 +00:00
return $rt ;
}
return null ;
}
2006-04-24 16:24:57 +00:00
/**
* Converts database - layer column types to basic types
*
* @ param string $real Real database - layer column type ( i . e . " varchar(255) " )
* @ return string Abstract column type ( i . e . " string " )
*/
2006-05-26 05:29:17 +00:00
function column ( $real ) {
if ( is_array ( $real )) {
$col = $real [ 'name' ];
if ( isset ( $real [ 'limit' ])) {
$col .= '(' . $real [ 'limit' ] . ')' ;
}
return $col ;
}
2007-12-08 06:08:03 +00:00
$col = str_replace ( ')' , '' , $real );
2007-02-02 20:14:03 +00:00
$limit = null ;
@ list ( $col , $limit ) = explode ( '(' , $col );
2006-05-26 05:29:17 +00:00
if ( in_array ( $col , array ( 'date' , 'time' , 'datetime' , 'timestamp' ))) {
return $col ;
}
if ( $col == 'bit' ) {
return 'boolean' ;
}
2008-01-10 07:02:33 +00:00
if ( strpos ( $col , 'int' ) !== false ) {
2006-05-26 05:29:17 +00:00
return 'integer' ;
}
if ( strpos ( $col , 'char' ) !== false ) {
return 'string' ;
}
if ( strpos ( $col , 'text' ) !== false ) {
return 'text' ;
}
if ( strpos ( $col , 'binary' ) !== false || $col == 'image' ) {
return 'binary' ;
}
2008-01-10 07:02:33 +00:00
if ( in_array ( $col , array ( 'float' , 'real' , 'decimal' , 'numeric' ))) {
2006-05-26 05:29:17 +00:00
return 'float' ;
}
return 'text' ;
}
2006-04-24 16:24:57 +00:00
/**
* Enter description here ...
*
* @ param unknown_type $results
*/
2006-05-26 05:29:17 +00:00
function resultSet ( & $results ) {
$this -> results =& $results ;
$this -> map = array ();
$num_fields = mssql_num_fields ( $results );
$index = 0 ;
$j = 0 ;
2007-06-20 06:15:35 +00:00
while ( $j < $num_fields ) {
2006-10-14 17:21:28 +00:00
$column = mssql_field_name ( $results , $j );
2006-05-26 05:29:17 +00:00
2006-10-14 17:21:28 +00:00
if ( strpos ( $column , '__' )) {
2007-04-14 23:34:08 +00:00
if ( isset ( $this -> __fieldMappings [ $column ]) && strpos ( $this -> __fieldMappings [ $column ], '.' )) {
$map = explode ( '.' , $this -> __fieldMappings [ $column ]);
2007-06-20 06:15:35 +00:00
} elseif ( isset ( $this -> __fieldMappings [ $column ])) {
2007-04-14 23:34:08 +00:00
$map = array ( 0 , $this -> __fieldMappings [ $column ]);
} else {
2007-05-24 05:33:55 +00:00
$map = array ( 0 , $column );
2006-10-20 02:32:50 +00:00
}
$this -> map [ $index ++ ] = $map ;
2006-05-26 05:29:17 +00:00
} else {
2006-10-14 17:21:28 +00:00
$this -> map [ $index ++ ] = array ( 0 , $column );
2006-05-26 05:29:17 +00:00
}
$j ++ ;
}
}
2007-03-28 16:39:15 +00:00
/**
2007-05-24 05:33:55 +00:00
* Builds final SQL statement
2007-03-28 16:39:15 +00:00
*
2007-12-25 10:37:08 +00:00
* @ param string $type Query type
2007-03-28 16:39:15 +00:00
* @ param array $data Query data
* @ return string
*/
2007-12-25 10:37:08 +00:00
function renderStatement ( $type , $data ) {
if ( strtolower ( $type ) == 'select' ) {
2008-04-18 06:27:58 +00:00
extract ( $data );
2008-05-03 14:15:47 +00:00
$fields = trim ( $fields );
if ( strpos ( $limit , 'TOP' ) !== false && strpos ( $fields , 'DISTINCT ' ) === 0 ) {
$limit = 'DISTINCT ' . trim ( $limit );
$fields = substr ( $fields , 9 );
}
2007-12-25 10:37:08 +00:00
if ( preg_match ( '/offset\s+([0-9]+)/i' , $limit , $offset )) {
$limit = preg_replace ( '/\s*offset.*$/i' , '' , $limit );
preg_match ( '/top\s+([0-9]+)/i' , $limit , $limitVal );
$offset = intval ( $offset [ 1 ]) + intval ( $limitVal [ 1 ]);
$rOrder = $this -> __switchSort ( $order );
list ( $order2 , $rOrder ) = array ( $this -> __mapFields ( $order ), $this -> __mapFields ( $rOrder ));
return " SELECT * FROM (SELECT { $limit } * FROM (SELECT TOP { $offset } { $fields } FROM { $table } { $alias } { $joins } { $conditions } { $order } ) AS Set1 { $rOrder } ) AS Set2 { $order2 } " ;
} else {
return " SELECT { $limit } { $fields } FROM { $table } { $alias } { $joins } { $conditions } { $order } " ;
}
2007-03-28 16:39:15 +00:00
} else {
2007-12-25 10:37:08 +00:00
return parent :: renderStatement ( $type , $data );
2007-03-28 16:39:15 +00:00
}
}
/**
2007-05-24 05:33:55 +00:00
* Reverses the sort direction of ORDER statements to get paging offsets to work correctly
2007-03-28 16:39:15 +00:00
*
* @ param string $order
* @ return string
* @ access private
*/
function __switchSort ( $order ) {
$order = preg_replace ( '/\s+ASC/i' , '__tmp_asc__' , $order );
$order = preg_replace ( '/\s+DESC/i' , ' ASC' , $order );
return preg_replace ( '/__tmp_asc__/' , ' DESC' , $order );
}
2007-04-14 23:34:08 +00:00
/**
* Translates field names used for filtering and sorting to shortened names using the field map
*
* @ param string $sql A snippet of SQL representing an ORDER or WHERE statement
* @ return string The value of $sql with field names replaced
* @ access private
*/
function __mapFields ( $sql ) {
if ( empty ( $sql ) || empty ( $this -> __fieldMappings )) {
return $sql ;
}
foreach ( $this -> __fieldMappings as $key => $val ) {
$sql = preg_replace ( '/' . preg_quote ( $val ) . '/' , $this -> name ( $key ), $sql );
$sql = preg_replace ( '/' . preg_quote ( $this -> name ( $val )) . '/' , $this -> name ( $key ), $sql );
}
return $sql ;
}
2006-10-20 02:32:50 +00:00
/**
* Returns an array of all result rows for a given SQL query .
* Returns false if no rows matched .
*
* @ param string $sql SQL statement
2007-10-22 16:54:36 +00:00
* @ param boolean $cache Enables returning / storing cached query results
2006-10-20 02:32:50 +00:00
* @ return array Array of resultset rows , or false if no rows matched
*/
2007-02-02 20:14:03 +00:00
function read ( & $model , $queryData = array (), $recursive = null ) {
$results = parent :: read ( $model , $queryData , $recursive );
2006-10-20 02:32:50 +00:00
$this -> __fieldMappings = array ();
2007-04-14 23:34:08 +00:00
$this -> __fieldMapBase = null ;
2006-10-20 02:32:50 +00:00
return $results ;
}
2006-04-24 16:24:57 +00:00
/**
* Fetches the next row from the current result set
*
* @ return unknown
*/
2006-05-26 05:29:17 +00:00
function fetchResult () {
if ( $row = mssql_fetch_row ( $this -> results )) {
$resultRow = array ();
$i = 0 ;
2007-06-20 06:15:35 +00:00
foreach ( $row as $index => $field ) {
2006-05-26 05:29:17 +00:00
list ( $table , $column ) = $this -> map [ $index ];
2006-10-14 17:21:28 +00:00
$resultRow [ $table ][ $column ] = $row [ $index ];
2006-05-26 05:29:17 +00:00
$i ++ ;
}
return $resultRow ;
} else {
return false ;
}
}
2008-04-18 06:27:58 +00:00
/**
* Generate a database - native column schema string
*
* @ param array $column An array structured like the following : array ( 'name' => 'value' , 'type' => 'value' [, options ]),
* where options can be 'default' , 'length' , or 'key' .
* @ return string
*/
function buildColumn ( $column ) {
$result = preg_replace ( '/(int|integer)\([0-9]+\)/i' , '$1' , parent :: buildColumn ( $column ));
2008-05-03 14:15:47 +00:00
$null = (
( isset ( $column [ 'null' ]) && $column [ 'null' ] == true ) ||
2008-05-11 18:53:54 +00:00
( array_key_exists ( 'default' , $column ) && $column [ 'default' ] === null ) ||
( array_keys ( $column ) == array ( 'type' , 'name' ))
2008-05-03 14:15:47 +00:00
);
2008-05-11 18:53:54 +00:00
$stringKey = ( isset ( $column [ 'key' ]) && $column [ 'key' ] == 'primary' && $column [ 'type' ] != 'integer' );
2008-05-03 14:15:47 +00:00
if ( $null ) {
2008-04-18 06:27:58 +00:00
$result .= " NULL " ;
}
return $result ;
}
2006-04-24 16:24:57 +00:00
}
2008-01-01 23:57:17 +00:00
2006-04-24 16:24:57 +00:00
?>