|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /* 00003 V5.14 8 Sept 2011 (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved. 00004 Released under both BSD license and Lesser GPL library license. 00005 Whenever there is any discrepancy between the two licenses, 00006 the BSD license will take precedence. 00007 Set tabs to 4 for best viewing. 00008 00009 Latest version is available at http://adodb.sourceforge.net 00010 00011 Native mssql driver. Requires mssql client. Works on Windows. 00012 http://www.microsoft.com/sql/technologies/php/default.mspx 00013 To configure for Unix, see 00014 http://phpbuilder.com/columns/alberto20000919.php3 00015 00016 $stream = sqlsrv_get_field($stmt, $index, SQLSRV_SQLTYPE_STREAM(SQLSRV_ENC_BINARY)); 00017 stream_filter_append($stream, "convert.iconv.ucs-2/utf-8"); // Voila, UTF-8 can be read directly from $stream 00018 00019 */ 00020 00021 // security - hide paths 00022 if (!defined('ADODB_DIR')) die(); 00023 00024 if (!function_exists('sqlsrv_configure')) { 00025 die("mssqlnative extension not installed"); 00026 } 00027 00028 if (!function_exists('sqlsrv_set_error_handling')) { 00029 function sqlsrv_set_error_handling($constant) { 00030 sqlsrv_configure("WarningsReturnAsErrors", $constant); 00031 } 00032 } 00033 if (!function_exists('sqlsrv_log_set_severity')) { 00034 function sqlsrv_log_set_severity($constant) { 00035 sqlsrv_configure("LogSeverity", $constant); 00036 } 00037 } 00038 if (!function_exists('sqlsrv_log_set_subsystems')) { 00039 function sqlsrv_log_set_subsystems($constant) { 00040 sqlsrv_configure("LogSubsystems", $constant); 00041 } 00042 } 00043 00044 00045 //---------------------------------------------------------------- 00046 // MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002 00047 // and this causes tons of problems because localized versions of 00048 // MSSQL will return the dates in dmy or mdy order; and also the 00049 // month strings depends on what language has been configured. The 00050 // following two variables allow you to control the localization 00051 // settings - Ugh. 00052 // 00053 // MORE LOCALIZATION INFO 00054 // ---------------------- 00055 // To configure datetime, look for and modify sqlcommn.loc, 00056 // typically found in c:\mssql\install 00057 // Also read : 00058 // http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918 00059 // Alternatively use: 00060 // CONVERT(char(12),datecol,120) 00061 // 00062 // Also if your month is showing as month-1, 00063 // e.g. Jan 13, 2002 is showing as 13/0/2002, then see 00064 // http://phplens.com/lens/lensforum/msgs.php?id=7048&x=1 00065 // it's a localisation problem. 00066 //---------------------------------------------------------------- 00067 00068 00069 // has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc 00070 if (ADODB_PHPVER >= 0x4300) { 00071 // docs say 4.2.0, but testing shows only since 4.3.0 does it work! 00072 ini_set('mssql.datetimeconvert',0); 00073 } else { 00074 global $ADODB_mssql_mths; // array, months must be upper-case 00075 $ADODB_mssql_date_order = 'mdy'; 00076 $ADODB_mssql_mths = array( 00077 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6, 00078 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12); 00079 } 00080 00081 //--------------------------------------------------------------------------- 00082 // Call this to autoset $ADODB_mssql_date_order at the beginning of your code, 00083 // just after you connect to the database. Supports mdy and dmy only. 00084 // Not required for PHP 4.2.0 and above. 00085 function AutoDetect_MSSQL_Date_Order($conn) 00086 { 00087 global $ADODB_mssql_date_order; 00088 $adate = $conn->GetOne('select getdate()'); 00089 if ($adate) { 00090 $anum = (int) $adate; 00091 if ($anum > 0) { 00092 if ($anum > 31) { 00093 //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently"); 00094 } else 00095 $ADODB_mssql_date_order = 'dmy'; 00096 } else 00097 $ADODB_mssql_date_order = 'mdy'; 00098 } 00099 } 00100 00101 class ADODB_mssqlnative extends ADOConnection { 00102 var $databaseType = "mssqlnative"; 00103 var $dataProvider = "mssqlnative"; 00104 var $replaceQuote = "''"; // string to use to replace quotes 00105 var $fmtDate = "'Y-m-d'"; 00106 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 00107 var $hasInsertID = true; 00108 var $substr = "substring"; 00109 var $length = 'len'; 00110 var $hasAffectedRows = true; 00111 var $poorAffectedRows = false; 00112 var $metaDatabasesSQL = "select name from sys.sysdatabases where name <> 'master'"; 00113 var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))"; 00114 var $metaColumnsSQL = # xtype==61 is datetime 00115 "select c.name,t.name,c.length, 00116 (case when c.xusertype=61 then 0 else c.xprec end), 00117 (case when c.xusertype=61 then 0 else c.xscale end) 00118 from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'"; 00119 var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE 00120 var $hasGenID = true; 00121 var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)'; 00122 var $sysTimeStamp = 'GetDate()'; 00123 var $maxParameterLen = 4000; 00124 var $arrayClass = 'ADORecordSet_array_mssqlnative'; 00125 var $uniqueSort = true; 00126 var $leftOuter = '*='; 00127 var $rightOuter = '=*'; 00128 var $ansiOuter = true; // for mssql7 or later 00129 var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000 00130 var $uniqueOrderBy = true; 00131 var $_bindInputArray = true; 00132 var $_dropSeqSQL = "drop table %s"; 00133 00134 function ADODB_mssqlnative() 00135 { 00136 if ($this->debug) { 00137 error_log("<pre>"); 00138 sqlsrv_set_error_handling( SQLSRV_ERRORS_LOG_ALL ); 00139 sqlsrv_log_set_severity( SQLSRV_LOG_SEVERITY_ALL ); 00140 sqlsrv_log_set_subsystems(SQLSRV_LOG_SYSTEM_ALL); 00141 sqlsrv_configure('warnings_return_as_errors', 0); 00142 } else { 00143 sqlsrv_set_error_handling(0); 00144 sqlsrv_log_set_severity(0); 00145 sqlsrv_log_set_subsystems(SQLSRV_LOG_SYSTEM_ALL); 00146 sqlsrv_configure('warnings_return_as_errors', 0); 00147 } 00148 } 00149 00150 function ServerInfo() 00151 { 00152 global $ADODB_FETCH_MODE; 00153 if ($this->fetchMode === false) { 00154 $savem = $ADODB_FETCH_MODE; 00155 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00156 } else 00157 $savem = $this->SetFetchMode(ADODB_FETCH_NUM); 00158 $arrServerInfo = sqlsrv_server_info($this->_connectionID); 00159 $ADODB_FETCH_MODE = $savem; 00160 $arr['description'] = $arrServerInfo['SQLServerName'].' connected to '.$arrServerInfo['CurrentDatabase']; 00161 $arr['version'] = $arrServerInfo['SQLServerVersion'];//ADOConnection::_findvers($arr['description']); 00162 return $arr; 00163 } 00164 00165 function IfNull( $field, $ifNull ) 00166 { 00167 return " ISNULL($field, $ifNull) "; // if MS SQL Server 00168 } 00169 00170 function _insertid() 00171 { 00172 // SCOPE_IDENTITY() 00173 // Returns the last IDENTITY value inserted into an IDENTITY column in 00174 // the same scope. A scope is a module -- a stored procedure, trigger, 00175 // function, or batch. Thus, two statements are in the same scope if 00176 // they are in the same stored procedure, function, or batch. 00177 return $this->GetOne($this->identitySQL); 00178 } 00179 00180 function _affectedrows() 00181 { 00182 return sqlsrv_rows_affected($this->_queryID); 00183 } 00184 00185 function CreateSequence($seq='adodbseq',$start=1) 00186 { 00187 if($this->debug) error_log("<hr>CreateSequence($seq,$start)"); 00188 sqlsrv_begin_transaction($this->_connectionID); 00189 $start -= 1; 00190 $this->Execute("create table $seq (id int)");//was float(53) 00191 $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)"); 00192 if (!$ok) { 00193 if($this->debug) error_log("<hr>Error: ROLLBACK"); 00194 sqlsrv_rollback($this->_connectionID); 00195 return false; 00196 } 00197 sqlsrv_commit($this->_connectionID); 00198 return true; 00199 } 00200 00201 function GenID($seq='adodbseq',$start=1) 00202 { 00203 if($this->debug) error_log("<hr>GenID($seq,$start)"); 00204 sqlsrv_begin_transaction($this->_connectionID); 00205 $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1"); 00206 if (!$ok) { 00207 $this->Execute("create table $seq (id int)"); 00208 $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)"); 00209 if (!$ok) { 00210 if($this->debug) error_log("<hr>Error: ROLLBACK"); 00211 sqlsrv_rollback($this->_connectionID); 00212 return false; 00213 } 00214 sqlsrv_commit($this->_connectionID); 00215 return $start; 00216 } 00217 $num = $this->GetOne("select id from $seq"); 00218 sqlsrv_commit($this->_connectionID); 00219 if($this->debug) error_log(" Returning: $num"); 00220 return $num; 00221 } 00222 00223 // Format date column in sql string given an input format that understands Y M D 00224 function SQLDate($fmt, $col=false) 00225 { 00226 if (!$col) $col = $this->sysTimeStamp; 00227 $s = ''; 00228 00229 $len = strlen($fmt); 00230 for ($i=0; $i < $len; $i++) { 00231 if ($s) $s .= '+'; 00232 $ch = $fmt[$i]; 00233 switch($ch) { 00234 case 'Y': 00235 case 'y': 00236 $s .= "datename(yyyy,$col)"; 00237 break; 00238 case 'M': 00239 $s .= "convert(char(3),$col,0)"; 00240 break; 00241 case 'm': 00242 $s .= "replace(str(month($col),2),' ','0')"; 00243 break; 00244 case 'Q': 00245 case 'q': 00246 $s .= "datename(quarter,$col)"; 00247 break; 00248 case 'D': 00249 case 'd': 00250 $s .= "replace(str(day($col),2),' ','0')"; 00251 break; 00252 case 'h': 00253 $s .= "substring(convert(char(14),$col,0),13,2)"; 00254 break; 00255 00256 case 'H': 00257 $s .= "replace(str(datepart(hh,$col),2),' ','0')"; 00258 break; 00259 00260 case 'i': 00261 $s .= "replace(str(datepart(mi,$col),2),' ','0')"; 00262 break; 00263 case 's': 00264 $s .= "replace(str(datepart(ss,$col),2),' ','0')"; 00265 break; 00266 case 'a': 00267 case 'A': 00268 $s .= "substring(convert(char(19),$col,0),18,2)"; 00269 break; 00270 00271 default: 00272 if ($ch == '\\') { 00273 $i++; 00274 $ch = substr($fmt,$i,1); 00275 } 00276 $s .= $this->qstr($ch); 00277 break; 00278 } 00279 } 00280 return $s; 00281 } 00282 00283 00284 function BeginTrans() 00285 { 00286 if ($this->transOff) return true; 00287 $this->transCnt += 1; 00288 if ($this->debug) error_log('<hr>begin transaction'); 00289 sqlsrv_begin_transaction($this->_connectionID); 00290 return true; 00291 } 00292 00293 function CommitTrans($ok=true) 00294 { 00295 if ($this->transOff) return true; 00296 if ($this->debug) error_log('<hr>commit transaction'); 00297 if (!$ok) return $this->RollbackTrans(); 00298 if ($this->transCnt) $this->transCnt -= 1; 00299 sqlsrv_commit($this->_connectionID); 00300 return true; 00301 } 00302 function RollbackTrans() 00303 { 00304 if ($this->transOff) return true; 00305 if ($this->debug) error_log('<hr>rollback transaction'); 00306 if ($this->transCnt) $this->transCnt -= 1; 00307 sqlsrv_rollback($this->_connectionID); 00308 return true; 00309 } 00310 00311 function SetTransactionMode( $transaction_mode ) 00312 { 00313 $this->_transmode = $transaction_mode; 00314 if (empty($transaction_mode)) { 00315 $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); 00316 return; 00317 } 00318 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 00319 $this->Execute("SET TRANSACTION ".$transaction_mode); 00320 } 00321 00322 /* 00323 Usage: 00324 00325 $this->BeginTrans(); 00326 $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables 00327 00328 # some operation on both tables table1 and table2 00329 00330 $this->CommitTrans(); 00331 00332 See http://www.swynk.com/friends/achigrik/SQL70Locks.asp 00333 */ 00334 function RowLock($tables,$where,$col='1 as adodbignore') 00335 { 00336 if ($col == '1 as adodbignore') $col = 'top 1 null as ignore'; 00337 if (!$this->transCnt) $this->BeginTrans(); 00338 return $this->GetOne("select $col from $tables with (ROWLOCK,HOLDLOCK) where $where"); 00339 } 00340 00341 function SelectDB($dbName) 00342 { 00343 $this->database = $dbName; 00344 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions 00345 if ($this->_connectionID) { 00346 $rs = $this->Execute('USE '.$dbName); 00347 if($rs) { 00348 return true; 00349 } else return false; 00350 } 00351 else return false; 00352 } 00353 00354 function ErrorMsg() 00355 { 00356 $retErrors = sqlsrv_errors(SQLSRV_ERR_ALL); 00357 if($retErrors != null) { 00358 foreach($retErrors as $arrError) { 00359 $this->_errorMsg .= "SQLState: ".$arrError[ 'SQLSTATE']."\n"; 00360 $this->_errorMsg .= "Error Code: ".$arrError[ 'code']."\n"; 00361 $this->_errorMsg .= "Message: ".$arrError[ 'message']."\n"; 00362 } 00363 } else { 00364 $this->_errorMsg = "No errors found"; 00365 } 00366 return $this->_errorMsg; 00367 } 00368 00369 function ErrorNo() 00370 { 00371 if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode; 00372 $err = sqlsrv_errors(SQLSRV_ERR_ALL); 00373 if($err[0]) return $err[0]['code']; 00374 else return -1; 00375 } 00376 00377 // returns true or false 00378 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) 00379 { 00380 if (!function_exists('sqlsrv_connect')) return null; 00381 $connectionInfo = array("Database"=>$argDatabasename,'UID'=>$argUsername,'PWD'=>$argPassword); 00382 if ($this->debug) error_log("<hr>connecting... hostname: $argHostname params: ".var_export($connectionInfo,true)); 00383 //if ($this->debug) error_log("<hr>_connectionID before: ".serialize($this->_connectionID)); 00384 if(!($this->_connectionID = sqlsrv_connect($argHostname,$connectionInfo))) { 00385 if ($this->debug) error_log( "<hr><b>errors</b>: ".print_r( sqlsrv_errors(), true)); 00386 return false; 00387 } 00388 //if ($this->debug) error_log(" _connectionID after: ".serialize($this->_connectionID)); 00389 //if ($this->debug) error_log("<hr>defined functions: <pre>".var_export(get_defined_functions(),true)."</pre>"); 00390 return true; 00391 } 00392 00393 // returns true or false 00394 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 00395 { 00396 //return null;//not implemented. NOTE: Persistent connections have no effect if PHP is used as a CGI program. (FastCGI!) 00397 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); 00398 } 00399 00400 function Prepare($sql) 00401 { 00402 $stmt = sqlsrv_prepare( $this->_connectionID, $sql); 00403 if (!$stmt) return $sql; 00404 return array($sql,$stmt); 00405 } 00406 00407 // returns concatenated string 00408 // MSSQL requires integers to be cast as strings 00409 // automatically cast every datatype to VARCHAR(255) 00410 // @author David Rogers (introspectshun) 00411 function Concat() 00412 { 00413 $s = ""; 00414 $arr = func_get_args(); 00415 00416 // Split single record on commas, if possible 00417 if (sizeof($arr) == 1) { 00418 foreach ($arr as $arg) { 00419 $args = explode(',', $arg); 00420 } 00421 $arr = $args; 00422 } 00423 00424 array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";')); 00425 $s = implode('+',$arr); 00426 if (sizeof($arr) > 0) return "$s"; 00427 00428 return ''; 00429 } 00430 00431 /* 00432 Unfortunately, it appears that mssql cannot handle varbinary > 255 chars 00433 So all your blobs must be of type "image". 00434 00435 Remember to set in php.ini the following... 00436 00437 ; Valid range 0 - 2147483647. Default = 4096. 00438 mssql.textlimit = 0 ; zero to pass through 00439 00440 ; Valid range 0 - 2147483647. Default = 4096. 00441 mssql.textsize = 0 ; zero to pass through 00442 */ 00443 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') 00444 { 00445 00446 if (strtoupper($blobtype) == 'CLOB') { 00447 $sql = "UPDATE $table SET $column='" . $val . "' WHERE $where"; 00448 return $this->Execute($sql) != false; 00449 } 00450 $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where"; 00451 return $this->Execute($sql) != false; 00452 } 00453 00454 // returns query ID if successful, otherwise false 00455 function _query($sql,$inputarr=false) 00456 { 00457 $this->_errorMsg = false; 00458 if (is_array($inputarr)) { 00459 $rez = sqlsrv_query($this->_connectionID,$sql,$inputarr); 00460 } else if (is_array($sql)) { 00461 $rez = sqlsrv_query($this->_connectionID,$sql[1],$inputarr); 00462 } else { 00463 $rez = sqlsrv_query($this->_connectionID,$sql); 00464 } 00465 if ($this->debug) error_log("<hr>running query: ".var_export($sql,true)."<hr>input array: ".var_export($inputarr,true)."<hr>result: ".var_export($rez,true)); 00466 if(!$rez) $rez = false; 00467 return $rez; 00468 } 00469 00470 // returns true or false 00471 function _close() 00472 { 00473 if ($this->transCnt) $this->RollbackTrans(); 00474 $rez = @sqlsrv_close($this->_connectionID); 00475 $this->_connectionID = false; 00476 return $rez; 00477 } 00478 00479 // mssql uses a default date like Dec 30 2000 12:00AM 00480 static function UnixDate($v) 00481 { 00482 return ADORecordSet_array_mssqlnative::UnixDate($v); 00483 } 00484 00485 static function UnixTimeStamp($v) 00486 { 00487 return ADORecordSet_array_mssqlnative::UnixTimeStamp($v); 00488 } 00489 00490 function &MetaIndexes($table,$primary=false, $owner = false) 00491 { 00492 $table = $this->qstr($table); 00493 00494 $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno, 00495 CASE WHEN I.indid BETWEEN 1 AND 254 AND (I.status & 2048 = 2048 OR I.Status = 16402 AND O.XType = 'V') THEN 1 ELSE 0 END AS IsPK, 00496 CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique 00497 FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id 00498 INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid 00499 INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid 00500 WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table 00501 ORDER BY O.name, I.Name, K.keyno"; 00502 00503 global $ADODB_FETCH_MODE; 00504 $save = $ADODB_FETCH_MODE; 00505 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00506 if ($this->fetchMode !== FALSE) { 00507 $savem = $this->SetFetchMode(FALSE); 00508 } 00509 00510 $rs = $this->Execute($sql); 00511 if (isset($savem)) { 00512 $this->SetFetchMode($savem); 00513 } 00514 $ADODB_FETCH_MODE = $save; 00515 00516 if (!is_object($rs)) { 00517 return FALSE; 00518 } 00519 00520 $indexes = array(); 00521 while ($row = $rs->FetchRow()) { 00522 if (!$primary && $row[5]) continue; 00523 00524 $indexes[$row[0]]['unique'] = $row[6]; 00525 $indexes[$row[0]]['columns'][] = $row[1]; 00526 } 00527 return $indexes; 00528 } 00529 00530 function MetaForeignKeys($table, $owner=false, $upper=false) 00531 { 00532 global $ADODB_FETCH_MODE; 00533 00534 $save = $ADODB_FETCH_MODE; 00535 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00536 $table = $this->qstr(strtoupper($table)); 00537 00538 $sql = 00539 "select object_name(constid) as constraint_name, 00540 col_name(fkeyid, fkey) as column_name, 00541 object_name(rkeyid) as referenced_table_name, 00542 col_name(rkeyid, rkey) as referenced_column_name 00543 from sysforeignkeys 00544 where upper(object_name(fkeyid)) = $table 00545 order by constraint_name, referenced_table_name, keyno"; 00546 00547 $constraints =& $this->GetArray($sql); 00548 00549 $ADODB_FETCH_MODE = $save; 00550 00551 $arr = false; 00552 foreach($constraints as $constr) { 00553 //print_r($constr); 00554 $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3]; 00555 } 00556 if (!$arr) return false; 00557 00558 $arr2 = false; 00559 00560 foreach($arr as $k => $v) { 00561 foreach($v as $a => $b) { 00562 if ($upper) $a = strtoupper($a); 00563 $arr2[$a] = $b; 00564 } 00565 } 00566 return $arr2; 00567 } 00568 00569 //From: Fernando Moreira <FMoreira@imediata.pt> 00570 function MetaDatabases() 00571 { 00572 $this->SelectDB("master"); 00573 $rs =& $this->Execute($this->metaDatabasesSQL); 00574 $rows = $rs->GetRows(); 00575 $ret = array(); 00576 for($i=0;$i<count($rows);$i++) { 00577 $ret[] = $rows[$i][0]; 00578 } 00579 $this->SelectDB($this->database); 00580 if($ret) 00581 return $ret; 00582 else 00583 return false; 00584 } 00585 00586 // "Stein-Aksel Basma" <basma@accelero.no> 00587 // tested with MSSQL 2000 00588 function &MetaPrimaryKeys($table) 00589 { 00590 global $ADODB_FETCH_MODE; 00591 00592 $schema = ''; 00593 $this->_findschema($table,$schema); 00594 if (!$schema) $schema = $this->database; 00595 if ($schema) $schema = "and k.table_catalog like '$schema%'"; 00596 00597 $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k, 00598 information_schema.table_constraints tc 00599 where tc.constraint_name = k.constraint_name and tc.constraint_type = 00600 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position "; 00601 00602 $savem = $ADODB_FETCH_MODE; 00603 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00604 $a = $this->GetCol($sql); 00605 $ADODB_FETCH_MODE = $savem; 00606 00607 if ($a && sizeof($a)>0) return $a; 00608 $false = false; 00609 return $false; 00610 } 00611 00612 00613 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 00614 { 00615 if ($mask) { 00616 $save = $this->metaTablesSQL; 00617 $mask = $this->qstr(($mask)); 00618 $this->metaTablesSQL .= " AND name like $mask"; 00619 } 00620 $ret =& ADOConnection::MetaTables($ttype,$showSchema); 00621 00622 if ($mask) { 00623 $this->metaTablesSQL = $save; 00624 } 00625 return $ret; 00626 } 00627 } 00628 00629 /*-------------------------------------------------------------------------------------- 00630 Class Name: Recordset 00631 --------------------------------------------------------------------------------------*/ 00632 00633 class ADORecordset_mssqlnative extends ADORecordSet { 00634 00635 var $databaseType = "mssqlnative"; 00636 var $canSeek = false; 00637 var $fieldOffset = 0; 00638 // _mths works only in non-localised system 00639 00640 function ADORecordset_mssqlnative($id,$mode=false) 00641 { 00642 if ($mode === false) { 00643 global $ADODB_FETCH_MODE; 00644 $mode = $ADODB_FETCH_MODE; 00645 00646 } 00647 $this->fetchMode = $mode; 00648 return $this->ADORecordSet($id,$mode); 00649 } 00650 00651 00652 function _initrs() 00653 { 00654 global $ADODB_COUNTRECS; 00655 if ($this->connection->debug) error_log("(before) ADODB_COUNTRECS: {$ADODB_COUNTRECS} _numOfRows: {$this->_numOfRows} _numOfFields: {$this->_numOfFields}"); 00656 /*$retRowsAff = sqlsrv_rows_affected($this->_queryID);//"If you need to determine the number of rows a query will return before retrieving the actual results, appending a SELECT COUNT ... query would let you get that information, and then a call to next_result would move you to the "real" results." 00657 error_log("rowsaff: ".serialize($retRowsAff)); 00658 $this->_numOfRows = ($ADODB_COUNTRECS)? $retRowsAff:-1;*/ 00659 $this->_numOfRows = -1;//not supported 00660 $fieldmeta = sqlsrv_field_metadata($this->_queryID); 00661 $this->_numOfFields = ($fieldmeta)? count($fieldmeta):-1; 00662 if ($this->connection->debug) error_log("(after) _numOfRows: {$this->_numOfRows} _numOfFields: {$this->_numOfFields}"); 00663 } 00664 00665 00666 //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se> 00667 // get next resultset - requires PHP 4.0.5 or later 00668 function NextRecordSet() 00669 { 00670 if (!sqlsrv_next_result($this->_queryID)) return false; 00671 $this->_inited = false; 00672 $this->bind = false; 00673 $this->_currentRow = -1; 00674 $this->Init(); 00675 return true; 00676 } 00677 00678 /* Use associative array to get fields array */ 00679 function Fields($colname) 00680 { 00681 if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname]; 00682 if (!$this->bind) { 00683 $this->bind = array(); 00684 for ($i=0; $i < $this->_numOfFields; $i++) { 00685 $o = $this->FetchField($i); 00686 $this->bind[strtoupper($o->name)] = $i; 00687 } 00688 } 00689 00690 return $this->fields[$this->bind[strtoupper($colname)]]; 00691 } 00692 00693 /* Returns: an object containing field information. 00694 Get column information in the Recordset object. fetchField() can be used in order to obtain information about 00695 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by 00696 fetchField() is retrieved. */ 00697 00698 function FetchField($fieldOffset = -1) 00699 { 00700 if ($this->connection->debug) error_log("<hr>fetchfield: $fieldOffset, fetch array: <pre>".print_r($this->fields,true)."</pre> backtrace: ".adodb_backtrace(false)); 00701 if ($fieldOffset != -1) $this->fieldOffset = $fieldOffset; 00702 $arrKeys = array_keys($this->fields); 00703 if(array_key_exists($this->fieldOffset,$arrKeys) && !array_key_exists($arrKeys[$this->fieldOffset],$this->fields)) { 00704 $f = false; 00705 } else { 00706 $f = new ADOFetchObj(); 00707 $f->name = $arrKeys[$this->fieldOffset]; 00708 if($fieldOffset == -1) $this->fieldOffset++; 00709 } 00710 00711 if (empty($f)) { 00712 $f = false;//PHP Notice: Only variable references should be returned by reference 00713 } 00714 return $f; 00715 } 00716 00717 function _seek($row) 00718 { 00719 return false;//There is no support for cursors in the driver at this time. All data is returned via forward-only streams. 00720 } 00721 00722 // speedup 00723 function MoveNext() 00724 { 00725 if ($this->connection->debug) error_log("movenext()"); 00726 //if ($this->connection->debug) error_log("eof (beginning): ".$this->EOF); 00727 if ($this->EOF) return false; 00728 00729 $this->_currentRow++; 00730 if ($this->connection->debug) error_log("_currentRow: ".$this->_currentRow); 00731 00732 if ($this->_fetch()) return true; 00733 $this->EOF = true; 00734 //if ($this->connection->debug) error_log("eof (end): ".$this->EOF); 00735 00736 return false; 00737 } 00738 00739 00740 // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4 00741 // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot! 00742 function _fetch($ignore_fields=false) 00743 { 00744 if ($this->connection->debug) error_log("_fetch()"); 00745 if ($this->fetchMode & ADODB_FETCH_BOTH) { 00746 if ($this->fetchMode & ADODB_FETCH_NUM) { 00747 if ($this->connection->debug) error_log("fetch mode: both"); 00748 $this->fields = @sqlsrv_fetch_array($this->_queryID,SQLSRV_FETCH_BOTH); 00749 } else { 00750 if ($this->connection->debug) error_log("fetch mode: assoc"); 00751 $this->fields = @sqlsrv_fetch_array($this->_queryID,SQLSRV_FETCH_ASSOC); 00752 } 00753 00754 if (ADODB_ASSOC_CASE == 0) { 00755 foreach($this->fields as $k=>$v) { 00756 $this->fields[strtolower($k)] = $v; 00757 } 00758 } else if (ADODB_ASSOC_CASE == 1) { 00759 foreach($this->fields as $k=>$v) { 00760 $this->fields[strtoupper($k)] = $v; 00761 } 00762 } 00763 } else { 00764 if ($this->connection->debug) error_log("fetch mode: num"); 00765 $this->fields = @sqlsrv_fetch_array($this->_queryID,SQLSRV_FETCH_NUMERIC); 00766 } 00767 if(is_array($this->fields) && array_key_exists(1,$this->fields) && !array_key_exists(0,$this->fields)) {//fix fetch numeric keys since they're not 0 based 00768 $arrFixed = array(); 00769 foreach($this->fields as $key=>$value) { 00770 if(is_numeric($key)) { 00771 $arrFixed[$key-1] = $value; 00772 } else { 00773 $arrFixed[$key] = $value; 00774 } 00775 } 00776 //if($this->connection->debug) error_log("<hr>fixing non 0 based return array, old: ".print_r($this->fields,true)." new: ".print_r($arrFixed,true)); 00777 $this->fields = $arrFixed; 00778 } 00779 if(is_array($this->fields)) { 00780 foreach($this->fields as $key=>$value) { 00781 if (is_object($value) && method_exists($value, 'format')) {//is DateTime object 00782 $this->fields[$key] = $value->format("Y-m-d\TH:i:s\Z"); 00783 } 00784 } 00785 } 00786 if($this->fields === null) $this->fields = false; 00787 if ($this->connection->debug) error_log("<hr>after _fetch, fields: <pre>".print_r($this->fields,true)." backtrace: ".adodb_backtrace(false)); 00788 return $this->fields; 00789 } 00790 00791 /* close() only needs to be called if you are worried about using too much memory while your script 00792 is running. All associated result memory for the specified result identifier will automatically be freed. */ 00793 function _close() 00794 { 00795 $rez = sqlsrv_free_stmt($this->_queryID); 00796 $this->_queryID = false; 00797 return $rez; 00798 } 00799 00800 // mssql uses a default date like Dec 30 2000 12:00AM 00801 static function UnixDate($v) 00802 { 00803 return ADORecordSet_array_mssqlnative::UnixDate($v); 00804 } 00805 00806 static function UnixTimeStamp($v) 00807 { 00808 return ADORecordSet_array_mssqlnative::UnixTimeStamp($v); 00809 } 00810 } 00811 00812 00813 class ADORecordSet_array_mssqlnative extends ADORecordSet_array { 00814 function ADORecordSet_array_mssqlnative($id=-1,$mode=false) 00815 { 00816 $this->ADORecordSet_array($id,$mode); 00817 } 00818 00819 // mssql uses a default date like Dec 30 2000 12:00AM 00820 static function UnixDate($v) 00821 { 00822 00823 if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v); 00824 00825 global $ADODB_mssql_mths,$ADODB_mssql_date_order; 00826 00827 //Dec 30 2000 12:00AM 00828 if ($ADODB_mssql_date_order == 'dmy') { 00829 if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) { 00830 return parent::UnixDate($v); 00831 } 00832 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; 00833 00834 $theday = $rr[1]; 00835 $themth = substr(strtoupper($rr[2]),0,3); 00836 } else { 00837 if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) { 00838 return parent::UnixDate($v); 00839 } 00840 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; 00841 00842 $theday = $rr[2]; 00843 $themth = substr(strtoupper($rr[1]),0,3); 00844 } 00845 $themth = $ADODB_mssql_mths[$themth]; 00846 if ($themth <= 0) return false; 00847 // h-m-s-MM-DD-YY 00848 return mktime(0,0,0,$themth,$theday,$rr[3]); 00849 } 00850 00851 static function UnixTimeStamp($v) 00852 { 00853 00854 if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v); 00855 00856 global $ADODB_mssql_mths,$ADODB_mssql_date_order; 00857 00858 //Dec 30 2000 12:00AM 00859 if ($ADODB_mssql_date_order == 'dmy') { 00860 if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|" 00861 ,$v, $rr)) return parent::UnixTimeStamp($v); 00862 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; 00863 00864 $theday = $rr[1]; 00865 $themth = substr(strtoupper($rr[2]),0,3); 00866 } else { 00867 if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|" 00868 ,$v, $rr)) return parent::UnixTimeStamp($v); 00869 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; 00870 00871 $theday = $rr[2]; 00872 $themth = substr(strtoupper($rr[1]),0,3); 00873 } 00874 00875 $themth = $ADODB_mssql_mths[$themth]; 00876 if ($themth <= 0) return false; 00877 00878 switch (strtoupper($rr[6])) { 00879 case 'P': 00880 if ($rr[4]<12) $rr[4] += 12; 00881 break; 00882 case 'A': 00883 if ($rr[4]==12) $rr[4] = 0; 00884 break; 00885 default: 00886 break; 00887 } 00888 // h-m-s-MM-DD-YY 00889 return mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]); 00890 } 00891 } 00892 00893 /* 00894 Code Example 1: 00895 00896 select object_name(constid) as constraint_name, 00897 object_name(fkeyid) as table_name, 00898 col_name(fkeyid, fkey) as column_name, 00899 object_name(rkeyid) as referenced_table_name, 00900 col_name(rkeyid, rkey) as referenced_column_name 00901 from sysforeignkeys 00902 where object_name(fkeyid) = x 00903 order by constraint_name, table_name, referenced_table_name, keyno 00904 00905 Code Example 2: 00906 select constraint_name, 00907 column_name, 00908 ordinal_position 00909 from information_schema.key_column_usage 00910 where constraint_catalog = db_name() 00911 and table_name = x 00912 order by constraint_name, ordinal_position 00913 00914 http://www.databasejournal.com/scripts/article.php/1440551 00915 */ 00916 00917 ?>