Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/drivers/adodb-mssqlnative.inc.php
Go to the documentation of this file.
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 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations