Mercurial > pub > Impl
comparison Lib/IMPL/SQL/Schema/Traits/mysql.pm @ 32:56cef8e3cda6
+1
| author | Sergey |
|---|---|
| date | Mon, 09 Nov 2009 01:39:31 +0300 |
| parents | |
| children | 32d2350fccf9 |
comparison
equal
deleted
inserted
replaced
| 31:d59526f6310e | 32:56cef8e3cda6 |
|---|---|
| 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; |
