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