source: branches/comu-ver2/data/module/adodb/adodb-datadict.inc.php @ 18701

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

Copyright の更新(#601)

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id Revision Date
  • Property svn:mime-type set to text/x-httpd-php
Line 
1<?php
2
3/**
4  v4.992 10 Nov 2009  (c) 2000-2010 John Lim (jlim#natsoft.com). 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
21if (!defined('ADODB_DIR')) die();
22
23function 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";
26print "<p>$str</p>";
27$a= Lens_ParseArgs($str);
28print "<pre>";
29print_r($a);
30print "</pre>";
31}
32
33
34if (!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*/
54function 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
164class 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
219    function MetaType($t,$len=-1,$fieldobj=false)
220    {       
221        static $typeMap = array(
222        'VARCHAR' => 'C',
223        'VARCHAR2' => 'C',
224        'CHAR' => 'C',
225        'C' => 'C',
226        'STRING' => 'C',
227        'NCHAR' => 'C',
228        'NVARCHAR' => 'C',
229        'VARYING' => 'C',
230        'BPCHAR' => 'C',
231        'CHARACTER' => 'C',
232        'INTERVAL' => 'C',  # Postgres
233        'MACADDR' => 'C', # postgres
234        ##
235        'LONGCHAR' => 'X',
236        'TEXT' => 'X',
237        'NTEXT' => 'X',
238        'M' => 'X',
239        'X' => 'X',
240        'CLOB' => 'X',
241        'NCLOB' => 'X',
242        'LVARCHAR' => 'X',
243        ##
244        'BLOB' => 'B',
245        'IMAGE' => 'B',
246        'BINARY' => 'B',
247        'VARBINARY' => 'B',
248        'LONGBINARY' => 'B',
249        'B' => 'B',
250        ##
251        'YEAR' => 'D', // mysql
252        'DATE' => 'D',
253        'D' => 'D',
254        ##
255        'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
256        ##
257        'TIME' => 'T',
258        'TIMESTAMP' => 'T',
259        'DATETIME' => 'T',
260        'TIMESTAMPTZ' => 'T',
261        'T' => 'T',
262        'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
263        ##
264        'BOOL' => 'L',
265        'BOOLEAN' => 'L',
266        'BIT' => 'L',
267        'L' => 'L',
268        ##
269        'COUNTER' => 'R',
270        'R' => 'R',
271        'SERIAL' => 'R', // ifx
272        'INT IDENTITY' => 'R',
273        ##
274        'INT' => 'I',
275        'INT2' => 'I',
276        'INT4' => 'I',
277        'INT8' => 'I',
278        'INTEGER' => 'I',
279        'INTEGER UNSIGNED' => 'I',
280        'SHORT' => 'I',
281        'TINYINT' => 'I',
282        'SMALLINT' => 'I',
283        'I' => 'I',
284        ##
285        'LONG' => 'N', // interbase is numeric, oci8 is blob
286        'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
287        'DECIMAL' => 'N',
288        'DEC' => 'N',
289        'REAL' => 'N',
290        'DOUBLE' => 'N',
291        'DOUBLE PRECISION' => 'N',
292        'SMALLFLOAT' => 'N',
293        'FLOAT' => 'N',
294        'NUMBER' => 'N',
295        'NUM' => 'N',
296        'NUMERIC' => 'N',
297        'MONEY' => 'N',
298       
299        ## informix 9.2
300        'SQLINT' => 'I',
301        'SQLSERIAL' => 'I',
302        'SQLSMINT' => 'I',
303        'SQLSMFLOAT' => 'N',
304        'SQLFLOAT' => 'N',
305        'SQLMONEY' => 'N',
306        'SQLDECIMAL' => 'N',
307        'SQLDATE' => 'D',
308        'SQLVCHAR' => 'C',
309        'SQLCHAR' => 'C',
310        'SQLDTIME' => 'T',
311        'SQLINTERVAL' => 'N',
312        'SQLBYTES' => 'B',
313        'SQLTEXT' => 'X',
314         ## informix 10
315        "SQLINT8" => 'I8',
316        "SQLSERIAL8" => 'I8',
317        "SQLNCHAR" => 'C',
318        "SQLNVCHAR" => 'C',
319        "SQLLVARCHAR" => 'X',
320        "SQLBOOL" => 'L'
321        );
322       
323        if (!$this->connection->IsConnected()) {
324            $t = strtoupper($t);
325            if (isset($typeMap[$t])) return $typeMap[$t];
326            return 'N';
327        }
328        return $this->connection->MetaType($t,$len,$fieldobj);
329    }
330   
331    function NameQuote($name = NULL,$allowBrackets=false)
332    {
333        if (!is_string($name)) {
334            return FALSE;
335        }
336       
337        $name = trim($name);
338       
339        if ( !is_object($this->connection) ) {
340            return $name;
341        }
342       
343        $quote = $this->connection->nameQuote;
344       
345        // if name is of the form `name`, quote it
346        if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
347            return $quote . $matches[1] . $quote;
348        }
349       
350        // if name contains special characters, quote it
351        $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
352       
353        if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
354            return $quote . $name . $quote;
355        }
356       
357        return $name;
358    }
359   
360    function TableName($name)
361    {
362        if ( $this->schema ) {
363            return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
364        }
365        return $this->NameQuote($name);
366    }
367   
368    // Executes the sql array returned by GetTableSQL and GetIndexSQL
369    function ExecuteSQLArray($sql, $continueOnError = true)
370    {
371        $rez = 2;
372        $conn = &$this->connection;
373        $saved = $conn->debug;
374        foreach($sql as $line) {
375           
376            if ($this->debug) $conn->debug = true;
377            $ok = $conn->Execute($line);
378            $conn->debug = $saved;
379            if (!$ok) {
380                if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
381                if (!$continueOnError) return 0;
382                $rez = 1;
383            }
384        }
385        return $rez;
386    }
387   
388    /**
389        Returns the actual type given a character code.
390       
391        C:  varchar
392        X:  CLOB (character large object) or largest varchar size if CLOB is not supported
393        C2: Multibyte varchar
394        X2: Multibyte CLOB
395       
396        B:  BLOB (binary large object)
397       
398        D:  Date
399        T:  Date-time
400        L:  Integer field suitable for storing booleans (0 or 1)
401        I:  Integer
402        F:  Floating point number
403        N:  Numeric or decimal number
404    */
405   
406    function ActualType($meta)
407    {
408        return $meta;
409    }
410   
411    function CreateDatabase($dbname,$options=false)
412    {
413        $options = $this->_Options($options);
414        $sql = array();
415       
416        $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
417        if (isset($options[$this->upperName]))
418            $s .= ' '.$options[$this->upperName];
419       
420        $sql[] = $s;
421        return $sql;
422    }
423   
424    /*
425     Generates the SQL to create index. Returns an array of sql strings.
426    */
427    function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
428    {
429        if (!is_array($flds)) {
430            $flds = explode(',',$flds);
431        }
432       
433        foreach($flds as $key => $fld) {
434            # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
435            $flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
436        }
437       
438        return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
439    }
440   
441    function DropIndexSQL ($idxname, $tabname = NULL)
442    {
443        return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
444    }
445   
446    function SetSchema($schema)
447    {
448        $this->schema = $schema;
449    }
450   
451    function AddColumnSQL($tabname, $flds)
452    {
453        $tabname = $this->TableName ($tabname);
454        $sql = array();
455        list($lines,$pkey,$idxs) = $this->_GenFields($flds);
456        // genfields can return FALSE at times
457        if ($lines  == null) $lines = array();
458        $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
459        foreach($lines as $v) {
460            $sql[] = $alter . $v;
461        }
462        if (is_array($idxs)) {
463            foreach($idxs as $idx => $idxdef) {
464                $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
465                $sql = array_merge($sql, $sql_idxs);
466            }
467        }
468        return $sql;
469    }
470   
471    /**
472     * Change the definition of one column
473     *
474     * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
475     * to allow, recreating the table and copying the content over to the new table
476     * @param string $tabname table-name
477     * @param string $flds column-name and type for the changed column
478     * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
479     * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
480     * @return array with SQL strings
481     */
482    function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
483    {
484        $tabname = $this->TableName ($tabname);
485        $sql = array();
486        list($lines,$pkey,$idxs) = $this->_GenFields($flds);
487        // genfields can return FALSE at times
488        if ($lines == null) $lines = array();
489        $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
490        foreach($lines as $v) {
491            $sql[] = $alter . $v;
492        }
493        if (is_array($idxs)) {
494            foreach($idxs as $idx => $idxdef) {
495                $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
496                $sql = array_merge($sql, $sql_idxs);
497            }
498
499        }
500        return $sql;
501    }
502   
503    /**
504     * Rename one column
505     *
506     * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
507     * @param string $tabname table-name
508     * @param string $oldcolumn column-name to be renamed
509     * @param string $newcolumn new column-name
510     * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
511     * @return array with SQL strings
512     */
513    function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
514    {
515        $tabname = $this->TableName ($tabname);
516        if ($flds) {
517            list($lines,$pkey,$idxs) = $this->_GenFields($flds);
518            // genfields can return FALSE at times
519            if ($lines == null) $lines = array();
520            list(,$first) = each($lines);
521            list(,$column_def) = split("[\t ]+",$first,2);
522        }
523        return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
524    }
525       
526    /**
527     * Drop one column
528     *
529     * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
530     * to allow, recreating the table and copying the content over to the new table
531     * @param string $tabname table-name
532     * @param string $flds column-name and type for the changed column
533     * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
534     * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
535     * @return array with SQL strings
536     */
537    function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
538    {
539        $tabname = $this->TableName ($tabname);
540        if (!is_array($flds)) $flds = explode(',',$flds);
541        $sql = array();
542        $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
543        foreach($flds as $v) {
544            $sql[] = $alter . $this->NameQuote($v);
545        }
546        return $sql;
547    }
548   
549    function DropTableSQL($tabname)
550    {
551        return array (sprintf($this->dropTable, $this->TableName($tabname)));
552    }
553   
554    function RenameTableSQL($tabname,$newname)
555    {
556        return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
557    }   
558   
559    /**
560     Generate the SQL to create table. Returns an array of sql strings.
561    */
562    function CreateTableSQL($tabname, $flds, $tableoptions=array())
563    {
564        list($lines,$pkey,$idxs) = $this->_GenFields($flds, true);
565        // genfields can return FALSE at times
566        if ($lines == null) $lines = array();
567       
568        $taboptions = $this->_Options($tableoptions);
569        $tabname = $this->TableName ($tabname);
570        $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
571       
572        // ggiunta - 2006/10/12 - KLUDGE:
573        // if we are on autoincrement, and table options includes REPLACE, the
574        // autoincrement sequence has already been dropped on table creation sql, so
575        // we avoid passing REPLACE to trigger creation code. This prevents
576        // creating sql that double-drops the sequence
577        if ($this->autoIncrement && isset($taboptions['REPLACE']))
578            unset($taboptions['REPLACE']);
579        $tsql = $this->_Triggers($tabname,$taboptions);
580        foreach($tsql as $s) $sql[] = $s;
581       
582        if (is_array($idxs)) {
583            foreach($idxs as $idx => $idxdef) {
584                $sql_idxs = $this->CreateIndexSql($idx, $tabname,  $idxdef['cols'], $idxdef['opts']);
585                $sql = array_merge($sql, $sql_idxs);
586            }
587        }
588
589        return $sql;
590    }
591   
592    function _GenFields($flds,$widespacing=false)
593    {
594        if (is_string($flds)) {
595            $padding = '     ';
596            $txt = $flds.$padding;
597            $flds = array();
598            $flds0 = Lens_ParseArgs($txt,',');
599            $hasparam = false;
600            foreach($flds0 as $f0) {
601                $f1 = array();
602                foreach($f0 as $token) {
603                    switch (strtoupper($token)) {
604                    case 'INDEX':
605                        $f1['INDEX'] = '';
606                        // fall through intentionally
607                    case 'CONSTRAINT':
608                    case 'DEFAULT':
609                        $hasparam = $token;
610                        break;
611                    default:
612                        if ($hasparam) $f1[$hasparam] = $token;
613                        else $f1[] = $token;
614                        $hasparam = false;
615                        break;
616                    }
617                }
618                // 'index' token without a name means single column index: name it after column
619                if (array_key_exists('INDEX', $f1) && $f1['INDEX'] == '') {
620                    $f1['INDEX'] = isset($f0['NAME']) ? $f0['NAME'] : $f0[0];
621                    // check if column name used to create an index name was quoted
622                    if (($f1['INDEX'][0] == '"' || $f1['INDEX'][0] == "'" || $f1['INDEX'][0] == "`") &&
623                        ($f1['INDEX'][0] == substr($f1['INDEX'], -1))) {
624                        $f1['INDEX'] = $f1['INDEX'][0].'idx_'.substr($f1['INDEX'], 1, -1).$f1['INDEX'][0];
625                    }
626                    else
627                        $f1['INDEX'] = 'idx_'.$f1['INDEX'];
628                }
629                // reset it, so we don't get next field 1st token as INDEX...
630                $hasparam = false;
631
632                $flds[] = $f1;
633               
634            }
635        }
636        $this->autoIncrement = false;
637        $lines = array();
638        $pkey = array();
639        $idxs = array();
640        foreach($flds as $fld) {
641            $fld = _array_change_key_case($fld);
642           
643            $fname = false;
644            $fdefault = false;
645            $fautoinc = false;
646            $ftype = false;
647            $fsize = false;
648            $fprec = false;
649            $fprimary = false;
650            $fnoquote = false;
651            $fdefts = false;
652            $fdefdate = false;
653            $fconstraint = false;
654            $fnotnull = false;
655            $funsigned = false;
656            $findex = '';
657            $funiqueindex = false;
658           
659            //-----------------
660            // Parse attributes
661            foreach($fld as $attr => $v) {
662                if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
663                else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
664               
665                switch($attr) {
666                case '0':
667                case 'NAME':    $fname = $v; break;
668                case '1':
669                case 'TYPE':    $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
670               
671                case 'SIZE':   
672                                $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
673                                if ($dotat === false) $fsize = $v;
674                                else {
675                                    $fsize = substr($v,0,$dotat);
676                                    $fprec = substr($v,$dotat+1);
677                                }
678                                break;
679                case 'UNSIGNED': $funsigned = true; break;
680                case 'AUTOINCREMENT':
681                case 'AUTO':    $fautoinc = true; $fnotnull = true; break;
682                case 'KEY':
683                // a primary key col can be non unique in itself (if key spans many cols...)
684                case 'PRIMARY': $fprimary = $v; $fnotnull = true; /*$funiqueindex = true;*/ break;
685                case 'DEF':
686                case 'DEFAULT': $fdefault = $v; break;
687                case 'NOTNULL': $fnotnull = $v; break;
688                case 'NOQUOTE': $fnoquote = $v; break;
689                case 'DEFDATE': $fdefdate = $v; break;
690                case 'DEFTIMESTAMP': $fdefts = $v; break;
691                case 'CONSTRAINT': $fconstraint = $v; break;
692                // let INDEX keyword create a 'very standard' index on column
693                case 'INDEX': $findex = $v; break;
694                case 'UNIQUE': $funiqueindex = true; break;
695                } //switch
696            } // foreach $fld
697           
698            //--------------------
699            // VALIDATE FIELD INFO
700            if (!strlen($fname)) {
701                if ($this->debug) ADOConnection::outp("Undefined NAME");
702                return false;
703            }
704           
705            $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
706            $fname = $this->NameQuote($fname);
707           
708            if (!strlen($ftype)) {
709                if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
710                return false;
711            } else {
712                $ftype = strtoupper($ftype);
713            }
714           
715            $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
716           
717            if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
718           
719            if ($fprimary) $pkey[] = $fname;
720           
721            // some databases do not allow blobs to have defaults
722            if ($ty == 'X') $fdefault = false;
723           
724            // build list of indexes
725            if ($findex != '') {
726                if (array_key_exists($findex, $idxs)) {
727                    $idxs[$findex]['cols'][] = ($fname);
728                    if (in_array('UNIQUE', $idxs[$findex]['opts']) != $funiqueindex) {
729                        if ($this->debug) ADOConnection::outp("Index $findex defined once UNIQUE and once not");
730                    }
731                    if ($funiqueindex && !in_array('UNIQUE', $idxs[$findex]['opts']))
732                        $idxs[$findex]['opts'][] = 'UNIQUE';
733                }
734                else
735                {
736                    $idxs[$findex] = array();
737                    $idxs[$findex]['cols'] = array($fname);
738                    if ($funiqueindex)
739                        $idxs[$findex]['opts'] = array('UNIQUE');
740                    else
741                        $idxs[$findex]['opts'] = array();
742                }
743            }
744
745            //--------------------
746            // CONSTRUCT FIELD SQL
747            if ($fdefts) {
748                if (substr($this->connection->databaseType,0,5) == 'mysql') {
749                    $ftype = 'TIMESTAMP';
750                } else {
751                    $fdefault = $this->connection->sysTimeStamp;
752                }
753            } else if ($fdefdate) {
754                if (substr($this->connection->databaseType,0,5) == 'mysql') {
755                    $ftype = 'TIMESTAMP';
756                } else {
757                    $fdefault = $this->connection->sysDate;
758                }
759            } else if ($fdefault !== false && !$fnoquote) {
760                if ($ty == 'C' or $ty == 'X' or
761                    ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) {
762
763                    if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') {
764                        // convert default date into database-aware code
765                        if ($ty == 'T')
766                        {
767                            $fdefault = $this->connection->DBTimeStamp($fdefault);
768                        }
769                        else
770                        {
771                            $fdefault = $this->connection->DBDate($fdefault);
772                        }
773                    }
774                    else
775                    if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
776                        $fdefault = trim($fdefault);
777                    else if (strtolower($fdefault) != 'null')
778                        $fdefault = $this->connection->qstr($fdefault);
779                }
780            }
781            $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
782           
783            // add index creation
784            if ($widespacing) $fname = str_pad($fname,24);
785           
786             // check for field names appearing twice
787            if (array_key_exists($fid, $lines)) {
788                 ADOConnection::outp("Field '$fname' defined twice");
789            }
790           
791            $lines[$fid] = $fname.' '.$ftype.$suffix;
792           
793            if ($fautoinc) $this->autoIncrement = true;
794        } // foreach $flds
795       
796        return array($lines,$pkey,$idxs);
797    }
798
799    /**
800         GENERATE THE SIZE PART OF THE DATATYPE
801            $ftype is the actual type
802            $ty is the type defined originally in the DDL
803    */
804    function _GetSize($ftype, $ty, $fsize, $fprec)
805    {
806        if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
807            $ftype .= "(".$fsize;
808            if (strlen($fprec)) $ftype .= ",".$fprec;
809            $ftype .= ')';
810        }
811        return $ftype;
812    }
813   
814   
815    // return string must begin with space
816    function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
817    {   
818        $suffix = '';
819        if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
820        if ($fnotnull) $suffix .= ' NOT NULL';
821        if ($fconstraint) $suffix .= ' '.$fconstraint;
822        return $suffix;
823    }
824   
825    function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
826    {
827        $sql = array();
828       
829        if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
830            $sql[] = sprintf ($this->dropIndex, $idxname);
831            if ( isset($idxoptions['DROP']) )
832                return $sql;
833        }
834       
835        if ( empty ($flds) ) {
836            return $sql;
837        }
838       
839        $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
840   
841        $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
842       
843        if ( isset($idxoptions[$this->upperName]) )
844            $s .= $idxoptions[$this->upperName];
845       
846        if ( is_array($flds) )
847            $flds = implode(', ',$flds);
848        $s .= '(' . $flds . ')';
849        $sql[] = $s;
850       
851        return $sql;
852    }
853   
854    function _DropAutoIncrement($tabname)
855    {
856        return false;
857    }
858   
859    function _TableSQL($tabname,$lines,$pkey,$tableoptions)
860    {
861        $sql = array();
862       
863        if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
864            $sql[] = sprintf($this->dropTable,$tabname);
865            if ($this->autoIncrement) {
866                $sInc = $this->_DropAutoIncrement($tabname);
867                if ($sInc) $sql[] = $sInc;
868            }
869            if ( isset ($tableoptions['DROP']) ) {
870                return $sql;
871            }
872        }
873        $s = "CREATE TABLE $tabname (\n";
874        $s .= implode(",\n", $lines);
875        if (sizeof($pkey)>0) {
876            $s .= ",\n                 PRIMARY KEY (";
877            $s .= implode(", ",$pkey).")";
878        }
879        if (isset($tableoptions['CONSTRAINTS']))
880            $s .= "\n".$tableoptions['CONSTRAINTS'];
881       
882        if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
883            $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
884       
885        $s .= "\n)";
886        if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
887        $sql[] = $s;
888       
889        return $sql;
890    }
891   
892    /**
893        GENERATE TRIGGERS IF NEEDED
894        used when table has auto-incrementing field that is emulated using triggers
895    */
896    function _Triggers($tabname,$taboptions)
897    {
898        return array();
899    }
900   
901    /**
902        Sanitize options, so that array elements with no keys are promoted to keys
903    */
904    function _Options($opts)
905    {
906        if (!is_array($opts)) return array();
907        $newopts = array();
908        foreach($opts as $k => $v) {
909            if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
910            else $newopts[strtoupper($k)] = $v;
911        }
912        return $newopts;
913    }
914   
915    /**
916    "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
917   
918    This function changes/adds new fields to your table. You don't
919    have to know if the col is new or not. It will check on its own.
920    */
921    function ChangeTableSQL($tablename, $flds, $tableoptions = false)
922    {
923    global $ADODB_FETCH_MODE;
924   
925        $save = $ADODB_FETCH_MODE;
926        $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
927        if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
928       
929        // check table exists
930        $save_handler = $this->connection->raiseErrorFn;
931        $this->connection->raiseErrorFn = '';
932        $cols = $this->MetaColumns($tablename);
933        $this->connection->raiseErrorFn = $save_handler;
934       
935        if (isset($savem)) $this->connection->SetFetchMode($savem);
936        $ADODB_FETCH_MODE = $save;
937       
938        if ( empty($cols)) {
939            return $this->CreateTableSQL($tablename, $flds, $tableoptions);
940        }
941       
942        if (is_array($flds)) {
943        // Cycle through the update fields, comparing
944        // existing fields to fields to update.
945        // if the Metatype and size is exactly the
946        // same, ignore - by Mark Newham
947            $holdflds = array();
948            foreach($flds as $k=>$v) {
949                if ( isset($cols[$k]) && is_object($cols[$k]) ) {
950                    // If already not allowing nulls, then don't change
951                    $obj = $cols[$k];
952                    if (isset($obj->not_null) && $obj->not_null)
953                        $v = str_replace('NOT NULL','',$v);
954
955                    $c = $cols[$k];
956                    $ml = $c->max_length;
957                    $mt = $this->MetaType($c->type,$ml);
958                    if ($ml == -1) $ml = '';
959                    if ($mt == 'X') $ml = $v['SIZE'];
960                    if (($mt != $v['TYPE']) ||  $ml != $v['SIZE']) {
961                        $holdflds[$k] = $v;
962                    }
963                } else {
964                    $holdflds[$k] = $v;
965                }       
966            }
967            $flds = $holdflds;
968        }
969   
970
971        // already exists, alter table instead
972        list($lines,$pkey,$idxs) = $this->_GenFields($flds);
973        // genfields can return FALSE at times
974        if ($lines == null) $lines = array();
975        $alter = 'ALTER TABLE ' . $this->TableName($tablename);
976        $sql = array();
977
978        foreach ( $lines as $id => $v ) {
979            if ( isset($cols[$id]) && is_object($cols[$id]) ) {
980           
981                $flds = Lens_ParseArgs($v,',');
982               
983                //  We are trying to change the size of the field, if not allowed, simply ignore the request.
984                // $flds[1] holds the type, $flds[2] holds the size -postnuke addition
985                if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
986                 && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
987                    if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1]));
988                    #echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
989                    continue;   
990                }
991                $sql[] = $alter . $this->alterCol . ' ' . $v;
992            } else {
993                $sql[] = $alter . $this->addCol . ' ' . $v;
994            }
995        }
996       
997        return $sql;
998    }
999} // class
1000?>
Note: See TracBrowser for help on using the repository browser.