@Ghazascanner
_2019runbot
Ghazascanner File Manager
server :Linux phosweb007 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64
Current Path :
/
homepage
/
v-mt
/
lib
/
MT
/
ObjectDriver
/
DDL
/
Path :
Upload File :
New :
File
Dir
//homepage/v-mt/lib/MT/ObjectDriver/DDL/Pg.pm
# Movable Type (r) (C) 2001-2008 Six Apart, Ltd. All Rights Reserved. # This code cannot be redistributed without permission from www.sixapart.com. # For more information, consult your Movable Type license. # # $Id: Pg.pm 1174 2008-01-08 21:02:50Z bchoate $ package MT::ObjectDriver::DDL::Pg; use strict; use warnings; use base qw( MT::ObjectDriver::DDL ); sub can_add_column { 1 } sub can_drop_column { 1 } sub can_alter_column { 0 } sub index_defs { my $ddl = shift; my ($class) = @_; my $driver = $class->driver; my $dbh = $driver->r_handle; my $field_prefix = $class->datasource; my $table_name = $class->table_name; my $sth = $dbh->prepare(<<SQL) SELECT cidx.relname as index_name, idx.indisunique, idx.indisprimary, idx.indnatts, idx.indkey, am.amname FROM pg_index idx INNER JOIN pg_class cidx ON idx.indexrelid = cidx.oid INNER JOIN pg_class ctbl ON idx.indrelid = ctbl.oid INNER JOIN pg_am am ON cidx.relam = am.oid WHERE ctbl.relname = '$table_name' SQL or return undef; $sth->execute or return undef; my $defs = {}; while (my $row = $sth->fetchrow_hashref) { next if 1 == $row->{'indisprimary'}; my $key = $row->{'index_name'}; next unless $key =~ m/^(mt_)?\Q$field_prefix\E_/; $key = 'mt_' . $key unless $key =~ m/^mt_/; my $type = $row->{'amname'}; # ignore fulltext or other unrecognized indexes for now next unless $type eq 'btree'; my $is_unique = $row->{'indisunique'}; $key =~ s/^mt_\Q$field_prefix\E_//; my $indkeys = $row->{'indkey'}; $indkeys =~ s/\s+/,/g; my $sth_att = $dbh->prepare(<<ATTSQL) SELECT attnum, attname FROM pg_attribute att INNER JOIN pg_class ctbl ON att.attrelid = ctbl.oid WHERE att.attnum IN ($indkeys) AND ctbl.relname = '$table_name' ATTSQL or next; $sth_att->execute or next; my $row_att = $sth_att->fetchall_hashref('attnum'); $sth_att->finish; my $cols; if ( 1 == $row->{'indnatts'} ) { # $indkeys have column's attnum my $col = $row_att->{$indkeys}->{'attname'}; $col =~ s/^\Q$field_prefix\E_//; $cols = [ $col ]; } else { my @cols; for my $indkey ( split ',', $indkeys ) { my $col = $row_att->{$indkey}->{'attname'}; $col =~ s/^\Q$field_prefix\E_//; push @cols, $col; } $cols = \@cols; } if ( $is_unique ) { $defs->{$key} = { 'unique' => 1, 'columns' => $cols }; } else { if ((@$cols == 1) && ($key eq $cols->[0])) { $defs->{$key} = 1; } else { $defs->{$key} = { 'columns' => $cols }; } } } $sth->finish; return $defs; } sub column_defs { my $ddl = shift; my ($class) = @_; my $table_name = $class->table_name; my $field_prefix = $class->datasource; my $dbh = $class->driver->r_handle; return undef unless $dbh; local $dbh->{RaiseError} = 0; my $attr = $dbh->func($table_name, 'table_attributes') or return undef; return undef unless @$attr; my $defs = {}; foreach my $col (@$attr) { my $coltype = $ddl->db2type($col->{TYPE}); my $colname = lc $col->{NAME}; $colname =~ s/^\Q$field_prefix\E_//i; $defs->{$colname}{type} = $coltype; if ( $coltype eq 'string') { if (defined $col->{SIZE}) { $defs->{$colname}{size} = $col->{SIZE}; } else { $defs->{$colname}{type} = 'text'; } } if ( $col->{NOTNULL} ) { $defs->{$colname}{not_null} = 1; } if ( $col->{PRIMARY_KEY} ) { $defs->{$colname}{key} = 1; } } $defs; } sub drop_sequence { my $ddl = shift; my ($class) = @_; my $driver = $class->driver; my $dbh = $driver->rw_handle; # do this, but ignore error since it usually means the # sequence didn't exist to begin with if (my $col = $class->properties->{primary_key}) { ## If it's a complex primary key, use the second half. if(ref $col) { $col = $col->[1]; } my $def = $class->column_def($col); if (exists($def->{auto}) && $def->{auto}) { #if ($def->{type} eq 'integer') { my $seq = $driver->dbd->sequence_name($class); local $dbh->{RaiseError} = 0; $dbh->do('DROP SEQUENCE ' . $seq); } } 1; } sub create_sequence { my $ddl = shift; my ($class) = @_; my $driver = $class->driver; my $dbh = $driver->rw_handle; if ( my $col = $class->properties->{primary_key} ) { ## If it's a complex primary key, use the second half. if(ref $col) { $col = $col->[1]; } my $def = $class->column_def($col); if (exists($def->{auto}) && $def->{auto}) { #if ($def->{type} eq 'integer') { my $seq = $driver->dbd->sequence_name($class); my $table_name = $class->table_name; my $field_prefix = $class->datasource; my $max_sql = 'SELECT MAX(' . $field_prefix . '_' . $col . ') FROM ' . $table_name; my ($start) = $dbh->selectrow_array($max_sql); $dbh->do('CREATE SEQUENCE ' . $seq . ($start ? (' START ' . ($start + 1)) : '')); } } 1; } sub type2db { my $ddl = shift; my ($def) = @_; my $type = $def->{type}; if ($type eq 'string') { return 'varchar(' . $def->{size} . ')'; } elsif ($type eq 'smallint' ) { return 'smallint'; } elsif ($type eq 'bigint' ) { return 'bigint'; } elsif ($type eq 'boolean') { return 'smallint'; } elsif ($type eq 'datetime') { return 'timestamp'; } elsif ($type eq 'timestamp') { return 'timestamp'; } elsif ($type eq 'integer') { return 'integer'; } elsif ($type eq 'blob') { return 'bytea'; } elsif ($type eq 'text') { return 'text'; } elsif ($type eq 'float') { return 'float'; } Carp::croak("undefined type: " . $type); } sub column_sql { my $ddl = shift; my ($class, $name) = @_; # ugly but we need to return the sql to express # a column differently based on whether we are declaring # the column for creating a table or for altering a column. # postgres 7.x does not support the 'not null' and 'default' # keywords when altering the column. if ((caller(1))[3] =~ m/::create_table_sql$/) { my $def = $class->column_def($name); return $ddl->SUPER::column_sql($class, $name); } my $field_prefix = $class->datasource; my $def = $class->column_def($name); my $type = $ddl->type2db($def); return $field_prefix . '_' . $name . ' ' . $type; } sub add_column_sql { my $ddl = shift; my ($class, $name) = @_; my $sql = $ddl->column_sql($class, $name); my $driver = $class->driver; my $table_name = $class->table_name; my $field_prefix = $class->datasource; my $dbh = $driver->r_handle; my @stmt = ("ALTER TABLE $table_name ADD $sql"); my $def = $class->column_def($name); my $default_value; if (exists $def->{default}) { $default_value = $def->{default}; if (($def->{type} =~ m/time/) || $driver->dbd->is_date_col($name)) { $default_value = $dbh->quote($driver->dbd->ts2db($default_value)); } elsif ($def->{type} !~ m/int|float|boolean/) { $default_value = $dbh->quote($default_value); } push @stmt, "ALTER TABLE $table_name ALTER COLUMN ${field_prefix}_${name} SET DEFAULT " . $default_value; } if ($def->{key}) { push @stmt, "ALTER TABLE $table_name ADD PRIMARY KEY (${field_prefix}_${name})"; } elsif (($def->{not_null}) && (70300 < $dbh->{pg_server_version}) && (exists $def->{default})) { #postgresql under 7.3.0 does not support not null in alter table #plus,we can't set not null unless there are no rows contains null push @stmt, "UPDATE $table_name SET ${field_prefix}_${name} = $default_value WHERE ${field_prefix}_${name} IS NULL"; push @stmt, "ALTER TABLE $table_name ALTER COLUMN ${field_prefix}_${name} SET NOT NULL"; } return @stmt; } sub alter_column_sql { my $ddl = shift; my ($class, $name) = @_; my $sql = $ddl->SUPER::alter_column_sql(@_); $sql =~ s/\bMODIFY\b/ALTER COLUMN/; return $sql; } sub cast_column_sql { my $ddl = shift; my ($class, $name, $from_def) = @_; my $field_prefix = $class->datasource; my $def = $class->column_def($name); if (($from_def->{type} eq 'text') && ($def->{type} eq 'blob')) { return "cast(decode(${field_prefix}_$name, 'escape') as " . $ddl->type2db($def) . ')'; } elsif (($from_def->{type} eq 'blob') && ($def->{type} eq 'text')) { return "cast(encode(${field_prefix}_$name, 'escape') as " . $ddl->type2db($def) . ')'; } else { return "cast(${field_prefix}_$name as " . $ddl->type2db($def) . ')'; } } 1;