[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

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

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1