root/releases/elgg0.8rc2/lib/adodb/adodb-datadict.inc.php

Revision 725, 20.5 kB (checked in by misja, 2 years ago)

Updated ADODB library.

  • Property svn:eol-style set to native
Line 
1 <?php
2
3 /**
4   V4.93 10 Oct 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
5   Released under both BSD license and Lesser GPL library license.
6   Whenever there is any discrepancy between the two licenses,
7   the BSD license will take precedence.
8     
9   Set tabs to 4 for best viewing.
10  
11      DOCUMENTATION:
12     
13         See adodb/tests/test-datadict.php for docs and examples.
14 */
15
16 /*
17     Test script for parser
18 */
19
20 // security - hide paths
21 if (!defined('ADODB_DIR')) die();
22
23 function Lens_ParseTest()
24 {
25 $str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds";
26 print "<p>$str</p>";
27 $a= Lens_ParseArgs($str);
28 print "<pre>";
29 print_r($a);
30 print "</pre>";
31 }
32
33
34 if (!function_exists('ctype_alnum')) {
35     function ctype_alnum($text) {
36         return preg_match('/^[a-z0-9]*$/i', $text);
37     }
38 }
39
40 //Lens_ParseTest();
41
42 /**
43     Parse arguments, treat "text" (text) and 'text' as quotation marks.
44     To escape, use "" or '' or ))
45     
46     Will read in "abc def" sans quotes, as: abc def
47     Same with 'abc def'.
48     However if `abc def`, then will read in as `abc def`
49     
50     @param endstmtchar    Character that indicates end of statement
51     @param tokenchars     Include the following characters in tokens apart from A-Z and 0-9
52     @returns 2 dimensional array containing parsed tokens.
53 */
54 function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
55 {
56     $pos = 0;
57     $intoken = false;
58     $stmtno = 0;
59     $endquote = false;
60     $tokens = array();
61     $tokens[$stmtno] = array();
62     $max = strlen($args);
63     $quoted = false;
64     $tokarr = array();
65     
66     while ($pos < $max) {
67         $ch = substr($args,$pos,1);
68         switch($ch) {
69         case ' ':
70         case "\t":
71         case "\n":
72         case "\r":
73             if (!$quoted) {
74                 if ($intoken) {
75                     $intoken = false;
76                     $tokens[$stmtno][] = implode('',$tokarr);
77                 }
78                 break;
79             }
80             
81             $tokarr[] = $ch;
82             break;
83         
84         case '`':
85             if ($intoken) $tokarr[] = $ch;
86         case '(':
87         case ')':   
88         case '"':
89         case "'":
90             
91             if ($intoken) {
92                 if (empty($endquote)) {
93                     $tokens[$stmtno][] = implode('',$tokarr);
94                     if ($ch == '(') $endquote = ')';
95                     else $endquote = $ch;
96                     $quoted = true;
97                     $intoken = true;
98                     $tokarr = array();
99                 } else if ($endquote == $ch) {
100                     $ch2 = substr($args,$pos+1,1);
101                     if ($ch2 == $endquote) {
102                         $pos += 1;
103                         $tokarr[] = $ch2;
104                     } else {
105                         $quoted = false;
106                         $intoken = false;
107                         $tokens[$stmtno][] = implode('',$tokarr);
108                         $endquote = '';
109                     }
110                 } else
111                     $tokarr[] = $ch;
112                     
113             }else {
114             
115                 if ($ch == '(') $endquote = ')';
116                 else $endquote = $ch;
117                 $quoted = true;
118                 $intoken = true;
119                 $tokarr = array();
120                 if ($ch == '`') $tokarr[] = '`';
121             }
122             break;
123             
124         default:
125             
126             if (!$intoken) {
127                 if ($ch == $endstmtchar) {
128                     $stmtno += 1;
129                     $tokens[$stmtno] = array();
130                     break;
131                 }
132             
133                 $intoken = true;
134                 $quoted = false;
135                 $endquote = false;
136                 $tokarr = array();
137     
138             }
139             
140             if ($quoted) $tokarr[] = $ch;
141             else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
142             else {
143                 if ($ch == $endstmtchar) {           
144                     $tokens[$stmtno][] = implode('',$tokarr);
145                     $stmtno += 1;
146                     $tokens[$stmtno] = array();
147                     $intoken = false;
148                     $tokarr = array();
149                     break;
150                 }
151                 $tokens[$stmtno][] = implode('',$tokarr);
152                 $tokens[$stmtno][] = $ch;
153                 $intoken = false;
154             }
155         }
156         $pos += 1;
157     }
158     if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
159     
160     return $tokens;
161 }
162
163
164 class ADODB_DataDict {
165     var $connection;
166     var $debug = false;
167     var $dropTable = 'DROP TABLE %s';
168     var $renameTable = 'RENAME TABLE %s TO %s';
169     var $dropIndex = 'DROP INDEX %s';
170     var $addCol = ' ADD';
171     var $alterCol = ' ALTER COLUMN';
172     var $dropCol = ' DROP COLUMN';
173     var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s';    // table, old-column, new-column, column-definitions (not used by default)
174     var $nameRegex = '\w';
175     var $nameRegexBrackets = 'a-zA-Z0-9_\(\)';
176     var $schema = false;
177     var $serverInfo = array();
178     var $autoIncrement = false;
179     var $dataProvider;
180     var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql
181     var $blobSize = 100;     /// any varchar/char field this size or greater is treated as a blob
182                             /// in other words, we use a text area for editting.
183     
184     function GetCommentSQL($table,$col)
185     {
186         return false;
187     }
188     
189     function SetCommentSQL($table,$col,$cmt)
190     {
191         return false;
192     }
193     
194     function MetaTables()
195     {
196         if (!$this->connection->IsConnected()) return array();
197         return $this->connection->MetaTables();
198     }
199     
200     function MetaColumns($tab, $upper=true, $schema=false)
201     {
202         if (!$this->connection->IsConnected()) return array();
203         return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema);
204     }
205     
206     function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
207     {
208         if (!$this->connection->IsConnected()) return array();
209         return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
210     }
211     
212     function MetaIndexes($table, $primary = false, $owner = false)
213     {
214         if (!$this->connection->IsConnected()) return array();
215         return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner);
216     }
217     
218     function MetaType($t,$len=-1,$fieldobj=false)
219     {
220         return ADORecordSet::MetaType($t,$len,$fieldobj);
221     }
222     
223     function NameQuote($name = NULL,$allowBrackets=false)
224     {
225         if (!is_string($name)) {
226             return FALSE;
227         }
228         
229         $name = trim($name);
230         
231         if ( !is_object($this->connection) ) {
232             return $name;
233         }
234         
235         $quote = $this->connection->nameQuote;
236         
237         // if name is of the form `name`, quote it
238         if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
239             return $quote . $matches[1] . $quote;
240         }
241         
242         // if name contains special characters, quote it
243         $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
244         
245         if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
246             return $quote . $name . $quote;
247         }
248         
249         return $name;
250     }
251     
252     function TableName($name)
253     {
254         if ( $this->schema ) {
255             return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
256         }
257         return $this->NameQuote($name);
258     }
259     
260     // Executes the sql array returned by GetTableSQL and GetIndexSQL
261     function ExecuteSQLArray($sql, $continueOnError = true)
262     {
263         $rez = 2;
264         $conn = &$this->connection;
265         $saved = $conn->debug;
266         foreach($sql as $line) {
267             
268             if ($this->debug) $conn->debug = true;
269             $ok = $conn->Execute($line);
270             $conn->debug = $saved;
271             if (!$ok) {
272                 if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
273                 if (!$continueOnError) return 0;
274                 $rez = 1;
275             }
276         }
277         return $rez;
278     }
279     
280     /*
281          Returns the actual type given a character code.
282         
283         C:  varchar
284         X:  CLOB (character large object) or largest varchar size if CLOB is not supported
285         C2: Multibyte varchar
286         X2: Multibyte CLOB
287         
288         B:  BLOB (binary large object)
289         
290         D:  Date
291         T:  Date-time
292         L:  Integer field suitable for storing booleans (0 or 1)
293         I:  Integer
294         F:  Floating point number
295         N:  Numeric or decimal number
296     */
297     
298     function ActualType($meta)
299     {
300         return $meta;
301     }
302     
303     function CreateDatabase($dbname,$options=false)
304     {
305         $options = $this->_Options($options);
306         $sql = array();
307         
308         $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
309         if (isset($options[$this->upperName]))
310             $s .= ' '.$options[$this->upperName];
311         
312         $sql[] = $s;
313         return $sql;
314     }
315     
316     /*
317      Generates the SQL to create index. Returns an array of sql strings.
318     */
319     function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
320     {
321         if (!is_array($flds)) {
322             $flds = explode(',',$flds);
323         }
324         
325         foreach($flds as $key => $fld) {
326             # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
327             $flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
328         }
329         
330         return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
331     }
332     
333     function DropIndexSQL ($idxname, $tabname = NULL)
334     {
335         return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
336     }
337     
338     function SetSchema($schema)
339     {
340         $this->schema = $schema;
341     }
342     
343     function AddColumnSQL($tabname, $flds)
344     {
345         $tabname = $this->TableName ($tabname);
346         $sql = array();
347         list($lines,$pkey) = $this->_GenFields($flds);
348         $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
349         foreach($lines as $v) {
350             $sql[] = $alter . $v;
351         }
352         return $sql;
353     }
354     
355     /**
356      * Change the definition of one column
357      *
358      * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
359      * to allow, recreating the table and copying the content over to the new table
360      * @param string $tabname table-name
361      * @param string $flds column-name and type for the changed column
362      * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
363      * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
364      * @return array with SQL strings
365      */
366     function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
367     {
368         $tabname = $this->TableName ($tabname);
369         $sql = array();
370         list($lines,$pkey) = $this->_GenFields($flds);
371         $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
372         foreach($lines as $v) {
373             $sql[] = $alter . $v;
374         }
375         return $sql;
376     }
377     
378     /**
379      * Rename one column
380      *
381      * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
382      * @param string $tabname table-name
383      * @param string $oldcolumn column-name to be renamed
384      * @param string $newcolumn new column-name
385      * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
386      * @return array with SQL strings
387      */
388     function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
389     {
390         $tabname = $this->TableName ($tabname);
391         if ($flds) {
392             list($lines,$pkey) = $this->_GenFields($flds);
393             list(,$first) = each($lines);
394             list(,$column_def) = split("[\t ]+",$first,2);
395         }
396         return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
397     }
398         
399     /**
400      * Drop one column
401      *
402      * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
403      * to allow, recreating the table and copying the content over to the new table
404      * @param string $tabname table-name
405      * @param string $flds column-name and type for the changed column
406      * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
407      * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
408      * @return array with SQL strings
409      */
410     function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
411     {
412         $tabname = $this->TableName ($tabname);
413         if (!is_array($flds)) $flds = explode(',',$flds);
414         $sql = array();
415         $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
416         foreach($flds as $v) {
417             $sql[] = $alter . $this->NameQuote($v);
418         }
419         return $sql;
420     }
421     
422     function DropTableSQL($tabname)
423     {
424         return array (sprintf($this->dropTable, $this->TableName($tabname)));
425     }
426     
427     function RenameTableSQL($tabname,$newname)
428     {
429         return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
430     }   
431     
432     /*
433      Generate the SQL to create table. Returns an array of sql strings.
434     */
435     function CreateTableSQL($tabname, $flds, $tableoptions=false)
436     {
437         if (!$tableoptions) $tableoptions = array();
438         
439         list($lines,$pkey) = $this->_GenFields($flds, true);
440         
441         $taboptions = $this->_Options($tableoptions);
442         $tabname = $this->TableName ($tabname);
443         $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
444         
445         $tsql = $this->_Triggers($tabname,$taboptions);
446         foreach($tsql as $s) $sql[] = $s;
447         
448         return $sql;
449     }
450     
451     function _GenFields($flds,$widespacing=false)
452     {
453         if (is_string($flds)) {
454             $padding = '     ';
455             $txt = $flds.$padding;
456             $flds = array();
457             $flds0 = Lens_ParseArgs($txt,',');
458             $hasparam = false;
459             foreach($flds0 as $f0) {
460                 $f1 = array();
461                 foreach($f0 as $token) {
462                     switch (strtoupper($token)) {
463                     case 'CONSTRAINT':
464                     case 'DEFAULT':
465                         $hasparam = $token;
466                         break;
467                     default:
468                         if ($hasparam) $f1[$hasparam] = $token;
469                         else $f1[] = $token;
470                         $hasparam = false;
471                         break;
472                     }
473                 }
474                 $flds[] = $f1;
475                 
476             }
477         }
478         $this->autoIncrement = false;
479         $lines = array();
480         $pkey = array();
481         foreach($flds as $fld) {
482             $fld = _array_change_key_case($fld);
483         
484             $fname = false;
485             $fdefault = false;
486             $fautoinc = false;
487             $ftype = false;
488             $fsize = false;
489             $fprec = false;
490             $fprimary = false;
491             $fnoquote = false;
492             $fdefts = false;
493             $fdefdate = false;
494             $fconstraint = false;
495             $fnotnull = false;
496             $funsigned = false;
497             
498             //-----------------
499             // Parse attributes
500             foreach($fld as $attr => $v) {
501                 if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
502                 else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr =