[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/adodb/drivers/ -> adodb-mssqlnative.inc.php (source)

   1  <?php
   2  /* 
   3  V5.11 5 May 2010   (c) 2000-2010 John Lim (jlim#natsoft.com). All rights reserved.
   4    Released under both BSD license and Lesser GPL library license. 
   5    Whenever there is any discrepancy between the two licenses, 
   6    the BSD license will take precedence. 
   7  Set tabs to 4 for best viewing.
   8    
   9    Latest version is available at http://adodb.sourceforge.net
  10    
  11    Native mssql driver. Requires mssql client. Works on Windows. 
  12      http://www.microsoft.com/sql/technologies/php/default.mspx
  13    To configure for Unix, see 
  14         http://phpbuilder.com/columns/alberto20000919.php3
  15  
  16      $stream = sqlsrv_get_field($stmt, $index, SQLSRV_SQLTYPE_STREAM(SQLSRV_ENC_BINARY));
  17      stream_filter_append($stream, "convert.iconv.ucs-2/utf-8"); // Voila, UTF-8 can be read directly from $stream
  18  
  19  */
  20  
  21  // security - hide paths
  22  if (!defined('ADODB_DIR')) die();
  23  
  24  if (!function_exists('sqlsrv_configure')) {
  25      die("mssqlnative extension not installed");
  26  }
  27  
  28  if (!function_exists('sqlsrv_set_error_handling')) {
  29  	function sqlsrv_set_error_handling($constant) {
  30          sqlsrv_configure("WarningsReturnAsErrors", $constant);
  31      }
  32  }
  33  if (!function_exists('sqlsrv_log_set_severity')) {
  34  	function sqlsrv_log_set_severity($constant) {
  35          sqlsrv_configure("LogSeverity", $constant);
  36      }
  37  }
  38  if (!function_exists('sqlsrv_log_set_subsystems')) {
  39  	function sqlsrv_log_set_subsystems($constant) {
  40          sqlsrv_configure("LogSubsystems", $constant);
  41      }
  42  }
  43  
  44  
  45  //----------------------------------------------------------------
  46  // MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002
  47  // and this causes tons of problems because localized versions of 
  48  // MSSQL will return the dates in dmy or  mdy order; and also the 
  49  // month strings depends on what language has been configured. The 
  50  // following two variables allow you to control the localization
  51  // settings - Ugh.
  52  //
  53  // MORE LOCALIZATION INFO
  54  // ----------------------
  55  // To configure datetime, look for and modify sqlcommn.loc, 
  56  //      typically found in c:\mssql\install
  57  // Also read :
  58  //     http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918
  59  // Alternatively use:
  60  //        CONVERT(char(12),datecol,120)
  61  //
  62  // Also if your month is showing as month-1, 
  63  //   e.g. Jan 13, 2002 is showing as 13/0/2002, then see
  64  //     http://phplens.com/lens/lensforum/msgs.php?id=7048&x=1
  65  //   it's a localisation problem.
  66  //----------------------------------------------------------------
  67  
  68  
  69  // has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc
  70  if (ADODB_PHPVER >= 0x4300) {
  71  // docs say 4.2.0, but testing shows only since 4.3.0 does it work!
  72      ini_set('mssql.datetimeconvert',0); 
  73  } else {
  74      global $ADODB_mssql_mths;        // array, months must be upper-case
  75      $ADODB_mssql_date_order = 'mdy'; 
  76      $ADODB_mssql_mths = array(
  77          'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
  78          'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
  79  }
  80  
  81  //---------------------------------------------------------------------------
  82  // Call this to autoset $ADODB_mssql_date_order at the beginning of your code,
  83  // just after you connect to the database. Supports mdy and dmy only.
  84  // Not required for PHP 4.2.0 and above.
  85  function AutoDetect_MSSQL_Date_Order($conn)
  86  {
  87      global $ADODB_mssql_date_order;
  88      $adate = $conn->GetOne('select getdate()');
  89      if ($adate) {
  90          $anum = (int) $adate;
  91          if ($anum > 0) {
  92              if ($anum > 31) {
  93                  //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently");
  94              } else
  95                  $ADODB_mssql_date_order = 'dmy';
  96          } else
  97              $ADODB_mssql_date_order = 'mdy';
  98      }
  99  }
 100  
 101  class ADODB_mssqlnative extends ADOConnection {
 102      var $databaseType = "mssqlnative";    
 103      var $dataProvider = "mssqlnative";
 104      var $replaceQuote = "''"; // string to use to replace quotes
 105      var $fmtDate = "'Y-m-d'";
 106      var $fmtTimeStamp = "'Y-m-d H:i:s'";
 107      var $hasInsertID = true;
 108      var $substr = "substring";
 109      var $length = 'len';
 110      var $hasAffectedRows = true;
 111      var $poorAffectedRows = false;
 112      var $metaDatabasesSQL = "select name from sys.sysdatabases where name <> 'master'";
 113      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'))";
 114      var $metaColumnsSQL = # xtype==61 is datetime
 115          "select c.name,t.name,c.length,
 116          (case when c.xusertype=61 then 0 else c.xprec end),
 117          (case when c.xusertype=61 then 0 else c.xscale end) 
 118          from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
 119      var $hasTop = 'top';        // support mssql SELECT TOP 10 * FROM TABLE
 120      var $hasGenID = true;
 121      var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
 122      var $sysTimeStamp = 'GetDate()';
 123      var $maxParameterLen = 4000;
 124      var $arrayClass = 'ADORecordSet_array_mssqlnative';
 125      var $uniqueSort = true;
 126      var $leftOuter = '*=';
 127      var $rightOuter = '=*';
 128      var $ansiOuter = true; // for mssql7 or later
 129      var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000
 130      var $uniqueOrderBy = true;
 131      var $_bindInputArray = true;
 132      var $_dropSeqSQL = "drop table %s";
 133      
 134  	function ADODB_mssqlnative() 
 135      {        
 136          if ($this->debug) {
 137              error_log("<pre>");
 138              sqlsrv_set_error_handling( SQLSRV_ERRORS_LOG_ALL );
 139              sqlsrv_log_set_severity( SQLSRV_LOG_SEVERITY_ALL );
 140              sqlsrv_log_set_subsystems(SQLSRV_LOG_SYSTEM_ALL);
 141              sqlsrv_configure('warnings_return_as_errors', 0);
 142          } else {
 143              sqlsrv_set_error_handling(0);
 144              sqlsrv_log_set_severity(0);
 145              sqlsrv_log_set_subsystems(SQLSRV_LOG_SYSTEM_ALL);
 146              sqlsrv_configure('warnings_return_as_errors', 0);
 147          }
 148      }
 149  
 150  	function ServerInfo()
 151      {
 152          global $ADODB_FETCH_MODE;
 153          if ($this->fetchMode === false) {
 154              $savem = $ADODB_FETCH_MODE;
 155              $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 156          } else 
 157              $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
 158          $arrServerInfo = sqlsrv_server_info($this->_connectionID);
 159          $arr['description'] = $arrServerInfo['SQLServerName'].' connected to '.$arrServerInfo['CurrentDatabase'];
 160          $arr['version'] = $arrServerInfo['SQLServerVersion'];//ADOConnection::_findvers($arr['description']);
 161          return $arr;
 162      }
 163      
 164  	function IfNull( $field, $ifNull ) 
 165      {
 166          return " ISNULL($field, $ifNull) "; // if MS SQL Server
 167      }
 168      
 169  	function _insertid()
 170      {
 171      // SCOPE_IDENTITY()
 172      // Returns the last IDENTITY value inserted into an IDENTITY column in 
 173      // the same scope. A scope is a module -- a stored procedure, trigger, 
 174      // function, or batch. Thus, two statements are in the same scope if 
 175      // they are in the same stored procedure, function, or batch.
 176          return $this->GetOne($this->identitySQL);
 177      }
 178  
 179  	function _affectedrows()
 180      {
 181          return sqlsrv_rows_affected($this->_queryID);
 182      }
 183      
 184  	function CreateSequence($seq='adodbseq',$start=1)
 185      {
 186          if($this->debug) error_log("<hr>CreateSequence($seq,$start)");
 187          sqlsrv_begin_transaction($this->_connectionID);
 188          $start -= 1;
 189          $this->Execute("create table $seq (id int)");//was float(53)
 190          $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
 191          if (!$ok) {
 192              if($this->debug) error_log("<hr>Error: ROLLBACK");
 193              sqlsrv_rollback($this->_connectionID);
 194              return false;
 195          }
 196          sqlsrv_commit($this->_connectionID);
 197          return true;
 198      }
 199  
 200  	function GenID($seq='adodbseq',$start=1)
 201      {
 202          if($this->debug) error_log("<hr>GenID($seq,$start)");
 203          sqlsrv_begin_transaction($this->_connectionID);
 204          $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
 205          if (!$ok) {
 206              $this->Execute("create table $seq (id int)");
 207              $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
 208              if (!$ok) {
 209                  if($this->debug) error_log("<hr>Error: ROLLBACK");
 210                  sqlsrv_rollback($this->_connectionID);
 211                  return false;
 212              }
 213              sqlsrv_commit($this->_connectionID);
 214              return $start;
 215          }
 216          $num = $this->GetOne("select id from $seq");
 217          sqlsrv_commit($this->_connectionID);
 218          if($this->debug) error_log(" Returning: $num");
 219          return $num;
 220      }
 221      
 222      // Format date column in sql string given an input format that understands Y M D
 223  	function SQLDate($fmt, $col=false)
 224      {    
 225          if (!$col) $col = $this->sysTimeStamp;
 226          $s = '';
 227          
 228          $len = strlen($fmt);
 229          for ($i=0; $i < $len; $i++) {
 230              if ($s) $s .= '+';
 231              $ch = $fmt[$i];
 232              switch($ch) {
 233              case 'Y':
 234              case 'y':
 235                  $s .= "datename(yyyy,$col)";
 236                  break;
 237              case 'M':
 238                  $s .= "convert(char(3),$col,0)";
 239                  break;
 240              case 'm':
 241                  $s .= "replace(str(month($col),2),' ','0')";
 242                  break;
 243              case 'Q':
 244              case 'q':
 245                  $s .= "datename(quarter,$col)";
 246                  break;
 247              case 'D':
 248              case 'd':
 249                  $s .= "replace(str(day($col),2),' ','0')";
 250                  break;
 251              case 'h':
 252                  $s .= "substring(convert(char(14),$col,0),13,2)";
 253                  break;
 254              
 255              case 'H':
 256                  $s .= "replace(str(datepart(hh,$col),2),' ','0')";
 257                  break;
 258                  
 259              case 'i':
 260                  $s .= "replace(str(datepart(mi,$col),2),' ','0')";
 261                  break;
 262              case 's':
 263                  $s .= "replace(str(datepart(ss,$col),2),' ','0')";
 264                  break;
 265              case 'a':
 266              case 'A':
 267                  $s .= "substring(convert(char(19),$col,0),18,2)";
 268                  break;
 269                  
 270              default:
 271                  if ($ch == '\\') {
 272                      $i++;
 273                      $ch = substr($fmt,$i,1);
 274                  }
 275                  $s .= $this->qstr($ch);
 276                  break;
 277              }
 278          }
 279          return $s;
 280      }
 281  
 282      
 283  	function BeginTrans()
 284      {
 285          if ($this->transOff) return true; 
 286          $this->transCnt += 1;
 287          if ($this->debug) error_log('<hr>begin transaction');
 288          sqlsrv_begin_transaction($this->_connectionID);
 289             return true;
 290      }
 291          
 292  	function CommitTrans($ok=true) 
 293      { 
 294          if ($this->transOff) return true; 
 295          if ($this->debug) error_log('<hr>commit transaction');
 296          if (!$ok) return $this->RollbackTrans();
 297          if ($this->transCnt) $this->transCnt -= 1;
 298          sqlsrv_commit($this->_connectionID);
 299          return true;
 300      }
 301  	function RollbackTrans()
 302      {
 303          if ($this->transOff) return true; 
 304          if ($this->debug) error_log('<hr>rollback transaction');
 305          if ($this->transCnt) $this->transCnt -= 1;
 306          sqlsrv_rollback($this->_connectionID);
 307          return true;
 308      }
 309      
 310  	function SetTransactionMode( $transaction_mode ) 
 311      {
 312          $this->_transmode  = $transaction_mode;
 313          if (empty($transaction_mode)) {
 314              $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
 315              return;
 316          }
 317          if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
 318          $this->Execute("SET TRANSACTION ".$transaction_mode);
 319      }
 320      
 321      /*
 322          Usage:
 323          
 324          $this->BeginTrans();
 325          $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables
 326          
 327          # some operation on both tables table1 and table2
 328          
 329          $this->CommitTrans();
 330          
 331          See http://www.swynk.com/friends/achigrik/SQL70Locks.asp
 332      */
 333  	function RowLock($tables,$where,$col='1 as adodbignore') 
 334      {
 335          if ($col == '1 as adodbignore') $col = 'top 1 null as ignore';
 336          if (!$this->transCnt) $this->BeginTrans();
 337          return $this->GetOne("select $col from $tables with (ROWLOCK,HOLDLOCK) where $where");
 338      }
 339       
 340  	function SelectDB($dbName) 
 341      {
 342          $this->database = $dbName;
 343          $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
 344          if ($this->_connectionID) {
 345              $rs = $this->Execute('USE '.$dbName); 
 346              if($rs) {
 347                  return true;
 348              } else return false;        
 349          }
 350          else return false;    
 351      }
 352      
 353  	function ErrorMsg() 
 354      {
 355          $retErrors = sqlsrv_errors(SQLSRV_ERR_ALL);
 356          if($retErrors != null) {
 357              foreach($retErrors as $arrError) {
 358                  $this->_errorMsg .= "SQLState: ".$arrError[ 'SQLSTATE']."\n";
 359                  $this->_errorMsg .= "Error Code: ".$arrError[ 'code']."\n";
 360                  $this->_errorMsg .= "Message: ".$arrError[ 'message']."\n";
 361              }
 362          } else {
 363              $this->_errorMsg = "No errors found";
 364          }
 365          return $this->_errorMsg;
 366      }
 367      
 368  	function ErrorNo() 
 369      {
 370          if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode;
 371          $err = sqlsrv_errors(SQLSRV_ERR_ALL);
 372          if($err[0]) return $err[0]['code'];
 373          else return -1;
 374      }
 375      
 376      // returns true or false
 377  	function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
 378      {
 379          if (!function_exists('sqlsrv_connect')) return null;
 380          $connectionInfo = array("Database"=>$argDatabasename,'UID'=>$argUsername,'PWD'=>$argPassword);
 381          if ($this->debug) error_log("<hr>connecting... hostname: $argHostname params: ".var_export($connectionInfo,true));
 382          //if ($this->debug) error_log("<hr>_connectionID before: ".serialize($this->_connectionID));
 383          if(!($this->_connectionID = sqlsrv_connect($argHostname,$connectionInfo))) { 
 384              if ($this->debug) error_log( "<hr><b>errors</b>: ".print_r( sqlsrv_errors(), true));
 385              return false;
 386          }
 387          //if ($this->debug) error_log(" _connectionID after: ".serialize($this->_connectionID));
 388          //if ($this->debug) error_log("<hr>defined functions: <pre>".var_export(get_defined_functions(),true)."</pre>");
 389          return true;    
 390      }
 391      
 392      // returns true or false
 393  	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 394      {
 395          //return null;//not implemented. NOTE: Persistent connections have no effect if PHP is used as a CGI program. (FastCGI!)
 396          return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
 397      }
 398      
 399  	function Prepare($sql)
 400      {
 401          $stmt = sqlsrv_prepare( $this->_connectionID, $sql);
 402          if (!$stmt)  return $sql;
 403          return array($sql,$stmt);
 404      }
 405      
 406      // returns concatenated string
 407      // MSSQL requires integers to be cast as strings
 408      // automatically cast every datatype to VARCHAR(255)
 409      // @author David Rogers (introspectshun)
 410      function Concat()
 411      {
 412          $s = "";
 413          $arr = func_get_args();
 414  
 415          // Split single record on commas, if possible
 416          if (sizeof($arr) == 1) {
 417              foreach ($arr as $arg) {
 418                  $args = explode(',', $arg);
 419              }
 420              $arr = $args;
 421          }
 422  
 423          array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";'));
 424          $s = implode('+',$arr);
 425          if (sizeof($arr) > 0) return "$s";
 426          
 427          return '';
 428      }
 429      
 430      /* 
 431          Unfortunately, it appears that mssql cannot handle varbinary > 255 chars
 432          So all your blobs must be of type "image".
 433          
 434          Remember to set in php.ini the following...
 435          
 436          ; Valid range 0 - 2147483647. Default = 4096. 
 437          mssql.textlimit = 0 ; zero to pass through 
 438  
 439          ; Valid range 0 - 2147483647. Default = 4096. 
 440          mssql.textsize = 0 ; zero to pass through 
 441      */
 442  	function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
 443      {
 444      
 445          if (strtoupper($blobtype) == 'CLOB') {
 446              $sql = "UPDATE $table SET $column='" . $val . "' WHERE $where";
 447              return $this->Execute($sql) != false;
 448          }
 449          $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";
 450          return $this->Execute($sql) != false;
 451      }
 452      
 453      // returns query ID if successful, otherwise false
 454  	function _query($sql,$inputarr=false)
 455      {
 456          $this->_errorMsg = false;
 457          if (is_array($inputarr)) {
 458              $rez = sqlsrv_query($this->_connectionID,$sql,$inputarr);
 459          } else if (is_array($sql)) {
 460              $rez = sqlsrv_query($this->_connectionID,$sql[1],$inputarr);
 461          } else {
 462              $rez = sqlsrv_query($this->_connectionID,$sql);
 463          }
 464          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));//"<hr>connection: ".serialize($this->_connectionID)
 465          //fix for returning true on anything besides select statements
 466          if (is_array($sql)) $sql = $sql[1];
 467          $sql = ltrim($sql);
 468          if(stripos($sql, 'SELECT') !== 0 && $rez !== false) {
 469              if ($this->debug) error_log(" isn't a select query, returning boolean true");
 470              return true;
 471          }
 472          //end fix
 473          if(!$rez) $rez = false;
 474          return $rez;
 475      }
 476      
 477      // returns true or false
 478  	function _close()
 479      { 
 480          if ($this->transCnt) $this->RollbackTrans();
 481          $rez = @sqlsrv_close($this->_connectionID);
 482          $this->_connectionID = false;
 483          return $rez;
 484      }
 485      
 486      // mssql uses a default date like Dec 30 2000 12:00AM
 487  	static function UnixDate($v)
 488      {
 489          return ADORecordSet_array_mssql::UnixDate($v);
 490      }
 491      
 492  	static function UnixTimeStamp($v)
 493      {
 494          return ADORecordSet_array_mssql::UnixTimeStamp($v);
 495      }    
 496  
 497      function &MetaIndexes($table,$primary=false, $owner = false)
 498      {
 499          $table = $this->qstr($table);
 500  
 501          $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno, 
 502              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,
 503              CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique
 504              FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id 
 505              INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid 
 506              INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid
 507              WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table
 508              ORDER BY O.name, I.Name, K.keyno";
 509  
 510          global $ADODB_FETCH_MODE;
 511          $save = $ADODB_FETCH_MODE;
 512          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 513          if ($this->fetchMode !== FALSE) {
 514              $savem = $this->SetFetchMode(FALSE);
 515          }
 516          
 517          $rs = $this->Execute($sql);
 518          if (isset($savem)) {
 519              $this->SetFetchMode($savem);
 520          }
 521          $ADODB_FETCH_MODE = $save;
 522  
 523          if (!is_object($rs)) {
 524              return FALSE;
 525          }
 526  
 527          $indexes = array();
 528          while ($row = $rs->FetchRow()) {
 529              if (!$primary && $row[5]) continue;
 530              
 531              $indexes[$row[0]]['unique'] = $row[6];
 532              $indexes[$row[0]]['columns'][] = $row[1];
 533          }
 534          return $indexes;
 535      }
 536      
 537  	function MetaForeignKeys($table, $owner=false, $upper=false)
 538      {
 539          global $ADODB_FETCH_MODE;
 540      
 541          $save = $ADODB_FETCH_MODE;
 542          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 543          $table = $this->qstr(strtoupper($table));
 544          
 545          $sql = 
 546              "select object_name(constid) as constraint_name,
 547                  col_name(fkeyid, fkey) as column_name,
 548                  object_name(rkeyid) as referenced_table_name,
 549                     col_name(rkeyid, rkey) as referenced_column_name
 550              from sysforeignkeys
 551              where upper(object_name(fkeyid)) = $table
 552              order by constraint_name, referenced_table_name, keyno";
 553          
 554          $constraints =& $this->GetArray($sql);
 555          
 556          $ADODB_FETCH_MODE = $save;
 557          
 558          $arr = false;
 559          foreach($constraints as $constr) {
 560              //print_r($constr);
 561              $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3]; 
 562          }
 563          if (!$arr) return false;
 564          
 565          $arr2 = false;
 566          
 567          foreach($arr as $k => $v) {
 568              foreach($v as $a => $b) {
 569                  if ($upper) $a = strtoupper($a);
 570                  $arr2[$a] = $b;
 571              }
 572          }
 573          return $arr2;
 574      }
 575  
 576      //From: Fernando Moreira <FMoreira@imediata.pt>
 577  	function MetaDatabases() 
 578      { 
 579          $this->SelectDB("master");
 580          $rs =& $this->Execute($this->metaDatabasesSQL);
 581          $rows = $rs->GetRows();
 582          $ret = array();
 583          for($i=0;$i<count($rows);$i++) {
 584              $ret[] = $rows[$i][0];
 585          }
 586          $this->SelectDB($this->database);
 587          if($ret)
 588              return $ret;
 589          else 
 590              return false;
 591      } 
 592  
 593      // "Stein-Aksel Basma" <basma@accelero.no>
 594      // tested with MSSQL 2000
 595      function &MetaPrimaryKeys($table)
 596      {
 597          global $ADODB_FETCH_MODE;
 598      
 599          $schema = '';
 600          $this->_findschema($table,$schema);
 601          if (!$schema) $schema = $this->database;
 602          if ($schema) $schema = "and k.table_catalog like '$schema%'"; 
 603  
 604          $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k,
 605          information_schema.table_constraints tc 
 606          where tc.constraint_name = k.constraint_name and tc.constraint_type =
 607          'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position ";
 608          
 609          $savem = $ADODB_FETCH_MODE;
 610          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 611          $a = $this->GetCol($sql);
 612          $ADODB_FETCH_MODE = $savem;
 613          
 614          if ($a && sizeof($a)>0) return $a;
 615          $false = false;
 616          return $false;      
 617      }
 618  
 619      
 620      function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
 621      {
 622          if ($mask) {
 623              $save = $this->metaTablesSQL;
 624              $mask = $this->qstr(($mask));
 625              $this->metaTablesSQL .= " AND name like $mask";
 626          }
 627          $ret =& ADOConnection::MetaTables($ttype,$showSchema);
 628  
 629          if ($mask) {
 630              $this->metaTablesSQL = $save;
 631          }
 632          return $ret;
 633      }
 634  }
 635      
 636  /*--------------------------------------------------------------------------------------
 637       Class Name: Recordset
 638  --------------------------------------------------------------------------------------*/
 639  
 640  class ADORecordset_mssqlnative extends ADORecordSet {    
 641  
 642      var $databaseType = "mssqlnative";
 643      var $canSeek = false;
 644      var $fieldOffset = 0;
 645      // _mths works only in non-localised system
 646      
 647  	function ADORecordset_mssqlnative($id,$mode=false)
 648      {
 649          if ($mode === false) { 
 650              global $ADODB_FETCH_MODE;
 651              $mode = $ADODB_FETCH_MODE;
 652  
 653          }
 654          $this->fetchMode = $mode;
 655          return $this->ADORecordSet($id,$mode);
 656      }
 657      
 658      
 659  	function _initrs()
 660      {
 661          global $ADODB_COUNTRECS;    
 662          if ($this->connection->debug) error_log("(before) ADODB_COUNTRECS: {$ADODB_COUNTRECS} _numOfRows: {$this->_numOfRows} _numOfFields: {$this->_numOfFields}");
 663          /*$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."
 664          error_log("rowsaff: ".serialize($retRowsAff));
 665          $this->_numOfRows = ($ADODB_COUNTRECS)? $retRowsAff:-1;*/
 666          $this->_numOfRows = -1;//not supported
 667          $fieldmeta = sqlsrv_field_metadata($this->_queryID);
 668          $this->_numOfFields = ($fieldmeta)? count($fieldmeta):-1;
 669          if ($this->connection->debug) error_log("(after) _numOfRows: {$this->_numOfRows} _numOfFields: {$this->_numOfFields}");
 670      }
 671      
 672  
 673      //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se>
 674      // get next resultset - requires PHP 4.0.5 or later
 675  	function NextRecordSet()
 676      {
 677          if (!sqlsrv_next_result($this->_queryID)) return false;
 678          $this->_inited = false;
 679          $this->bind = false;
 680          $this->_currentRow = -1;
 681          $this->Init();
 682          return true;
 683      }
 684  
 685      /* Use associative array to get fields array */
 686  	function Fields($colname)
 687      {
 688          if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname];
 689          if (!$this->bind) {
 690              $this->bind = array();
 691              for ($i=0; $i < $this->_numOfFields; $i++) {
 692                  $o = $this->FetchField($i);
 693                  $this->bind[strtoupper($o->name)] = $i;
 694              }
 695          }
 696          
 697          return $this->fields[$this->bind[strtoupper($colname)]];
 698      }
 699      
 700      /*    Returns: an object containing field information. 
 701          Get column information in the Recordset object. fetchField() can be used in order to obtain information about
 702          fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
 703          fetchField() is retrieved.    */
 704  
 705      function &FetchField($fieldOffset = -1) 
 706      {
 707          if ($this->connection->debug) error_log("<hr>fetchfield: $fieldOffset, fetch array: <pre>".print_r($this->fields,true)."</pre> backtrace: ".adodb_backtrace(false));
 708          if ($fieldOffset != -1) $this->fieldOffset = $fieldOffset;
 709          $arrKeys = array_keys($this->fields);
 710          if(array_key_exists($this->fieldOffset,$arrKeys) && !array_key_exists($arrKeys[$this->fieldOffset],$this->fields)) {
 711              $f = false;
 712          } else {
 713              $f = $this->fields[ $arrKeys[$this->fieldOffset] ];
 714              if($fieldOffset == -1) $this->fieldOffset++;
 715          }
 716  
 717          if (empty($f)) {
 718              $f = false;//PHP Notice: Only variable references should be returned by reference
 719          }
 720          return $f;
 721      }
 722      
 723  	function _seek($row) 
 724      {
 725          return false;//There is no support for cursors in the driver at this time.  All data is returned via forward-only streams.
 726      }
 727  
 728      // speedup
 729  	function MoveNext() 
 730      {
 731          if ($this->connection->debug) error_log("movenext()");
 732          //if ($this->connection->debug) error_log("eof (beginning): ".$this->EOF);
 733          if ($this->EOF) return false;
 734          
 735          $this->_currentRow++;
 736          if ($this->connection->debug) error_log("_currentRow: ".$this->_currentRow);
 737          
 738          if ($this->_fetch()) return true;
 739          $this->EOF = true;
 740          //if ($this->connection->debug) error_log("eof (end): ".$this->EOF);
 741          
 742          return false;
 743      }
 744  
 745      
 746      // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4
 747      // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot!
 748  	function _fetch($ignore_fields=false) 
 749      {
 750          if ($this->connection->debug) error_log("_fetch()");
 751          if ($this->fetchMode & ADODB_FETCH_ASSOC) {
 752              if ($this->fetchMode & ADODB_FETCH_NUM) {
 753                  if ($this->connection->debug) error_log("fetch mode: both");
 754                  $this->fields = @sqlsrv_fetch_array($this->_queryID,SQLSRV_FETCH_BOTH);
 755              } else {
 756                  if ($this->connection->debug) error_log("fetch mode: assoc");
 757                  $this->fields = @sqlsrv_fetch_array($this->_queryID,SQLSRV_FETCH_ASSOC);
 758              }
 759              
 760              if (ADODB_ASSOC_CASE == 0) {
 761                  foreach($this->fields as $k=>$v) {
 762                      $this->fields[strtolower($k)] = $v;
 763                  }
 764              } else if (ADODB_ASSOC_CASE == 1) {
 765                  foreach($this->fields as $k=>$v) {
 766                      $this->fields[strtoupper($k)] = $v;
 767                  }
 768              }
 769          } else {
 770              if ($this->connection->debug) error_log("fetch mode: num");
 771              $this->fields = @sqlsrv_fetch_array($this->_queryID,SQLSRV_FETCH_NUMERIC);
 772          }
 773          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 
 774              $arrFixed = array();
 775              foreach($this->fields as $key=>$value) {
 776                  if(is_numeric($key)) {
 777                      $arrFixed[$key-1] = $value;
 778                  } else {
 779                      $arrFixed[$key] = $value;
 780                  }
 781              }
 782              //if($this->connection->debug) error_log("<hr>fixing non 0 based return array, old: ".print_r($this->fields,true)." new: ".print_r($arrFixed,true));
 783              $this->fields = $arrFixed;
 784          }
 785          if(is_array($this->fields)) {
 786              foreach($this->fields as $key=>$value) {
 787                  if (is_object($value) && method_exists($value, 'format')) {//is DateTime object
 788                      $this->fields[$key] = $value->format("Y-m-d\TH:i:s\Z");
 789                  }
 790              }
 791          }
 792          if($this->fields === null) $this->fields = false;
 793          if ($this->connection->debug) error_log("<hr>after _fetch, fields: <pre>".print_r($this->fields,true)." backtrace: ".adodb_backtrace(false));
 794          return $this->fields;
 795      }
 796      
 797      /*    close() only needs to be called if you are worried about using too much memory while your script
 798          is running. All associated result memory for the specified result identifier will automatically be freed.    */
 799  	function _close() 
 800      {
 801          $rez = sqlsrv_free_stmt($this->_queryID);    
 802          $this->_queryID = false;
 803          return $rez;
 804      }
 805  
 806      // mssql uses a default date like Dec 30 2000 12:00AM
 807  	static function UnixDate($v)
 808      {
 809          return ADORecordSet_array_mssqlnative::UnixDate($v);
 810      }
 811      
 812  	static function UnixTimeStamp($v)
 813      {
 814          return ADORecordSet_array_mssqlnative::UnixTimeStamp($v);
 815      }
 816  }
 817  
 818  
 819  class ADORecordSet_array_mssqlnative extends ADORecordSet_array {
 820  	function ADORecordSet_array_mssqlnative($id=-1,$mode=false) 
 821      {
 822          $this->ADORecordSet_array($id,$mode);
 823      }
 824      
 825          // mssql uses a default date like Dec 30 2000 12:00AM
 826  	static function UnixDate($v)
 827      {
 828      
 829          if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);
 830          
 831          global $ADODB_mssql_mths,$ADODB_mssql_date_order;
 832      
 833          //Dec 30 2000 12:00AM 
 834          if ($ADODB_mssql_date_order == 'dmy') {
 835              if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
 836                  return parent::UnixDate($v);
 837              }
 838              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
 839              
 840              $theday = $rr[1];
 841              $themth =  substr(strtoupper($rr[2]),0,3);
 842          } else {
 843              if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
 844                  return parent::UnixDate($v);
 845              }
 846              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
 847              
 848              $theday = $rr[2];
 849              $themth = substr(strtoupper($rr[1]),0,3);
 850          }
 851          $themth = $ADODB_mssql_mths[$themth];
 852          if ($themth <= 0) return false;
 853          // h-m-s-MM-DD-YY
 854          return  mktime(0,0,0,$themth,$theday,$rr[3]);
 855      }
 856      
 857  	static function UnixTimeStamp($v)
 858      {
 859      
 860          if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);
 861          
 862          global $ADODB_mssql_mths,$ADODB_mssql_date_order;
 863      
 864          //Dec 30 2000 12:00AM
 865           if ($ADODB_mssql_date_order == 'dmy') {
 866               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})|"
 867              ,$v, $rr)) return parent::UnixTimeStamp($v);
 868              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
 869          
 870              $theday = $rr[1];
 871              $themth =  substr(strtoupper($rr[2]),0,3);
 872          } else {
 873              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})|"
 874              ,$v, $rr)) return parent::UnixTimeStamp($v);
 875              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
 876          
 877              $theday = $rr[2];
 878              $themth = substr(strtoupper($rr[1]),0,3);
 879          }
 880          
 881          $themth = $ADODB_mssql_mths[$themth];
 882          if ($themth <= 0) return false;
 883          
 884          switch (strtoupper($rr[6])) {
 885          case 'P':
 886              if ($rr[4]<12) $rr[4] += 12;
 887              break;
 888          case 'A':
 889              if ($rr[4]==12) $rr[4] = 0;
 890              break;
 891          default:
 892              break;
 893          }
 894          // h-m-s-MM-DD-YY
 895          return  mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);
 896      }
 897  }
 898  
 899  /*
 900  Code Example 1:
 901  
 902  select     object_name(constid) as constraint_name,
 903             object_name(fkeyid) as table_name, 
 904          col_name(fkeyid, fkey) as column_name,
 905      object_name(rkeyid) as referenced_table_name,
 906         col_name(rkeyid, rkey) as referenced_column_name
 907  from sysforeignkeys
 908  where object_name(fkeyid) = x
 909  order by constraint_name, table_name, referenced_table_name,  keyno
 910  
 911  Code Example 2:
 912  select     constraint_name,
 913      column_name,
 914      ordinal_position
 915  from information_schema.key_column_usage
 916  where constraint_catalog = db_name()
 917  and table_name = x
 918  order by constraint_name, ordinal_position
 919  
 920  http://www.databasejournal.com/scripts/article.php/1440551
 921  */
 922  
 923  ?>


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7