Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F5202
DatabaseMssql.php
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
•
bzimport
Nov 21 2014, 10:21 PM
2014-11-21 22:21:57 (UTC+0)
Size
21 KB
Referenced Files
None
Subscribers
None
DatabaseMssql.php
View Options
<?php
/**
* This script is the MSSQL Server database abstraction layer
*
* See maintenance/mssql/README for development notes and other specific information
* @ingroup Database
* @file
*/
/**
* @ingroup Database
*/
class
DatabaseMssql
extends
Database
{
var
$mAffectedRows
;
var
$mLastResult
;
var
$mLastError
;
var
$mLastErrorNo
;
var
$mDatabaseFile
;
var
$mLimitOffset
;
/**
* Constructor
*/
function
__construct
(
$server
=
false
,
$user
=
false
,
$password
=
false
,
$dbName
=
false
,
$failFunction
=
false
,
$flags
=
0
,
$tablePrefix
=
'get from global'
)
{
global
$wgOut
,
$wgDBprefix
,
$wgCommandLineMode
;
if
(!
isset
(
$wgOut
))
$wgOut
=
NULL
;
# Can't get a reference if it hasn't been set yet
$this
->
mOut
=&
$wgOut
;
$this
->
mFailFunction
=
$failFunction
;
$this
->
mFlags
=
$flags
;
if
(
$this
->
mFlags
&
DBO_DEFAULT
)
{
if
(
$wgCommandLineMode
)
{
$this
->
mFlags
&=
~
DBO_TRX
;
}
else
{
$this
->
mFlags
|=
DBO_TRX
;
}
}
/** Get the default table prefix*/
$this
->
mTablePrefix
=
$tablePrefix
==
'get from global'
?
$wgDBprefix
:
$tablePrefix
;
if
(
$server
)
$this
->
open
(
$server
,
$user
,
$password
,
$dbName
);
}
/**
* todo: check if these should be true like parent class
*/
function
implicitGroupby
()
{
return
false
;
}
function
implicitOrderby
()
{
return
false
;
}
function
cascadingDeletes
()
{
return
true
;
}
static
function
newFromParams
(
$server
,
$user
,
$password
,
$dbName
,
$failFunction
=
false
,
$flags
=
0
)
{
return
new
DatabaseMssql
(
$server
,
$user
,
$password
,
$dbName
,
$failFunction
,
$flags
);
}
/** Open an MSSQL database and return a resource handle to it
* NOTE: only $dbName is used, the other parameters are irrelevant for MSSQL databases
*/
function
open
(
$server
,
$user
,
$password
,
$dbName
)
{
wfProfileIn
(
__METHOD__
);
# Test for missing mysql.so
# First try to load it
if
(!@
extension_loaded
(
'mssql'
))
{
@
dl
(
'mssql.so'
);
}
# Fail now
# Otherwise we get a suppressed fatal error, which is very hard to track down
if
(!
function_exists
(
'mssql_connect'
))
{
throw
new
DBConnectionError
(
$this
,
"MSSQL functions missing, have you compiled PHP with the --with-mssql option?
\n
"
);
}
$this
->
close
();
$this
->
mServer
=
$server
;
$this
->
mUser
=
$user
;
$this
->
mPassword
=
$password
;
$this
->
mDBname
=
$dbName
;
wfProfileIn
(
"dbconnect-$server"
);
# Try to connect up to three times
# The kernel's default SYN retransmission period is far too slow for us,
# so we use a short timeout plus a manual retry.
$this
->
mConn
=
false
;
$max
=
3
;
for
(
$i
=
0
;
$i
<
$max
&&
!
$this
->
mConn
;
$i
++
)
{
if
(
$i
>
1
)
{
usleep
(
1000
);
}
if
(
$this
->
mFlags
&
DBO_PERSISTENT
)
{
@/**/
$this
->
mConn
=
mssql_pconnect
(
$server
,
$user
,
$password
);
}
else
{
# Create a new connection...
@/**/
$this
->
mConn
=
mssql_connect
(
$server
,
$user
,
$password
,
true
);
}
}
wfProfileOut
(
"dbconnect-$server"
);
if
(
$dbName
!=
''
)
{
if
(
$this
->
mConn
!==
false
)
{
$success
=
@/**/
mssql_select_db
(
$dbName
,
$this
->
mConn
);
if
(!
$success
)
{
$error
=
"Error selecting database $dbName on server {$this->mServer} "
.
"from client host "
.
wfHostname
()
.
"
\n
"
;
wfLogDBError
(
" Error selecting database $dbName on server {$this->mServer}
\n
"
);
wfDebug
(
$error
);
}
}
else
{
wfDebug
(
"DB connection error
\n
"
);
wfDebug
(
"Server: $server, User: $user, Password: "
.
substr
(
$password
,
0
,
3
).
"...
\n
"
);
$success
=
false
;
}
}
else
{
# Delay USE query
$success
=
(
bool
)
$this
->
mConn
;
}
if
(!
$success
)
$this
->
reportConnectionError
();
$this
->
mOpened
=
$success
;
wfProfileOut
(
__METHOD__
);
return
$success
;
}
/**
* Close an MSSQL database
*/
function
close
()
{
$this
->
mOpened
=
false
;
if
(
$this
->
mConn
)
{
if
(
$this
->
trxLevel
())
$this
->
commit
();
return
mssql_close
(
$this
->
mConn
);
}
else
return
true
;
}
/**
* Begin a transaction, committing any previously open transaction
*/
function
begin
(
$fname
=
'Database::begin'
)
{
$this
->
commit
();
$this
->
mTrxLevel
=
1
;
# Avoid recursion in Database::query
$this
->
query
(
'BEGIN TRANSACTION'
,
$fname
);
}
/**
* End a transaction
*/
function
commit
(
$fname
=
'Database::commit'
)
{
if
(
$this
->
mTrxLevel
)
$this
->
query
(
'COMMIT TRANSACTION'
,
$fname
);
$this
->
mTrxLevel
=
0
;
}
/**
* Rollback a transaction.
* No-op on non-transactional databases.
*/
function
rollback
(
$fname
=
'Database::rollback'
)
{
$this
->
query
(
'ROLLBACK TRANSACTION'
,
$fname
,
true
);
$this
->
mTrxLevel
=
0
;
}
/**
* - MSSQL doesn't seem to do buffered results
* - the transaction syntax is modified here to avoid having to replicate
* Database::query which uses BEGIN, COMMIT, ROLLBACK
*/
function
doQuery
(
$sql
)
{
$ret
=
mssql_query
(
$sql
,
$this
->
mConn
);
if
(
$ret
===
false
)
{
$err
=
mssql_get_last_message
();
if
(
$err
)
$this
->
mLastError
=
$err
;
$row
=
mssql_fetch_row
(
mssql_query
(
'select @@ERROR'
,
$this
->
mConn
));
if
(
$row
[
0
])
$this
->
mLastErrorNo
=
$row
[
0
];
}
else
$this
->
mLastErrorNo
=
false
;
return
$ret
;
}
/**
* Free a result object
*/
function
freeResult
(
$res
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
if
(
!@/**/
mssql_free_result
(
$res
)
)
{
throw
new
DBUnexpectedError
(
$this
,
"Unable to free MSSQL result"
);
}
}
/**
* Fetch the next row from the given result object, in object form.
* Fields can be retrieved with $row->fieldname, with fields acting like
* member variables.
*
* @param $res SQL result object as returned from Database::query(), etc.
* @return MySQL row object
* @throws DBUnexpectedError Thrown if the database returns an error
*/
function
fetchObject
(
$res
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
if
(
$this
->
mLimitOffset
)
{
@/**/
mssql_data_seek
(
$res
,
$this
->
mLimitOffset
);
$this
->
mLimitOffset
=
0
;
}
@/**/
$row
=
mssql_fetch_object
(
$res
);
if
(
$this
->
lastErrno
()
)
{
throw
new
DBUnexpectedError
(
$this
,
'Error in fetchObject(): '
.
htmlspecialchars
(
$this
->
lastError
()
)
);
}
return
$row
;
}
/**
* Fetch the next row from the given result object, in associative array
* form. Fields are retrieved with $row['fieldname'].
*
* @param $res SQL result object as returned from Database::query(), etc.
* @return MySQL row object
* @throws DBUnexpectedError Thrown if the database returns an error
*/
function
fetchRow
(
$res
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
if
(
$this
->
mLimitOffset
)
{
@/**/
mssql_data_seek
(
$res
,
$this
->
mLimitOffset
);
$this
->
mLimitOffset
=
0
;
}
@/**/
$row
=
mssql_fetch_array
(
$res
);
if
(
$this
->
lastErrno
()
)
{
throw
new
DBUnexpectedError
(
$this
,
'Error in fetchRow(): '
.
htmlspecialchars
(
$this
->
lastError
()
)
);
}
return
$row
;
}
/**
* Get the number of rows in a result object
*/
function
numRows
(
$res
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
@/**/
$n
=
mssql_num_rows
(
$res
);
if
(
$this
->
lastErrno
()
)
{
throw
new
DBUnexpectedError
(
$this
,
'Error in numRows(): '
.
htmlspecialchars
(
$this
->
lastError
()
)
);
}
return
$n
;
}
/**
* Get the number of fields in a result object
* See documentation for mysql_num_fields()
* @param $res SQL result object as returned from Database::query(), etc.
*/
function
numFields
(
$res
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
return
mssql_num_fields
(
$res
);
}
/**
* Get a field name in a result object
* See documentation for mysql_field_name():
* http://www.php.net/mysql_field_name
* @param $res SQL result object as returned from Database::query(), etc.
* @param $n Int
*/
function
fieldName
(
$res
,
$n
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
return
mssql_field_name
(
$res
,
$n
);
}
/**
* Get the inserted value of an auto-increment row
*
* The value inserted should be fetched from nextSequenceValue()
*
* Example:
* $id = $dbw->nextSequenceValue('page_page_id_seq');
* $dbw->insert('page',array('page_id' => $id));
* $id = $dbw->insertId();
*/
function
insertId
()
{
$row
=
mssql_fetch_row
(
mssql_query
(
'select SCOPE_IDENTITY()'
,
$this
->
mConn
));
return
$row
[
0
];
}
/**
* Change the position of the cursor in a result object
* See mysql_data_seek()
* @param $res SQL result object as returned from Database::query(), etc.
* @param $row Database row
*/
function
dataSeek
(
$res
,
$row
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
return
mssql_data_seek
(
$res
,
$row
);
}
/**
* Get the last error number
*/
function
lastErrno
()
{
return
$this
->
mLastErrorNo
;
}
/**
* Get a description of the last error
*/
function
lastError
()
{
return
$this
->
mLastError
;
}
/**
* Get the number of rows affected by the last write query
*/
function
affectedRows
()
{
return
mssql_rows_affected
(
$this
->
mConn
);
}
/**
* Returns an optional USE INDEX clause to go after the table, and a
* string to go at the end of the query
*
* @private
*
* @param $options Array: an associative array of options to be turned into
* an SQL query, valid keys are listed in the function.
* @return array
*/
function
makeSelectOptions
(
$options
)
{
$preLimitTail
=
$postLimitTail
=
''
;
$startOpts
=
$useIndex
=
''
;
$noKeyOptions
=
array
();
foreach
(
$options
as
$key
=>
$option
)
{
if
(
is_numeric
(
$key
)
)
{
$noKeyOptions
[
$option
]
=
true
;
}
}
if
(
isset
(
$options
[
'GROUP BY'
]
)
)
$preLimitTail
.=
" GROUP BY {$options['GROUP BY']}"
;
if
(
isset
(
$options
[
'HAVING'
]
)
)
$preLimitTail
.=
" HAVING {$options['HAVING']}"
;
if
(
isset
(
$options
[
'ORDER BY'
]
)
)
$preLimitTail
.=
" ORDER BY {$options['ORDER BY']}"
;
if
(
isset
(
$noKeyOptions
[
'FOR UPDATE'
]
)
)
$useIndex
.=
' WITH (UPDLOCK) '
;
if
(
isset
(
$noKeyOptions
[
'LOCK IN SHARE MODE'
]
)
)
$useIndex
.=
' WITH (HOLDLOCK) '
;
if
(
isset
(
$noKeyOptions
[
'DISTINCT'
]
)
||
isset
(
$noKeyOptions
[
'DISTINCTROW'
]
)
)
$startOpts
.=
'DISTINCT'
;
# Various MySQL extensions
#if ( isset( $noKeyOptions['STRAIGHT_JOIN'] ) ) $startOpts .= ' /*! STRAIGHT_JOIN */';
#if ( isset( $noKeyOptions['HIGH_PRIORITY'] ) ) $startOpts .= ' HIGH_PRIORITY';
#if ( isset( $noKeyOptions['SQL_BIG_RESULT'] ) ) $startOpts .= ' SQL_BIG_RESULT';
#if ( isset( $noKeyOptions['SQL_BUFFER_RESULT'] ) ) $startOpts .= ' SQL_BUFFER_RESULT';
#if ( isset( $noKeyOptions['SQL_SMALL_RESULT'] ) ) $startOpts .= ' SQL_SMALL_RESULT';
#if ( isset( $noKeyOptions['SQL_CALC_FOUND_ROWS'] ) ) $startOpts .= ' SQL_CALC_FOUND_ROWS';
#if ( isset( $noKeyOptions['SQL_CACHE'] ) ) $startOpts .= ' SQL_CACHE';
#if ( isset( $noKeyOptions['SQL_NO_CACHE'] ) ) $startOpts .= ' SQL_NO_CACHE';
return
array
(
$startOpts
,
$useIndex
,
$preLimitTail
,
$postLimitTail
);
}
/**
* Estimate rows in dataset
* Returns estimated count, based on EXPLAIN output
* Takes same arguments as Database::select()
*/
function
estimateRowCount
(
$table
,
$vars
=
'*'
,
$conds
=
''
,
$fname
=
'Database::estimateRowCount'
,
$options
=
array
()
)
{
$rows
=
0
;
$res
=
$this
->
select
(
$table
,
'COUNT(*)'
,
$conds
,
$fname
,
$options
);
if
(
$res
)
{
$row
=
$this
->
fetchRow
(
$res
);
$rows
=
$row
[
0
];
}
$this
->
freeResult
(
$res
);
return
$rows
;
}
/**
* Determines whether a field exists in a table
* Usually aborts on failure
* If errors are explicitly ignored, returns NULL on failure
*/
function
fieldExists
(
$table
,
$field
,
$fname
=
'Database::fieldExists'
)
{
$table
=
$this
->
tableName
(
$table
);
$sql
=
"SELECT TOP 1 * FROM $table"
;
$res
=
$this
->
query
(
$sql
,
'Database::fieldExists'
);
$found
=
false
;
while
(
$row
=
$this
->
fetchArray
(
$res
)
)
{
if
(
isset
(
$row
[
$field
])
)
{
$found
=
true
;
break
;
}
}
$this
->
freeResult
(
$res
);
return
$found
;
}
/**
* Get information about an index into an object
* Returns false if the index does not exist
*/
function
indexInfo
(
$table
,
$index
,
$fname
=
'Database::indexInfo'
)
{
throw
new
DBUnexpectedError
(
$this
,
'Database::indexInfo called which is not supported yet'
);
return
NULL
;
}
/**
* Query whether a given table exists
*/
function
tableExists
(
$table
)
{
$table
=
$this
->
tableName
(
$table
);
$res
=
$this
->
query
(
"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '$table'"
);
$exist
=
(
$res
->
numRows
()
>
0
);
$this
->
freeResult
(
$res
);
return
$exist
;
}
/**
* mysql_fetch_field() wrapper
* Returns false if the field doesn't exist
*
* @param $table
* @param $field
*/
function
fieldInfo
(
$table
,
$field
)
{
$table
=
$this
->
tableName
(
$table
);
$res
=
$this
->
query
(
"SELECT TOP 1 * FROM $table"
);
$n
=
mssql_num_fields
(
$res
->
result
);
for
(
$i
=
0
;
$i
<
$n
;
$i
++
)
{
$meta
=
mssql_fetch_field
(
$res
->
result
,
$i
);
if
(
$field
==
$meta
->
name
)
{
return
new
MSSQLField
(
$meta
);
}
}
return
false
;
}
/**
* mysql_field_type() wrapper
*/
function
fieldType
(
$res
,
$index
)
{
if
(
$res
instanceof
ResultWrapper
)
{
$res
=
$res
->
result
;
}
return
mssql_field_type
(
$res
,
$index
);
}
/**
* INSERT wrapper, inserts an array into a table
*
* $a may be a single associative array, or an array of these with numeric keys, for
* multi-row insert.
*
* Usually aborts on failure
* If errors are explicitly ignored, returns success
*
* Same as parent class implementation except that it removes primary key from column lists
* because MSSQL doesn't support writing nulls to IDENTITY (AUTO_INCREMENT) columns
*/
function
insert
(
$table
,
$a
,
$fname
=
'Database::insert'
,
$options
=
array
()
)
{
# No rows to insert, easy just return now
if
(
!
count
(
$a
)
)
{
return
true
;
}
$table
=
$this
->
tableName
(
$table
);
if
(
!
is_array
(
$options
)
)
{
$options
=
array
(
$options
);
}
if
(
!
isset
(
$a
[
0
])
||
!
is_array
(
$a
[
0
]
)
)
$a
=
array
(
$a
);
# Remove null _id fields - null doesn't imply 'default' for MSSQL.
foreach
(
$a
as
$i
=>
$row
)
{
foreach
(
$row
as
$key
=>
$val
)
{
if
(
substr
(
$key
,
-
3
)
==
'_id'
&&
is_null
(
$val
))
unset
(
$a
[
$i
][
$key
]);
}
}
$keys
=
array_keys
(
$a
[
0
]);
$ignore
=
array_search
(
'IGNORE'
,
$options
);
if
(
$ignore
!==
false
)
{
unset
(
$options
[
$ignore
]);
$ignore
=
true
;
}
$prefix
=
$suffix
=
''
;
$explicit_id
=
array_search
(
'EXPLICIT_ID'
,
$options
);
if
(
$explicit_id
!==
false
)
{
unset
(
$options
[
$explicit_id
]);
$prefix
=
"SET IDENTITY_INSERT $table ON;"
;
$suffix
=
"SET IDENTITY_INSERT $table OFF;"
;
}
$sql
=
'INSERT '
.
implode
(
' '
,
$options
).
" INTO $table ("
.
implode
(
','
,
$keys
).
') VALUES '
;
$firstrow
=
true
;
foreach
(
$a
as
$i
=>
$row
)
{
# If ignore, then do each row separately
if
(
$ignore
)
{
$ifnot
=
'IF NOT EXISTS (SELECT * FROM '
.
$table
.
' WHERE '
;
$firstkey
=
true
;
foreach
(
$row
as
$k
=>
$v
)
{
if
(
$firstkey
)
$firstkey
=
false
;
else
$ifnot
.=
' AND '
;
$ifnot
.=
$k
.
' = '
.
$this
->
addQuotes
(
$v
);
}
$ifnot
.=
')'
;
$this
->
query
(
"$prefix $ifnot $sql ("
.
$this
->
makeList
(
$row
).
"); $suffix"
,
$fname
);
}
else
{
if
(
$firstrow
)
$firstrow
=
false
;
else
$sql
.=
','
;
$sql
.=
'('
.
$this
->
makeList
(
$row
).
')'
;
}
}
if
(
$ignore
)
return
true
;
$result
=
(
bool
)
$this
->
query
(
"$prefix $sql $suffix"
,
$fname
);
return
$result
;
}
/**
* Change the current database
*/
function
selectDB
(
$db
)
{
$this
->
mDBname
=
$db
;
return
mssql_select_db
(
$db
,
$this
->
mConn
);
}
/**
* MSSQL has a problem with the backtick quoting, so all this does is ensure the prefix is added exactly once
*/
function
tableName
(
$name
)
{
if
(
$this
->
mTablePrefix
)
return
strpos
(
$name
,
$this
->
mTablePrefix
)
===
0
?
$name
:
"{$this->mTablePrefix}$name"
;
else
return
$name
;
}
/**
* MSSQL doubles quotes instead of escaping them
* @param $s String to be slashed.
* @return string slashed string.
*/
function
strencode
(
$s
)
{
$s
=
str_replace
(
'
\'
'
,
'
\'\'
'
,
$s
);
$s
=
str_replace
(
chr
(
0
),
"'+CHAR(0)+'"
,
$s
);
return
$s
;
}
/**
* USE INDEX clause
*/
function
useIndexClause
(
$index
)
{
return
""
;
}
/**
* REPLACE query wrapper
* MSSQL simulates this with a DELETE followed by INSERT
* $row is the row to insert, an associative array
* $uniqueIndexes is an array of indexes. Each element may be either a
* field name or an array of field names
*
* It may be more efficient to leave off unique indexes which are unlikely to collide.
* However if you do this, you run the risk of encountering errors which wouldn't have
* occurred in MySQL
*
* @todo migrate comment to phodocumentor format
*/
function
replace
(
$table
,
$uniqueIndexes
,
$rows
,
$fname
=
'Database::replace'
)
{
$table
=
$this
->
tableName
(
$table
);
if
(
count
(
$rows
)==
0
)
{
return
;
}
# Single row case
if
(
!
is_array
(
reset
(
$rows
)
)
)
{
$rows
=
array
(
$rows
);
}
foreach
(
$rows
as
$row
)
{
# Delete rows which collide
if
(
$uniqueIndexes
)
{
$sql
=
"DELETE FROM $table WHERE "
;
$first
=
true
;
foreach
(
$uniqueIndexes
as
$index
)
{
if
(
$first
)
{
$first
=
false
;
$sql
.=
"("
;
}
else
{
$sql
.=
') OR ('
;
}
if
(
is_array
(
$index
)
)
{
$first2
=
true
;
foreach
(
$index
as
$col
)
{
if
(
$first2
)
{
$first2
=
false
;
}
else
{
$sql
.=
' AND '
;
}
$sql
.=
$col
.
'='
.
$this
->
addQuotes
(
$row
[
$col
]
);
}
}
else
{
$sql
.=
$index
.
'='
.
$this
->
addQuotes
(
$row
[
$index
]
);
}
}
$sql
.=
')'
;
$this
->
query
(
$sql
,
$fname
);
}
# Now insert the row
$sql
=
"INSERT INTO $table ("
.
$this
->
makeList
(
array_keys
(
$row
),
LIST_NAMES
)
.
') VALUES ('
.
$this
->
makeList
(
$row
,
LIST_COMMA
)
.
')'
;
$this
->
query
(
$sql
,
$fname
);
}
}
/**
* Returns the size of a text field, or -1 for "unlimited"
*/
function
textFieldSize
(
$table
,
$field
)
{
$table
=
$this
->
tableName
(
$table
);
$sql
=
"SELECT TOP 1 * FROM $table;"
;
$res
=
$this
->
query
(
$sql
,
'Database::textFieldSize'
);
$row
=
$this
->
fetchObject
(
$res
);
$this
->
freeResult
(
$res
);
$m
=
array
();
if
(
preg_match
(
'/
\(
(.*)
\)
/'
,
$row
->
Type
,
$m
)
)
{
$size
=
$m
[
1
];
}
else
{
$size
=
-
1
;
}
return
$size
;
}
/**
* Construct a LIMIT query with optional offset
* This is used for query pages
* $sql string SQL query we will append the limit to
* $limit integer the SQL limit
* $offset integer the SQL offset (default false)
*/
function
limitResult
(
$sql
,
$limit
,
$offset
=
false
)
{
if
(
!
is_numeric
(
$limit
)
)
{
throw
new
DBUnexpectedError
(
$this
,
"Invalid non-numeric limit passed to limitResult()
\n
"
);
}
if
(
$offset
)
{
$this
->
mLimitOffset
=
$offset
;
$limit
+=
$offset
;
}
$sql
=
ereg_replace
(
"^SELECT"
,
"SELECT TOP $limit"
,
$sql
);
return
$sql
;
}
/**
* Returns an SQL expression for a simple conditional.
*
* @param $cond String: SQL expression which will result in a boolean value
* @param $trueVal String: SQL expression to return if true
* @param $falseVal String: SQL expression to return if false
* @return string SQL fragment
*/
function
conditional
(
$cond
,
$trueVal
,
$falseVal
)
{
return
" (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) "
;
}
/**
* Should determine if the last failure was due to a deadlock
* @return bool
*/
function
wasDeadlock
()
{
return
$this
->
lastErrno
()
==
1205
;
}
/**
* Return DB-style timestamp used for MSSQL schema
*/
function
timestamp
(
$ts
=
0
)
{
return
wfTimestamp
(
TS_DB
,
$ts
);
}
/**
* @return string wikitext of a link to the server software's web site
*/
function
getSoftwareLink
()
{
return
"[http://www.microsoft.com/sql/default.mspx Microsoft SQL Server 2005 Home]"
;
}
/**
* @return string Version information from the database
*/
function
getServerVersion
()
{
$row
=
mssql_fetch_row
(
mssql_query
(
'select @@VERSION'
,
$this
->
mConn
));
return
ereg
(
"^(.+[0-9]+
\\
.[0-9]+
\\
.[0-9]+) "
,
$row
[
0
],
$m
)
?
$m
[
1
]
:
$row
[
0
];
}
function
limitResultForUpdate
(
$sql
,
$num
)
{
return
$sql
;
}
/**
* not done
*/
public
function
setTimeout
(
$timeout
)
{
return
;
}
function
ping
()
{
wfDebug
(
"Function ping() not written for MSSQL yet"
);
return
true
;
}
/**
* How lagged is this slave?
*/
public
function
getLag
()
{
return
0
;
}
/**
* Called by the installer script
* - this is the same way as DatabasePostgresql.php, MySQL reads in tables.sql and interwiki.sql using dbsource (which calls db->sourceFile)
*/
public
function
setup_database
()
{
global
$IP
,
$wgDBTableOptions
;
$wgDBTableOptions
=
''
;
$mysql_iw
=
"$IP/maintenance/interwiki.sql"
;
$mssql_tmpl
=
"$IP/maintenance/mssql/tables.sql"
;
# Parse the MSSQL template replacing inline variables such as /*$wgDBprefix*/
$err
=
$this
->
sourceFile
(
$mssql_tmpl
);
if
(
$err
!==
true
)
dieout
(
"<li>Failed to prepare database</li>"
);
# Use DatabasePostgres's code to populate interwiki from MySQL template
$f
=
fopen
(
$mysql_iw
,
'r'
);
if
(
$f
==
false
)
dieout
(
"<li>Could not find the interwiki.sql file</li>"
);
$sql
=
"INSERT INTO {$this->mTablePrefix}interwiki(iw_prefix,iw_url,iw_local) VALUES "
;
while
(!
feof
(
$f
))
{
$line
=
fgets
(
$f
,
1024
);
$matches
=
array
();
if
(!
preg_match
(
'/^
\s
*(
\(
.+?),(
\d
)
\)
/'
,
$line
,
$matches
))
continue
;
$this
->
query
(
"$sql $matches[1],$matches[2])"
);
}
}
/**
* No-op lock functions
*/
public
function
lock
(
$lockName
,
$method
)
{
return
true
;
}
public
function
unlock
(
$lockName
,
$method
)
{
return
true
;
}
public
function
getSearchEngine
()
{
return
"SearchEngineDummy"
;
}
}
/**
* @ingroup Database
*/
class
MSSQLField
extends
MySQLField
{
function
__construct
()
{
}
static
function
fromText
(
$db
,
$table
,
$field
)
{
$n
=
new
MSSQLField
;
$n
->
name
=
$field
;
$n
->
tablename
=
$table
;
return
$n
;
}
}
// end DatabaseMssql class
File Metadata
Details
Attached
Mime Type
text/x-php
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4763
Default Alt Text
DatabaseMssql.php (21 KB)
Attached To
Mode
T17493: syntax errors with MSSQL
Attached
Detach File
Event Timeline
Log In to Comment