Mercurial > pub > Impl
view Lib/Schema/DB/Table.pm @ 94:79bf75223afe
Fixed security related bugs
author | wizard |
---|---|
date | Thu, 29 Apr 2010 01:31:27 +0400 |
parents | 16ada169ca75 |
children |
line wrap: on
line source
use strict; package Schema::DB::Table; use Carp; use Common; use Schema::DB::Column; use Schema::DB::Constraint; use Schema::DB::Constraint::PrimaryKey; use Schema::DB::Constraint::ForeignKey; our @ISA = qw(Object); srand time; BEGIN { DeclareProperty Name => ACCESS_READ; DeclareProperty Schema => ACCESS_READ; DeclareProperty Columns => ACCESS_READ; DeclareProperty Constraints => ACCESS_READ; DeclareProperty ColumnsByName => ACCESS_NONE; DeclareProperty PrimaryKey => ACCESS_READ; DeclareProperty Tag => ACCESS_ALL; } sub CTOR { my ($this,%args) = @_; $this->{$Name} = $args{'Name'} or die new Exception('a table name is required'); $this->{$Schema} = $args{'Schema'} or die new Exception('a parent schema is required'); } sub InsertColumn { my ($this,$column,$index) = @_; $index = ($this->{$Columns} ? scalar(@{$this->{$Columns}}) : 0) if not defined $index; die new Exception("Index is out of range") if ($index < 0 || $index > ($this->{$Columns} ? scalar(@{$this->{$Columns}}) : 0)); if (UNIVERSAL::isa($column,'Schema::DB::Column')) { } elsif (UNIVERSAL::isa($column,'HASH')) { $column = new Schema::DB::Column(%{$column}); } else { die new Exception("The invalid parameter"); } if (exists $this->{$ColumnsByName}->{$column->Name}) { die new Exception("The column already exists",$column->name); } else { $this->{$ColumnsByName}->{$column->Name} = $column; splice @{$this->{$Columns}},$index,0,$column; } return $column; } sub RemoveColumn { my ($this,$NameOrColumn,$Force) = @_; my $ColName; if (UNIVERSAL::isa($NameOrColumn,'Schema::DB::Column')) { $ColName = $NameOrColumn->Name; } elsif (not ref $NameOrColumn) { $ColName = $NameOrColumn; } if (exists $this->{$ColumnsByName}->{$ColName}) { my $index = 0; foreach my $column(@{$this->{$Columns}}) { last if $column->Name eq $ColName; $index++; } my $column = $this->{$Columns}[$index]; if (my @constraints = $this->GetColumnConstraints($column)){ $Force or die new Exception('Can\'t remove column which is used in the constraints',@constraints); $this->RemoveConstraint($_) foreach @constraints; } my $removed = splice @{$this->{$Columns}},$index,1; delete $this->{$ColumnsByName}->{$ColName}; return $removed; } else { die new Exception("The column not found",$NameOrColumn->Name); } } sub Column { my ($this,$name) = @_; return $this->{$ColumnsByName}->{$name}; } sub ColumnAt { my ($this,$index) = @_; die new Exception("The index is out of range") if $index < 0 || $index >= ($this->{$Columns} ? scalar(@{$this->{$Columns}}) : 0); return $this->{$Columns}[$index]; } sub AddConstraint { my ($this,$Constraint) = @_; die new Exception('The invalid parameter') if not UNIVERSAL::isa($Constraint,'Schema::DB::Constraint'); $Constraint->Table == $this or die new Exception('The constaint must belong to the target table'); if (exists $this->{$Constraints}->{$Constraint->Name}) { die new Exception('The table already has the specified constraint',$Constraint->Name); } else { if (UNIVERSAL::isa($Constraint,'Schema::DB::Constraint::PrimaryKey')) { not $this->{$PrimaryKey} or die new Exception('The table already has a primary key'); $this->{$PrimaryKey} = $Constraint; } $this->{$Constraints}->{$Constraint->Name} = $Constraint; } } sub RemoveConstraint { my ($this,$Constraint,$Force) = @_; my $cn = UNIVERSAL::isa($Constraint,'Schema::DB::Constraint') ? $Constraint->Name : $Constraint; $Constraint = $this->{$Constraints}->{$cn} or die new Exception('The specified constraint doesn\'t exists',$cn); if (UNIVERSAL::isa($Constraint,'Schema::DB::Constraint::PrimaryKey')) { not scalar keys %{$this->{$PrimaryKey}->ConnectedFK} or die new Exception('Can\'t remove Primary Key unless some foreign keys referenses it'); delete $this->{$PrimaryKey}; } $Constraint->Dispose; delete $this->{$Constraints}->{$cn}; return $cn; } sub GetColumnConstraints { my ($this,@Columns) = @_; my @cn = map { UNIVERSAL::isa($_ ,'Schema::DB::Column') ? $_ ->Name : $_ } @Columns; exists $this->{$ColumnsByName}->{$_} or die new Exception('The specified column isn\'t found',$_) foreach @cn; return grep {$_->HasColumn(@cn)} values %{$this->{$Constraints}}; } sub SetPrimaryKey { my ($this,@ColumnList) = @_; $this->AddConstraint(new Schema::DB::Constraint::PrimaryKey(Name => $this->{$Name}.'_PK', Table => $this,Columns => \@ColumnList)); } sub LinkTo { my ($this,$table,@ColumnList) = @_; $table->PrimaryKey or die new Exception('The referenced table must have a primary key'); my $constraintName = $this->{$Name}.'_'.$table->Name.'_FK_'.join('_',map {ref $_ ? $_->Name : $_} @ColumnList); $this->AddConstraint(new Schema::DB::Constraint::ForeignKey(Name => $constraintName, Table => $this,Columns => \@ColumnList, ReferencedTable => $table, ReferencedColumns => scalar($table->PrimaryKey->Columns))); } sub Dispose { my ($this) = @_; $_->Dispose() foreach values %{$this->{$Constraints}}; undef %{$this}; $this->SUPER::Dispose(); } 1;