[ Index ]

PHP Cross Reference of Moodle 310

title

Body

[close]

/lib/adodb/drivers/ -> adodb-mssql.inc.php (source)

   1  <?php
   2  /*
   3  @version   v5.20.16  12-Jan-2020
   4  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   5  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   6    Released under both BSD license and Lesser GPL library license.
   7    Whenever there is any discrepancy between the two licenses,
   8    the BSD license will take precedence.
   9  Set tabs to 4 for best viewing.
  10  
  11    Latest version is available at http://adodb.org/
  12  
  13    Native mssql driver. Requires mssql client. Works on Windows.
  14    To configure for Unix, see
  15         http://phpbuilder.com/columns/alberto20000919.php3
  16  
  17  */
  18  
  19  
  20  // security - hide paths
  21  if (!defined('ADODB_DIR')) die();
  22  
  23  //----------------------------------------------------------------
  24  // MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002
  25  // and this causes tons of problems because localized versions of
  26  // MSSQL will return the dates in dmy or  mdy order; and also the
  27  // month strings depends on what language has been configured. The
  28  // following two variables allow you to control the localization
  29  // settings - Ugh.
  30  //
  31  // MORE LOCALIZATION INFO
  32  // ----------------------
  33  // To configure datetime, look for and modify sqlcommn.loc,
  34  //      typically found in c:\mssql\install
  35  // Also read :
  36  //     http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918
  37  // Alternatively use:
  38  //        CONVERT(char(12),datecol,120)
  39  //----------------------------------------------------------------
  40  
  41  
  42  // has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc
  43  if (ADODB_PHPVER >= 0x4300) {
  44  // docs say 4.2.0, but testing shows only since 4.3.0 does it work!
  45      ini_set('mssql.datetimeconvert',0);
  46  } else {
  47  global $ADODB_mssql_mths;        // array, months must be upper-case
  48  
  49  
  50      $ADODB_mssql_date_order = 'mdy';
  51      $ADODB_mssql_mths = array(
  52          'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
  53          'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
  54  }
  55  
  56  //---------------------------------------------------------------------------
  57  // Call this to autoset $ADODB_mssql_date_order at the beginning of your code,
  58  // just after you connect to the database. Supports mdy and dmy only.
  59  // Not required for PHP 4.2.0 and above.
  60  function AutoDetect_MSSQL_Date_Order($conn)
  61  {
  62  global $ADODB_mssql_date_order;
  63      $adate = $conn->GetOne('select getdate()');
  64      if ($adate) {
  65          $anum = (int) $adate;
  66          if ($anum > 0) {
  67              if ($anum > 31) {
  68                  //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently");
  69              } else
  70                  $ADODB_mssql_date_order = 'dmy';
  71          } else
  72              $ADODB_mssql_date_order = 'mdy';
  73      }
  74  }
  75  
  76  class ADODB_mssql extends ADOConnection {
  77      var $databaseType = "mssql";
  78      var $dataProvider = "mssql";
  79      var $replaceQuote = "''"; // string to use to replace quotes
  80      var $fmtDate = "'Y-m-d'";
  81      var $fmtTimeStamp = "'Y-m-d\TH:i:s'";
  82      var $hasInsertID = true;
  83      var $substr = "substring";
  84      var $length = 'len';
  85      var $hasAffectedRows = true;
  86      var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
  87      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'))";
  88      var $metaColumnsSQL = # xtype==61 is datetime
  89      "select c.name,t.name,c.length,c.isnullable, c.status,
  90          (case when c.xusertype=61 then 0 else c.xprec end),
  91          (case when c.xusertype=61 then 0 else c.xscale end)
  92      from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
  93      var $hasTop = 'top';        // support mssql SELECT TOP 10 * FROM TABLE
  94      var $hasGenID = true;
  95      var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
  96      var $sysTimeStamp = 'GetDate()';
  97      var $_has_mssql_init;
  98      var $maxParameterLen = 4000;
  99      var $arrayClass = 'ADORecordSet_array_mssql';
 100      var $uniqueSort = true;
 101      var $leftOuter = '*=';
 102      var $rightOuter = '=*';
 103      var $ansiOuter = true; // for mssql7 or later
 104      var $poorAffectedRows = true;
 105      var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000
 106      var $uniqueOrderBy = true;
 107      var $_bindInputArray = true;
 108      var $forceNewConnect = false;
 109  
 110  	function __construct()
 111      {
 112          $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0);
 113      }
 114  
 115  	function ServerInfo()
 116      {
 117      global $ADODB_FETCH_MODE;
 118  
 119  
 120          if ($this->fetchMode === false) {
 121              $savem = $ADODB_FETCH_MODE;
 122              $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 123          } else
 124              $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
 125  
 126          if (0) {
 127              $stmt = $this->PrepareSP('sp_server_info');
 128              $val = 2;
 129              $this->Parameter($stmt,$val,'attribute_id');
 130              $row = $this->GetRow($stmt);
 131          }
 132  
 133          $row = $this->GetRow("execute sp_server_info 2");
 134  
 135  
 136          if ($this->fetchMode === false) {
 137              $ADODB_FETCH_MODE = $savem;
 138          } else
 139              $this->SetFetchMode($savem);
 140  
 141          $arr['description'] = $row[2];
 142          $arr['version'] = ADOConnection::_findvers($arr['description']);
 143          return $arr;
 144      }
 145  
 146  	function IfNull( $field, $ifNull )
 147      {
 148          return " ISNULL($field, $ifNull) "; // if MS SQL Server
 149      }
 150  
 151  	function _insertid()
 152      {
 153      // SCOPE_IDENTITY()
 154      // Returns the last IDENTITY value inserted into an IDENTITY column in
 155      // the same scope. A scope is a module -- a stored procedure, trigger,
 156      // function, or batch. Thus, two statements are in the same scope if
 157      // they are in the same stored procedure, function, or batch.
 158          if ($this->lastInsID !== false) {
 159              return $this->lastInsID; // InsID from sp_executesql call
 160          } else {
 161              return $this->GetOne($this->identitySQL);
 162          }
 163      }
 164  
 165  
 166  
 167      /**
 168      * Correctly quotes a string so that all strings are escaped. We prefix and append
 169      * to the string single-quotes.
 170      * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
 171      *
 172      * @param s         the string to quote
 173      * @param [magic_quotes]    if $s is GET/POST var, set to get_magic_quotes_gpc().
 174      *              This undoes the stupidity of magic quotes for GPC.
 175      *
 176      * @return  quoted string to be sent back to database
 177      */
 178  	function qstr($s,$magic_quotes=false)
 179      {
 180           if (!$magic_quotes) {
 181               return  "'".str_replace("'",$this->replaceQuote,$s)."'";
 182          }
 183  
 184           // undo magic quotes for " unless sybase is on
 185           $sybase = ini_get('magic_quotes_sybase');
 186           if (!$sybase) {
 187               $s = str_replace('\\"','"',$s);
 188               if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
 189                   return "'$s'";
 190               else {// change \' to '' for sybase/mssql
 191                   $s = str_replace('\\\\','\\',$s);
 192                   return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
 193               }
 194           } else {
 195               return "'".$s."'";
 196          }
 197      }
 198  // moodle change end - see readme_moodle.txt
 199  
 200  	function _affectedrows()
 201      {
 202          return $this->GetOne('select @@rowcount');
 203      }
 204  
 205      var $_dropSeqSQL = "drop table %s";
 206  
 207  	function CreateSequence($seq='adodbseq',$start=1)
 208      {
 209  
 210          $this->Execute('BEGIN TRANSACTION adodbseq');
 211          $start -= 1;
 212          $this->Execute("create table $seq (id float(53))");
 213          $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
 214          if (!$ok) {
 215                  $this->Execute('ROLLBACK TRANSACTION adodbseq');
 216                  return false;
 217          }
 218          $this->Execute('COMMIT TRANSACTION adodbseq');
 219          return true;
 220      }
 221  
 222  	function GenID($seq='adodbseq',$start=1)
 223      {
 224          //$this->debug=1;
 225          $this->Execute('BEGIN TRANSACTION adodbseq');
 226          $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
 227          if (!$ok) {
 228              $this->Execute("create table $seq (id float(53))");
 229              $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
 230              if (!$ok) {
 231                  $this->Execute('ROLLBACK TRANSACTION adodbseq');
 232                  return false;
 233              }
 234              $this->Execute('COMMIT TRANSACTION adodbseq');
 235              return $start;
 236          }
 237          $num = $this->GetOne("select id from $seq");
 238          $this->Execute('COMMIT TRANSACTION adodbseq');
 239          return $num;
 240  
 241          // in old implementation, pre 1.90, we returned GUID...
 242          //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");
 243      }
 244  
 245  
 246  	function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
 247      {
 248          $nrows = (int) $nrows;
 249          $offset = (int) $offset;
 250          if ($nrows > 0 && $offset <= 0) {
 251              $sql = preg_replace(
 252                  '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql);
 253  
 254              if ($secs2cache)
 255                  $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
 256              else
 257                  $rs = $this->Execute($sql,$inputarr);
 258          } else
 259              $rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
 260  
 261          return $rs;
 262      }
 263  
 264  
 265      // Format date column in sql string given an input format that understands Y M D
 266  	function SQLDate($fmt, $col=false)
 267      {
 268          if (!$col) $col = $this->sysTimeStamp;
 269          $s = '';
 270  
 271          $len = strlen($fmt);
 272          for ($i=0; $i < $len; $i++) {
 273              if ($s) $s .= '+';
 274              $ch = $fmt[$i];
 275              switch($ch) {
 276              case 'Y':
 277              case 'y':
 278                  $s .= "datename(yyyy,$col)";
 279                  break;
 280              case 'M':
 281                  $s .= "convert(char(3),$col,0)";
 282                  break;
 283              case 'm':
 284                  $s .= "replace(str(month($col),2),' ','0')";
 285                  break;
 286              case 'Q':
 287              case 'q':
 288                  $s .= "datename(quarter,$col)";
 289                  break;
 290              case 'D':
 291              case 'd':
 292                  $s .= "replace(str(day($col),2),' ','0')";
 293                  break;
 294              case 'h':
 295                  $s .= "substring(convert(char(14),$col,0),13,2)";
 296                  break;
 297  
 298              case 'H':
 299                  $s .= "replace(str(datepart(hh,$col),2),' ','0')";
 300                  break;
 301  
 302              case 'i':
 303                  $s .= "replace(str(datepart(mi,$col),2),' ','0')";
 304                  break;
 305              case 's':
 306                  $s .= "replace(str(datepart(ss,$col),2),' ','0')";
 307                  break;
 308              case 'a':
 309              case 'A':
 310                  $s .= "substring(convert(char(19),$col,0),18,2)";
 311                  break;
 312  
 313              default:
 314                  if ($ch == '\\') {
 315                      $i++;
 316                      $ch = substr($fmt,$i,1);
 317                  }
 318                  $s .= $this->qstr($ch);
 319                  break;
 320              }
 321          }
 322          return $s;
 323      }
 324  
 325  
 326  	function BeginTrans()
 327      {
 328          if ($this->transOff) return true;
 329          $this->transCnt += 1;
 330             $ok = $this->Execute('BEGIN TRAN');
 331             return $ok;
 332      }
 333  
 334  	function CommitTrans($ok=true)
 335      {
 336          if ($this->transOff) return true;
 337          if (!$ok) return $this->RollbackTrans();
 338          if ($this->transCnt) $this->transCnt -= 1;
 339          $ok = $this->Execute('COMMIT TRAN');
 340          return $ok;
 341      }
 342  	function RollbackTrans()
 343      {
 344          if ($this->transOff) return true;
 345          if ($this->transCnt) $this->transCnt -= 1;
 346          $ok = $this->Execute('ROLLBACK TRAN');
 347          return $ok;
 348      }
 349  
 350  	function SetTransactionMode( $transaction_mode )
 351      {
 352          $this->_transmode  = $transaction_mode;
 353          if (empty($transaction_mode)) {
 354              $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
 355              return;
 356          }
 357          if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
 358          $this->Execute("SET TRANSACTION ".$transaction_mode);
 359      }
 360  
 361      /*
 362          Usage:
 363  
 364          $this->BeginTrans();
 365          $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables
 366  
 367          # some operation on both tables table1 and table2
 368  
 369          $this->CommitTrans();
 370  
 371          See http://www.swynk.com/friends/achigrik/SQL70Locks.asp
 372      */
 373  	function RowLock($tables,$where,$col='1 as adodbignore')
 374      {
 375          if ($col == '1 as adodbignore') $col = 'top 1 null as ignore';
 376          if (!$this->transCnt) $this->BeginTrans();
 377          return $this->GetOne("select $col from $tables with (ROWLOCK,HOLDLOCK) where $where");
 378      }
 379  
 380  
 381  	function MetaColumns($table, $normalize=true)
 382      {
 383  //        $arr = ADOConnection::MetaColumns($table);
 384  //        return $arr;
 385  
 386          $this->_findschema($table,$schema);
 387          if ($schema) {
 388              $dbName = $this->database;
 389              $this->SelectDB($schema);
 390          }
 391          global $ADODB_FETCH_MODE;
 392          $save = $ADODB_FETCH_MODE;
 393          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 394  
 395          if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
 396          $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
 397  
 398          if ($schema) {
 399              $this->SelectDB($dbName);
 400          }
 401  
 402          if (isset($savem)) $this->SetFetchMode($savem);
 403          $ADODB_FETCH_MODE = $save;
 404          if (!is_object($rs)) {
 405              $false = false;
 406              return $false;
 407          }
 408  
 409          $retarr = array();
 410          while (!$rs->EOF){
 411              $fld = new ADOFieldObject();
 412              $fld->name = $rs->fields[0];
 413              $fld->type = $rs->fields[1];
 414  
 415              $fld->not_null = (!$rs->fields[3]);
 416              $fld->auto_increment = ($rs->fields[4] == 128);        // sys.syscolumns status field. 0x80 = 128 ref: http://msdn.microsoft.com/en-us/library/ms186816.aspx
 417  
 418              if (isset($rs->fields[5]) && $rs->fields[5]) {
 419                  if ($rs->fields[5]>0) $fld->max_length = $rs->fields[5];
 420                  $fld->scale = $rs->fields[6];
 421                  if ($fld->scale>0) $fld->max_length += 1;
 422              } else
 423                  $fld->max_length = $rs->fields[2];
 424  
 425              if ($save == ADODB_FETCH_NUM) {
 426                  $retarr[] = $fld;
 427              } else {
 428                  $retarr[strtoupper($fld->name)] = $fld;
 429              }
 430                  $rs->MoveNext();
 431              }
 432  
 433              $rs->Close();
 434              return $retarr;
 435  
 436      }
 437  
 438  
 439  	function MetaIndexes($table,$primary=false, $owner=false)
 440      {
 441          $table = $this->qstr($table);
 442  
 443          $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno,
 444              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,
 445              CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique
 446              FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id
 447              INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid
 448              INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid
 449              WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table
 450              ORDER BY O.name, I.Name, K.keyno";
 451  
 452          global $ADODB_FETCH_MODE;
 453          $save = $ADODB_FETCH_MODE;
 454          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 455          if ($this->fetchMode !== FALSE) {
 456              $savem = $this->SetFetchMode(FALSE);
 457          }
 458  
 459          $rs = $this->Execute($sql);
 460          if (isset($savem)) {
 461              $this->SetFetchMode($savem);
 462          }
 463          $ADODB_FETCH_MODE = $save;
 464  
 465          if (!is_object($rs)) {
 466              return FALSE;
 467          }
 468  
 469          $indexes = array();
 470          while ($row = $rs->FetchRow()) {
 471              if ($primary && !$row[5]) continue;
 472  
 473              $indexes[$row[0]]['unique'] = $row[6];
 474              $indexes[$row[0]]['columns'][] = $row[1];
 475          }
 476          return $indexes;
 477      }
 478  
 479  	function MetaForeignKeys($table, $owner=false, $upper=false)
 480      {
 481      global $ADODB_FETCH_MODE;
 482  
 483          $save = $ADODB_FETCH_MODE;
 484          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 485          $table = $this->qstr(strtoupper($table));
 486  
 487          $sql =
 488  "select object_name(constid) as constraint_name,
 489      col_name(fkeyid, fkey) as column_name,
 490      object_name(rkeyid) as referenced_table_name,
 491         col_name(rkeyid, rkey) as referenced_column_name
 492  from sysforeignkeys
 493  where upper(object_name(fkeyid)) = $table
 494  order by constraint_name, referenced_table_name, keyno";
 495  
 496          $constraints = $this->GetArray($sql);
 497  
 498          $ADODB_FETCH_MODE = $save;
 499  
 500          $arr = false;
 501          foreach($constraints as $constr) {
 502              //print_r($constr);
 503              $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3];
 504          }
 505          if (!$arr) return false;
 506  
 507          $arr2 = false;
 508  
 509          foreach($arr as $k => $v) {
 510              foreach($v as $a => $b) {
 511                  if ($upper) $a = strtoupper($a);
 512                  $arr2[$a] = $b;
 513              }
 514          }
 515          return $arr2;
 516      }
 517  
 518      //From: Fernando Moreira <FMoreira@imediata.pt>
 519  	function MetaDatabases()
 520      {
 521          if(@mssql_select_db("master")) {
 522                   $qry=$this->metaDatabasesSQL;
 523                   if($rs=@mssql_query($qry,$this->_connectionID)){
 524                           $tmpAr=$ar=array();
 525                           while($tmpAr=@mssql_fetch_row($rs))
 526                                   $ar[]=$tmpAr[0];
 527                          @mssql_select_db($this->database);
 528                           if(sizeof($ar))
 529                                   return($ar);
 530                           else
 531                                   return(false);
 532                   } else {
 533                           @mssql_select_db($this->database);
 534                           return(false);
 535                   }
 536           }
 537           return(false);
 538      }
 539  
 540      // "Stein-Aksel Basma" <basma@accelero.no>
 541      // tested with MSSQL 2000
 542  	function MetaPrimaryKeys($table, $owner=false)
 543      {
 544      global $ADODB_FETCH_MODE;
 545  
 546          $schema = '';
 547          $this->_findschema($table,$schema);
 548          if (!$schema) $schema = $this->database;
 549          if ($schema) $schema = "and k.table_catalog like '$schema%'";
 550  
 551          $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k,
 552          information_schema.table_constraints tc
 553          where tc.constraint_name = k.constraint_name and tc.constraint_type =
 554          'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position ";
 555  
 556          $savem = $ADODB_FETCH_MODE;
 557          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 558          $a = $this->GetCol($sql);
 559          $ADODB_FETCH_MODE = $savem;
 560  
 561          if ($a && sizeof($a)>0) return $a;
 562          $false = false;
 563          return $false;
 564      }
 565  
 566  
 567  	function MetaTables($ttype=false,$showSchema=false,$mask=false)
 568      {
 569          if ($mask) {
 570              $save = $this->metaTablesSQL;
 571              $mask = $this->qstr(($mask));
 572              $this->metaTablesSQL .= " AND name like $mask";
 573          }
 574          $ret = ADOConnection::MetaTables($ttype,$showSchema);
 575  
 576          if ($mask) {
 577              $this->metaTablesSQL = $save;
 578          }
 579          return $ret;
 580      }
 581  
 582  	function SelectDB($dbName)
 583      {
 584          $this->database = $dbName;
 585          $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
 586          if ($this->_connectionID) {
 587              return @mssql_select_db($dbName);
 588          }
 589          else return false;
 590      }
 591  
 592  	function ErrorMsg()
 593      {
 594          if (empty($this->_errorMsg)){
 595              $this->_errorMsg = mssql_get_last_message();
 596          }
 597          return $this->_errorMsg;
 598      }
 599  
 600  	function ErrorNo()
 601      {
 602          if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode;
 603          if (empty($this->_errorMsg)) {
 604              $this->_errorMsg = mssql_get_last_message();
 605          }
 606          $id = @mssql_query("select @@ERROR",$this->_connectionID);
 607          if (!$id) return false;
 608          $arr = mssql_fetch_array($id);
 609          @mssql_free_result($id);
 610          if (is_array($arr)) return $arr[0];
 611         else return -1;
 612      }
 613  
 614      // returns true or false, newconnect supported since php 5.1.0.
 615  	function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$newconnect=false)
 616      {
 617          if (!function_exists('mssql_pconnect')) return null;
 618          $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword,$newconnect);
 619          if ($this->_connectionID === false) return false;
 620          if ($argDatabasename) return $this->SelectDB($argDatabasename);
 621          return true;
 622      }
 623  
 624  
 625      // returns true or false
 626  	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 627      {
 628          if (!function_exists('mssql_pconnect')) return null;
 629          $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword);
 630          if ($this->_connectionID === false) return false;
 631  
 632          // persistent connections can forget to rollback on crash, so we do it here.
 633          if ($this->autoRollback) {
 634              $cnt = $this->GetOne('select @@TRANCOUNT');
 635              while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN');
 636          }
 637          if ($argDatabasename) return $this->SelectDB($argDatabasename);
 638          return true;
 639      }
 640  
 641  	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 642      {
 643          return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
 644      }
 645  
 646  	function Prepare($sql)
 647      {
 648          $sqlarr = explode('?',$sql);
 649          if (sizeof($sqlarr) <= 1) return $sql;
 650          $sql2 = $sqlarr[0];
 651          for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
 652              $sql2 .=  '@P'.($i-1) . $sqlarr[$i];
 653          }
 654          return array($sql,$this->qstr($sql2),$max,$sql2);
 655      }
 656  
 657  	function PrepareSP($sql,$param=true)
 658      {
 659          if (!$this->_has_mssql_init) {
 660              ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
 661              return $sql;
 662          }
 663          $stmt = mssql_init($sql,$this->_connectionID);
 664          if (!$stmt)  return $sql;
 665          return array($sql,$stmt);
 666      }
 667  
 668      // returns concatenated string
 669      // MSSQL requires integers to be cast as strings
 670      // automatically cast every datatype to VARCHAR(255)
 671      // @author David Rogers (introspectshun)
 672      function Concat()
 673      {
 674              $s = "";
 675              $arr = func_get_args();
 676  
 677              // Split single record on commas, if possible
 678              if (sizeof($arr) == 1) {
 679                  foreach ($arr as $arg) {
 680                      $args = explode(',', $arg);
 681                  }
 682                  $arr = $args;
 683              }
 684  
 685              array_walk(
 686                  $arr,
 687                  function(&$value, $key) {
 688                      $value = "CAST(" . $value . " AS VARCHAR(255))";
 689                  }
 690              );
 691              $s = implode('+',$arr);
 692              if (sizeof($arr) > 0) return "$s";
 693  
 694              return '';
 695      }
 696  
 697      /*
 698      Usage:
 699          $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
 700  
 701          # note that the parameter does not have @ in front!
 702          $db->Parameter($stmt,$id,'myid');
 703          $db->Parameter($stmt,$group,'group',false,64);
 704          $db->Execute($stmt);
 705  
 706          @param $stmt Statement returned by Prepare() or PrepareSP().
 707          @param $var PHP variable to bind to. Can set to null (for isNull support).
 708          @param $name Name of stored procedure variable name to bind to.
 709          @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
 710          @param [$maxLen] Holds an maximum length of the variable.
 711          @param [$type] The data type of $var. Legal values depend on driver.
 712  
 713          See mssql_bind documentation at php.net.
 714      */
 715  	function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
 716      {
 717          if (!$this->_has_mssql_init) {
 718              ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0");
 719              return false;
 720          }
 721  
 722          $isNull = is_null($var); // php 4.0.4 and above...
 723  
 724          if ($type === false)
 725              switch(gettype($var)) {
 726              default:
 727              case 'string': $type = SQLVARCHAR; break;
 728              case 'double': $type = SQLFLT8; break;
 729              case 'integer': $type = SQLINT4; break;
 730              case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0
 731              }
 732  
 733          if  ($this->debug) {
 734              $prefix = ($isOutput) ? 'Out' : 'In';
 735              $ztype = (empty($type)) ? 'false' : $type;
 736              ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
 737          }
 738          /*
 739              See http://phplens.com/lens/lensforum/msgs.php?id=7231
 740  
 741              RETVAL is HARD CODED into php_mssql extension:
 742              The return value (a long integer value) is treated like a special OUTPUT parameter,
 743              called "RETVAL" (without the @). See the example at mssql_execute to
 744              see how it works. - type: one of this new supported PHP constants.
 745                  SQLTEXT, SQLVARCHAR,SQLCHAR, SQLINT1,SQLINT2, SQLINT4, SQLBIT,SQLFLT8
 746          */
 747          if ($name !== 'RETVAL') $name = '@'.$name;
 748          return mssql_bind($stmt[1], $name, $var, $type, $isOutput, $isNull, $maxLen);
 749      }
 750  
 751      /*
 752          Unfortunately, it appears that mssql cannot handle varbinary > 255 chars
 753          So all your blobs must be of type "image".
 754  
 755          Remember to set in php.ini the following...
 756  
 757          ; Valid range 0 - 2147483647. Default = 4096.
 758          mssql.textlimit = 0 ; zero to pass through
 759  
 760          ; Valid range 0 - 2147483647. Default = 4096.
 761          mssql.textsize = 0 ; zero to pass through
 762      */
 763  	function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
 764      {
 765  
 766          if (strtoupper($blobtype) == 'CLOB') {
 767              $sql = "UPDATE $table SET $column='" . $val . "' WHERE $where";
 768              return $this->Execute($sql) != false;
 769          }
 770          $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";
 771          return $this->Execute($sql) != false;
 772      }
 773  
 774      // returns query ID if successful, otherwise false
 775  	function _query($sql,$inputarr=false)
 776      {
 777          $this->_errorMsg = false;
 778          if (is_array($inputarr)) {
 779  
 780              # bind input params with sp_executesql:
 781              # see http://www.quest-pipelines.com/newsletter-v3/0402_F.htm
 782              # works only with sql server 7 and newer
 783              $getIdentity = false;
 784              if (!is_array($sql) && preg_match('/^\\s*insert/i', $sql)) {
 785                  $getIdentity = true;
 786                  $sql .= (preg_match('/;\\s*$/i', $sql) ? ' ' : '; ') . $this->identitySQL;
 787              }
 788              if (!is_array($sql)) $sql = $this->Prepare($sql);
 789              $params = '';
 790              $decl = '';
 791              $i = 0;
 792              foreach($inputarr as $v) {
 793                  if ($decl) {
 794                      $decl .= ', ';
 795                      $params .= ', ';
 796                  }
 797                  if (is_string($v)) {
 798                      $len = strlen($v);
 799                      if ($len == 0) $len = 1;
 800  
 801                      if ($len > 4000 ) {
 802                          // NVARCHAR is max 4000 chars. Let's use NTEXT
 803                          $decl .= "@P$i NTEXT";
 804                      } else {
 805                          $decl .= "@P$i NVARCHAR($len)";
 806                      }
 807  
 808  
 809                      if (substr($v,0,1) == "'" && substr($v,-1,1) == "'")
 810                          /*
 811                          * String is already fully quoted
 812                          */
 813                          $inputVar = $v;
 814                      else
 815                          $inputVar = $this->qstr($v);
 816  
 817                      $params .= "@P$i=N" . $inputVar;    
 818                  } else if (is_integer($v)) {
 819                      $decl .= "@P$i INT";
 820                      $params .= "@P$i=".$v;
 821                  } else if (is_float($v)) {
 822                      $decl .= "@P$i FLOAT";
 823                      $params .= "@P$i=".$v;
 824                  } else if (is_bool($v)) {
 825                      $decl .= "@P$i INT"; # Used INT just in case BIT in not supported on the user's MSSQL version. It will cast appropriately.
 826                      $params .= "@P$i=".(($v)?'1':'0'); # True == 1 in MSSQL BIT fields and acceptable for storing logical true in an int field
 827                  } else {
 828                      $decl .= "@P$i CHAR"; # Used char because a type is required even when the value is to be NULL.
 829                      $params .= "@P$i=NULL";
 830                      }
 831                  $i += 1;
 832              }
 833              $decl = $this->qstr($decl);
 834              if ($this->debug) ADOConnection::outp("<font size=-1>sp_executesql N{$sql[1]},N$decl,$params</font>");
 835              $rez = mssql_query("sp_executesql N{$sql[1]},N$decl,$params", $this->_connectionID);
 836              if ($getIdentity) {
 837                  $arr = @mssql_fetch_row($rez);
 838                  $this->lastInsID = isset($arr[0]) ? $arr[0] : false;
 839                  @mssql_data_seek($rez, 0);
 840              }
 841  
 842          } else if (is_array($sql)) {
 843              # PrepareSP()
 844              $rez = mssql_execute($sql[1]);
 845              $this->lastInsID = false;
 846  
 847          } else {
 848              $rez = mssql_query($sql,$this->_connectionID);
 849              $this->lastInsID = false;
 850          }
 851          return $rez;
 852      }
 853  
 854      // returns true or false
 855  	function _close()
 856      {
 857          if ($this->transCnt) $this->RollbackTrans();
 858          $rez = @mssql_close($this->_connectionID);
 859          $this->_connectionID = false;
 860          return $rez;
 861      }
 862  
 863      // mssql uses a default date like Dec 30 2000 12:00AM
 864  	static function UnixDate($v)
 865      {
 866          return ADORecordSet_array_mssql::UnixDate($v);
 867      }
 868  
 869  	static function UnixTimeStamp($v)
 870      {
 871          return ADORecordSet_array_mssql::UnixTimeStamp($v);
 872      }
 873  }
 874  
 875  /*--------------------------------------------------------------------------------------
 876       Class Name: Recordset
 877  --------------------------------------------------------------------------------------*/
 878  
 879  class ADORecordset_mssql extends ADORecordSet {
 880  
 881      var $databaseType = "mssql";
 882      var $canSeek = true;
 883      var $hasFetchAssoc; // see http://phplens.com/lens/lensforum/msgs.php?id=6083
 884      // _mths works only in non-localised system
 885  
 886  	function __construct($id,$mode=false)
 887      {
 888          // freedts check...
 889          $this->hasFetchAssoc = function_exists('mssql_fetch_assoc');
 890  
 891          if ($mode === false) {
 892              global $ADODB_FETCH_MODE;
 893              $mode = $ADODB_FETCH_MODE;
 894  
 895          }
 896          $this->fetchMode = $mode;
 897          return parent::__construct($id,$mode);
 898      }
 899  
 900  
 901  	function _initrs()
 902      {
 903      GLOBAL $ADODB_COUNTRECS;
 904          $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1;
 905          $this->_numOfFields = @mssql_num_fields($this->_queryID);
 906      }
 907  
 908  
 909      //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se>
 910      // get next resultset - requires PHP 4.0.5 or later
 911  	function NextRecordSet()
 912      {
 913          if (!mssql_next_result($this->_queryID)) return false;
 914          $this->_inited = false;
 915          $this->bind = false;
 916          $this->_currentRow = -1;
 917          $this->Init();
 918          return true;
 919      }
 920  
 921      /* Use associative array to get fields array */
 922  	function Fields($colname)
 923      {
 924          if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname];
 925          if (!$this->bind) {
 926              $this->bind = array();
 927              for ($i=0; $i < $this->_numOfFields; $i++) {
 928                  $o = $this->FetchField($i);
 929                  $this->bind[strtoupper($o->name)] = $i;
 930              }
 931          }
 932  
 933           return $this->fields[$this->bind[strtoupper($colname)]];
 934      }
 935  
 936      /*    Returns: an object containing field information.
 937          Get column information in the Recordset object. fetchField() can be used in order to obtain information about
 938          fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
 939          fetchField() is retrieved.    */
 940  
 941  	function FetchField($fieldOffset = -1)
 942      {
 943          if ($fieldOffset != -1) {
 944              $f = @mssql_fetch_field($this->_queryID, $fieldOffset);
 945          }
 946          else if ($fieldOffset == -1) {    /*    The $fieldOffset argument is not provided thus its -1     */
 947              $f = @mssql_fetch_field($this->_queryID);
 948          }
 949          $false = false;
 950          if (empty($f)) return $false;
 951          return $f;
 952      }
 953  
 954  	function _seek($row)
 955      {
 956          return @mssql_data_seek($this->_queryID, $row);
 957      }
 958  
 959      // speedup
 960  	function MoveNext()
 961      {
 962          if ($this->EOF) return false;
 963  
 964          $this->_currentRow++;
 965  
 966          if ($this->fetchMode & ADODB_FETCH_ASSOC) {
 967              if ($this->fetchMode & ADODB_FETCH_NUM) {
 968                  //ADODB_FETCH_BOTH mode
 969                  $this->fields = @mssql_fetch_array($this->_queryID);
 970              }
 971              else {
 972                  if ($this->hasFetchAssoc) {// only for PHP 4.2.0 or later
 973                       $this->fields = @mssql_fetch_assoc($this->_queryID);
 974                  } else {
 975                      $flds = @mssql_fetch_array($this->_queryID);
 976                      if (is_array($flds)) {
 977                          $fassoc = array();
 978                          foreach($flds as $k => $v) {
 979                              if (is_numeric($k)) continue;
 980                              $fassoc[$k] = $v;
 981                          }
 982                          $this->fields = $fassoc;
 983                      } else
 984                          $this->fields = false;
 985                  }
 986              }
 987  
 988              if (is_array($this->fields)) {
 989                  if (ADODB_ASSOC_CASE == 0) {
 990                      foreach($this->fields as $k=>$v) {
 991                          $kn = strtolower($k);
 992                          if ($kn <> $k) {
 993                              unset($this->fields[$k]);
 994                              $this->fields[$kn] = $v;
 995                          }
 996                      }
 997                  } else if (ADODB_ASSOC_CASE == 1) {
 998                      foreach($this->fields as $k=>$v) {
 999                          $kn = strtoupper($k);
1000                          if ($kn <> $k) {
1001                              unset($this->fields[$k]);
1002                              $this->fields[$kn] = $v;
1003                          }
1004                      }
1005                  }
1006              }
1007          } else {
1008              $this->fields = @mssql_fetch_row($this->_queryID);
1009          }
1010          if ($this->fields) return true;
1011          $this->EOF = true;
1012  
1013          return false;
1014      }
1015  
1016  
1017      // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4
1018      // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot!
1019  	function _fetch($ignore_fields=false)
1020      {
1021          if ($this->fetchMode & ADODB_FETCH_ASSOC) {
1022              if ($this->fetchMode & ADODB_FETCH_NUM) {
1023                  //ADODB_FETCH_BOTH mode
1024                  $this->fields = @mssql_fetch_array($this->_queryID);
1025              } else {
1026                  if ($this->hasFetchAssoc) // only for PHP 4.2.0 or later
1027                      $this->fields = @mssql_fetch_assoc($this->_queryID);
1028                  else {
1029                      $this->fields = @mssql_fetch_array($this->_queryID);
1030                      if (@is_array($$this->fields)) {
1031                          $fassoc = array();
1032                          foreach($$this->fields as $k => $v) {
1033                              if (is_integer($k)) continue;
1034                              $fassoc[$k] = $v;
1035                          }
1036                          $this->fields = $fassoc;
1037                      }
1038                  }
1039              }
1040  
1041              if (!$this->fields) {
1042              } else if (ADODB_ASSOC_CASE == 0) {
1043                  foreach($this->fields as $k=>$v) {
1044                      $kn = strtolower($k);
1045                      if ($kn <> $k) {
1046                          unset($this->fields[$k]);
1047                          $this->fields[$kn] = $v;
1048                      }
1049                  }
1050              } else if (ADODB_ASSOC_CASE == 1) {
1051                  foreach($this->fields as $k=>$v) {
1052                      $kn = strtoupper($k);
1053                      if ($kn <> $k) {
1054                          unset($this->fields[$k]);
1055                          $this->fields[$kn] = $v;
1056                      }
1057                  }
1058              }
1059          } else {
1060              $this->fields = @mssql_fetch_row($this->_queryID);
1061          }
1062          return $this->fields;
1063      }
1064  
1065      /*    close() only needs to be called if you are worried about using too much memory while your script
1066          is running. All associated result memory for the specified result identifier will automatically be freed.    */
1067  
1068  	function _close()
1069      {
1070          if($this->_queryID) {
1071              $rez = mssql_free_result($this->_queryID);
1072              $this->_queryID = false;
1073              return $rez;
1074          }
1075          return true;
1076      }
1077  
1078      // mssql uses a default date like Dec 30 2000 12:00AM
1079  	static function UnixDate($v)
1080      {
1081          return ADORecordSet_array_mssql::UnixDate($v);
1082      }
1083  
1084  	static function UnixTimeStamp($v)
1085      {
1086          return ADORecordSet_array_mssql::UnixTimeStamp($v);
1087      }
1088  
1089  }
1090  
1091  
1092  class ADORecordSet_array_mssql extends ADORecordSet_array {
1093  	function __construct($id=-1,$mode=false)
1094      {
1095          parent::__construct($id,$mode);
1096      }
1097  
1098          // mssql uses a default date like Dec 30 2000 12:00AM
1099  	static function UnixDate($v)
1100      {
1101  
1102          if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);
1103  
1104      global $ADODB_mssql_mths,$ADODB_mssql_date_order;
1105  
1106          //Dec 30 2000 12:00AM
1107          if ($ADODB_mssql_date_order == 'dmy') {
1108              if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
1109                  return parent::UnixDate($v);
1110              }
1111              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
1112  
1113              $theday = $rr[1];
1114              $themth =  substr(strtoupper($rr[2]),0,3);
1115          } else {
1116              if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
1117                  return parent::UnixDate($v);
1118              }
1119              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
1120  
1121              $theday = $rr[2];
1122              $themth = substr(strtoupper($rr[1]),0,3);
1123          }
1124          $themth = $ADODB_mssql_mths[$themth];
1125          if ($themth <= 0) return false;
1126          // h-m-s-MM-DD-YY
1127          return  mktime(0,0,0,$themth,$theday,$rr[3]);
1128      }
1129  
1130  	static function UnixTimeStamp($v)
1131      {
1132  
1133          if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);
1134  
1135      global $ADODB_mssql_mths,$ADODB_mssql_date_order;
1136  
1137          //Dec 30 2000 12:00AM
1138           if ($ADODB_mssql_date_order == 'dmy') {
1139               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})|"
1140              ,$v, $rr)) return parent::UnixTimeStamp($v);
1141              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
1142  
1143              $theday = $rr[1];
1144              $themth =  substr(strtoupper($rr[2]),0,3);
1145          } else {
1146              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})|"
1147              ,$v, $rr)) return parent::UnixTimeStamp($v);
1148              if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
1149  
1150              $theday = $rr[2];
1151              $themth = substr(strtoupper($rr[1]),0,3);
1152          }
1153  
1154          $themth = $ADODB_mssql_mths[$themth];
1155          if ($themth <= 0) return false;
1156  
1157          switch (strtoupper($rr[6])) {
1158          case 'P':
1159              if ($rr[4]<12) $rr[4] += 12;
1160              break;
1161          case 'A':
1162              if ($rr[4]==12) $rr[4] = 0;
1163              break;
1164          default:
1165              break;
1166          }
1167          // h-m-s-MM-DD-YY
1168          return  mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);
1169      }
1170  }
1171  
1172  /*
1173  Code Example 1:
1174  
1175  select     object_name(constid) as constraint_name,
1176             object_name(fkeyid) as table_name,
1177          col_name(fkeyid, fkey) as column_name,
1178      object_name(rkeyid) as referenced_table_name,
1179         col_name(rkeyid, rkey) as referenced_column_name
1180  from sysforeignkeys
1181  where object_name(fkeyid) = x
1182  order by constraint_name, table_name, referenced_table_name,  keyno
1183  
1184  Code Example 2:
1185  select     constraint_name,
1186      column_name,
1187      ordinal_position
1188  from information_schema.key_column_usage
1189  where constraint_catalog = db_name()
1190  and table_name = x
1191  order by constraint_name, ordinal_position
1192  
1193  http://www.databasejournal.com/scripts/article.php/1440551
1194  */


Generated: Wed Jan 22 11:59:49 2025 Cross-referenced by PHPXref 0.7.1