Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/drivers/adodb-mssql.inc.php
Go to the documentation of this file.
00001 <?php
00002 /* 
00003 V5.14 8 Sept 2011  (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved.
00004   Released under both BSD license and Lesser GPL library license. 
00005   Whenever there is any discrepancy between the two licenses, 
00006   the BSD license will take precedence. 
00007 Set tabs to 4 for best viewing.
00008   
00009   Latest version is available at http://adodb.sourceforge.net
00010   
00011   Native mssql driver. Requires mssql client. Works on Windows. 
00012   To configure for Unix, see 
00013         http://phpbuilder.com/columns/alberto20000919.php3
00014         
00015 */
00016 
00017 
00018 // security - hide paths
00019 if (!defined('ADODB_DIR')) die();
00020 
00021 //----------------------------------------------------------------
00022 // MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002
00023 // and this causes tons of problems because localized versions of 
00024 // MSSQL will return the dates in dmy or  mdy order; and also the 
00025 // month strings depends on what language has been configured. The 
00026 // following two variables allow you to control the localization
00027 // settings - Ugh.
00028 //
00029 // MORE LOCALIZATION INFO
00030 // ----------------------
00031 // To configure datetime, look for and modify sqlcommn.loc, 
00032 //      typically found in c:\mssql\install
00033 // Also read :
00034 //       http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918
00035 // Alternatively use:
00036 //         CONVERT(char(12),datecol,120)
00037 //----------------------------------------------------------------
00038 
00039 
00040 // has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc
00041 if (ADODB_PHPVER >= 0x4300) {
00042 // docs say 4.2.0, but testing shows only since 4.3.0 does it work!
00043         ini_set('mssql.datetimeconvert',0); 
00044 } else {
00045 global $ADODB_mssql_mths;               // array, months must be upper-case
00046 
00047 
00048         $ADODB_mssql_date_order = 'mdy'; 
00049         $ADODB_mssql_mths = array(
00050                 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
00051                 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
00052 }
00053 
00054 //---------------------------------------------------------------------------
00055 // Call this to autoset $ADODB_mssql_date_order at the beginning of your code,
00056 // just after you connect to the database. Supports mdy and dmy only.
00057 // Not required for PHP 4.2.0 and above.
00058 function AutoDetect_MSSQL_Date_Order($conn)
00059 {
00060 global $ADODB_mssql_date_order;
00061         $adate = $conn->GetOne('select getdate()');
00062         if ($adate) {
00063                 $anum = (int) $adate;
00064                 if ($anum > 0) {
00065                         if ($anum > 31) {
00066                                 //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently");
00067                         } else
00068                                 $ADODB_mssql_date_order = 'dmy';
00069                 } else
00070                         $ADODB_mssql_date_order = 'mdy';
00071         }
00072 }
00073 
00074 class ADODB_mssql extends ADOConnection {
00075         var $databaseType = "mssql";    
00076         var $dataProvider = "mssql";
00077         var $replaceQuote = "''"; // string to use to replace quotes
00078         var $fmtDate = "'Y-m-d'";
00079         var $fmtTimeStamp = "'Y-m-d H:i:s'";
00080         var $hasInsertID = true;
00081         var $substr = "substring";
00082         var $length = 'len';
00083         var $hasAffectedRows = true;
00084         var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
00085         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'))";
00086         var $metaColumnsSQL = # xtype==61 is datetime
00087 "select c.name,t.name,c.length,
00088         (case when c.xusertype=61 then 0 else c.xprec end),
00089         (case when c.xusertype=61 then 0 else c.xscale end) 
00090         from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
00091         var $hasTop = 'top';            // support mssql SELECT TOP 10 * FROM TABLE
00092         var $hasGenID = true;
00093         var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
00094         var $sysTimeStamp = 'GetDate()';
00095         var $_has_mssql_init;
00096         var $maxParameterLen = 4000;
00097         var $arrayClass = 'ADORecordSet_array_mssql';
00098         var $uniqueSort = true;
00099         var $leftOuter = '*=';
00100         var $rightOuter = '=*';
00101         var $ansiOuter = true; // for mssql7 or later
00102         var $poorAffectedRows = true;
00103         var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000
00104         var $uniqueOrderBy = true;
00105         var $_bindInputArray = true;
00106         var $forceNewConnect = false;
00107         
00108         function ADODB_mssql() 
00109         {               
00110                 $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0);
00111         }
00112 
00113         function ServerInfo()
00114         {
00115         global $ADODB_FETCH_MODE;
00116         
00117         
00118                 if ($this->fetchMode === false) {
00119                         $savem = $ADODB_FETCH_MODE;
00120                         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00121                 } else 
00122                         $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
00123                                 
00124                 if (0) {
00125                         $stmt = $this->PrepareSP('sp_server_info');
00126                         $val = 2;
00127                         $this->Parameter($stmt,$val,'attribute_id');
00128                         $row = $this->GetRow($stmt);
00129                 }
00130                 
00131                 $row = $this->GetRow("execute sp_server_info 2");
00132                 
00133                 
00134                 if ($this->fetchMode === false) {
00135                         $ADODB_FETCH_MODE = $savem;
00136                 } else
00137                         $this->SetFetchMode($savem);
00138                 
00139                 $arr['description'] = $row[2];
00140                 $arr['version'] = ADOConnection::_findvers($arr['description']);
00141                 return $arr;
00142         }
00143         
00144         function IfNull( $field, $ifNull ) 
00145         {
00146                 return " ISNULL($field, $ifNull) "; // if MS SQL Server
00147         }
00148         
00149         function _insertid()
00150         {
00151         // SCOPE_IDENTITY()
00152         // Returns the last IDENTITY value inserted into an IDENTITY column in 
00153         // the same scope. A scope is a module -- a stored procedure, trigger, 
00154         // function, or batch. Thus, two statements are in the same scope if 
00155         // they are in the same stored procedure, function, or batch.
00156         if ($this->lastInsID !== false) {
00157             return $this->lastInsID; // InsID from sp_executesql call
00158         } else {
00159                         return $this->GetOne($this->identitySQL);
00160                 }
00161         }
00162 
00163 
00164 
00176         function qstr($s,$magic_quotes=false)
00177         {
00178                 if (!$magic_quotes) {
00179                         return  "'".str_replace("'",$this->replaceQuote,$s)."'";
00180                 }
00181 
00182                 // undo magic quotes for " unless sybase is on
00183                 $sybase = ini_get('magic_quotes_sybase');
00184                 if (!$sybase) {
00185                         $s = str_replace('\\"','"',$s);
00186                         if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
00187                                 return "'$s'";
00188                         else {// change \' to '' for sybase/mssql
00189                                 $s = str_replace('\\\\','\\',$s);
00190                                 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
00191                         }
00192                 } else {
00193                         return "'".$s."'";
00194                 }
00195         }
00196 // moodle change end - see readme_moodle.txt
00197 
00198         function _affectedrows()
00199         {
00200                 return $this->GetOne('select @@rowcount');
00201         }
00202 
00203         var $_dropSeqSQL = "drop table %s";
00204         
00205         function CreateSequence($seq='adodbseq',$start=1)
00206         {
00207                 
00208                 $this->Execute('BEGIN TRANSACTION adodbseq');
00209                 $start -= 1;
00210                 $this->Execute("create table $seq (id float(53))");
00211                 $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
00212                 if (!$ok) {
00213                                 $this->Execute('ROLLBACK TRANSACTION adodbseq');
00214                                 return false;
00215                 }
00216                 $this->Execute('COMMIT TRANSACTION adodbseq'); 
00217                 return true;
00218         }
00219 
00220         function GenID($seq='adodbseq',$start=1)
00221         {
00222                 //$this->debug=1;
00223                 $this->Execute('BEGIN TRANSACTION adodbseq');
00224                 $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
00225                 if (!$ok) {
00226                         $this->Execute("create table $seq (id float(53))");
00227                         $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
00228                         if (!$ok) {
00229                                 $this->Execute('ROLLBACK TRANSACTION adodbseq');
00230                                 return false;
00231                         }
00232                         $this->Execute('COMMIT TRANSACTION adodbseq'); 
00233                         return $start;
00234                 }
00235                 $num = $this->GetOne("select id from $seq");
00236                 $this->Execute('COMMIT TRANSACTION adodbseq'); 
00237                 return $num;
00238                 
00239                 // in old implementation, pre 1.90, we returned GUID...
00240                 //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");
00241         }
00242         
00243 
00244         function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
00245         {
00246                 if ($nrows > 0 && $offset <= 0) {
00247                         $sql = preg_replace(
00248                                 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql);
00249                                 
00250                         if ($secs2cache)
00251                                 $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
00252                         else
00253                                 $rs = $this->Execute($sql,$inputarr);
00254                 } else
00255                         $rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
00256         
00257                 return $rs;
00258         }
00259         
00260         
00261         // Format date column in sql string given an input format that understands Y M D
00262         function SQLDate($fmt, $col=false)
00263         {       
00264                 if (!$col) $col = $this->sysTimeStamp;
00265                 $s = '';
00266                 
00267                 $len = strlen($fmt);
00268                 for ($i=0; $i < $len; $i++) {
00269                         if ($s) $s .= '+';
00270                         $ch = $fmt[$i];
00271                         switch($ch) {
00272                         case 'Y':
00273                         case 'y':
00274                                 $s .= "datename(yyyy,$col)";
00275                                 break;
00276                         case 'M':
00277                                 $s .= "convert(char(3),$col,0)";
00278                                 break;
00279                         case 'm':
00280                                 $s .= "replace(str(month($col),2),' ','0')";
00281                                 break;
00282                         case 'Q':
00283                         case 'q':
00284                                 $s .= "datename(quarter,$col)";
00285                                 break;
00286                         case 'D':
00287                         case 'd':
00288                                 $s .= "replace(str(day($col),2),' ','0')";
00289                                 break;
00290                         case 'h':
00291                                 $s .= "substring(convert(char(14),$col,0),13,2)";
00292                                 break;
00293                         
00294                         case 'H':
00295                                 $s .= "replace(str(datepart(hh,$col),2),' ','0')";
00296                                 break;
00297                                 
00298                         case 'i':
00299                                 $s .= "replace(str(datepart(mi,$col),2),' ','0')";
00300                                 break;
00301                         case 's':
00302                                 $s .= "replace(str(datepart(ss,$col),2),' ','0')";
00303                                 break;
00304                         case 'a':
00305                         case 'A':
00306                                 $s .= "substring(convert(char(19),$col,0),18,2)";
00307                                 break;
00308                                 
00309                         default:
00310                                 if ($ch == '\\') {
00311                                         $i++;
00312                                         $ch = substr($fmt,$i,1);
00313                                 }
00314                                 $s .= $this->qstr($ch);
00315                                 break;
00316                         }
00317                 }
00318                 return $s;
00319         }
00320 
00321         
00322         function BeginTrans()
00323         {
00324                 if ($this->transOff) return true; 
00325                 $this->transCnt += 1;
00326                 $ok = $this->Execute('BEGIN TRAN');
00327                 return $ok;
00328         }
00329                 
00330         function CommitTrans($ok=true) 
00331         { 
00332                 if ($this->transOff) return true; 
00333                 if (!$ok) return $this->RollbackTrans();
00334                 if ($this->transCnt) $this->transCnt -= 1;
00335                 $ok = $this->Execute('COMMIT TRAN');
00336                 return $ok;
00337         }
00338         function RollbackTrans()
00339         {
00340                 if ($this->transOff) return true; 
00341                 if ($this->transCnt) $this->transCnt -= 1;
00342                 $ok = $this->Execute('ROLLBACK TRAN');
00343                 return $ok;
00344         }
00345         
00346         function SetTransactionMode( $transaction_mode ) 
00347         {
00348                 $this->_transmode  = $transaction_mode;
00349                 if (empty($transaction_mode)) {
00350                         $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
00351                         return;
00352                 }
00353                 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
00354                 $this->Execute("SET TRANSACTION ".$transaction_mode);
00355         }
00356         
00357         /*
00358                 Usage:
00359                 
00360                 $this->BeginTrans();
00361                 $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables
00362                 
00363                 # some operation on both tables table1 and table2
00364                 
00365                 $this->CommitTrans();
00366                 
00367                 See http://www.swynk.com/friends/achigrik/SQL70Locks.asp
00368         */
00369         function RowLock($tables,$where,$col='1 as adodbignore') 
00370         {
00371                 if ($col == '1 as adodbignore') $col = 'top 1 null as ignore';
00372                 if (!$this->transCnt) $this->BeginTrans();
00373                 return $this->GetOne("select $col from $tables with (ROWLOCK,HOLDLOCK) where $where");
00374         }
00375         
00376         
00377         function MetaIndexes($table,$primary=false, $owner=false)
00378         {
00379                 $table = $this->qstr($table);
00380 
00381                 $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno, 
00382                         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,
00383                         CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique
00384                         FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id 
00385                         INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid 
00386                         INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid
00387                         WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table
00388                         ORDER BY O.name, I.Name, K.keyno";
00389 
00390                 global $ADODB_FETCH_MODE;
00391                 $save = $ADODB_FETCH_MODE;
00392         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00393         if ($this->fetchMode !== FALSE) {
00394                 $savem = $this->SetFetchMode(FALSE);
00395         }
00396         
00397         $rs = $this->Execute($sql);
00398         if (isset($savem)) {
00399                 $this->SetFetchMode($savem);
00400         }
00401         $ADODB_FETCH_MODE = $save;
00402 
00403         if (!is_object($rs)) {
00404                 return FALSE;
00405         }
00406 
00407                 $indexes = array();
00408                 while ($row = $rs->FetchRow()) {
00409                         if ($primary && !$row[5]) continue;
00410                         
00411             $indexes[$row[0]]['unique'] = $row[6];
00412             $indexes[$row[0]]['columns'][] = $row[1];
00413         }
00414         return $indexes;
00415         }
00416         
00417         function MetaForeignKeys($table, $owner=false, $upper=false)
00418         {
00419         global $ADODB_FETCH_MODE;
00420         
00421                 $save = $ADODB_FETCH_MODE;
00422                 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00423                 $table = $this->qstr(strtoupper($table));
00424                 
00425                 $sql = 
00426 "select object_name(constid) as constraint_name,
00427         col_name(fkeyid, fkey) as column_name,
00428         object_name(rkeyid) as referenced_table_name,
00429         col_name(rkeyid, rkey) as referenced_column_name
00430 from sysforeignkeys
00431 where upper(object_name(fkeyid)) = $table
00432 order by constraint_name, referenced_table_name, keyno";
00433                 
00434                 $constraints = $this->GetArray($sql);
00435                 
00436                 $ADODB_FETCH_MODE = $save;
00437                 
00438                 $arr = false;
00439                 foreach($constraints as $constr) {
00440                         //print_r($constr);
00441                         $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3]; 
00442                 }
00443                 if (!$arr) return false;
00444                 
00445                 $arr2 = false;
00446                 
00447                 foreach($arr as $k => $v) {
00448                         foreach($v as $a => $b) {
00449                                 if ($upper) $a = strtoupper($a);
00450                                 $arr2[$a] = $b;
00451                         }
00452                 }
00453                 return $arr2;
00454         }
00455 
00456         //From: Fernando Moreira <FMoreira@imediata.pt>
00457         function MetaDatabases() 
00458         { 
00459                 if(@mssql_select_db("master")) { 
00460                                  $qry=$this->metaDatabasesSQL; 
00461                                  if($rs=@mssql_query($qry,$this->_connectionID)){ 
00462                                                  $tmpAr=$ar=array(); 
00463                                                  while($tmpAr=@mssql_fetch_row($rs)) 
00464                                                                  $ar[]=$tmpAr[0]; 
00465                                                 @mssql_select_db($this->database); 
00466                                                  if(sizeof($ar)) 
00467                                                                  return($ar); 
00468                                                  else 
00469                                                                  return(false); 
00470                                  } else { 
00471                                                  @mssql_select_db($this->database); 
00472                                                  return(false); 
00473                                  } 
00474                  } 
00475                  return(false); 
00476         } 
00477 
00478         // "Stein-Aksel Basma" <basma@accelero.no>
00479         // tested with MSSQL 2000
00480         function MetaPrimaryKeys($table, $owner=false)
00481         {
00482         global $ADODB_FETCH_MODE;
00483         
00484                 $schema = '';
00485                 $this->_findschema($table,$schema);
00486                 if (!$schema) $schema = $this->database;
00487                 if ($schema) $schema = "and k.table_catalog like '$schema%'"; 
00488 
00489                 $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k,
00490                 information_schema.table_constraints tc 
00491                 where tc.constraint_name = k.constraint_name and tc.constraint_type =
00492                 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position ";
00493                 
00494                 $savem = $ADODB_FETCH_MODE;
00495                 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00496                 $a = $this->GetCol($sql);
00497                 $ADODB_FETCH_MODE = $savem;
00498                 
00499                 if ($a && sizeof($a)>0) return $a;
00500                 $false = false;
00501                 return $false;    
00502         }
00503 
00504         
00505         function MetaTables($ttype=false,$showSchema=false,$mask=false) 
00506         {
00507                 if ($mask) {
00508                         $save = $this->metaTablesSQL;
00509                         $mask = $this->qstr(($mask));
00510                         $this->metaTablesSQL .= " AND name like $mask";
00511                 }
00512                 $ret = ADOConnection::MetaTables($ttype,$showSchema);
00513                 
00514                 if ($mask) {
00515                         $this->metaTablesSQL = $save;
00516                 }
00517                 return $ret;
00518         }
00519  
00520         function SelectDB($dbName) 
00521         {
00522                 $this->database = $dbName;
00523                 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
00524                 if ($this->_connectionID) {
00525                         return @mssql_select_db($dbName);               
00526                 }
00527                 else return false;      
00528         }
00529         
00530         function ErrorMsg() 
00531         {
00532                 if (empty($this->_errorMsg)){
00533                         $this->_errorMsg = mssql_get_last_message();
00534                 }
00535                 return $this->_errorMsg;
00536         }
00537         
00538         function ErrorNo() 
00539         {
00540                 if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode;
00541                 if (empty($this->_errorMsg)) {
00542                         $this->_errorMsg = mssql_get_last_message();
00543                 }
00544                 $id = @mssql_query("select @@ERROR",$this->_connectionID);
00545                 if (!$id) return false;
00546                 $arr = mssql_fetch_array($id);
00547                 @mssql_free_result($id);
00548                 if (is_array($arr)) return $arr[0];
00549            else return -1;
00550         }
00551         
00552         // returns true or false, newconnect supported since php 5.1.0.
00553         function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$newconnect=false)
00554         {
00555                 if (!function_exists('mssql_pconnect')) return null;
00556                 $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword,$newconnect);
00557                 if ($this->_connectionID === false) return false;
00558                 if ($argDatabasename) return $this->SelectDB($argDatabasename);
00559                 return true;    
00560         }
00561         
00562         
00563         // returns true or false
00564         function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
00565         {
00566                 if (!function_exists('mssql_pconnect')) return null;
00567                 $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword);
00568                 if ($this->_connectionID === false) return false;
00569                 
00570                 // persistent connections can forget to rollback on crash, so we do it here.
00571                 if ($this->autoRollback) {
00572                         $cnt = $this->GetOne('select @@TRANCOUNT');
00573                         while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN'); 
00574                 }
00575                 if ($argDatabasename) return $this->SelectDB($argDatabasename);
00576                 return true;    
00577         }
00578         
00579         function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
00580     {
00581                 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
00582     }
00583 
00584         function Prepare($sql)
00585         {
00586                 $sqlarr = explode('?',$sql);
00587                 if (sizeof($sqlarr) <= 1) return $sql;
00588                 $sql2 = $sqlarr[0];
00589                 for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
00590                         $sql2 .=  '@P'.($i-1) . $sqlarr[$i];
00591                 } 
00592                 return array($sql,$this->qstr($sql2),$max,$sql2);
00593         }
00594         
00595         function PrepareSP($sql,$param=true)
00596         {
00597                 if (!$this->_has_mssql_init) {
00598                         ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
00599                         return $sql;
00600                 }
00601                 $stmt = mssql_init($sql,$this->_connectionID);
00602                 if (!$stmt)  return $sql;
00603                 return array($sql,$stmt);
00604         }
00605         
00606         // returns concatenated string
00607     // MSSQL requires integers to be cast as strings
00608     // automatically cast every datatype to VARCHAR(255)
00609     // @author David Rogers (introspectshun)
00610     function Concat()
00611     {
00612             $s = "";
00613             $arr = func_get_args();
00614 
00615             // Split single record on commas, if possible
00616             if (sizeof($arr) == 1) {
00617                 foreach ($arr as $arg) {
00618                     $args = explode(',', $arg);
00619                 }
00620                 $arr = $args;
00621             }
00622 
00623             array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";'));
00624             $s = implode('+',$arr);
00625             if (sizeof($arr) > 0) return "$s";
00626             
00627                         return '';
00628     }
00629         
00630         /* 
00631         Usage:
00632                 $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
00633                 
00634                 # note that the parameter does not have @ in front!
00635                 $db->Parameter($stmt,$id,'myid');
00636                 $db->Parameter($stmt,$group,'group',false,64);
00637                 $db->Execute($stmt);
00638                 
00639                 @param $stmt Statement returned by Prepare() or PrepareSP().
00640                 @param $var PHP variable to bind to. Can set to null (for isNull support).
00641                 @param $name Name of stored procedure variable name to bind to.
00642                 @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
00643                 @param [$maxLen] Holds an maximum length of the variable.
00644                 @param [$type] The data type of $var. Legal values depend on driver.
00645                 
00646                 See mssql_bind documentation at php.net.
00647         */
00648         function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
00649         {
00650                 if (!$this->_has_mssql_init) {
00651                         ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0");
00652                         return false;
00653                 }
00654 
00655                 $isNull = is_null($var); // php 4.0.4 and above...
00656                         
00657                 if ($type === false) 
00658                         switch(gettype($var)) {
00659                         default:
00660                         case 'string': $type = SQLVARCHAR; break;
00661                         case 'double': $type = SQLFLT8; break;
00662                         case 'integer': $type = SQLINT4; break;
00663                         case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0
00664                         }
00665                 
00666                 if  ($this->debug) {
00667                         $prefix = ($isOutput) ? 'Out' : 'In';
00668                         $ztype = (empty($type)) ? 'false' : $type;
00669                         ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
00670                 }
00671                 /*
00672                         See http://phplens.com/lens/lensforum/msgs.php?id=7231
00673                         
00674                         RETVAL is HARD CODED into php_mssql extension:
00675                         The return value (a long integer value) is treated like a special OUTPUT parameter, 
00676                         called "RETVAL" (without the @). See the example at mssql_execute to 
00677                         see how it works. - type: one of this new supported PHP constants. 
00678                                 SQLTEXT, SQLVARCHAR,SQLCHAR, SQLINT1,SQLINT2, SQLINT4, SQLBIT,SQLFLT8 
00679                 */
00680                 if ($name !== 'RETVAL') $name = '@'.$name;
00681                 return mssql_bind($stmt[1], $name, $var, $type, $isOutput, $isNull, $maxLen);
00682         }
00683         
00684         /* 
00685                 Unfortunately, it appears that mssql cannot handle varbinary > 255 chars
00686                 So all your blobs must be of type "image".
00687                 
00688                 Remember to set in php.ini the following...
00689                 
00690                 ; Valid range 0 - 2147483647. Default = 4096. 
00691                 mssql.textlimit = 0 ; zero to pass through 
00692 
00693                 ; Valid range 0 - 2147483647. Default = 4096. 
00694                 mssql.textsize = 0 ; zero to pass through 
00695         */
00696         function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
00697         {
00698         
00699                 if (strtoupper($blobtype) == 'CLOB') {
00700                         $sql = "UPDATE $table SET $column='" . $val . "' WHERE $where";
00701                         return $this->Execute($sql) != false;
00702                 }
00703                 $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";
00704                 return $this->Execute($sql) != false;
00705         }
00706         
00707         // returns query ID if successful, otherwise false
00708         function _query($sql,$inputarr=false)
00709         {
00710                 $this->_errorMsg = false;
00711                 if (is_array($inputarr)) {
00712                         
00713                         # bind input params with sp_executesql: 
00714                         # see http://www.quest-pipelines.com/newsletter-v3/0402_F.htm
00715                         # works only with sql server 7 and newer
00716             $getIdentity = false;
00717             if (!is_array($sql) && preg_match('/^\\s*insert/i', $sql)) {
00718                 $getIdentity = true;
00719                 $sql .= (preg_match('/;\\s*$/i', $sql) ? ' ' : '; ') . $this->identitySQL;
00720             }
00721                         if (!is_array($sql)) $sql = $this->Prepare($sql);
00722                         $params = '';
00723                         $decl = '';
00724                         $i = 0;
00725                         foreach($inputarr as $v) {
00726                                 if ($decl) {
00727                                         $decl .= ', ';
00728                                         $params .= ', ';
00729                                 }       
00730                                 if (is_string($v)) {
00731                                         $len = strlen($v);
00732                                         if ($len == 0) $len = 1;
00733                                         
00734                                         if ($len > 4000 ) {
00735                                                 // NVARCHAR is max 4000 chars. Let's use NTEXT
00736                                                 $decl .= "@P$i NTEXT";
00737                                         } else {
00738                                                 $decl .= "@P$i NVARCHAR($len)";
00739                                         }
00740 
00741                                         $params .= "@P$i=N". (strncmp($v,"'",1)==0? $v : $this->qstr($v));
00742                                 } else if (is_integer($v)) {
00743                                         $decl .= "@P$i INT";
00744                                         $params .= "@P$i=".$v;
00745                                 } else if (is_float($v)) {
00746                                         $decl .= "@P$i FLOAT";
00747                                         $params .= "@P$i=".$v;
00748                                 } else if (is_bool($v)) {
00749                                         $decl .= "@P$i INT"; # Used INT just in case BIT in not supported on the user's MSSQL version. It will cast appropriately.
00750                                         $params .= "@P$i=".(($v)?'1':'0'); # True == 1 in MSSQL BIT fields and acceptable for storing logical true in an int field
00751                                 } else {
00752                                         $decl .= "@P$i CHAR"; # Used char because a type is required even when the value is to be NULL.
00753                                         $params .= "@P$i=NULL";
00754                                         }
00755                                 $i += 1;
00756                         }
00757                         $decl = $this->qstr($decl);
00758                         if ($this->debug) ADOConnection::outp("<font size=-1>sp_executesql N{$sql[1]},N$decl,$params</font>");
00759                         $rez = mssql_query("sp_executesql N{$sql[1]},N$decl,$params", $this->_connectionID);
00760             if ($getIdentity) {
00761                 $arr = @mssql_fetch_row($rez);
00762                 $this->lastInsID = isset($arr[0]) ? $arr[0] : false;
00763                 @mssql_data_seek($rez, 0);
00764             }
00765                         
00766                 } else if (is_array($sql)) {
00767                         # PrepareSP()
00768                         $rez = mssql_execute($sql[1]);
00769             $this->lastInsID = false;
00770                         
00771                 } else {
00772                         $rez = mssql_query($sql,$this->_connectionID);
00773             $this->lastInsID = false;
00774                 }
00775                 return $rez;
00776         }
00777         
00778         // returns true or false
00779         function _close()
00780         { 
00781                 if ($this->transCnt) $this->RollbackTrans();
00782                 $rez = @mssql_close($this->_connectionID);
00783                 $this->_connectionID = false;
00784                 return $rez;
00785         }
00786         
00787         // mssql uses a default date like Dec 30 2000 12:00AM
00788         static function UnixDate($v)
00789         {
00790                 return ADORecordSet_array_mssql::UnixDate($v);
00791         }
00792         
00793         static function UnixTimeStamp($v)
00794         {
00795                 return ADORecordSet_array_mssql::UnixTimeStamp($v);
00796         }       
00797 }
00798         
00799 /*--------------------------------------------------------------------------------------
00800          Class Name: Recordset
00801 --------------------------------------------------------------------------------------*/
00802 
00803 class ADORecordset_mssql extends ADORecordSet { 
00804 
00805         var $databaseType = "mssql";
00806         var $canSeek = true;
00807         var $hasFetchAssoc; // see http://phplens.com/lens/lensforum/msgs.php?id=6083
00808         // _mths works only in non-localised system
00809         
00810         function ADORecordset_mssql($id,$mode=false)
00811         {
00812                 // freedts check...
00813                 $this->hasFetchAssoc = function_exists('mssql_fetch_assoc');
00814 
00815                 if ($mode === false) { 
00816                         global $ADODB_FETCH_MODE;
00817                         $mode = $ADODB_FETCH_MODE;
00818 
00819                 }
00820                 $this->fetchMode = $mode;
00821                 return $this->ADORecordSet($id,$mode);
00822         }
00823         
00824         
00825         function _initrs()
00826         {
00827         GLOBAL $ADODB_COUNTRECS;        
00828                 $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1;
00829                 $this->_numOfFields = @mssql_num_fields($this->_queryID);
00830         }
00831         
00832 
00833         //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se>
00834         // get next resultset - requires PHP 4.0.5 or later
00835         function NextRecordSet()
00836         {
00837                 if (!mssql_next_result($this->_queryID)) return false;
00838                 $this->_inited = false;
00839                 $this->bind = false;
00840                 $this->_currentRow = -1;
00841                 $this->Init();
00842                 return true;
00843         }
00844 
00845         /* Use associative array to get fields array */
00846         function Fields($colname)
00847         {
00848                 if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname];
00849                 if (!$this->bind) {
00850                         $this->bind = array();
00851                         for ($i=0; $i < $this->_numOfFields; $i++) {
00852                                 $o = $this->FetchField($i);
00853                                 $this->bind[strtoupper($o->name)] = $i;
00854                         }
00855                 }
00856                 
00857                  return $this->fields[$this->bind[strtoupper($colname)]];
00858         }
00859         
00860         /*      Returns: an object containing field information. 
00861                 Get column information in the Recordset object. fetchField() can be used in order to obtain information about
00862                 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
00863                 fetchField() is retrieved.      */
00864 
00865         function FetchField($fieldOffset = -1) 
00866         {
00867                 if ($fieldOffset != -1) {
00868                         $f = @mssql_fetch_field($this->_queryID, $fieldOffset);
00869                 }
00870                 else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
00871                         $f = @mssql_fetch_field($this->_queryID);
00872                 }
00873                 $false = false;
00874                 if (empty($f)) return $false;
00875                 return $f;
00876         }
00877         
00878         function _seek($row) 
00879         {
00880                 return @mssql_data_seek($this->_queryID, $row);
00881         }
00882 
00883         // speedup
00884         function MoveNext() 
00885         {
00886                 if ($this->EOF) return false;
00887                 
00888                 $this->_currentRow++;
00889                 
00890                 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
00891                         if ($this->fetchMode & ADODB_FETCH_NUM) {
00892                                 //ADODB_FETCH_BOTH mode
00893                                 $this->fields = @mssql_fetch_array($this->_queryID);
00894                         }
00895                         else {
00896                                 if ($this->hasFetchAssoc) {// only for PHP 4.2.0 or later
00897                                          $this->fields = @mssql_fetch_assoc($this->_queryID);
00898                                 } else {
00899                                         $flds = @mssql_fetch_array($this->_queryID);
00900                                         if (is_array($flds)) {
00901                                                 $fassoc = array();
00902                                                 foreach($flds as $k => $v) {
00903                                                         if (is_numeric($k)) continue;
00904                                                         $fassoc[$k] = $v;
00905                                                 }
00906                                                 $this->fields = $fassoc;
00907                                         } else
00908                                                 $this->fields = false;
00909                                 }
00910                         }
00911                         
00912                         if (is_array($this->fields)) {
00913                                 if (ADODB_ASSOC_CASE == 0) {
00914                                         foreach($this->fields as $k=>$v) {
00915                                                 $kn = strtolower($k);
00916                                                 if ($kn <> $k) {
00917                                                         unset($this->fields[$k]);
00918                                                         $this->fields[$kn] = $v;
00919                                                 }
00920                                         }
00921                                 } else if (ADODB_ASSOC_CASE == 1) {
00922                                         foreach($this->fields as $k=>$v) {
00923                                                 $kn = strtoupper($k);
00924                                                 if ($kn <> $k) {
00925                                                         unset($this->fields[$k]);
00926                                                         $this->fields[$kn] = $v;
00927                                                 }
00928                                         }
00929                                 }
00930                         }
00931                 } else {
00932                         $this->fields = @mssql_fetch_row($this->_queryID);
00933                 }
00934                 if ($this->fields) return true;
00935                 $this->EOF = true;
00936                 
00937                 return false;
00938         }
00939 
00940         
00941         // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4
00942         // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot!
00943         function _fetch($ignore_fields=false) 
00944         {
00945                 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
00946                         if ($this->fetchMode & ADODB_FETCH_NUM) {
00947                                 //ADODB_FETCH_BOTH mode
00948                                 $this->fields = @mssql_fetch_array($this->_queryID);
00949                         } else {
00950                                 if ($this->hasFetchAssoc) // only for PHP 4.2.0 or later
00951                                         $this->fields = @mssql_fetch_assoc($this->_queryID);
00952                                 else {
00953                                         $this->fields = @mssql_fetch_array($this->_queryID);
00954                                         if (@is_array($$this->fields)) {
00955                                                 $fassoc = array();
00956                                                 foreach($$this->fields as $k => $v) {
00957                                                         if (is_integer($k)) continue;
00958                                                         $fassoc[$k] = $v;
00959                                                 }
00960                                                 $this->fields = $fassoc;
00961                                         }
00962                                 }
00963                         }
00964                         
00965                         if (!$this->fields) {
00966                         } else if (ADODB_ASSOC_CASE == 0) {
00967                                 foreach($this->fields as $k=>$v) {
00968                                         $kn = strtolower($k);
00969                                         if ($kn <> $k) {
00970                                                 unset($this->fields[$k]);
00971                                                 $this->fields[$kn] = $v;
00972                                         }
00973                                 }
00974                         } else if (ADODB_ASSOC_CASE == 1) {
00975                                 foreach($this->fields as $k=>$v) {
00976                                         $kn = strtoupper($k);
00977                                         if ($kn <> $k) {
00978                                                 unset($this->fields[$k]);
00979                                                 $this->fields[$kn] = $v;
00980                                         }
00981                                 }
00982                         }
00983                 } else {
00984                         $this->fields = @mssql_fetch_row($this->_queryID);
00985                 }
00986                 return $this->fields;
00987         }
00988         
00989         /*      close() only needs to be called if you are worried about using too much memory while your script
00990                 is running. All associated result memory for the specified result identifier will automatically be freed.       */
00991 
00992         function _close() 
00993         {
00994                 $rez = mssql_free_result($this->_queryID);      
00995                 $this->_queryID = false;
00996                 return $rez;
00997         }
00998         // mssql uses a default date like Dec 30 2000 12:00AM
00999         static function UnixDate($v)
01000         {
01001                 return ADORecordSet_array_mssql::UnixDate($v);
01002         }
01003         
01004         static function UnixTimeStamp($v)
01005         {
01006                 return ADORecordSet_array_mssql::UnixTimeStamp($v);
01007         }
01008         
01009 }
01010 
01011 
01012 class ADORecordSet_array_mssql extends ADORecordSet_array {
01013         function ADORecordSet_array_mssql($id=-1,$mode=false) 
01014         {
01015                 $this->ADORecordSet_array($id,$mode);
01016         }
01017         
01018                 // mssql uses a default date like Dec 30 2000 12:00AM
01019         static function UnixDate($v)
01020         {
01021         
01022                 if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);
01023                 
01024         global $ADODB_mssql_mths,$ADODB_mssql_date_order;
01025         
01026                 //Dec 30 2000 12:00AM 
01027                 if ($ADODB_mssql_date_order == 'dmy') {
01028                         if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
01029                                 return parent::UnixDate($v);
01030                         }
01031                         if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
01032                         
01033                         $theday = $rr[1];
01034                         $themth =  substr(strtoupper($rr[2]),0,3);
01035                 } else {
01036                         if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
01037                                 return parent::UnixDate($v);
01038                         }
01039                         if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
01040                         
01041                         $theday = $rr[2];
01042                         $themth = substr(strtoupper($rr[1]),0,3);
01043                 }
01044                 $themth = $ADODB_mssql_mths[$themth];
01045                 if ($themth <= 0) return false;
01046                 // h-m-s-MM-DD-YY
01047                 return  mktime(0,0,0,$themth,$theday,$rr[3]);
01048         }
01049         
01050         static function UnixTimeStamp($v)
01051         {
01052         
01053                 if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);
01054                 
01055         global $ADODB_mssql_mths,$ADODB_mssql_date_order;
01056         
01057                 //Dec 30 2000 12:00AM
01058                  if ($ADODB_mssql_date_order == 'dmy') {
01059                          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})|"
01060                         ,$v, $rr)) return parent::UnixTimeStamp($v);
01061                         if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
01062                 
01063                         $theday = $rr[1];
01064                         $themth =  substr(strtoupper($rr[2]),0,3);
01065                 } else {
01066                         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})|"
01067                         ,$v, $rr)) return parent::UnixTimeStamp($v);
01068                         if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
01069                 
01070                         $theday = $rr[2];
01071                         $themth = substr(strtoupper($rr[1]),0,3);
01072                 }
01073                 
01074                 $themth = $ADODB_mssql_mths[$themth];
01075                 if ($themth <= 0) return false;
01076                 
01077                 switch (strtoupper($rr[6])) {
01078                 case 'P':
01079                         if ($rr[4]<12) $rr[4] += 12;
01080                         break;
01081                 case 'A':
01082                         if ($rr[4]==12) $rr[4] = 0;
01083                         break;
01084                 default:
01085                         break;
01086                 }
01087                 // h-m-s-MM-DD-YY
01088                 return  mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);
01089         }
01090 }
01091 
01092 /*
01093 Code Example 1:
01094 
01095 select  object_name(constid) as constraint_name,
01096         object_name(fkeyid) as table_name, 
01097         col_name(fkeyid, fkey) as column_name,
01098         object_name(rkeyid) as referenced_table_name,
01099         col_name(rkeyid, rkey) as referenced_column_name
01100 from sysforeignkeys
01101 where object_name(fkeyid) = x
01102 order by constraint_name, table_name, referenced_table_name,  keyno
01103 
01104 Code Example 2:
01105 select  constraint_name,
01106         column_name,
01107         ordinal_position
01108 from information_schema.key_column_usage
01109 where constraint_catalog = db_name()
01110 and table_name = x
01111 order by constraint_name, ordinal_position
01112 
01113 http://www.databasejournal.com/scripts/article.php/1440551
01114 */
01115 
01116 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations