32
|
1 package IMPL::SQL::Schema::Traits::mysql::Handler;
|
|
2 use strict;
|
|
3 use base qw(IMPL::Object);
|
|
4 use IMPL::Class::Property;
|
|
5 use IMPL::Class::Property::Direct;
|
|
6
|
|
7 BEGIN {
|
|
8 public _direct property SqlBatch => prop_none;
|
|
9 }
|
|
10
|
|
11 sub formatTypeNameInteger {
|
|
12 my ($type) = @_;
|
|
13
|
|
14 return $type->Name.($type->MaxLength ? '('.$type->MaxLength.')' : '').($type->Unsigned ? ' UNSIGNED': '').($type->Zerofill ? ' ZEROFILL' : '');
|
|
15 }
|
|
16
|
|
17 sub formatTypeNameReal {
|
|
18 my ($type) = @_;
|
|
19
|
|
20 return $type->Name.($type->MaxLength ? '('.$type->MaxLength.', '.$type->Scale.')' : '').($type->Unsigned ? ' UNSIGNED': '').($type->Zerofill ? ' ZEROFILL' : '');
|
|
21 }
|
|
22
|
|
23 sub formatTypeNameNumeric {
|
|
24 my ($type) = @_;
|
|
25 $type->MaxLength or die new IMPL::InvalidArgumentException('The length and precission must be specified',$type->Name);
|
|
26 return $type->Name.($type->MaxLength ? '('.$type->MaxLength.', '.$type->Scale.')' : '').($type->Unsigned ? ' UNSIGNED': '').($type->Zerofill ? ' ZEROFILL' : '');
|
|
27 }
|
|
28
|
|
29 sub formatTypeName {
|
|
30 my ($type) = @_;
|
|
31 return $type->Name;
|
|
32 }
|
|
33
|
|
34 sub formatTypeNameChar {
|
|
35 my ($type) = @_;
|
|
36
|
|
37 return (
|
|
38 $type->Name.'('.$type->MaxLength.')'. (UNIVERSAL::isa($type,'IMPL::SQL::Schema::Type::mysql::CHAR') ? $type->Encoding : '')
|
|
39 );
|
|
40 }
|
|
41
|
|
42 sub formatTypeNameVarChar {
|
|
43 my ($type) = @_;
|
|
44
|
|
45 return (
|
|
46 $type->Name.'('.$type->MaxLength.')'. (UNIVERSAL::isa($type,'IMPL::SQL::Schema::Type::mysql::VARCHAR') ? $type->Encoding : '')
|
|
47 );
|
|
48 }
|
|
49
|
|
50 sub formatTypeNameEnum {
|
|
51 my ($type) = @_;
|
|
52 die new Exception('Enum must be a type of either IMPL::SQL::Schema::Type::mysql::ENUM or IMPL::SQL::Schema::Type::mysql::SET') if not (UNIVERSAL::isa($type,'IMPL::SQL::Schema::Type::mysql::ENUM') or UNIVERSAL::isa($type,'IMPL::SQL::Schema::Type::mysql::SET'));
|
|
53 return (
|
|
54 $type->Name.'('.join(',',map {quote($_)} $type->Values).')'
|
|
55 );
|
|
56 }
|
|
57
|
|
58 sub quote{
|
|
59 if (wantarray) {
|
|
60 return map { my $str=$_; $str=~ s/'/''/g; "'$str'"; } @_;
|
|
61 } else {
|
|
62 return join '',map { my $str=$_; $str=~ s/'/''/g; "'$str'"; } @_;
|
|
63 }
|
|
64 }
|
|
65
|
|
66 sub quote_names {
|
|
67 if (wantarray) {
|
|
68 return map { my $str=$_; $str=~ s/`/``/g; "`$str`"; } @_;
|
|
69 } else {
|
|
70 return join '',map { my $str=$_; $str=~ s/`/``/g; "`$str`"; } @_;
|
|
71 }
|
|
72 }
|
|
73
|
|
74 sub formatStringValue {
|
|
75 my ($value) = @_;
|
|
76
|
|
77 if (ref $value) {
|
|
78 if (UNIVERSAL::isa($value,'IMPL::SQL::Schema::mysql::Expression')) {
|
|
79 return $value->as_string;
|
|
80 } else {
|
|
81 die new Exception('Can\'t format the object as a value',ref $value);
|
|
82 }
|
|
83 } else {
|
|
84 return quote($value);
|
|
85 }
|
|
86 }
|
|
87
|
|
88
|
|
89 sub formatNumberValue {
|
|
90 my ($value) = @_;
|
|
91
|
|
92 if (ref $value) {
|
|
93 if (UNIVERSAL::isa($value,'IMPL::SQL::Schema::mysql::Expression')) {
|
|
94 return $value->as_string;
|
|
95 } else {
|
|
96 die new Exception('Can\'t format the object as a value',ref $value);
|
|
97 }
|
|
98 } else {
|
|
99 $value =~ /^((\+|-)\s*)?\d+(\.\d+)?(e(\+|-)?\d+)?$/ or die new Exception('The specified value isn\'t a valid number',$value);
|
|
100 return $value;
|
|
101 }
|
|
102 }
|
|
103
|
|
104
|
|
105 my %TypesFormat = (
|
|
106 TINYINT => {
|
|
107 formatType => \&formatTypeNameInteger,
|
|
108 formatValue => \&formatNumberValue
|
|
109 },
|
|
110 SMALLINT => {
|
|
111 formatType => \&formatTypeNameInteger,
|
|
112 formatValue => \&formatNumberValue
|
|
113 },
|
|
114 MEDIUMINT => {
|
|
115 formatType => \&formatTypeNameInteger,
|
|
116 formatValue => \&formatNumberValue
|
|
117 },
|
|
118 INT => {
|
|
119 formatType => \&formatTypeNameInteger,
|
|
120 formatValue => \&formatNumberValue
|
|
121 },
|
|
122 INTEGER => {
|
|
123 formatType => \&formatTypeNameInteger,
|
|
124 formatValue => \&formatNumberValue
|
|
125 },
|
|
126 BIGINT => {
|
|
127 formatType => \&formatTypeNameInteger,
|
|
128 formatValue => \&formatNumberValue
|
|
129 },
|
|
130 REAL => {
|
|
131 formatType => \&formatTypeNameReal,
|
|
132 formatValue => \&formatNumberValue
|
|
133 },
|
|
134 DOUBLE => {
|
|
135 formatType => \&formatTypeNameReal,
|
|
136 formatValue => \&formatNumberValue
|
|
137 },
|
|
138 FLOAT => {
|
|
139 formatType => \&formatTypeNameReal,
|
|
140 formatValue => \&formatNumberValue
|
|
141 },
|
|
142 DECIMAL => {
|
|
143 formatType => \&formatTypeNameNumeric,
|
|
144 formatValue => \&formatNumberValue
|
|
145 },
|
|
146 NUMERIC => {
|
|
147 formatType => \&formatTypeNameNumeric,
|
|
148 formatValue => \&formatNumberValue
|
|
149 },
|
|
150 DATE => {
|
|
151 formatType => \&formatTypeName,
|
|
152 formatValue => \&formatStringValue
|
|
153 },
|
|
154 TIME => {
|
|
155 formatType => \&formatTypeName,
|
|
156 formatValue => \&formatStringValue
|
|
157 },
|
|
158 TIMESTAMP => {
|
|
159 formatType => \&formatTypeName,
|
|
160 formatValue => \&formatStringValue
|
|
161 },
|
|
162 DATETIME => {
|
|
163 formatType => \&formatTypeName,
|
|
164 formatValue => \&formatStringValue
|
|
165 },
|
|
166 CHAR => {
|
|
167 formatType => \&formatTypeNameChar,
|
|
168 formatValue => \&formatStringValue
|
|
169 },
|
|
170 VARCHAR => {
|
|
171 formatType => \&formatTypeNameVarChar,
|
|
172 formatValue => \&formatStringValue
|
|
173 },
|
|
174 TINYBLOB => {
|
|
175 formatType => \&formatTypeName,
|
|
176 formatValue => \&formatStringValue
|
|
177 },
|
|
178 BLOB => {
|
|
179 formatType => \&formatTypeName,
|
|
180 formatValue => \&formatStringValue
|
|
181 },
|
|
182 MEDIUMBLOB => {
|
|
183 formatType => \&formatTypeName,
|
|
184 formatValue => \&formatStringValue
|
|
185 },
|
|
186 LONGBLOB => {
|
|
187 formatType => \&formatTypeName,
|
|
188 formatValue => \&formatStringValue
|
|
189 },
|
|
190 TINYTEXT => {
|
|
191 formatType => \&formatTypeName,
|
|
192 formatValue => \&formatStringValue
|
|
193 },
|
|
194 TEXT => {
|
|
195 formatType => \&formatTypeName,
|
|
196 formatValue => \&formatStringValue
|
|
197 },
|
|
198 MEDIUMTEXT => {
|
|
199 formatType => \&formatTypeName,
|
|
200 formatValue => \&formatStringValue
|
|
201 },
|
|
202 LONGTEXT => {
|
|
203 formatType => \&formatTypeName,
|
|
204 formatValue => \&formatStringValue
|
|
205 },
|
|
206 ENUM => {
|
|
207 formatType => \&formatTypeNameEnum,
|
|
208 formatValue => \&formatStringValue
|
|
209 },
|
|
210 SET => {
|
|
211 formatType => \&formatTypeNameEnum,
|
|
212 formatValue => \&formatStringValue
|
|
213 }
|
|
214 );
|
|
215
|
|
216
|
|
217 =pod
|
|
218 CREATE TABLE 'test'.'New Table' (
|
|
219 'dd' INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
220 `ff` VARCHAR(45) NOT NULL,
|
|
221 `ffg` VARCHAR(45) NOT NULL DEFAULT 'aaa',
|
|
222 `ddf` INTEGER UNSIGNED NOT NULL,
|
|
223 PRIMARY KEY(`dd`),
|
|
224 UNIQUE `Index_2`(`ffg`),
|
|
225 CONSTRAINT `FK_New Table_1` FOREIGN KEY `FK_New Table_1` (`ddf`)
|
|
226 REFERENCES `user` (`id`)
|
|
227 ON DELETE RESTRICT
|
|
228 ON UPDATE RESTRICT
|
|
229 )
|
|
230 ENGINE = InnoDB;
|
|
231 =cut
|
|
232 sub formatCreateTable {
|
|
233 my ($table,$level,%options) = @_;
|
|
234
|
|
235 my @sql;
|
|
236
|
|
237 # table body
|
|
238 push @sql, map { formatColumn($_,$level+1) } $table->Columns ;
|
|
239 if ($options{'skip_foreign_keys'}) {
|
|
240 push @sql, map { formatConstraint($_,$level+1) } grep {not UNIVERSAL::isa($_,'IMPL::SQL::Schema::Constraint::ForeignKey')} values %{$table->Constraints};
|
|
241 } else {
|
|
242 push @sql, map { formatConstraint($_,$level+1) } values %{$table->Constraints};
|
|
243 }
|
|
244
|
|
245 for(my $i = 0 ; $i < @sql -1; $i++) {
|
|
246 $sql[$i] .= ',';
|
|
247 }
|
|
248
|
|
249 unshift @sql, "CREATE TABLE ".quote_names($table->Name)."(";
|
|
250
|
|
251 if ($table->Tag) {
|
|
252 push @sql, ")";
|
|
253 push @sql, formatTableTag($table->Tag,$level);
|
|
254 $sql[$#sql].=';';
|
|
255 } else {
|
|
256 push @sql, ');';
|
|
257 }
|
|
258
|
|
259 return map { ("\t" x $level) . $_ } @sql;
|
|
260 }
|
|
261
|
|
262 sub formatDropTable {
|
|
263 my ($tableName,$level) = @_;
|
|
264
|
|
265 return "\t"x$level."DROP TABLE ".quote_names($tableName).";";
|
|
266 }
|
|
267
|
|
268 sub formatTableTag {
|
|
269 my ($tag,$level) = @_;
|
|
270 return map { "\t"x$level . "$_ = ".$tag->{$_} } grep {/^(ENGINE)$/i} keys %{$tag};
|
|
271 }
|
|
272
|
|
273 sub formatColumn {
|
|
274 my ($column,$level) = @_;
|
|
275 $level ||= 0;
|
|
276 return "\t"x$level.quote_names($column->Name)." ".formatType($column->Type)." ".($column->CanBeNull ? 'NULL' : 'NOT NULL').($column->DefaultValue ? formatValueToType($column->DefaultValue,$column->Type) : '' ).($column->Tag ? ' '.join(' ',$column->Tag) : '');
|
|
277 }
|
|
278
|
|
279 sub formatType {
|
|
280 my ($type) = @_;
|
|
281 my $format = $TypesFormat{uc $type->Name} or die new Exception('The unknown type name',$type->Name);
|
|
282 $format->{formatType}->($type);
|
|
283 }
|
|
284
|
|
285 sub formatValueToType {
|
|
286 my ($value,$type) = @_;
|
|
287
|
|
288 my $format = $TypesFormat{uc $type->Name} or die new Exception('The unknown type name',$type->Name);
|
|
289 $format->{formatValue}->($value);
|
|
290 }
|
|
291
|
|
292 sub formatConstraint {
|
|
293 my ($constraint,$level) = @_;
|
|
294
|
|
295 if (UNIVERSAL::isa($constraint,'IMPL::SQL::Schema::Constraint::ForeignKey')) {
|
|
296 return formatForeignKey($constraint,$level);
|
|
297 } else {
|
|
298 return formatIndex($constraint, $level);
|
|
299 }
|
|
300 }
|
|
301
|
|
302 sub formatIndex {
|
|
303 my ($constraint,$level) = @_;
|
|
304
|
|
305 my $name = quote_names($constraint->Name);
|
|
306 my $columns = join(',',map quote_names($_->Name),$constraint->Columns);
|
|
307
|
|
308 if (ref $constraint eq 'IMPL::SQL::Schema::Constraint::PrimaryKey') {
|
|
309 return "\t"x$level."PRIMARY KEY ($columns)";
|
|
310 } elsif ($constraint eq 'IMPL::SQL::Schema::Constraint::Unique') {
|
|
311 return "\t"x$level."UNIQUE $name ($columns)";
|
|
312 } elsif ($constraint eq 'IMPL::SQL::Schema::Constraint::Index') {
|
|
313 return "\t"x$level."INDEX $name ($columns)";
|
|
314 } else {
|
|
315 die new IMPL::InvalidArgumentException('The unknown constraint', ref $constraint);
|
|
316 }
|
|
317
|
|
318 }
|
|
319
|
|
320 sub formatForeignKey {
|
|
321 my ($constraint,$level) = @_;
|
|
322
|
|
323 my $name = quote_names($constraint->Name);
|
|
324 my $columns = join(',',map quote_names($_->Name),$constraint->Columns);
|
|
325
|
|
326 not $constraint->OnDelete or grep { uc $constraint->OnDelete eq $_ } ('RESTRICT','CASCADE','SET NULL','NO ACTION','SET DEFAULT') or die new IMPL::Exception('Invalid ON DELETE reference',$constraint->OnDelete);
|
|
327 not $constraint->OnUpdate or grep { uc $constraint->OnUpdate eq $_ } ('RESTRICT','CASCADE','SET NULL','NO ACTION','SET DEFAULT') or die new IMPL::Exception('Invalid ON UPDATE reference',$constraint->OnUpdate);
|
|
328
|
|
329 my $refname = quote_names($constraint->ReferencedPrimaryKey->Table->Name);
|
|
330 my $refcolumns = join(',',map quote_names($_->Name),$constraint->ReferencedPrimaryKey->Columns);
|
|
331 return (
|
|
332 "\t"x$level.
|
|
333 "CONSTRAINT $name FOREIGN KEY $name ($columns) REFERENCES $refname ($refcolumns)".
|
|
334 ($constraint->OnUpdate ? 'ON UPDATE'.$constraint->OnUpdate : '').
|
|
335 ($constraint->OnDelete ? 'ON DELETE'.$constraint->OnDelete : '')
|
|
336 );
|
|
337 }
|
|
338
|
|
339 sub formatAlterTableRename {
|
|
340 my ($oldName,$newName,$level) = @_;
|
|
341
|
|
342 return "\t"x$level."ALTER TABLE ".quote_names($oldName)." RENAME TO ".quote_names($newName).";";
|
|
343 }
|
|
344
|
|
345 sub formatAlterTableDropColumn {
|
|
346 my ($tableName, $columnName,$level) = @_;
|
|
347
|
|
348 return "\t"x$level."ALTER TABLE ".quote_names($tableName)." DROP COLUMN ".quote_names($columnName).";";
|
|
349 }
|
|
350
|
|
351 =pod
|
|
352 ALTER TABLE `test`.`user` ADD COLUMN `my_col` VARCHAR(45) NOT NULL AFTER `name2`
|
|
353 =cut
|
|
354 sub formatAlterTableAddColumn {
|
|
355 my ($tableName, $column, $table, $pos, $level) = @_;
|
|
356
|
|
357 my $posSpec = $pos == 0 ? 'FIRST' : 'AFTER '.quote_names($table->ColumnAt($pos-1)->Name);
|
|
358
|
|
359 return "\t"x$level."ALTER TABLE ".quote_names($tableName)." ADD COLUMN ".formatColumn($column) .' '. $posSpec.";";
|
|
360 }
|
|
361
|
|
362 =pod
|
|
363 ALTER TABLE `test`.`manager` MODIFY COLUMN `description` VARCHAR(256) NOT NULL DEFAULT NULL;
|
|
364 =cut
|
|
365 sub formatAlterTableChangeColumn {
|
|
366 my ($tableName,$column,$table,$pos,$level) = @_;
|
|
367 my $posSpec = $pos == 0 ? 'FIRST' : 'AFTER '.quote_names($table->ColumnAt($pos-1)->Name);
|
|
368 return "\t"x$level."ALTER TABLE ".quote_names($tableName)." MODIFY COLUMN ".formatColumn($column).' '. $posSpec.";";
|
|
369 }
|
|
370
|
|
371 =pod
|
|
372 ALTER TABLE `test`.`manager` DROP INDEX `Index_2`;
|
|
373 =cut
|
|
374 sub formatAlterTableDropConstraint {
|
|
375 my ($tableName,$constraint,$level) = @_;
|
|
376 my $constraintName;
|
|
377 if (ref $constraint eq 'IMPL::SQL::Schema::Constraint::PrimaryKey') {
|
|
378 $constraintName = 'PRIMARY KEY';
|
|
379 } elsif (ref $constraint eq 'IMPL::SQL::Schema::Constraint::ForeignKey') {
|
|
380 $constraintName = 'FOREIGN KEY '.quote_names($constraint->Name);
|
|
381 } elsif (UNIVERSAL::isa($constraint,'IMPL::SQL::Schema::Constraint::Index')) {
|
|
382 $constraintName = 'INDEX '.quote_names($constraint->Name);
|
|
383 } else {
|
|
384 die new IMPL::Exception("The unknow type of the constraint",ref $constraint);
|
|
385 }
|
|
386 return "\t"x$level."ALTER TABLE ".quote_names($tableName)." DROP $constraintName;";
|
|
387 }
|
|
388
|
|
389 =pod
|
|
390 ALTER TABLE `test`.`session` ADD INDEX `Index_2`(`id`, `name`);
|
|
391 =cut
|
|
392 sub formatAlterTableAddConstraint {
|
|
393 my ($tableName,$constraint,$level) = @_;
|
|
394
|
|
395 return "\t"x$level."ALTER TABLE ".quote_names($tableName)." ADD ".formatConstraint($constraint,0).';';
|
|
396 }
|
|
397
|
|
398 sub CreateTable {
|
|
399 my ($this,$tbl,%option) = @_;
|
|
400
|
|
401 push @{$this->{$SqlBatch}},join("\n",formatCreateTable($tbl,0,%option));
|
|
402
|
|
403 return 1;
|
|
404 }
|
|
405
|
|
406 sub DropTable {
|
|
407 my ($this,$tbl) = @_;
|
|
408
|
|
409 push @{$this->{$SqlBatch}},join("\n",formatDropTable($tbl,0));
|
|
410
|
|
411 return 1;
|
|
412 }
|
|
413
|
|
414 sub RenameTable {
|
|
415 my ($this,$oldName,$newName) = @_;
|
|
416
|
|
417 push @{$this->{$SqlBatch}},join("\n",formatAlterTableRename($oldName,$newName,0));
|
|
418
|
|
419 return 1;
|
|
420 }
|
|
421
|
|
422 sub AlterTableAddColumn {
|
|
423 my ($this,$tblName,$column,$table,$pos) = @_;
|
|
424
|
|
425 push @{$this->{$SqlBatch}},join("\n",formatAlterTableAddColumn($tblName,$column,$table,$pos,0));
|
|
426
|
|
427 return 1;
|
|
428 }
|
|
429 sub AlterTableDropColumn {
|
|
430 my ($this,$tblName,$columnName) = @_;
|
|
431
|
|
432 push @{$this->{$SqlBatch}},join("\n",formatAlterTableDropColumn($tblName,$columnName,0));
|
|
433
|
|
434 return 1;
|
|
435 }
|
|
436
|
|
437 sub AlterTableChangeColumn {
|
|
438 my ($this,$tblName,$column,$table,$pos) = @_;
|
|
439
|
|
440 push @{$this->{$SqlBatch}},join("\n",formatAlterTableChangeColumn($tblName,$column,$table,$pos,0));
|
|
441
|
|
442 return 1;
|
|
443 }
|
|
444
|
|
445 sub AlterTableAddConstraint {
|
|
446 my ($this,$tblName,$constraint) = @_;
|
|
447
|
|
448 push @{$this->{$SqlBatch}},join("\n",formatAlterTableAddConstraint($tblName,$constraint,0));
|
|
449
|
|
450 return 1;
|
|
451 }
|
|
452
|
|
453 sub AlterTableDropConstraint {
|
|
454 my ($this,$tblName,$constraint) = @_;
|
|
455
|
|
456 push @{$this->{$SqlBatch}},join("\n",formatAlterTableDropConstraint($tblName,$constraint,0));
|
|
457
|
|
458 return 1;
|
|
459 }
|
|
460
|
|
461 sub Sql {
|
|
462 my ($this) = @_;
|
|
463 if (wantarray) {
|
|
464 $this->SqlBatch;
|
|
465 } else {
|
|
466 return join("\n",$this->SqlBatch);
|
|
467 }
|
|
468 }
|
|
469
|
|
470 package IMPL::SQL::Schema::Traits::mysql;
|
|
471 use Common;
|
|
472 use base qw(IMPL::SQL::Schema::Traits);
|
|
473 use IMPL::Class::Property;
|
|
474 use IMPL::Class::Property::Direct;
|
|
475
|
|
476 BEGIN {
|
|
477 public _direct property PendingConstraints => prop_none;
|
|
478 }
|
|
479
|
|
480 sub CTOR {
|
|
481 my ($this,%args) = @_;
|
|
482
|
|
483 $args{'Handler'} = new IMPL::SQL::Schema::Traits::mysql::Handler;
|
|
484 $this->SUPER::CTOR(%args);
|
|
485 }
|
|
486
|
|
487 sub DropConstraint {
|
|
488 my ($this,$constraint) = @_;
|
|
489
|
|
490 if (UNIVERSAL::isa($constraint,'IMPL::SQL::Schema::Constraint::Index')) {
|
|
491 return 1 if not grep { $this->TableInfo->{$this->MapTableName($constraint->Table->Name)}->{'Columns'}->{$_->Name} != IMPL::SQL::Schema::Traits::STATE_REMOVED} $constraint->Columns;
|
|
492 my @constraints = grep {$_ != $constraint } $constraint->Table->GetColumnConstraints($constraint->Columns);
|
|
493 if (scalar @constraints == 1 and UNIVERSAL::isa($constraints[0],'IMPL::SQL::Schema::Constraint::ForeignKey')) {
|
|
494 my $fk = shift @constraints;
|
|
495 if ($this->TableInfo->{$this->MapTableName($fk->Table->Name)}->{'Constraints'}->{$fk->Name} != IMPL::SQL::Schema::Traits::STATE_REMOVED) {
|
|
496 push @{$this->PendingActions}, {Action => \&DropConstraint, Args => [$constraint]};
|
|
497 $this->{$PendingConstraints}->{$constraint->UniqName}->{'attempts'} ++;
|
|
498
|
|
499 die new IMPL::Exception('Can\'t drop the primary key becouse of the foreing key',$fk->UniqName) if $this->{$PendingConstraints}->{$constraint->UniqName}->{'attempts'} > 2;
|
|
500 return 2;
|
|
501 }
|
|
502 }
|
|
503 }
|
|
504 $this->SUPER::DropConstraint($constraint);
|
|
505 }
|
|
506
|
|
507 sub GetMetaTable {
|
|
508 my ($class,$dbh) = @_;
|
|
509
|
|
510 return IMPL::SQL::Schema::Traits::mysql::MetaTable->new( DBHandle => $dbh);
|
|
511 }
|
|
512
|
|
513 package IMPL::SQL::Schema::Traits::mysql::MetaTable;
|
|
514 use Common;
|
|
515 use base qw(IMPL::Object);
|
|
516 use IMPL::Class::Property;
|
|
517 use IMPL::Class::Property::Direct;
|
|
518
|
|
519 BEGIN {
|
|
520 public _direct property DBHandle => prop_none;
|
|
521 }
|
|
522
|
|
523 sub ReadProperty {
|
|
524 my ($this,$name) = @_;
|
|
525
|
|
526 local $this->{$DBHandle}->{PrintError};
|
|
527 $this->{$DBHandle}->{PrintError} = 0;
|
|
528 my ($val) = $this->{$DBHandle}->selectrow_array("SELECT value FROM _Meta WHERE name like ?", undef, $name);
|
|
529 return $val;
|
|
530 }
|
|
531
|
|
532 sub SetProperty {
|
|
533 my ($this,$name,$val) = @_;
|
|
534
|
|
535 if ( $this->{$DBHandle}->selectrow_arrayref("SELECT TABLE_NAME FROM information_schema.`TABLES` T where TABLE_SCHEMA like DATABASE() and TABLE_NAME like '_Meta'")) {
|
|
536 if ($this->{$DBHandle}->selectrow_arrayref("SELECT name FROM _Meta WHERE name like ?", undef, $name)) {
|
|
537 $this->{$DBHandle}->do("UPDATE _Meta SET value = ? WHERE name like ?",undef,$val,$name);
|
|
538 } else {
|
|
539 $this->{$DBHandle}->do("INSERT INTO _Meta(name,value) VALUES ('$name',?)",undef,$val);
|
|
540 }
|
|
541 } else {
|
|
542 $this->{$DBHandle}->do(q{
|
|
543 CREATE TABLE `_Meta` (
|
|
544 `name` VARCHAR(255) NOT NULL,
|
|
545 `value` LONGTEXT NULL,
|
|
546 PRIMARY KEY(`name`)
|
|
547 );
|
|
548 }) or die new IMPL::Exception("Failed to create table","_Meta");
|
|
549
|
|
550 $this->{$DBHandle}->do("INSERT INTO _Meta(name,value) VALUES (?,?)",undef,$name,$val);
|
|
551 }
|
|
552 }
|
|
553
|
|
554 1;
|