I'm working in a multi DB environment, and ddd statements prove to be as
unportable as hell, to say the least :)

My scripts however should be able to deal with whatever database (supported by
us) is thrown at it. At current time it is Unify and Oracle.

I'm attaching the beginnings of a module I've baptized DBD_create.pm which
should eventually catch all these differences for our databases, so I can use

my $expcnt = int (1.7 * scalar keys %ll_adr);
$dbh->create_table (qq;
    create table ll_adr (
        c_ll        numeric (9),
        d_in        numeric (8),
        d_end       numeric (8),
        type        char    (1),
        c_straat    numeric (6),
        hnr         numeric (5),
        hnr_l       char    (1),
        hnr_t       string  (4),
        hnr_a       string  (2),
        pc          string  (7),
        c_plaats    numeric (4),
        );, count => $expcnt);
$dbh->create_link ("ll_adr.c_ll"     => "leerling.c_ll");
$dbh->create_link ("ll_adr.c_straat" => "straat.c_straat");
$dbh->create_link ("ll_adr.c_plaats" => "plaats.c_plaats");

I'm still working on indices, and checking of the link fields: create_link
should croak if any of the tables or fields does not exist.

--8<--- DBD_create.pm
package DBI::db;

use base "DBI";

my ($char, $number, $amnt, $conf) = $ENV{DBTYPE} eq "ORACLE" ?
    ("varchar2", "number",  "number (9, 2)",
        [ "", " tablespace PROLEP storage ()" ]) :
    ("char",     "numeric", "amount (8) configuration (display (10, 2))",
        [ "configuration (estimated count is $expcnt),\n\t", "" ]);


sub _roundup ($)
{
    my $ref = shift;
    $$ref <= 50 and return 50;
    my $x = 64;
    $x <<= 1 while $$ref > $x;
    $$ref = $x;
    } # _roundup

sub DBI::db::create_table ($$;@)
{
    my ($dbh, $ddd, %options) = @_;
    my ($bytes, $table, @cnf, $pk) = (0);

    # be leanient against a comma after the last field
    $ddd =~ s/,([\s\n]*\))/$1/g;

    unless (exists $options{segment} or
            exists $options{count} && $options{count} > 120) {
        $options{count} //= 120;
        $options{count}   < 120 and $options{count} = 120;
        }

    $ddd =~ s/\b string \b\s* \(/char     \(/gx;
    if ($ENV{DBTYPE} eq "ORACLE") {
        my $ts = (split m:/:, $ENV{DBUSER}||$ENV{ORACLE_USERID})[0];
        $ddd =~ s/ \b numeric \b \s* \(/number   (/gx;
        $ddd =~ s/ \b char    \b \s* \(/varchar2 (/gx;

        # Detecting amounts:
        # - amount (7)  configuration (display (9, 2))
        # - huge amount configuration (display (18, 2))
        $ddd =~ s/ \b amount \s* \(\s* (\d+) \s*\)
                    (?: [\s\n]* configuration \s*\(
                        [\s\n]* [^)]*? display \s* \( (\d+) \s*,\s* (\d+) \s*\) [^)]* 
\)
                        \s*
                    )?  /number   ($1-$2-$3)/gx;
        $ddd =~ s/ \b huge amount \s*
                    (?:     configuration \s*\(
                        [\s\n]* [^)]*? display \s* \( (\d+) \s*,\s* (\d+) \s*\) [^)]* 
\)
                        [\s\n]*
                    )?  /number   (1-$1-$2)/gx;
        $ddd =~ s/(\d+)-(\d+)-(\d+)/sprintf"%d, %d", $2 > $1 ? $2 - 1 : $1, $3/ge;

        $bytes += $1 while $ddd =~ m/\(\s*(\d+)/g;

        $options{initial} //= 10 * int ($options{count} * $bytes / 10240);
        $options{initial}   < 50 and $options{initial} = 50;
        $options{"next"}  //= int ($options{initial} / 4);
        $options{"next"}    < 50 and $options{"next"} = 50;
        @cnf = map  { "$_ $options{$_}K"  }
               grep { exists $options{$_} && _roundup (\$options{$_}) }
               qw( initial next );
        $options{pctincrease} //= 0;
        push @cnf, "pctincrease $options{pctincrease}";
        $ddd =~ s/\)\s*;?\s*$/) tablespace $ts storage (@cnf)/;
        if ( $ddd =~ s/,[\s\n]*primary\s+(key)\s*\(([^)]+)\)// or
             $ddd =~ s/^(\s*(\S+)\b.*)\s+primary key\b/$1/m) {
            for (qw( initial next )) {
                $options{$_} /= 4;
                _roundup (\$options{$_});
                }
            $pk = join "\n",
                "alter table $ts.$table",
                "    add constraint pk_$table",
                "       primary key ($2)",
                "       using index tablespace $ts",
                "       storage (initial $options{initial}K next $options{'next'}K 
pctincrease 0)";
            }
        }
    else {
        exists $options{count} and
            push @cnf, "estimated count is $options{count}";
        exists $options{segment} and
            push @cnf, "segment is $options{segment}";
        exists $options{description} and
            push @cnf, "description '$options{description}'";
        if (@cnf) {
            my $cnf = join ",\n\t\t", @cnf;
            $ddd =~ s/\(/\(\n\tconfiguration ($cnf),/;
            }
        }
    for ($ddd, $pk) {
        $_ or next;
        $dbh->do ($_);
        #print STDERR "$_;\n";
        }
    } # create table

# $dbh->create_link (qw( ll_adr c_ll leerling c_ll ));
# $dbh->create_link ("bewon", "c_straat", "straat", "c_straat");
# $dbh->create_link ("vb.c_plaats" => "plaats.c_plaats");
# $dbh->create_link ("afn", [ "c_afn", "d_in" ] => "afnemer", [ "afn", "d_afn" ]);
sub DBI::db::create_link ($$$;$$$)
{
    my $dbh = shift;
    my ($tt, $tf) = $_[0] =~ m/^(\S+)\.(\S+)$/ ? ($1, $2, shift) : (splice @_, 0, 2);
    my ($rt, $rf) = $_[0] =~ m/^(\S+)\.(\S+)$/ ? ($1, $2, shift) : (splice @_, 0, 2);
    ref $rf or $rf = [ $rf ];
    ref $tf or $tf = [ $tf ];
    my $ln = shift || "${tt}_$tf->[0]_${rt}";
    local $" = ", ";
    if ($ENV{DBTYPE} eq "ORACLE") {
        my $ts = (split m:/:, $ENV{DBUSER}||$ENV{ORACLE_USERID})[0];
        $ln = qq;
            alter table $ts.$tt add constraint $ln foreign key
                (@$tf) references $ts.$rt (@$rf);
        }
    else {
        $ln = qq;
            create link index $ln on $tt (@$tf)
                references $rt (@$rf);
        }
    #print STDERR $ln, "\n";
    $dbh->do ($ln);
    } # create_link

1-->8---

-- 
H.Merijn Brand        Amsterdam Perl Mongers (http://amsterdam.pm.org/)
using perl-5.6.1, 5.8.0 & 632 on HP-UX 10.20 & 11.00, AIX 4.2, AIX 4.3,
     WinNT 4, Win2K pro & WinCE 2.11 often with Tk800.024 &/| DBD-Unify
ftp://ftp.funet.fi/pub/languages/perl/CPAN/authors/id/H/HM/HMBRAND/


Reply via email to