Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
36 kaklik 1
<?php
2
 
3
/**
4
  V4.80 8 Mar 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 = strtoupper($v);
503
 
504
				switch($attr) {
505
				case '0':
506
				case 'NAME': 	$fname = $v; break;
507
				case '1':
508
				case 'TYPE': 	$ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
509
 
510
				case 'SIZE': 	
511
								$dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
512
								if ($dotat === false) $fsize = $v;
513
								else {
514
									$fsize = substr($v,0,$dotat);
515
									$fprec = substr($v,$dotat+1);
516
								}
517
								break;
518
				case 'UNSIGNED': $funsigned = true; break;
519
				case 'AUTOINCREMENT':
520
				case 'AUTO':	$fautoinc = true; $fnotnull = true; break;
521
				case 'KEY':
522
				case 'PRIMARY':	$fprimary = $v; $fnotnull = true; break;
523
				case 'DEF':
524
				case 'DEFAULT': $fdefault = $v; break;
525
				case 'NOTNULL': $fnotnull = $v; break;
526
				case 'NOQUOTE': $fnoquote = $v; break;
527
				case 'DEFDATE': $fdefdate = $v; break;
528
				case 'DEFTIMESTAMP': $fdefts = $v; break;
529
				case 'CONSTRAINT': $fconstraint = $v; break;
530
				} //switch
531
			} // foreach $fld
532
 
533
			//--------------------
534
			// VALIDATE FIELD INFO
535
			if (!strlen($fname)) {
536
				if ($this->debug) ADOConnection::outp("Undefined NAME");
537
				return false;
538
			}
539
 
540
			$fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
541
			$fname = $this->NameQuote($fname);
542
 
543
			if (!strlen($ftype)) {
544
				if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
545
				return false;
546
			} else {
547
				$ftype = strtoupper($ftype);
548
			}
549
 
550
			$ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
551
 
552
			if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
553
 
554
			if ($fprimary) $pkey[] = $fname;
555
 
556
			// some databases do not allow blobs to have defaults
557
			if ($ty == 'X') $fdefault = false;
558
 
559
			//--------------------
560
			// CONSTRUCT FIELD SQL
561
			if ($fdefts) {
562
				if (substr($this->connection->databaseType,0,5) == 'mysql') {
563
					$ftype = 'TIMESTAMP';
564
				} else {
565
					$fdefault = $this->connection->sysTimeStamp;
566
				}
567
			} else if ($fdefdate) {
568
				if (substr($this->connection->databaseType,0,5) == 'mysql') {
569
					$ftype = 'TIMESTAMP';
570
				} else {
571
					$fdefault = $this->connection->sysDate;
572
				}
573
			} else if ($fdefault !== false && !$fnoquote)
574
				if ($ty == 'C' or $ty == 'X' or 
575
					( substr($fdefault,0,1) != "'" && !is_numeric($fdefault)))
576
					if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 
577
						$fdefault = trim($fdefault);
578
					else if (strtolower($fdefault) != 'null')
579
						$fdefault = $this->connection->qstr($fdefault);
580
			$suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
581
 
582
			if ($widespacing) $fname = str_pad($fname,24);
583
			$lines[$fid] = $fname.' '.$ftype.$suffix;
584
 
585
			if ($fautoinc) $this->autoIncrement = true;
586
		} // foreach $flds
587
 
588
		return array($lines,$pkey);
589
	}
590
	/*
591
		 GENERATE THE SIZE PART OF THE DATATYPE
592
			$ftype is the actual type
593
			$ty is the type defined originally in the DDL
594
	*/
595
	function _GetSize($ftype, $ty, $fsize, $fprec)
596
	{
597
		if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
598
			$ftype .= "(".$fsize;
599
			if (strlen($fprec)) $ftype .= ",".$fprec;
600
			$ftype .= ')';
601
		}
602
		return $ftype;
603
	}
604
 
605
 
606
	// return string must begin with space
607
	function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
608
	{	
609
		$suffix = '';
610
		if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
611
		if ($fnotnull) $suffix .= ' NOT NULL';
612
		if ($fconstraint) $suffix .= ' '.$fconstraint;
613
		return $suffix;
614
	}
615
 
616
	function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
617
	{
618
		$sql = array();
619
 
620
		if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
621
			$sql[] = sprintf ($this->dropIndex, $idxname);
622
			if ( isset($idxoptions['DROP']) )
623
				return $sql;
624
		}
625
 
626
		if ( empty ($flds) ) {
627
			return $sql;
628
		}
629
 
630
		$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
631
 
632
		$s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
633
 
634
		if ( isset($idxoptions[$this->upperName]) )
635
			$s .= $idxoptions[$this->upperName];
636
 
637
		if ( is_array($flds) )
638
			$flds = implode(', ',$flds);
639
		$s .= '(' . $flds . ')';
640
		$sql[] = $s;
641
 
642
		return $sql;
643
	}
644
 
645
	function _DropAutoIncrement($tabname)
646
	{
647
		return false;
648
	}
649
 
650
	function _TableSQL($tabname,$lines,$pkey,$tableoptions)
651
	{
652
		$sql = array();
653
 
654
		if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
655
			$sql[] = sprintf($this->dropTable,$tabname);
656
			if ($this->autoIncrement) {
657
				$sInc = $this->_DropAutoIncrement($tabname);
658
				if ($sInc) $sql[] = $sInc;
659
			}
660
			if ( isset ($tableoptions['DROP']) ) {
661
				return $sql;
662
			}
663
		}
664
		$s = "CREATE TABLE $tabname (\n";
665
		$s .= implode(",\n", $lines);
666
		if (sizeof($pkey)>0) {
667
			$s .= ",\n                 PRIMARY KEY (";
668
			$s .= implode(", ",$pkey).")";
669
		}
670
		if (isset($tableoptions['CONSTRAINTS'])) 
671
			$s .= "\n".$tableoptions['CONSTRAINTS'];
672
 
673
		if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 
674
			$s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
675
 
676
		$s .= "\n)";
677
		if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
678
		$sql[] = $s;
679
 
680
		return $sql;
681
	}
682
 
683
	/*
684
		GENERATE TRIGGERS IF NEEDED
685
		used when table has auto-incrementing field that is emulated using triggers
686
	*/
687
	function _Triggers($tabname,$taboptions)
688
	{
689
		return array();
690
	}
691
 
692
	/*
693
		Sanitize options, so that array elements with no keys are promoted to keys
694
	*/
695
	function _Options($opts)
696
	{
697
		if (!is_array($opts)) return array();
698
		$newopts = array();
699
		foreach($opts as $k => $v) {
700
			if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
701
			else $newopts[strtoupper($k)] = $v;
702
		}
703
		return $newopts;
704
	}
705
 
706
	/*
707
	"Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
708
 
709
	This function changes/adds new fields to your table. You don't
710
	have to know if the col is new or not. It will check on its own.
711
	*/
712
	function ChangeTableSQL($tablename, $flds, $tableoptions = false)
713
	{
714
	global $ADODB_FETCH_MODE;
715
 
716
		$save = $ADODB_FETCH_MODE;
717
		$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
718
		if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
719
 
720
		// check table exists
721
		$save_handler = $this->connection->raiseErrorFn;
722
		$this->connection->raiseErrorFn = '';
723
		$cols = $this->MetaColumns($tablename);
724
		$this->connection->raiseErrorFn = $save_handler;
725
 
726
		if (isset($savem)) $this->connection->SetFetchMode($savem);
727
		$ADODB_FETCH_MODE = $save;
728
 
729
		if ( empty($cols)) { 
730
			return $this->CreateTableSQL($tablename, $flds, $tableoptions);
731
		}
732
 
733
		if (is_array($flds)) {
734
		// Cycle through the update fields, comparing
735
		// existing fields to fields to update.
736
		// if the Metatype and size is exactly the
737
		// same, ignore - by Mark Newham
738
			$holdflds = array();
739
			foreach($flds as $k=>$v) {
740
				if ( isset($cols[$k]) && is_object($cols[$k]) ) {
741
					// If already not allowing nulls, then don't change
742
					$obj = $cols[$k];
743
					if (isset($obj->not_null) && $obj->not_null)
744
						$v = str_replace('NOT NULL','',$v);
745
 
746
					$c = $cols[$k];
747
					$ml = $c->max_length;
748
					$mt = $this->MetaType($c->type,$ml);
749
					if ($ml == -1) $ml = '';
750
					if ($mt == 'X') $ml = $v['SIZE'];
751
					if (($mt != $v['TYPE']) ||  $ml != $v['SIZE']) {
752
						$holdflds[$k] = $v;
753
					}
754
				} else {
755
					$holdflds[$k] = $v;
756
				}		
757
			}
758
			$flds = $holdflds;
759
		}
760
 
761
 
762
		// already exists, alter table instead
763
		list($lines,$pkey) = $this->_GenFields($flds);
764
		$alter = 'ALTER TABLE ' . $this->TableName($tablename);
765
		$sql = array();
766
 
767
		foreach ( $lines as $id => $v ) {
768
			if ( isset($cols[$id]) && is_object($cols[$id]) ) {
769
 
770
				$flds = Lens_ParseArgs($v,',');
771
 
772
				//  We are trying to change the size of the field, if not allowed, simply ignore the request.
773
				if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) continue;	 
774
 
775
				$sql[] = $alter . $this->alterCol . ' ' . $v;
776
			} else {
777
				$sql[] = $alter . $this->addCol . ' ' . $v;
778
			}
779
		}
780
 
781
		return $sql;
782
	}
783
} // class
784
?>