1   <?php
  2   /*
  3   V1.40 19 September 2001 (c) 2000, 2001 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 8.
  8    
  9     MySQL code that does not support transactions. Use mysqlt if you need transactions.
  10     Requires mysql client. Works on Windows and Unix.
  11    
  12    28 Feb 2001: MetaColumns bug fix - suggested by  Freek Dijkstra (phpeverywhere@macfreek.com)
  13   */
  14  
  15   if (! defined("_ADODB_MYSQL_LAYER")) {
  16    define("_ADODB_MYSQL_LAYER", 1 );
  17  
  18   class ADODB_mysql extends ADODBConnection {
  19           var $databaseType = 'mysql';
  20       var $hasInsertID = true;
  21       var $hasAffectedRows = true;        
  22           var $metaTablesSQL = "SHOW TABLES";     
  23           var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
  24           var $fmtTimeStamp = "'Y-m-d H:i:s'";
  25           var $hasLimit = true;
  26           var $hasMoveFirst = true;
  27           var $hasGenID = true;
  28           
  29           function ADODB_mysql()
  30           {                       
  31           }
  32           
  33       function _insertid()
  34       {
  35               return mysql_insert_id($this->_connectionID);
  36       }
  37      
  38       function _affectedrows()
  39       {
  40               return mysql_affected_rows($this->_connectionID);
  41       }
  42    
  43           // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
  44           // Reference on Last_Insert_ID on the recommended way to simulate sequences
  45           var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
  46           var $_genSeqSQL = "create table %s (id int not null)";
  47           var $_genSeq2SQL = "insert into %s values (0)";
  48           
  49           function GenID($seqname='adodbseq')
  50           {
  51                   if (!$this->hasGenID) return false;
  52                   
  53                   $getnext = sprintf($this->_genIDSQL,$seqname);
  54                   $rs = @$this->Execute($getnext);
  55                   if (!$rs) {
  56                           $u = strtoupper($seqname);
  57                           $this->Execute(sprintf($this->_genSeqSQL,$seqname));
  58                           $this->Execute(sprintf($this->_genSeq2SQL,$seqname));
  59                           $rs = $this->Execute($getnext);
  60                   }
  61                   $this->genID = mysql_insert_id($this->_connectionID);
  62                   
  63                   if ($rs) $rs->Close();
  64                   
  65                   return $this->genID;
  66           }
  67           
  68           function &MetaDatabases()
  69           {
  70                   $qid = mysql_list_dbs($this->_connectionID);
  71                   $arr = array();
  72                   $i = 0;
  73                   $max = mysql_num_rows($qid);
  74                   while ($i < $max) {
  75                           $arr[] = mysql_tablename($qid,$i);
  76                           $i += 1;
  77                   }
  78                   return $arr;
  79           }
  80  
  81           // returns concatenated string
  82           function Concat()
  83           {
  84                   $s = "";
  85                   $arr = func_get_args();
  86                   $first = true;
  87                   /*
  88                   foreach($arr as $a) {
  89                           if ($first) {
  90                                   $s = $a;
  91                                   $first = false;
  92                           } else $s .= ','.$a;
  93                   }*/
  94                   
  95                   // suggestion by andrew005@mnogo.ru
  96                   $s = implode(',',$arr);
  97                   if (strlen($s) > 0) return "CONCAT($s)";
  98                   else return '';
  99           }
  100           
  101           // returns true or false
  102           function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
  103           {
  104                   $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword);
  105                   if ($this->_connectionID === false) return false;
  106                   if ($argDatabasename) return $this->SelectDB($argDatabasename);
  107                   return true;    
  108           }
  109           
  110           // returns true or false
  111           function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
  112           {
  113                   $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword);
  114                   if ($this->_connectionID === false) return false;
  115                   if ($argDatabasename) return $this->SelectDB($argDatabasename);
  116                   return true;    
  117           }
  118           
  119           function &MetaColumns($table)
  120           {
  121                   if ($this->metaColumnsSQL) {
  122                   
  123                           $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
  124                           
  125                           if ($rs === false) return false;
  126                           
  127                           $retarr = array();
  128                           while (!$rs->EOF){
  129                                   $fld = new ADODBFieldObject();
  130                                   $fld->name = $rs->fields[0];
  131                                   $fld->type = $rs->fields[1];
  132                                           
  133                                   // split type into type(length):
  134                                   if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {
  135                                           $fld->type = $query_array[1];
  136                                           $fld->max_length = $query_array[2];
  137                                   } else {
  138                                           $fld->max_length = -1;
  139                                   }
  140                                   $fld->not_null = ($rs->fields[2] != 'YES');
  141                                   $fld->primary_key = ($rs->fields[3] == 'PRI');
  142                                   $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
  143                                   $fld->binary = (strpos($fld->type,'blob') !== false);
  144                                   
  145                                   $retarr[strtoupper($fld->name)] = $fld
  146                                   $rs->MoveNext();
  147                           }
  148                           $rs->Close();
  149                           return $retarr
  150                   }
  151                   return false;
  152           }
  153                   
  154           // returns true or false
  155           function SelectDB($dbName)
  156           {
  157                   $this->databaseName = $dbName;
  158                   if ($this->_connectionID) {
  159                           return @mysql_select_db($dbName,$this->_connectionID);          
  160                   }
  161                   else return false;      
  162           }
  163           
  164           // parameters use PostgreSQL convention, not MySQL
  165           function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)
  166           {
  167                   $offsetStr =($offset>=0) ? "$offset," : '';
  168                   
  169                   return ($secs) ? $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr,$arg3)
  170                           : $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr,$arg3);
  171                   
  172           }
  173           
  174           // returns queryID or false
  175           function _query($sql,$inputarr)
  176           {
  177                   global $ADODB_COUNTRECS;
  178                   
  179                   if($ADODB_COUNTRECS)
  180                           $r= @mysql_query($sql,$this->_connectionID);
  181                   else
  182                           $r = @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
  183                   
  184                   return $r;
  185           }
  186  
  187           /*      Returns: the last error message from previous database operation        */      
  188           function ErrorMsg()
  189           {
  190                   $this->_errorMsg = @mysql_error($this->_connectionID);
  191                   return $this->_errorMsg;
  192           }
  193           
  194           /*      Returns: the last error number from previous database operation */      
  195           function ErrorNo()
  196           {
  197                   return @mysql_errno($this->_connectionID);
  198           }
  199           
  200           // returns true or false
  201           function _close()
  202           {
  203                   return @mysql_close($this->_connectionID);
  204           }
  205                   
  206   }
  207           
  208   /*--------------------------------------------------------------------------------------
  209            Class Name: Recordset
  210   --------------------------------------------------------------------------------------*/
  211  
  212   class ADORecordSet_mysql extends ADORecordSet{  
  213           
  214           var $databaseType = "mysql";
  215           var $canSeek = true;
  216           var $fetchMode;
  217           
  218           function ADORecordSet_mysql($queryID) {
  219           GLOBAL $ADODB_FETCH_MODE;
  220           
  221                   switch ($ADODB_FETCH_MODE)
  222                   {
  223                   case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
  224                   case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
  225                   default:
  226                   case ADODB_FETCH_DEFAULT:
  227                   case ADODB_FETCH_BOTH:$this->fetchMode = MYSQL_BOTH; break;
  228                   }
  229           
  230                   $this->ADORecordSet($queryID);  
  231           }
  232           
  233           function _initrs()
  234           {
  235           GLOBAL $ADODB_COUNTRECS;
  236                   $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
  237                   $this->_numOfFields = @mysql_num_fields($this->_queryID);
  238           }
  239           
  240           function &FetchField($fieldOffset = -1) {
  241                   if ($fieldOffset != -1) {
  242                           $o =  @mysql_fetch_field($this->_queryID, $fieldOffset);
  243                           $f = @mysql_field_flags($this->_queryID,$fieldOffset);
  244                           $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich@att.com)
  245                           //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
  246                           $o->binary = (strpos($f,'binary')!== false);
  247                   }
  248                   else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
  249                           $o = @mysql_fetch_field($this->_queryID);
  250                           $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich@att.com)
  251                           //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
  252                   }
  253                   
  254                   return $o;
  255           }
  256  
  257           function _seek($row)
  258           {
  259                   return @mysql_data_seek($this->_queryID,$row);
  260           }
  261           
  262           // 10% speedup to move MoveNext to child class
  263           function MoveNext($ignore_fields=false)
  264           {
  265                   if ($this->_numOfRows != 0 && !$this->EOF) {            
  266                           $this->_currentRow++;
  267                           // using & below slows things down by 20%!
  268                           $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
  269                           
  270                           if (is_array($this->fields)) return true;
  271                   }
  272                   $this->EOF = true;
  273                   return false;
  274           }       
  275           
  276           function _fetch($ignore_fields=false)
  277           {
  278                   $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
  279                   return (is_array($this->fields));
  280           }
  281           
  282           function _close() {
  283                   return @mysql_free_result($this->_queryID);             
  284           }
  285           
  286           function MetaType($t,$len=-1,$fieldobj=false)
  287           {
  288                   $len = -1; // mysql max_length is not accurate
  289                   switch (strtoupper($t)) {
  290                   case 'STRING':
  291                   case 'CHAR':
  292                   case 'VARCHAR':
  293                   case 'TINYBLOB':
  294                   case 'TINYTEXT':
  295                   case 'ENUM':
  296                   case 'SET':
  297                           if ($len <= $this->blobSize) return 'C';
  298                           
  299                   case 'TEXT':
  300                   case 'LONGTEXT':
  301                   case 'MEDIUMTEXT':
  302                           return 'X';
  303                           
  304                   // php_mysql extension always returns 'blob' even if 'text'
  305                   // so we have to check whether binary...
  306                   case 'IMAGE':
  307                   case 'LONGBLOB':
  308                   case 'BLOB':
  309                   case 'MEDIUMBLOB':
  310                           return !empty($fieldobj->binary) ? 'B' : 'X';
  311                           
  312                   case 'DATE': return 'D';
  313                   
  314                   case 'DATETIME':
  315                   case 'TIMESTAMP': return 'T';
  316                   
  317                   case 'INT':
  318                   case 'INTEGER':
  319                   case 'BIGINT':
  320                   case 'TINYINT':
  321                   case 'MEDIUMINT':
  322                   case 'SMALLINT':
  323                           
  324                           if (!empty($fieldobj->primary_key)) return 'R';
  325                           else return 'I';
  326                   
  327                   default: return 'N';
  328                   }
  329           }
  330  
  331   }
  332   }
  333   ?>