Zikula 1.0.1
[ class tree: Zikula 1.0.1 ] [ index: Zikula 1.0.1 ] [ all elements ]

Source for file adodb-mssql.inc.php

Documentation is available at adodb-mssql.inc.php

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

Documentation generated on Fri, 18 Jul 2008 21:40:01 +0200 by phpDocumentor 1.4.1