|
Moodle
2.2.1
http://www.collinsharper.com
|
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 ?>