package DBIx::dbMan::Extension::StandardSQL;

use strict;
use base 'DBIx::dbMan::Extension';

our $VERSION = '0.14';

1;

sub IDENTIFICATION { return "000001-000014-000014"; }

sub preference { return 100; }

sub known_actions { return [ qw/SQL/ ]; }

sub handle_action {
	my ($obj,%action) = @_;

	$action{processed} = 1;
	if ($action{action} eq 'SQL') {
		if ($action{oper} eq 'complete') {
			$action{action} = 'CACHE';
			$action{type} = 'object' if lc $action{type} eq 'context';
			$action{cache_type} = 'sql_type_' . lc( $action{type} );

			if ($action{what} eq 'list') {
				# return in {list} list of {type}
				my $sth = $obj->{-dbi}->table_info();
				my $ret = $sth->fetchall_arrayref();
				my @all = ();
				if (defined $ret) {
					for (@$ret) {
						push @all,$_->[2] if lc $action{type} eq 'object' || lc $action{type} eq lc $_->[3];
					}
				}
				$sth->finish;
				$action{list} = \@all;
			}
		} elsif ($action{type} eq 'select' or $action{type} eq 'do') {
			$action{action} = 'NONE';
			unless ($obj->{-dbi}->current) {
				$obj->{-interface}->error("No current connection selected.");
				return %action;
			}
			
			my $explain_id = $$;
			if ($action{explain} and not $action{explain_2phase}) {
				$action{sql_save} = $action{sql};
				$action{sql} = qq!DELETE FROM plan_table WHERE statement_id = '$explain_id'!;
				$action{explain_2phase} = 1;
			} else {
				$action{sql} =~ s/explain\s+plan\s+for/explain plan set statement_id = '$explain_id' for/i;
				delete $action{explain_2phase};
			}

			$obj->{-interface}->status("Executing SQL...") unless $action{output_quiet};
			my $lr = $obj->{-dbi}->longreadlen();
			$obj->{-dbi}->longreadlen($action{longreadlen}) if $action{longreadlen};
			my $sth = $obj->{-dbi}->prepare($action{sql});
			if (exists $action{placeholders}) {
				my $i = 0;
				$sth->bind_param(++$i,$_) for @{$action{placeholders}};
			}
			unless (defined $sth) {
				$action{action} = 'OUTPUT';
				$action{output} = '';
                $obj->{-interface}->error( $obj->{-dbi}->errstr() );
				$action{processed} = 1;

				$obj->{-dbi}->longreadlen($lr) if $action{longreadlen};
				$obj->{-interface}->nostatus unless $action{output_quiet};
				return %action;
			}

			my $res = eval {
				return $sth->execute();
			};
            if ( $@ ) {
				$action{action} = 'OUTPUT';
                $action{output} = '';
				$action{processed} = 1;

                $obj->{-interface}->error( ( $@ =~ /^Catched signal INT/ ) ? "Interrupted by user.\n" : $@ );

				$obj->{-dbi}->longreadlen($lr) if $action{longreadlen};
				$obj->{-interface}->nostatus unless $action{output_quiet};
				return %action;
            }

			$obj->{-dbi}->longreadlen($lr) if $action{longreadlen};
			if (not defined $res) {
				my $errstr = $obj->{-dbi}->errstr();
				$errstr =~ s/^ERROR:\s*//;
				$obj->{-interface}->error($errstr);
			} else {
				if ($action{type} eq 'select' and not $action{explain}) {
					$action{fieldnames} = $sth->{NAME_uc};
					eval {
						$action{fieldtypes} = $sth->{TYPE};
					};
					if ($@) {
						$action{fieldtypes} = [ map { -9998 } @{$action{fieldnames}} ];
					}
                    $res = eval {
                        my $result = [];
                        while ( my $row = $sth->fetchrow_arrayref() ) {
                            push @$result, [ @$row ];
                        }
                        return $result;
                    };
                    if ( $@ ) {
                        $sth->finish;

                        $action{action} = 'OUTPUT';
                        $action{output} = '';
                        $action{processed} = 1;

                        $obj->{-interface}->error( ( $@ =~ /^Catched signal INT/ ) ? "Interrupted by user.\n" : $@ );

                        $obj->{-dbi}->longreadlen($lr) if $action{longreadlen};
                        $obj->{-interface}->nostatus unless $action{output_quiet};
                        return %action;
                    }
				}
				if ($action{explain}) {
					$action{action} = 'SQL';
					if ($action{explain_2phase}) {
						$action{sql} = $action{sql_save};
						$sth->finish;
						delete $action{processed};
						$obj->{-interface}->nostatus unless $action{output_quiet};
						return %action;
					}
					my $local_mempool = $obj->{-dbi}->mempool();
					if ( $local_mempool && $local_mempool->get( 'oracle_special_xplan' ) ) {
						$action{sql} = q!SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table',!.$explain_id.'))';
					} else {
						$action{sql} = q!SELECT '.' || LPAD(' ',2*LEVEL-1) || operation || ' ' || options || ' ' || object_name "Execution Plan" FROM plan_table WHERE statement_id = '!.$explain_id.q!' CONNECT BY PRIOR id = parent_id AND statement_id = '!.$explain_id.q!' START WITH id = 0 AND statement_id = '!.$explain_id.q!'!;
					}
					delete $action{explain};
				} else {
					$action{action} = 'SQL_RESULT';
					$action{result} = $res;
				}
			}
			$sth->finish;
			$obj->{-interface}->nostatus unless $action{output_quiet};
			$obj->{-dbi}->discard_profile_data;
			delete $action{processed};
		}
	}

	return %action;
}