]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiDB/adodb/drivers/adodb-mysql.inc.php
extra_empty_lines
[SourceForge/phpwiki.git] / lib / WikiDB / adodb / drivers / adodb-mysql.inc.php
1 <?php
2 /*
3 V4.22 15 Apr 2004  (c) 2000-2004 John Lim (jlim@natsoft.com.my). All rights reserved.
4   Released under both BSD license and Lesser GPL library license.
5   Whenever there is any discrepancy between the two licenses,
6   the BSD license will take precedence.
7   Set tabs to 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 ADOConnection {
19     var $databaseType = 'mysql';
20     var $dataProvider = 'mysql';
21     var $hasInsertID = true;
22     var $hasAffectedRows = true;
23     var $metaTablesSQL = "SHOW TABLES";
24     var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
25     var $fmtTimeStamp = "'Y-m-d H:i:s'";
26     var $hasLimit = true;
27     var $hasMoveFirst = true;
28     var $hasGenID = true;
29     var $upperCase = 'upper';
30     var $isoDates = true; // accepts dates in ISO format
31     var $sysDate = 'CURDATE()';
32     var $sysTimeStamp = 'NOW()';
33     var $hasTransactions = false;
34     var $forceNewConnect = false;
35     var $poorAffectedRows = true;
36     var $clientFlags = 0;
37     var $substr = "substring";
38     var $nameQuote = '`';               /// string to use to quote identifiers and names
39
40     function ADODB_mysql()
41     {
42     }
43
44     function ServerInfo()
45     {
46         $arr['description'] = ADOConnection::GetOne("select version()");
47         $arr['version'] = ADOConnection::_findvers($arr['description']);
48         return $arr;
49     }
50
51     function IfNull( $field, $ifNull )
52     {
53         return " IFNULL($field, $ifNull) "; // if MySQL
54     }
55
56     function &MetaTables($ttype=false,$showSchema=false,$mask=false)
57     {
58         if ($mask) {
59             $save = $this->metaTablesSQL;
60             $mask = $this->qstr($mask);
61             $this->metaTablesSQL .= " like $mask";
62         }
63         $ret =& ADOConnection::MetaTables($ttype,$showSchema);
64
65         if ($mask) {
66             $this->metaTablesSQL = $save;
67         }
68         return $ret;
69     }
70
71     function &MetaIndexes ($table, $primary = FALSE, $owner=false)
72     {
73         // save old fetch mode
74         global $ADODB_FETCH_MODE;
75
76         $save = $ADODB_FETCH_MODE;
77         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
78         if ($this->fetchMode !== FALSE) {
79                $savem = $this->SetFetchMode(FALSE);
80         }
81
82         // get index details
83         $rs = $this->Execute(sprintf('SHOW INDEX FROM %s',$table));
84
85         // restore fetchmode
86         if (isset($savem)) {
87                 $this->SetFetchMode($savem);
88         }
89         $ADODB_FETCH_MODE = $save;
90
91         if (!is_object($rs)) {
92                 return FALSE;
93         }
94
95         $indexes = array ();
96
97         // parse index data into array
98         while ($row = $rs->FetchRow()) {
99                 if ($primary == FALSE AND $row[2] == 'PRIMARY') {
100                         continue;
101                 }
102
103                 if (!isset($indexes[$row[2]])) {
104                         $indexes[$row[2]] = array(
105                                 'unique' => ($row[1] == 0),
106                                 'columns' => array()
107                         );
108                 }
109
110                 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
111         }
112
113         // sort columns by order in the index
114         foreach ( array_keys ($indexes) as $index )
115         {
116                 ksort ($indexes[$index]['columns']);
117         }
118
119         return $indexes;
120     }
121
122     // if magic quotes disabled, use mysql_real_escape_string()
123     function qstr($s,$magic_quotes=false)
124     {
125         if (!$magic_quotes) {
126
127             if (ADODB_PHPVER >= 0x4300) {
128                 if (is_resource($this->_connectionID))
129                     return "'".mysql_real_escape_string($s,$this->_connectionID)."'";
130             }
131             if ($this->replaceQuote[0] == '\\'){
132                 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
133             }
134             return  "'".str_replace("'",$this->replaceQuote,$s)."'";
135         }
136
137         // undo magic quotes for "
138         $s = str_replace('\\"','"',$s);
139         return "'$s'";
140     }
141
142     function _insertid()
143     {
144         return mysql_insert_id($this->_connectionID);
145     }
146
147     function GetOne($sql,$inputarr=false)
148     {
149         $rs =& $this->SelectLimit($sql,1,-1,$inputarr);
150         if ($rs) {
151             $rs->Close();
152             if ($rs->EOF) return false;
153             return reset($rs->fields);
154         }
155
156         return false;
157     }
158
159     function _affectedrows()
160     {
161             return mysql_affected_rows($this->_connectionID);
162     }
163
164      // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
165     // Reference on Last_Insert_ID on the recommended way to simulate sequences
166      var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
167     var $_genSeqSQL = "create table %s (id int not null)";
168     var $_genSeq2SQL = "insert into %s values (%s)";
169     var $_dropSeqSQL = "drop table %s";
170
171     function CreateSequence($seqname='adodbseq',$startID=1)
172     {
173         if (empty($this->_genSeqSQL)) return false;
174         $u = strtoupper($seqname);
175
176         $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
177         if (!$ok) return false;
178         return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
179     }
180
181
182     function GenID($seqname='adodbseq',$startID=1)
183     {
184         // post-nuke sets hasGenID to false
185         if (!$this->hasGenID) return false;
186
187         $savelog = $this->_logsql;
188         $this->_logsql = false;
189         $getnext = sprintf($this->_genIDSQL,$seqname);
190         $holdtransOK = $this->_transOK; // save the current status
191         $rs = @$this->Execute($getnext);
192         if (!$rs) {
193             if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
194             $u = strtoupper($seqname);
195             $this->Execute(sprintf($this->_genSeqSQL,$seqname));
196             $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
197             $rs = $this->Execute($getnext);
198         }
199         $this->genID = mysql_insert_id($this->_connectionID);
200
201         if ($rs) $rs->Close();
202
203         $this->_logsql = $savelog;
204         return $this->genID;
205     }
206
207       function &MetaDatabases()
208     {
209         $qid = mysql_list_dbs($this->_connectionID);
210         $arr = array();
211         $i = 0;
212         $max = mysql_num_rows($qid);
213         while ($i < $max) {
214             $db = mysql_tablename($qid,$i);
215             if ($db != 'mysql') $arr[] = $db;
216             $i += 1;
217         }
218         return $arr;
219     }
220
221
222     // Format date column in sql string given an input format that understands Y M D
223     function SQLDate($fmt, $col=false)
224     {
225         if (!$col) $col = $this->sysTimeStamp;
226         $s = 'DATE_FORMAT('.$col.",'";
227         $concat = false;
228         $len = strlen($fmt);
229         for ($i=0; $i < $len; $i++) {
230             $ch = $fmt[$i];
231             switch($ch) {
232             case 'Y':
233             case 'y':
234                 $s .= '%Y';
235                 break;
236             case 'Q':
237             case 'q':
238                 $s .= "'),Quarter($col)";
239
240                 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
241                 else $s .= ",('";
242                 $concat = true;
243                 break;
244             case 'M':
245                 $s .= '%b';
246                 break;
247
248             case 'm':
249                 $s .= '%m';
250                 break;
251             case 'D':
252             case 'd':
253                 $s .= '%d';
254                 break;
255
256             case 'H':
257                 $s .= '%H';
258                 break;
259
260             case 'h':
261                 $s .= '%I';
262                 break;
263
264             case 'i':
265                 $s .= '%i';
266                 break;
267
268             case 's':
269                 $s .= '%s';
270                 break;
271
272             case 'a':
273             case 'A':
274                 $s .= '%p';
275                 break;
276
277             default:
278
279                 if ($ch == '\\') {
280                     $i++;
281                     $ch = substr($fmt,$i,1);
282                 }
283                 $s .= $ch;
284                 break;
285             }
286         }
287         $s.="')";
288         if ($concat) $s = "CONCAT($s)";
289         return $s;
290     }
291
292
293     // returns concatenated string
294     // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
295     function Concat()
296     {
297         $s = "";
298         $arr = func_get_args();
299
300         // suggestion by andrew005@mnogo.ru
301         $s = implode(',',$arr);
302         if (strlen($s) > 0) return "CONCAT($s)";
303         else return '';
304     }
305
306     function OffsetDate($dayFraction,$date=false)
307     {
308         if (!$date) $date = $this->sysDate;
309         return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)";
310     }
311
312     // returns true or false
313     function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
314     {
315         if (ADODB_PHPVER >= 0x4300)
316             $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,
317                                                 $this->forceNewConnect,$this->clientFlags);
318         else if (ADODB_PHPVER >= 0x4200)
319             $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,
320                                                 $this->forceNewConnect);
321         else
322             $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword);
323
324         if ($this->_connectionID === false) return false;
325         if ($argDatabasename) return $this->SelectDB($argDatabasename);
326         return true;
327     }
328
329     // returns true or false
330     function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
331     {
332         if (ADODB_PHPVER >= 0x4300)
333             $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword,$this->clientFlags);
334         else
335             $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword);
336         if ($this->_connectionID === false) return false;
337         if ($this->autoRollback) $this->RollbackTrans();
338         if ($argDatabasename) return $this->SelectDB($argDatabasename);
339         return true;
340     }
341
342     function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
343     {
344         $this->forceNewConnect = true;
345         return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
346     }
347
348      function &MetaColumns($table)
349     {
350
351         if ($this->metaColumnsSQL) {
352         global $ADODB_FETCH_MODE;
353
354             $save = $ADODB_FETCH_MODE;
355             $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
356             if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
357
358             $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
359
360             if (isset($savem)) $this->SetFetchMode($savem);
361             $ADODB_FETCH_MODE = $save;
362
363             if ($rs === false) return false;
364
365             $retarr = array();
366             while (!$rs->EOF){
367                 $fld = new ADOFieldObject();
368                 $fld->name = $rs->fields[0];
369                 $type = $rs->fields[1];
370
371
372                 // split type into type(length):
373                 $fld->scale = null;
374                 if (strpos($type,',') && preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
375                     $fld->type = $query_array[1];
376                     $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
377                     $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
378                 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
379                     $fld->type = $query_array[1];
380                     $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
381                 } else {
382                     $fld->max_length = -1;
383                     $fld->type = $type;
384                 }
385                 /*
386                 // split type into type(length):
387                 if (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
388                     $fld->type = $query_array[1];
389                     $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
390                 } else {
391                     $fld->max_length = -1;
392                     $fld->type = $type;
393                 }*/
394                 $fld->not_null = ($rs->fields[2] != 'YES');
395                 $fld->primary_key = ($rs->fields[3] == 'PRI');
396                 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
397                 $fld->binary = (strpos($fld->type,'blob') !== false);
398
399                 if (!$fld->binary) {
400                     $d = $rs->fields[4];
401                     if ($d != "" && $d != "NULL") {
402                         $fld->has_default = true;
403                         $fld->default_value = $d;
404                     } else {
405                         $fld->has_default = false;
406                     }
407                 }
408                 if ($save == ADODB_FETCH_NUM) $retarr[] = $fld;
409                 else $retarr[strtoupper($fld->name)] = $fld;
410                 $rs->MoveNext();
411             }
412             $rs->Close();
413             return $retarr;
414         }
415         return false;
416     }
417
418     // returns true or false
419     function SelectDB($dbName)
420     {
421         $this->databaseName = $dbName;
422         if ($this->_connectionID) {
423             return @mysql_select_db($dbName,$this->_connectionID);
424         }
425         else return false;
426     }
427
428     // parameters use PostgreSQL convention, not MySQL
429     function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
430     {
431         $offsetStr =($offset>=0) ? "$offset," : '';
432
433         if ($secs)
434             $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr);
435         else
436             $rs =& $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr);
437         return $rs;
438     }
439
440
441     // returns queryID or false
442     function _query($sql,$inputarr)
443     {
444     //global $ADODB_COUNTRECS;
445         //if($ADODB_COUNTRECS)
446         return mysql_query($sql,$this->_connectionID);
447         //else return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
448     }
449
450     /*  Returns: the last error message from previous database operation        */
451     function ErrorMsg()
452     {
453
454         if ($this->_logsql) return $this->_errorMsg;
455         if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
456         else $this->_errorMsg = @mysql_error($this->_connectionID);
457         return $this->_errorMsg;
458     }
459
460     /*  Returns: the last error number from previous database operation */
461     function ErrorNo()
462     {
463         if ($this->_logsql) return $this->_errorCode;
464         if (empty($this->_connectionID))  return @mysql_errno();
465         else return @mysql_errno($this->_connectionID);
466     }
467
468
469
470     // returns true or false
471     function _close()
472     {
473         @mysql_close($this->_connectionID);
474         $this->_connectionID = false;
475     }
476
477
478     /*
479     * Maximum size of C field
480     */
481     function CharMax()
482     {
483         return 255;
484     }
485
486     /*
487     * Maximum size of X field
488     */
489     function TextMax()
490     {
491         return 4294967295;
492     }
493
494 }
495
496 /*--------------------------------------------------------------------------------------
497      Class Name: Recordset
498 --------------------------------------------------------------------------------------*/
499
500 class ADORecordSet_mysql extends ADORecordSet{
501
502     var $databaseType = "mysql";
503     var $canSeek = true;
504
505     function ADORecordSet_mysql($queryID,$mode=false)
506     {
507         if ($mode === false) {
508             global $ADODB_FETCH_MODE;
509             $mode = $ADODB_FETCH_MODE;
510         }
511         switch ($mode)
512         {
513         case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
514         case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
515         default:
516         case ADODB_FETCH_DEFAULT:
517         case ADODB_FETCH_BOTH:$this->fetchMode = MYSQL_BOTH; break;
518         }
519
520         $this->ADORecordSet($queryID);
521     }
522
523     function _initrs()
524     {
525     //GLOBAL $ADODB_COUNTRECS;
526     //  $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
527         $this->_numOfRows = @mysql_num_rows($this->_queryID);
528         $this->_numOfFields = @mysql_num_fields($this->_queryID);
529     }
530
531     function &FetchField($fieldOffset = -1)
532     {
533
534         if ($fieldOffset != -1) {
535             $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
536             $f = @mysql_field_flags($this->_queryID,$fieldOffset);
537             $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich@att.com)
538             //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
539             $o->binary = (strpos($f,'binary')!== false);
540         }
541         else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
542             $o = @mysql_fetch_field($this->_queryID);
543             $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich@att.com)
544             //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
545         }
546
547         return $o;
548     }
549
550     function &GetRowAssoc($upper=true)
551     {
552         if ($this->fetchMode == MYSQL_ASSOC && !$upper) return $this->fields;
553         $row =& ADORecordSet::GetRowAssoc($upper);
554         return $row;
555     }
556
557     /* Use associative array to get fields array */
558     function Fields($colname)
559     {
560         // added @ by "Michael William Miller" <mille562@pilot.msu.edu>
561         if ($this->fetchMode != MYSQL_NUM) return @$this->fields[$colname];
562
563         if (!$this->bind) {
564             $this->bind = array();
565             for ($i=0; $i < $this->_numOfFields; $i++) {
566                 $o = $this->FetchField($i);
567                 $this->bind[strtoupper($o->name)] = $i;
568             }
569         }
570          return $this->fields[$this->bind[strtoupper($colname)]];
571     }
572
573     function _seek($row)
574     {
575         if ($this->_numOfRows == 0) return false;
576         return @mysql_data_seek($this->_queryID,$row);
577     }
578
579
580     // 10% speedup to move MoveNext to child class
581     function MoveNext()
582     {
583     //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return adodb_movenext($this);
584
585         if ($this->EOF) return false;
586
587         $this->_currentRow++;
588         $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
589         if (is_array($this->fields)) return true;
590
591         $this->EOF = true;
592
593         /* -- tested raising an error -- appears pointless
594         $conn = $this->connection;
595         if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
596             $fn = $conn->raiseErrorFn;
597             $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
598         }
599         */
600         return false;
601     }
602
603     function _fetch()
604     {
605         $this->fields =  @mysql_fetch_array($this->_queryID,$this->fetchMode);
606         return is_array($this->fields);
607     }
608
609     function _close() {
610         @mysql_free_result($this->_queryID);
611         $this->_queryID = false;
612     }
613
614     function MetaType($t,$len=-1,$fieldobj=false)
615     {
616         if (is_object($t)) {
617             $fieldobj = $t;
618             $t = $fieldobj->type;
619             $len = $fieldobj->max_length;
620         }
621
622         $len = -1; // mysql max_length is not accurate
623         switch (strtoupper($t)) {
624         case 'STRING':
625         case 'CHAR':
626         case 'VARCHAR':
627         case 'TINYBLOB':
628         case 'TINYTEXT':
629         case 'ENUM':
630         case 'SET':
631             if ($len <= $this->blobSize) return 'C';
632
633         case 'TEXT':
634         case 'LONGTEXT':
635         case 'MEDIUMTEXT':
636             return 'X';
637
638         // php_mysql extension always returns 'blob' even if 'text'
639         // so we have to check whether binary...
640         case 'IMAGE':
641         case 'LONGBLOB':
642         case 'BLOB':
643         case 'MEDIUMBLOB':
644             return !empty($fieldobj->binary) ? 'B' : 'X';
645
646         case 'YEAR':
647         case 'DATE': return 'D';
648
649         case 'TIME':
650         case 'DATETIME':
651         case 'TIMESTAMP': return 'T';
652
653         case 'INT':
654         case 'INTEGER':
655         case 'BIGINT':
656         case 'TINYINT':
657         case 'MEDIUMINT':
658         case 'SMALLINT':
659
660             if (!empty($fieldobj->primary_key)) return 'R';
661             else return 'I';
662
663         default: return 'N';
664         }
665     }
666
667 }
668 }
669
670 // Local Variables:
671 // mode: php
672 // tab-width: 8
673 // c-basic-offset: 4
674 // c-hanging-comment-ender-p: nil
675 // indent-tabs-mode: nil
676 // End:
677 ?>