/usr/local/CPAN/dbMan/DBIx/dbMan/Extension/EditOracle.pm


package DBIx::dbMan::Extension::EditOracle;

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

our $VERSION = '0.07';

1;

sub IDENTIFICATION { return "000001-000047-000007"; }

sub preference { return 0; }

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

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

	$action{processed} = 1;
	if ($action{action} eq 'EDIT' and $obj->{-dbi}->driver eq 'Oracle') {
		if ($action{testerror}) {
			$action{action} = 'NONE';
			my $d = $obj->{-dbi}->selectall_arrayref(q!SELECT line, position, text FROM user_errors WHERE name = ? AND type = ? ORDER BY sequence!,{},$action{what},$action{type});
			if (defined $d and @$d) {
				$action{action} = 'OUTPUT';
				$action{output} = "I detect some errors on object $action{what} (type $action{type}):\n";
				my $tab = new Text::FormatTable '| r | r | l |';
				$tab->rule;
				$tab->head('ROW','COLUMN','ERROR');
				$tab->rule;
				for (@$d) { $tab->row(@$_); }
				$tab->rule;
				$action{output} .= $tab->render($obj->{-interface}->render_size);
			}
			return %action;
		}
		if ($action{type} =~ /^(FUNCTION|PROCEDURE|PACKAGE|PACKAGE BODY|TRIGGER|VIEW)$/) {
			$action{action} = 'NONE';
			my $d;
			my $lr = $obj->{-dbi}->longreadlen();
			$obj->{-dbi}->longreadlen(100000);
			my $schema = '';
			$schema = uc $1 if $action{what} =~ s/^([^.]+)\.//;
			my $schema_add = '';
			my @schema = ();
			if ($schema) {
				$schema_add = ' AND owner = ?';
				push @schema,$schema;
			}
			my $basetable = $schema?'all':'user';
			if ($action{type} eq 'TRIGGER') {
				$d = $obj->{-dbi}->selectall_arrayref(q!SELECT description,trigger_body FROM !.$basetable.q!_triggers WHERE trigger_name = ?!.$schema_add,{},$action{what},@schema);
			} elsif ($action{type} eq 'VIEW') {
				$d = $obj->{-dbi}->selectall_arrayref(q!SELECT text FROM !.$basetable.q!_views WHERE view_name = ?!.$schema_add,{},$action{what},@schema);
			} else {
				$d = $obj->{-dbi}->selectall_arrayref(q!SELECT text FROM !.$basetable.q!_source WHERE name = ? AND type = ?!.$schema_add.q! ORDER BY line!,{},$action{what},$action{type},@schema);
			}
			$action{what} = "$schema.".$action{what} if $schema;
			$obj->{-dbi}->longreadlen($lr);
			if (defined $d and @$d) {
				my $text = "CREATE OR REPLACE ";
				if ($action{type} eq 'TRIGGER') {
					my $desc = $d->[0][0];
					$desc =~ s/\n/ /gs;
					$text .= 'TRIGGER '.$desc."\n".$d->[0][1];
				} elsif ($action{type} eq 'VIEW') {
					$text .= 'VIEW '.$action{what}." AS\n".join '',map { $_->[0] } @$d;
				} else {
					$text .= join '',map { $_->[0] } @$d;
				}
				my $nt = '';
				my $started = 0;
				for my $t (split /\n/,$text) {
					next if $t =~ /-- \|dbMan\| /;
					$t =~ s/\s+$//;
					next if not $started and $t =~ /^\s*$/;
					++$started;
					$nt .= "$t\n";
				}
				$text = $nt;
				$text =~ s/\n+$//s;
				$text =~ s/\s+$//s;
				$text .= ";" if $text =~ /end$/;
				$text .= "\n\n";

				if ($obj->{-mempool}->get('edit_object_errors')) {
					$d = $obj->{-dbi}->selectall_arrayref(q!SELECT line, position, text FROM user_errors WHERE name = ? AND type = ? ORDER BY sequence!,{},$action{what},$action{type});
					if (defined $d and @$d) {
						my $tab = new Text::FormatTable '| r | r | l |';
						$tab->rule;
						$tab->head('ROW','COLUMN','ERROR');
						$tab->rule;
						for (@$d) { $tab->row(@$_); }
						$tab->rule;
						$text = "-- |dbMan|  Errors in object $action{what} (type $action{type}):\n" . join("\n", map { "-- |dbMan|  ".$_ } split /\n/,$tab->render($obj->{-interface}->render_size)) . "\n-- |dbMan|  Note: Rows are numbered from line with CREATE OR REPLACE.\n\n" . $text;
					}
				}
				my $editor = $ENV{DBMAN_EDITOR} || $ENV{EDITOR} || 'vi';
				my $t = $action{type};  $t =~ s/ /_/g;
				my $filename = "/tmp/dbman.edit_object.$t.$action{name}.$$.plsql";
				if (open F,">$filename") {
					print F $text;
					close F;
					$text = '';
					my $modi = -M $filename;
					$obj->{-interface}->go_away();
					system "$editor $filename";
					$obj->{-interface}->come_back();
					if (-M $filename ne $modi and open F,$filename) {
						$text = join '',<F>;
						close F;
					}
					unlink $filename if -e $filename;
				} else { $text = ''; }
				if ($text) {
					my $started = 0;
					my $nt = '';
					for my $t (split /\n/,$text) {
						next if $t =~ /-- \|dbMan\| /;
						$t =~ s/\s+$//;
						next if not $started and $t =~ /^\s*$/;
						++$started;
						$nt .= "$t\n";
					}
					$text = $nt;
					$text =~ s/\n+$//s;
					$text .= "\n\n";

					$action{action} = 'OUTPUT';
					$action{output} = "I must save edited object into database.\n";
					$obj->{-interface}->add_to_actionlist({ action => 'SQL', type => 'do', sql => $text, longreadlen => 100000});
					$obj->{-interface}->add_to_actionlist({ action => 'EDIT', what => $action{what}, type => $action{type}, testerror => 1 });
				} else {
					$action{action} = 'OUTPUT';
					$action{output} = "I needn't save edited object into database.\n";
				}
			}
		} else {
			$action{action} = 'OUTPUT';
			$action{output} = "Editing of $action{type} isn't implemented yet.\n";
		}
	}

	return %action;
}