Merge branch 'master' of git://github.com/openemr/openemr
[openemr.git] / library / adodb / drivers / adodb-mssql.inc.php
blob30325f39848d8f6da24cd15cece7492e5c32ed68
1 <?php
2 /*
3 V4.20 22 Feb 2004 (c) 2000-2004 John Lim (jlim@natsoft.com.my). 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.
9 Latest version is available at http://php.weblogs.com/
11 Native mssql driver. Requires mssql client. Works on Windows.
12 To configure for Unix, see
13 http://phpbuilder.com/columns/alberto20000919.php3
17 //----------------------------------------------------------------
18 // MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002
19 // and this causes tons of problems because localized versions of
20 // MSSQL will return the dates in dmy or mdy order; and also the
21 // month strings depends on what language has been configured. The
22 // following two variables allow you to control the localization
23 // settings - Ugh.
25 // MORE LOCALIZATION INFO
26 // ----------------------
27 // To configure datetime, look for and modify sqlcommn.loc,
28 // typically found in c:\mssql\install
29 // Also read :
30 // http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918
31 // Alternatively use:
32 // CONVERT(char(12),datecol,120)
33 //----------------------------------------------------------------
36 // has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc
37 if (ADODB_PHPVER >= 0x4300) {
38 // docs say 4.2.0, but testing shows only since 4.3.0 does it work!
39 ini_set('mssql.datetimeconvert',0);
40 } else {
41 global $ADODB_mssql_mths; // array, months must be upper-case
44 $ADODB_mssql_date_order = 'mdy';
45 $ADODB_mssql_mths = array(
46 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
47 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
50 //---------------------------------------------------------------------------
51 // Call this to autoset $ADODB_mssql_date_order at the beginning of your code,
52 // just after you connect to the database. Supports mdy and dmy only.
53 // Not required for PHP 4.2.0 and above.
54 function AutoDetect_MSSQL_Date_Order($conn)
56 global $ADODB_mssql_date_order;
57 $adate = $conn->GetOne('select getdate()');
58 if ($adate) {
59 $anum = (int) $adate;
60 if ($anum > 0) {
61 if ($anum > 31) {
62 //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently");
63 } else
64 $ADODB_mssql_date_order = 'dmy';
65 } else
66 $ADODB_mssql_date_order = 'mdy';
70 class ADODB_mssql extends ADOConnection {
71 var $databaseType = "mssql";
72 var $dataProvider = "mssql";
73 var $replaceQuote = "''"; // string to use to replace quotes
74 var $fmtDate = "'Y-m-d'";
75 var $fmtTimeStamp = "'Y-m-d h:i:sA'";
76 var $hasInsertID = true;
77 var $substr = "substring";
78 var $length = 'len';
79 var $upperCase = 'upper';
80 var $hasAffectedRows = true;
81 var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
82 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'))";
83 var $metaColumnsSQL = # xtype==61 is datetime
84 "select c.name,t.name,c.length,
85 (case when c.xusertype=61 then 0 else c.xprec end),
86 (case when c.xusertype=61 then 0 else c.xscale end)
87 from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
88 var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE
89 var $hasGenID = true;
90 var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
91 var $sysTimeStamp = 'GetDate()';
92 var $_has_mssql_init;
93 var $maxParameterLen = 4000;
94 var $arrayClass = 'ADORecordSet_array_mssql';
95 var $uniqueSort = true;
96 var $leftOuter = '*=';
97 var $rightOuter = '=*';
98 var $ansiOuter = true; // for mssql7 or later
99 var $poorAffectedRows = true;
100 var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000
101 var $uniqueOrderBy = true;
102 var $_bindInputArray = true;
105 function ADODB_mssql()
107 $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0);
110 function ServerInfo()
112 global $ADODB_FETCH_MODE;
114 $stmt = $this->PrepareSP('sp_server_info');
115 $val = 2;
116 if ($this->fetchMode === false) {
117 $savem = $ADODB_FETCH_MODE;
118 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
119 } else
120 $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
123 $this->Parameter($stmt,$val,'attribute_id');
124 $row = $this->GetRow($stmt);
126 //$row = $this->GetRow("execute sp_server_info 2");
128 if ($this->fetchMode === false) {
129 $ADODB_FETCH_MODE = $savem;
130 } else
131 $this->SetFetchMode($savem);
133 $arr['description'] = $row[2];
134 $arr['version'] = ADOConnection::_findvers($arr['description']);
135 return $arr;
138 function IfNull( $field, $ifNull )
140 return " ISNULL($field, $ifNull) "; // if MS SQL Server
143 function _insertid()
145 // SCOPE_IDENTITY()
146 // Returns the last IDENTITY value inserted into an IDENTITY column in
147 // the same scope. A scope is a module -- a stored procedure, trigger,
148 // function, or batch. Thus, two statements are in the same scope if
149 // they are in the same stored procedure, function, or batch.
150 return $this->GetOne($this->identitySQL);
153 function _affectedrows()
155 return $this->GetOne('select @@rowcount');
158 var $_dropSeqSQL = "drop table %s";
160 function CreateSequence($seq='adodbseq',$start=1)
162 $start -= 1;
163 $this->Execute("create table $seq (id float(53))");
164 $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
165 if (!$ok) {
166 $this->Execute('ROLLBACK TRANSACTION adodbseq');
167 return false;
169 $this->Execute('COMMIT TRANSACTION adodbseq');
170 return true;
173 function GenID($seq='adodbseq',$start=1)
175 //$this->debug=1;
176 $this->Execute('BEGIN TRANSACTION adodbseq');
177 $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
178 if (!$ok) {
179 $this->Execute("create table $seq (id float(53))");
180 $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
181 if (!$ok) {
182 $this->Execute('ROLLBACK TRANSACTION adodbseq');
183 return false;
185 $this->Execute('COMMIT TRANSACTION adodbseq');
186 return $start;
188 $num = $this->GetOne("select id from $seq");
189 $this->Execute('COMMIT TRANSACTION adodbseq');
190 return $num;
192 // in old implementation, pre 1.90, we returned GUID...
193 //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");
197 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
199 if ($nrows > 0 && $offset <= 0) {
200 $sql = preg_replace(
201 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql);
202 $rs =& $this->Execute($sql,$inputarr);
203 } else
204 $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
206 return $rs;
210 // Format date column in sql string given an input format that understands Y M D
211 function SQLDate($fmt, $col=false)
213 if (!$col) $col = $this->sysTimeStamp;
214 $s = '';
216 $len = strlen($fmt);
217 for ($i=0; $i < $len; $i++) {
218 if ($s) $s .= '+';
219 $ch = $fmt[$i];
220 switch($ch) {
221 case 'Y':
222 case 'y':
223 $s .= "datename(yyyy,$col)";
224 break;
225 case 'M':
226 $s .= "convert(char(3),$col,0)";
227 break;
228 case 'm':
229 $s .= "replace(str(month($col),2),' ','0')";
230 break;
231 case 'Q':
232 case 'q':
233 $s .= "datename(quarter,$col)";
234 break;
235 case 'D':
236 case 'd':
237 $s .= "replace(str(day($col),2),' ','0')";
238 break;
239 case 'h':
240 $s .= "substring(convert(char(14),$col,0),13,2)";
241 break;
243 case 'H':
244 $s .= "replace(str(datepart(hh,$col),2),' ','0')";
245 break;
247 case 'i':
248 $s .= "replace(str(datepart(mi,$col),2),' ','0')";
249 break;
250 case 's':
251 $s .= "replace(str(datepart(ss,$col),2),' ','0')";
252 break;
253 case 'a':
254 case 'A':
255 $s .= "substring(convert(char(19),$col,0),18,2)";
256 break;
258 default:
259 if ($ch == '\\') {
260 $i++;
261 $ch = substr($fmt,$i,1);
263 $s .= $this->qstr($ch);
264 break;
267 return $s;
271 function BeginTrans()
273 if ($this->transOff) return true;
274 $this->transCnt += 1;
275 $this->Execute('BEGIN TRAN');
276 return true;
279 function CommitTrans($ok=true)
281 if ($this->transOff) return true;
282 if (!$ok) return $this->RollbackTrans();
283 if ($this->transCnt) $this->transCnt -= 1;
284 $this->Execute('COMMIT TRAN');
285 return true;
287 function RollbackTrans()
289 if ($this->transOff) return true;
290 if ($this->transCnt) $this->transCnt -= 1;
291 $this->Execute('ROLLBACK TRAN');
292 return true;
296 Usage:
298 $this->BeginTrans();
299 $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables
301 # some operation on both tables table1 and table2
303 $this->CommitTrans();
305 See http://www.swynk.com/friends/achigrik/SQL70Locks.asp
307 function RowLock($tables,$where)
309 if (!$this->transCnt) $this->BeginTrans();
310 return $this->GetOne("select top 1 null as ignore from $tables with (ROWLOCK,HOLDLOCK) where $where");
313 function MetaForeignKeys($table, $owner=false, $upper=false)
315 global $ADODB_FETCH_MODE;
317 $save = $ADODB_FETCH_MODE;
318 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
319 $table = $this->qstr(strtoupper($table));
321 $sql =
322 "select object_name(constid) as constraint_name,
323 col_name(fkeyid, fkey) as column_name,
324 object_name(rkeyid) as referenced_table_name,
325 col_name(rkeyid, rkey) as referenced_column_name
326 from sysforeignkeys
327 where upper(object_name(fkeyid)) = $table
328 order by constraint_name, referenced_table_name, keyno";
330 $constraints =& $this->GetArray($sql);
332 $ADODB_FETCH_MODE = $save;
334 $arr = false;
335 foreach($constraints as $constr) {
336 //print_r($constr);
337 $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3];
339 if (!$arr) return false;
341 $arr2 = false;
343 foreach($arr as $k => $v) {
344 foreach($v as $a => $b) {
345 if ($upper) $a = strtoupper($a);
346 $arr2[$a] = $b;
349 return $arr2;
352 //From: Fernando Moreira <FMoreira@imediata.pt>
353 function MetaDatabases()
355 if(@mssql_select_db("master")) {
356 $qry=$this->metaDatabasesSQL;
357 if($rs=@mssql_query($qry)){
358 $tmpAr=$ar=array();
359 while($tmpAr=@mssql_fetch_row($rs))
360 $ar[]=$tmpAr[0];
361 @mssql_select_db($this->databaseName);
362 if(sizeof($ar))
363 return($ar);
364 else
365 return(false);
366 } else {
367 @mssql_select_db($this->databaseName);
368 return(false);
371 return(false);
374 // "Stein-Aksel Basma" <basma@accelero.no>
375 // tested with MSSQL 2000
376 function MetaPrimaryKeys($table)
378 $sql = "select k.column_name from information_schema.key_column_usage k,
379 information_schema.table_constraints tc
380 where tc.constraint_name = k.constraint_name and tc.constraint_type =
381 'PRIMARY KEY' and k.table_name = '$table'";
383 $a = $this->GetCol($sql);
384 if ($a && sizeof($a)>0) return $a;
385 return false;
389 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
391 if ($mask) {
392 $save = $this->metaTablesSQL;
393 $mask = $this->qstr(($mask));
394 $this->metaTablesSQL .= " AND name like $mask";
396 $ret =& ADOConnection::MetaTables($ttype,$showSchema);
398 if ($mask) {
399 $this->metaTablesSQL = $save;
401 return $ret;
404 function SelectDB($dbName)
406 $this->databaseName = $dbName;
407 if ($this->_connectionID) {
408 return @mssql_select_db($dbName);
410 else return false;
413 function ErrorMsg()
415 if (empty($this->_errorMsg)){
416 $this->_errorMsg = mssql_get_last_message();
418 return $this->_errorMsg;
421 function ErrorNo()
423 if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode;
424 if (empty($this->_errorMsg)) {
425 $this->_errorMsg = mssql_get_last_message();
427 $id = @mssql_query("select @@ERROR",$this->_connectionID);
428 if (!$id) return false;
429 $arr = mssql_fetch_array($id);
430 @mssql_free_result($id);
431 if (is_array($arr)) return $arr[0];
432 else return -1;
435 // returns true or false
436 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
438 if (!function_exists('mssql_pconnect')) return false;
439 $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword);
440 if ($this->_connectionID === false) return false;
441 if ($argDatabasename) return $this->SelectDB($argDatabasename);
442 return true;
446 // returns true or false
447 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
449 if (!function_exists('mssql_pconnect')) return false;
450 $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword);
451 if ($this->_connectionID === false) return false;
453 // persistent connections can forget to rollback on crash, so we do it here.
454 if ($this->autoRollback) {
455 $cnt = $this->GetOne('select @@TRANCOUNT');
456 while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN');
458 if ($argDatabasename) return $this->SelectDB($argDatabasename);
459 return true;
462 function Prepare($sql)
464 $sqlarr = explode('?',$sql);
465 if (sizeof($sqlarr) <= 1) return $sql;
466 $sql2 = $sqlarr[0];
467 for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
468 $sql2 .= '@P'.($i-1) . $sqlarr[$i];
470 return array($sql,$this->qstr($sql2),$max);
473 function PrepareSP($sql)
475 if (!$this->_has_mssql_init) {
476 ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
477 return $sql;
479 $stmt = mssql_init($sql,$this->_connectionID);
480 if (!$stmt) return $sql;
481 return array($sql,$stmt);
485 Usage:
486 $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
488 # note that the parameter does not have @ in front!
489 $db->Parameter($stmt,$id,'myid');
490 $db->Parameter($stmt,$group,'group',false,64);
491 $db->Execute($stmt);
493 @param $stmt Statement returned by Prepare() or PrepareSP().
494 @param $var PHP variable to bind to. Can set to null (for isNull support).
495 @param $name Name of stored procedure variable name to bind to.
496 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
497 @param [$maxLen] Holds an maximum length of the variable.
498 @param [$type] The data type of $var. Legal values depend on driver.
500 See mssql_bind documentation at php.net.
502 function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
504 if (!$this->_has_mssql_init) {
505 ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0");
506 return $sql;
509 $isNull = is_null($var); // php 4.0.4 and above...
511 if ($type === false)
512 switch(gettype($var)) {
513 default:
514 case 'string': $type = SQLCHAR; break;
515 case 'double': $type = SQLFLT8; break;
516 case 'integer': $type = SQLINT4; break;
517 case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0
520 if ($this->debug) {
521 $prefix = ($isOutput) ? 'Out' : 'In';
522 $ztype = (empty($type)) ? 'false' : $type;
523 ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
526 See http://phplens.com/lens/lensforum/msgs.php?id=7231
528 RETVAL is HARD CODED into php_mssql extension:
529 The return value (a long integer value) is treated like a special OUTPUT parameter,
530 called "RETVAL" (without the @). See the example at mssql_execute to
531 see how it works. - type: one of this new supported PHP constants.
532 SQLTEXT, SQLVARCHAR,SQLCHAR, SQLINT1,SQLINT2, SQLINT4, SQLBIT,SQLFLT8
534 if ($name !== 'RETVAL') $name = '@'.$name;
535 return mssql_bind($stmt[1], $name, $var, $type, $isOutput, $isNull, $maxLen);
539 Unfortunately, it appears that mssql cannot handle varbinary > 255 chars
540 So all your blobs must be of type "image".
542 Remember to set in php.ini the following...
544 ; Valid range 0 - 2147483647. Default = 4096.
545 mssql.textlimit = 0 ; zero to pass through
547 ; Valid range 0 - 2147483647. Default = 4096.
548 mssql.textsize = 0 ; zero to pass through
550 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
552 $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";
553 return $this->Execute($sql) != false;
556 // returns query ID if successful, otherwise false
557 function _query($sql,$inputarr)
559 $this->_errorMsg = false;
560 if (is_array($inputarr)) {
562 # bind input params with sp_executesql:
563 # see http://www.quest-pipelines.com/newsletter-v3/0402_F.htm
564 # works only with sql server 7 and newer
565 if (!is_array($sql)) $sql = $this->Prepare($sql);
566 $params = '';
567 $decl = '';
568 $i = 0;
569 foreach($inputarr as $v) {
570 if ($decl) {
571 $decl .= ', ';
572 $params .= ', ';
574 if (is_string($v)) {
575 $len = strlen($v);
576 if ($len == 0) $len = 1;
578 if ($len > 4000 ) {
579 // NVARCHAR is max 4000 chars. Let's use NTEXT
580 $decl .= "@P$i NTEXT";
581 } else {
582 $decl .= "@P$i NVARCHAR($len)";
585 $params .= "@P$i=N". (strncmp($v,"'",1)==0? $v : $this->qstr($v));
586 } else if (is_integer($v)) {
587 $decl .= "@P$i INT";
588 $params .= "@P$i=".$v;
589 } else {
590 $decl .= "@P$i FLOAT";
591 $params .= "@P$i=".$v;
593 $i += 1;
595 $decl = $this->qstr($decl);
596 if ($this->debug) ADOConnection::outp("<font size=-1>sp_executesql N{$sql[1]},N$decl,$params</font>");
597 $rez = mssql_query("sp_executesql N{$sql[1]},N$decl,$params");
599 } else if (is_array($sql)) {
600 # PrepareSP()
601 $rez = mssql_execute($sql[1]);
603 } else {
604 $rez = mssql_query($sql,$this->_connectionID);
606 return $rez;
609 // returns true or false
610 function _close()
612 if ($this->transCnt) $this->RollbackTrans();
613 $rez = @mssql_close($this->_connectionID);
614 $this->_connectionID = false;
615 return $rez;
618 // mssql uses a default date like Dec 30 2000 12:00AM
619 function UnixDate($v)
621 return ADORecordSet_array_mssql::UnixDate($v);
624 function UnixTimeStamp($v)
626 return ADORecordSet_array_mssql::UnixTimeStamp($v);
630 /*--------------------------------------------------------------------------------------
631 Class Name: Recordset
632 --------------------------------------------------------------------------------------*/
634 class ADORecordset_mssql extends ADORecordSet {
636 var $databaseType = "mssql";
637 var $canSeek = true;
638 var $hasFetchAssoc; // see http://phplens.com/lens/lensforum/msgs.php?id=6083
639 // _mths works only in non-localised system
641 function ADORecordset_mssql($id,$mode=false)
643 // freedts check...
644 $this->hasFetchAssoc = function_exists('mssql_fetch_assoc');
646 if ($mode === false) {
647 global $ADODB_FETCH_MODE;
648 $mode = $ADODB_FETCH_MODE;
650 $this->fetchMode = $mode;
651 return $this->ADORecordSet($id,$mode);
655 function _initrs()
657 GLOBAL $ADODB_COUNTRECS;
658 $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1;
659 $this->_numOfFields = @mssql_num_fields($this->_queryID);
663 //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se>
664 // get next resultset - requires PHP 4.0.5 or later
665 function NextRecordSet()
667 if (!mssql_next_result($this->_queryID)) return false;
668 $this->_inited = false;
669 $this->bind = false;
670 $this->_currentRow = -1;
671 $this->Init();
672 return true;
675 /* Use associative array to get fields array */
676 function Fields($colname)
678 if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname];
679 if (!$this->bind) {
680 $this->bind = array();
681 for ($i=0; $i < $this->_numOfFields; $i++) {
682 $o = $this->FetchField($i);
683 $this->bind[strtoupper($o->name)] = $i;
687 return $this->fields[$this->bind[strtoupper($colname)]];
690 /* Returns: an object containing field information.
691 Get column information in the Recordset object. fetchField() can be used in order to obtain information about
692 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
693 fetchField() is retrieved. */
695 function FetchField($fieldOffset = -1)
697 if ($fieldOffset != -1) {
698 return @mssql_fetch_field($this->_queryID, $fieldOffset);
700 else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
701 return @mssql_fetch_field($this->_queryID);
703 return null;
706 function _seek($row)
708 return @mssql_data_seek($this->_queryID, $row);
711 // speedup
712 function MoveNext()
714 if ($this->EOF) return false;
716 $this->_currentRow++;
718 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
719 if ($this->fetchMode & ADODB_FETCH_NUM) {
720 //ADODB_FETCH_BOTH mode
721 $this->fields = @mssql_fetch_array($this->_queryID);
723 else {
724 if ($this->hasFetchAssoc) {// only for PHP 4.2.0 or later
725 $this->fields = @mssql_fetch_assoc($this->_queryID);
726 } else {
727 $flds = @mssql_fetch_array($this->_queryID);
728 if (is_array($flds)) {
729 $fassoc = array();
730 foreach($flds as $k => $v) {
731 if (is_numeric($k)) continue;
732 $fassoc[$k] = $v;
734 $this->fields = $fassoc;
735 } else
736 $this->fields = false;
740 if (is_array($this->fields)) {
741 if (ADODB_ASSOC_CASE == 0) {
742 foreach($this->fields as $k=>$v) {
743 $this->fields[strtolower($k)] = $v;
745 } else if (ADODB_ASSOC_CASE == 1) {
746 foreach($this->fields as $k=>$v) {
747 $this->fields[strtoupper($k)] = $v;
751 } else {
752 $this->fields = @mssql_fetch_row($this->_queryID);
754 if ($this->fields) return true;
755 $this->EOF = true;
757 return false;
761 // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4
762 // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot!
763 function _fetch($ignore_fields=false)
765 if ($this->fetchMode & ADODB_FETCH_ASSOC) {
766 if ($this->fetchMode & ADODB_FETCH_NUM) {
767 //ADODB_FETCH_BOTH mode
768 $this->fields = @mssql_fetch_array($this->_queryID);
769 } else {
770 if ($this->hasFetchAssoc) // only for PHP 4.2.0 or later
771 $this->fields = @mssql_fetch_assoc($this->_queryID);
772 else {
773 $this->fields = @mssql_fetch_array($this->_queryID);
774 if (is_array($$this->fields)) {
775 $fassoc = array();
776 foreach($$this->fields as $k => $v) {
777 if (is_integer($k)) continue;
778 $fassoc[$k] = $v;
780 $this->fields = $fassoc;
785 if (!$this->fields) {
786 } else if (ADODB_ASSOC_CASE == 0) {
787 foreach($this->fields as $k=>$v) {
788 $this->fields[strtolower($k)] = $v;
790 } else if (ADODB_ASSOC_CASE == 1) {
791 foreach($this->fields as $k=>$v) {
792 $this->fields[strtoupper($k)] = $v;
795 } else {
796 $this->fields = @mssql_fetch_row($this->_queryID);
798 return $this->fields;
801 /* close() only needs to be called if you are worried about using too much memory while your script
802 is running. All associated result memory for the specified result identifier will automatically be freed. */
804 function _close()
806 $rez = mssql_free_result($this->_queryID);
807 $this->_queryID = false;
808 return $rez;
810 // mssql uses a default date like Dec 30 2000 12:00AM
811 function UnixDate($v)
813 return ADORecordSet_array_mssql::UnixDate($v);
816 function UnixTimeStamp($v)
818 return ADORecordSet_array_mssql::UnixTimeStamp($v);
824 class ADORecordSet_array_mssql extends ADORecordSet_array {
825 function ADORecordSet_array_mssql($id=-1,$mode=false)
827 $this->ADORecordSet_array($id,$mode);
830 // mssql uses a default date like Dec 30 2000 12:00AM
831 function UnixDate($v)
834 if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);
836 global $ADODB_mssql_mths,$ADODB_mssql_date_order;
838 //Dec 30 2000 12:00AM
839 if ($ADODB_mssql_date_order == 'dmy') {
840 if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
841 return parent::UnixDate($v);
843 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
845 $theday = $rr[1];
846 $themth = substr(strtoupper($rr[2]),0,3);
847 } else {
848 if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
849 return parent::UnixDate($v);
851 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
853 $theday = $rr[2];
854 $themth = substr(strtoupper($rr[1]),0,3);
856 $themth = $ADODB_mssql_mths[$themth];
857 if ($themth <= 0) return false;
858 // h-m-s-MM-DD-YY
859 return mktime(0,0,0,$themth,$theday,$rr[3]);
862 function UnixTimeStamp($v)
865 if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);
867 global $ADODB_mssql_mths,$ADODB_mssql_date_order;
869 //Dec 30 2000 12:00AM
870 if ($ADODB_mssql_date_order == 'dmy') {
871 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})|"
872 ,$v, $rr)) return parent::UnixTimeStamp($v);
873 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
875 $theday = $rr[1];
876 $themth = substr(strtoupper($rr[2]),0,3);
877 } else {
878 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})|"
879 ,$v, $rr)) return parent::UnixTimeStamp($v);
880 if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
882 $theday = $rr[2];
883 $themth = substr(strtoupper($rr[1]),0,3);
886 $themth = $ADODB_mssql_mths[$themth];
887 if ($themth <= 0) return false;
889 switch (strtoupper($rr[6])) {
890 case 'P':
891 if ($rr[4]<12) $rr[4] += 12;
892 break;
893 case 'A':
894 if ($rr[4]==12) $rr[4] = 0;
895 break;
896 default:
897 break;
899 // h-m-s-MM-DD-YY
900 return mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);
905 Code Example 1:
907 select object_name(constid) as constraint_name,
908 object_name(fkeyid) as table_name,
909 col_name(fkeyid, fkey) as column_name,
910 object_name(rkeyid) as referenced_table_name,
911 col_name(rkeyid, rkey) as referenced_column_name
912 from sysforeignkeys
913 where object_name(fkeyid) = x
914 order by constraint_name, table_name, referenced_table_name, keyno
916 Code Example 2:
917 select constraint_name,
918 column_name,
919 ordinal_position
920 from information_schema.key_column_usage
921 where constraint_catalog = db_name()
922 and table_name = x
923 order by constraint_name, ordinal_position
925 http://www.databasejournal.com/scripts/article.php/1440551