DB-Object
view release on metacpan or search on metacpan
lib/DB/Object/Statement.pm view on Meta::CPAN
if( !scalar( grep{ /^$type$/i } @allowed ) )
{
return( $self->error( "You may not flag statement of type \U$type\E to be ignored:\n$query" ) );
}
# Incompatible. Do not bother going further
return( $self ) if( $query =~ /^\s*(?:$allowed)\s+(?:DELAYED|LOW_PRIORITY|HIGH_PRIORITY)\s+/i );
return( $self ) if( $type eq 'ALTER' && $query !~ /^\s*$type\s+TABLE\s+/i );
$query =~ s/^(\s*)($allowed)(\s+)/$1$2 IGNORE /;
# my $sth = $self->prepare( $query ) ||
# $self->{ 'query' } = $query;
# saving parameters to bind later on must have been done previously
my $sth = $self->_cache_this( $query ) ||
return( $self->error( "Error while preparing new ignored query:\n$query" ) );
if( !defined( wantarray() ) )
{
$sth->execute() ||
return( $self->error( "Error while executing new ignored query:\n$query" ) );
}
return( $sth );
}
sub join
{
my $self = shift( @_ );
my $data = shift( @_ );
my $on;
if( @_ )
{
$on = ( scalar( @_ ) == 1 && ref( $_[0] ) ) ? shift( @_ ) : [ @_ ];
}
my $q = $self->query_object || return( $self->error( "No query formatter object was set" ) );
my $tbl_o = $q->table_object || return( $self->error( "No table object is set in query object." ) );
my $query = $q->query ||
return( $self->error( "No query prepared for join with another table." ) );
if( $query !~ /^[[:blank:]]*SELECT[[:blank:]]+/i )
{
return( $self->error( "You may not perform a join on a query other than select." ) );
}
my $constant = $q->constant;
# Constant is set and query object marked as final, which means this statement has already been processed as a join and so we skip all further processing.
if( scalar( keys( %$constant ) ) && $q->final )
{
return( $self );
}
my $table = $tbl_o->table;
my $db = $tbl_o->database;
my $multi_db = $tbl_o->prefix_database;
my $alias = $tbl_o->as;
my $new_fields = '';
my $new_table = '';
my $new_db = '';
my $class = ref( $self );
my $q_source = $q->clone;
# clone() does a shallow copy - $q_source->{elements} would share the same object
# as $q->{elements}. Any subsequent _save_bind() on $q would then corrupt the
# element list of the cached statement. We reset elements here so $q_source gets
# its own fresh object, populated by _query_components below.
$q_source->{elements} = $q_source->new_elements;
# clone() copies the hash shallowly, which means {table_object} is a strong reference
# in the clone even though _query_object_create() weakens it for freshly created query
# objects. If left strong, $q_source permanently retains the table object, which in turn
# retains every new query object created by _reset_query() on each execute() cycle,
# causing an ~8 MB per-iteration memory leak. Weaken it here to restore correct ownership.
Scalar::Util::weaken( $q_source->{table_object} ) if( $q_source->{table_object} && !Scalar::Util::isweak( $q_source->{table_object} ) );
Scalar::Util::weaken( $q_source->{database_object} ) if( $q_source->{database_object} && !Scalar::Util::isweak( $q_source->{database_object} ) );
my $q_target;
# On the duplicated table object, add the current table in the join
$q_source->join_tables( $tbl_o ) if( !$q_source->join_tables->length );
# $data is a DB::Object::Postgres::Statement object - we get all its parameter and merge them with ours
# if( ref( $data ) && ref( $data ) eq $class )
if( ref( $data ) && $self->_is_a( $data, $class ) )
{
$q_target = $data->query_object;
}
# $data is the table name
else
{
my $join_tbl;
if( $self->_is_object( $data ) && $data->isa( 'DB::Object::Tables' ) )
{
$join_tbl = $data;
}
elsif( $self->_is_object( $data ) )
{
return( $self->error( "I was expecting either a table name as a scalar or a table object, but instead got \"$data\" (", ref( $data ), ")." ) );
}
else
{
return( $self->error( "No such table \"$data\" exists in database \"$db\"." ) ) if( !$self->database_object->table_exists( $data ) );
$join_tbl = $self->database_object->table( $data );
return( $self->error( "Could not get a table object from \"$data\"." ) ) if( !$join_tbl );
}
$join_tbl->prefixed( $db ne $join_tbl->database_object->database ? 3 : 1 );
my $sth_tmp = $join_tbl->select || return( $self->pass_error( $join_tbl->error ) );
$q_target = $sth_tmp->query_object ||
return( $self->error( "Could not get a query object out of the dummy select query I made from table \"$data\"." ) );
$new_fields = $q_target->selected_fields;
# NOTE: 2021-08-22: If we reset it here, we lose the table aliasing
# $join_tbl->reset;
# $join_tbl->prefixed( $db ne $join_tbl->database_object->database ? 3 : 1 ) unless( $join_tbl->prefixed );
$new_table = $join_tbl->prefix;
$join_tbl->reset;
# We assume this table is part of our same database
$new_db = $db;
# my $db_data = $self->getdefault( $new_table );
# $new_fields = $db_data->format_statement();
$new_fields = '';
}
# TODO: check this or remove it
# $q_target->table_object->prefixed( $db ne $q_target->database_object->database ? 3 : 1 );
$new_fields = $q_target->selected_fields;
$new_table = $q_target->table_object->name;
# $new_table = $q_target->table_object->prefix;
$new_db = $q_target->database_object->database;
$q_source->join_tables->push( $q_target->table_object );
if( $q->where && $q_target->where )
{
# We must NOT call $q_source->where( AND(...) ) here because _where_having would
# reconstruct the WHERE via process_where_condition, losing the bind elements that
# were built up in $q->where. Instead we build a merged Clause directly, copying
# the existing elements from $q->where so they are available to _save_bind below.
my $merged = $q_source->new_clause;
$merged->merge( $self->AND( $q->where, $q_target->new_clause({ value => '( ' . ( $q_target->where ) . ' )' }) ) );
( run in 2.763 seconds using v1.01-cache-2.11-cpan-437f7b0c052 )