DB-Object
view release on metacpan or search on metacpan
lib/DB/Object/Postgres/Tables.pm view on Meta::CPAN
warn( "The options '", join( ', ', @errors ), "' were either not recognized or malformed and thus were ignored.\n" );
}
# Check statement
my $select = '';
if( $sth && ref( $sth ) && ( $sth->isa( "DB::Object::Postgres::Statement" ) || $sth->can( 'as_string' ) ) )
{
$select = $sth->as_string();
if( $select !~ /^\s*(?:IGNORE|REPLACE)*\s*\bSELECT\s+/ )
{
return( $self->error( "SELECT statement to use to create table is invalid:\n$select" ) );
}
}
if( $self->exists() == 0 )
{
my $query = 'CREATE ' . ( $temp ? 'TEMPORARY ' : '' ) . "TABLE $table ";
# Structure of table if any -
# structure may very well be provided using a select statement, such as:
# CREATE TEMPORARY TABLE ploppy TYPE=HEAP COMMENT='this is kewl' MAX_ROWS=10 SELECT * FROM some_table LIMIT 0,0
my $def = "(\n" . CORE::join( ",\n", @$data ) . "\n)" if( $data && ref( $data ) && @$data );
$def .= " INHERITS (" . $opt->{ 'inherits' } . ")" if( $opt->{ 'inherits' } );
my $tdef = CORE::join( ' ', map{ "\U$_\E = $opt->{ $_ }" } @options );
if( !$def && !$select )
{
return( $self->error( "Lacking table '$table' structure information to create it." ) );
}
$query .= join( ' ', $def, $tdef, $select );
my $new = $self->database_object->prepare( $query ) ||
return( $self->error( "Error while preparing query to create table '$table':\n$query", $self->database_object->errstr() ) );
# Trick so other method may follow, such as as_string(), fetchrow(), rows()
if( !defined( wantarray() ) )
{
# print( STDERR "create(): wantarrays in void context.\n" );
$new->execute() ||
return( $self->error( "Error while executing query to create table '$table':\n$query", $new->errstr() ) );
}
$self->reset_structure;
$self->database_object->table_push( $table );
return( $new );
}
else
{
return( $self->error( "Table '$table' already exists." ) );
}
}
sub create_info
{
my $self = shift( @_ );
my $table = $self->{table};
$self->structure || return( $self->pass_error );
my $struct = $self->{structure};
my $fields = $self->{fields};
my $default = $self->{default};
my $primary = $self->{primary};
my @output = ();
foreach my $field ( sort{ $fields->{ $a } <=> $fields->{ $b } } keys( %$fields ) )
{
push( @output, "$field $struct->{ $field }" );
}
push( @output, "PRIMARY KEY(" . CORE::join( ',', @$primary ) . ")" ) if( $primary && @$primary );
my $info = $self->stat( $table );
my @opt = ();
my $addons = $info->{create_options};
if( $addons )
{
$addons =~ s/(\A|\s+)([\w\_]+)\s*=\s*/$1\U$2\E=/g;
push( @opt, $addons );
}
push( @opt, "COMMENT='" . quotemeta( $info->{ 'comment' } ) . "'" ) if( $info->{comment} );
my $str = "CREATE TABLE $table (\n\t" . CORE::join( ",\n\t", @output ) . "\n)";
$str .= ' ' . CORE::join( ' ', @opt ) if( @opt );
$str .= ';';
return( @output ? $str : undef() );
}
# NOTE: sub default is inherited from DB::Object::Tables
# sub default
# <https://www.postgresql.org/docs/10/sql-altertable.html>
sub disable_trigger
{
my $self = shift( @_ );
my $table = $self->{table} ||
return( $self->error( "No table was provided to disable trigger." ) );
my $opts = $self->_get_args_as_hash( @_ );
$opts->{all} //= 0;
# This feature exists only since version 8.1
unless( $self->database_object->version >= version->declare( '8.1' ) )
{
return( $self->error( "Disabling trigger on a table requires PostgreSQL version 8.1 or higher." ) );
}
my $query = 'ALTER TABLE ' . $table . ' DISABLE TRIGGER ';
if( defined( $opts->{name} ) && length( $opts->{name} ) )
{
$query .= $opts->{name};
}
else
{
$query .= $opts->{all} ? 'ALL' : 'USER';
}
my $sth = $self->database_object->prepare( $query ) ||
return( $self->error( "Error while preparing query to disable trigger for table '$table':\n$query", $self->database_object->errstr() ) );
if( !defined( wantarray() ) )
{
$sth->execute() ||
return( $self->error( "Error while executing query to disable trigger for table '$table':\n$query", $sth->errstr() ) );
}
return( $sth );
}
sub drop
{
my $self = shift( @_ );
my $table = $self->{table} ||
return( $self->error( "No table was provided to drop." ) );
my $opts = $self->_get_args_as_hash( @_ );
my $query = 'DROP TABLE';
$query .= ' IF EXISTS' if( $opts->{ 'if-exists' } || $opts->{if_exists} );
$query .= " $table";
if( $opts->{cascade} )
{
lib/DB/Object/Postgres/Tables.pm view on Meta::CPAN
sub on_conflict
{
my $self = shift( @_ );
my $q = $self->_reset_query;
# Void
return( $q->on_conflict( @_ ) ) if( !defined( wantarray() ) );
if( wantarray() )
{
my( @val ) = $q->on_conflict( @_ ) || return( $self->pass_error( $q->error ) );
return( @val );
}
else
{
my $val = $q->on_conflict( @_ );
return( $self->pass_error( $q->error ) ) if( !defined( $val ) );
return( $val );
}
}
sub optimize { return( shift->error( "optimize() is not implemented PostgreSQL." ) ); }
sub parent { return( shift->_set_get_scalar( 'parent', @_ ) ); }
sub qualified_name
{
my $self = shift( @_ );
my @val = ();
CORE::push( @val, $self->database_object->database ) if( $self->{prefixed} > 2 );
CORE::push( @val, $self->schema ) if( $self->{prefixed} > 1 && $self->schema );
CORE::push( @val, $self->name );
return( CORE::join( '.', @val ) );
}
sub rename
{
my $self = shift( @_ );
my $table = $self->{table} ||
return( $self->error( 'No table was provided to rename' ) );
my $new = shift( @_ ) ||
return( $self->error( "No new table name was provided to rename table '$table'." ) );
if( $new !~ /^[\w\_]+$/ )
{
return( $self->error( "Bad new table name '$new'." ) );
}
my $query = "ALTER TABLE $table RENAME TO $new";
my $sth = $self->database_object->prepare( $query ) ||
return( $self->error( "Error while preparing query to rename table '$table' into '$new':\n$query", $self->database_object->errstr() ) );
if( !defined( wantarray() ) )
{
$sth->execute() ||
return( $self->error( "Error while executing query to rename table '$table' into '$new':\n$query", $sth->errstr() ) );
}
$self->reset_structure;
return( $sth );
}
sub repair { return( shift->error( "repair() is not implemented PostgreSQL." ) ); }
sub reset { return( shift->DB::Object::Tables::reset( @_ ) ); }
sub stat { return( shift->error( "stat() is not implemented PostgreSQL." ) ); }
sub structure
{
my $self = shift( @_ );
return( $self->_clone( $self->{_cache_structure} ) ) if( $self->{_cache_structure} && !CORE::length( $self->{_reset_structure} // '' ) );
my $table = $self->{table} ||
return( $self->error( "No table provided to get its structure." ) );
my $struct = $self->{structure} // {};
my $fields = $self->{fields} // {};
my $types_dict = $self->database_object->datatype_dict;
$self->_load_class( 'DB::Object::Fields::Field' ) || return( $self->pass_error );
my $q = $self->_reset_query;
# <https://stackoverflow.com/questions/6777456/list-all-index-names-column-names-and-its-table-name-of-a-postgresql-database>
# If we have a cache, use it instead of reprocessing it.
# <https://stackoverflow.com/questions/52376045/why-does-atttypmod-differ-from-character-maximum-length>
# my $query = <<EOT;
# SELECT
# a.table_schema AS "schema_name"
# ,CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'table' END as "table_type"
# ,a.column_name AS "field"
# ,a.ordinal_position AS "field_num"
# ,a.column_default AS "default"
# ,a.*
# FROM information_schema.columns a
# LEFT JOIN pg_catalog.pg_class c ON c.relname = a.table_name
# WHERE a.table_name = ?
# ORDER BY a.ordinal_position
# EOT
# <https://www.postgresql.org/docs/14/catalog-pg-attrdef.html>
# We could use:
# generate_subscripts(i.indkey, 1)
# instead of:
# generate_series(1,array_upper(string_to_array(i.indkey::text, ' ' )::int2[],1))
# but this is not supported by PostgreSQL v8.0; only from v8.4 onward
my $query = <<EOT;
SELECT
n.nspname AS "schema_name"
,c.relname AS "table_name"
,CASE c.relkind
WHEN 'r' THEN 'table'
WHEN 'v' THEN 'view'
WHEN 'm' THEN 'materialized view'
WHEN 's' THEN 'special'
WHEN 'f' THEN 'foreign table'
WHEN 'p' THEN 'table'
END as "table_type"
,a.attname AS "field"
,a.attnum AS "field_num"
,CASE
WHEN a.atttypmod = -1 THEN null
WHEN t.oid IN (1042, 1043) THEN a.atttypmod - 4
WHEN t.oid IN (1560, 1562) THEN a.atttypmod
ELSE NULL
END AS "character_maximum_length"
,CASE SUBSTRING(t.typname,1,1)
WHEN '_' THEN SUBSTRING(t.typname,2)
ELSE t.typname
END AS "data_type"
,pg_catalog.format_type(a.atttypid,a.atttypmod) AS "format_type"
( run in 0.716 second using v1.01-cache-2.11-cpan-39bf76dae61 )