source: branches/comu-ver2/data/module/adodb/drivers/adodb-mssql.inc.php.bak @ 18701

Revision 18701, 30.7 KB checked in by nanasess, 14 years ago (diff)

Copyright の更新(#601)

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