Author: spadkins
Date: Mon Dec  4 11:33:33 2006
New Revision: 8356

Modified:
   p5ee/trunk/App-Repository/lib/App/Repository.pm
   p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm
   p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm

Log:
insert_rows(), and mods to import_rows()

Modified: p5ee/trunk/App-Repository/lib/App/Repository.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository.pm     (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository.pm     Mon Dec  4 11:33:33 2006
@@ -102,8 +102,8 @@
 
     $rep->commit();
     $rep->rollback();
-    $rep->import_rows($table, $file, $options);
-    $rep->export_rows($table, $file, $options);
+    $rep->import_rows($table, $columns, $file, $options);
+    $rep->export_rows($table, $columns, $file, $options);
 
 =cut
 
@@ -1772,7 +1772,6 @@
 # need to do a select after insert.  However, there might be defaults
 # set in the database that I don't know about, and I want them to be
 # reflected in the returned object.
-# NOTE 2: Tables which have
 # $object = $rep->new_object($table, [EMAIL PROTECTED], [EMAIL PROTECTED]);
 # $object = $rep->new_object($table, \%obj_values);
 # $object = $rep->new_object($table, $col, $value);
@@ -2373,6 +2372,28 @@
 =cut
 
 #############################################################################
+# begin_work()
+#############################################################################
+
+=head2 begin_work()
+
+    * Signature: $rep->begin_work();
+    * Param:     void
+    * Return:    void
+    * Throws:    App::Exception::Repository
+    * Since:     0.01
+
+    Sample Usage: 
+
+    $rep->begin_work();
+
+=cut
+
+sub begin_work {
+    my $self = shift;
+}
+
+#############################################################################
 # commit()
 #############################################################################
 
@@ -2471,12 +2492,12 @@
 
 =head2 import_rows()
 
-    * Signature: $rep->import_rows($table, $file);
-    * Signature: $rep->import_rows($table, $file, $options);
+    * Signature: $rep->import_rows($table, $columns, $file);
+    * Signature: $rep->import_rows($table, $columns, $file, $options);
     * Param:     $table        string
+    * Param:     $columns      ARRAY     names of columns of the fields in the 
file
     * Param:     $file         string
     * Param:     $options      named
-    * Param:     columns       ARRAY     names of columns of the fields in the 
file
     * Param:     replace       boolean   rows should replace existing rows 
based on unique indexes
     * Param:     field_sep     char      character which separates the fields 
in the file (can by "\t")
     * Param:     field_quote   char      character which optionally encloses 
the fields in the file (i.e. '"')
@@ -2490,17 +2511,17 @@
     $rep->import_rows("usr","usr.dat");
 
     # root:x:0:0:root:/root:/bin/bash
-    $rep->import_rows("usr", "/etc/passwd" ,{
-        field_sep => ":",
-        columns => [ "username", "password", "uid", "gid", "comment", 
"home_directory", "shell" ],
-    });
+    $rep->import_rows("usr",
+        [ "username", "password", "uid", "gid", "comment", "home_directory", 
"shell" ],
+        "/etc/passwd" ,
+        { field_sep => ":", });
 
 =cut
 
 sub import_rows {
     &App::sub_entry if ($App::trace);
-    my ($self, $table, $file, $options) = @_;
-    my $columns = $options->{columns} || $self->{table}{$table}{columns};
+    my ($self, $table, $columns, $file, $options) = @_;
+    $columns = $self->_get_default_columns($table) if (!$columns);
     my $field_sep = $options->{field_sep} || ",";
     my $field_quote = $options->{field_quote};
     my $field_escape = $options->{field_escape};
@@ -2511,6 +2532,7 @@
         chomp;
         if ($field_quote) {
             @row = ();
+            # TODO: use the _read_rows_from_file() method
             # TODO: incorporate escaping
             $field_regexp        = 
"$field_sep?$field_quote([^$field_quote]*)$field_quote";
             $quoted_field_regexp = "$field_sep?([^$field_sep]*)";
@@ -2543,8 +2565,8 @@
 
 =head2 export_rows()
 
-    * Signature: $rep->export_rows($table, $file);
-    * Signature: $rep->export_rows($table, $file, $options);
+    * Signature: $rep->export_rows($table, $columns, $file);
+    * Signature: $rep->export_rows($table, $columns, $file, $options);
     * Param:     $table        string
     * Param:     $file         string
     * Param:     $options      named
@@ -2571,9 +2593,8 @@
 
 sub export_rows {
     &App::sub_entry if ($App::trace);
-    my ($self, $table, $file, $options) = @_;
-
-    my $columns = $options->{columns} || $self->{table}{$table}{columns};
+    my ($self, $table, $columns, $file, $options) = @_;
+    $columns = $self->_get_default_columns($table) if (!$columns);
     my $rows = $self->get_rows($table, {}, $columns);
     my $field_sep = $options->{field_sep} || ",";
     my $field_quote = $options->{field_quote};
@@ -2607,6 +2628,60 @@
     &App::sub_exit() if ($App::trace);
 }
 
+sub _read_rows_from_file {
+    &App::sub_entry if ($App::trace);
+    my ($self, $fh, $cols, $options) = @_;
+    my $maxrows             = $options->{maxrows};
+    my $null_value          = $options->{null_value};
+    $null_value = '\N' if (!defined $null_value);
+    my $field_sep           = $options->{field_sep} || ",";
+    my $field_quote         = $options->{field_quote} || "";
+    my $field_escape        = $options->{field_escape} || "";
+    die "TODO: field_escape not yet implemented" if ($field_escape);
+    my $fieldsep_regexp     = ($field_sep eq "|") ? '\|' : $field_sep;
+    my $quoted_field_regexp = 
"$field_sep?$field_quote([^$field_quote]*)$field_quote";
+    my $field_regexp        = "$field_sep?([^$field_sep]*)";
+    my $num_cols = $#$cols + 1;
+    my $rows_read = 0;
+    my $rows = [];
+    my ($num_values_read, $line, $line_remainder, $row);
+    while (<$fh>) {
+        chomp;
+        $line = $_;
+        if ($line) {
+            if (!$field_quote && !$field_escape) {
+                $row = [ map { $_ eq $null_value ? undef : $_ } 
split(/$fieldsep_regexp/, $line) ];
+                $num_values_read = $#$row + 1;
+            }
+            else {
+                $num_values_read = 0;
+                $line_remainder = $line;
+                $row = [];
+                while ($line_remainder) {
+                    if ($line_remainder =~ s/^$quoted_field_regexp//) {
+                        push(@$row, $1 eq $null_value ? undef : $1);
+                    }
+                    elsif ($line_remainder =~ s/^$field_regexp//) {
+                        push(@$row, $1 eq $null_value ? undef : $1);
+                    }
+                    else {
+                        die "Imported data [$line] doesn't match quoted or 
unquoted field at [$line_remainder]";
+                    }
+                }
+            }
+            die "In imported data [$line], num values on line 
[$num_values_read] != num columns expected [$num_cols]"
+                if ($num_values_read != $num_cols);
+            push(@$rows, $row);
+            $rows_read ++;
+            if ($maxrows && $rows_read >= $maxrows) {
+                last;
+            }
+        }
+    }
+    &App::sub_exit($rows) if ($App::trace);
+    return($rows);
+}
+
 #############################################################################
 # METHODS
 #############################################################################

Modified: p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm Mon Dec  4 11:33:33 2006
@@ -2181,7 +2181,7 @@
 # $nrows = $rep->_insert_rows ($table, [EMAIL PROTECTED], [EMAIL PROTECTED]);
 sub _insert_rows {
     &App::sub_entry if ($App::trace);
-    my ($self, $table, $cols, $rows) = @_;
+    my ($self, $table, $cols, $rows, $options) = @_;
     $self->{error} = "";
     my ($sql, $retval);
    
@@ -2190,35 +2190,72 @@
 
     my $nrows = 0;
     my $ok = 1;
-    $sql = $self->_mk_insert_row_sql($table, $cols);
     my $context_options = $self->{context}{options};
     my $debug_sql = $context_options->{debug_sql};
+    my $explain_sql = $context_options->{explain_sql};
     my ($timer, $elapsed_time);
     if ($debug_sql) {
         $timer = $self->_get_timer();
     }
-    foreach my $row (@$rows) {
-        if ($debug_sql) {
-            print "DEBUG_SQL: _insert_rows()\n";
-            print "DEBUG_SQL: bind vars [", join("|",map { defined $_ ? $_ : 
"undef" } @$row), "]\n";
-            print $sql;
-        }
-        if ($context_options->{explain_sql}) {
-            $self->explain_sql($sql);
-        }
-        $retval = $dbh->do($sql, undef, @$row);
-        if ($debug_sql) {
-            print "DEBUG_SQL: retval [$retval] $DBI::errstr\n";
-            print "\n";
-        }
-
-        if ($retval) {
-            $nrows ++;
+    if (ref($rows) eq "ARRAY") {
+        $sql = $self->_mk_insert_row_sql($table, $cols);
+        foreach my $row (@$rows) {
+            if ($debug_sql) {
+                print "DEBUG_SQL: _insert_rows()\n";
+                print "DEBUG_SQL: bind vars [", join("|",map { defined $_ ? $_ 
: "undef" } @$row), "]\n";
+                print $sql;
+            }
+            if ($explain_sql) {
+                $self->explain_sql($sql);
+            }
+            $retval = $dbh->do($sql, undef, @$row);
+            if ($debug_sql) {
+                print "DEBUG_SQL: retval [$retval] $DBI::errstr\n";
+                print "\n";
+            }
+    
+            if ($retval) {
+                $nrows ++;
+            }
+            else {
+                $self->{numrows} = $nrows;
+                $ok = 0;
+                last;
+            }
         }
-        else {
-            $self->{numrows} = $nrows;
-            $ok = 0;
-            last;
+    }
+    else {
+        my $fh = $rows;                # assume it is a file handle
+        $rows = [];                    # we will be refilling this buffer
+        my %options = ( %$options );   # make a copy so it can be modified
+        $options->{maxrows} = 100;
+        $sql = $self->_mk_insert_row_sql($table, $cols);
+        while (1) {
+            $rows = $self->_read_rows_from_file($fh, $cols, \%options);
+            last if ($#$rows == -1);
+            foreach my $row (@$rows) {
+                if ($debug_sql) {
+                    print "DEBUG_SQL: _insert_rows()\n";
+                    print "DEBUG_SQL: bind vars [", join("|",map { defined $_ 
? $_ : "undef" } @$row), "]\n";
+                    print $sql;
+                }
+                if ($context_options->{explain_sql}) {
+                    $self->explain_sql($sql);
+                }
+                $retval = $dbh->do($sql, undef, @$row);
+                if ($debug_sql) {
+                    print "DEBUG_SQL: retval [$retval] $DBI::errstr\n";
+                    print "\n";
+                }
+        
+                if ($retval) {
+                    $nrows ++;
+                }
+                else {
+                    $self->{numrows} = $nrows;
+                    $ok = 0;
+                }
+            }
         }
     }
     if ($debug_sql) {
@@ -2377,6 +2414,7 @@
         $timer = $self->_get_timer();
         print "DEBUG_SQL: _do()\n";
         print $sql;
+        print "\n" if ($sql !~ /\n$/);
     }
     if ($context_options->{explain_sql}) {
         $self->explain_sql($sql);

Modified: p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm       (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm       Mon Dec  4 
11:33:33 2006
@@ -107,6 +107,11 @@
     return($dsn);
 }
 
+sub _last_inserted_id {
+    my ($self) = @_;
+    return($self->{dbh}{mysql_insertid});
+}
+
 sub _mk_select_sql_suffix {
     &App::sub_entry if ($App::trace);
     my ($self, $table, $options) = @_;
@@ -119,9 +124,140 @@
     return($suffix);
 }
 
-sub _last_inserted_id {
-    my ($self) = @_;
-    return($self->{dbh}{mysql_insertid});
+# $insert_sql = $rep->_mk_insert_rows_sql ($table, [EMAIL PROTECTED], [EMAIL 
PROTECTED], \%options);
+# i.e. $options->{replace}
+sub _mk_insert_rows_sql {
+    &App::sub_entry if ($App::trace);
+    my ($self, $table, $cols, $rows, $options) = @_;
+
+    $self->_load_table_metadata($table) if (!defined 
$self->{table}{$table}{loaded});
+    my $dbh = $self->{dbh};
+
+    if ($#$cols == -1) {
+        $self->{error} = "Database->_mk_insert_row_sql(): no columns 
specified";
+        return();
+    }
+    my $tabcols = $self->{table}{$table}{column};
+
+    my $insert = $options->{replace} ? "replace" : "insert";
+    my $sql = "$insert into $table\n  (" . join(", ", @$cols) . ")\nvalues\n";
+    my ($value, $colnum, $quoted, $row, $col);
+    for (my $rownum = 0; $rownum <= $#$rows; $rownum++) {
+        $row = $rows->[$rownum];
+        for ($colnum = 0; $colnum <= $#$cols; $colnum++) {
+            $col = $cols->[$colnum];
+            if (!defined $row || $#$row == -1) {
+                $value = "?";
+            }
+            else {
+                $value = $row->[$colnum];
+                if (!defined $value) {
+                    $value = "NULL";
+                }
+                else {
+                    $quoted = (defined $tabcols->{$col}{quoted}) ? 
($tabcols->{$col}{quoted}) : ($value !~ /^-?[0-9.]+$/);
+                    if ($quoted) {
+                        $value = $dbh->quote($value);
+                    }
+                }
+            }
+            if ($tabcols->{$col}{dbexpr_update}) {
+                $value = sprintf($tabcols->{$col}{dbexpr_update}, $value);
+            }
+            $sql .= ($colnum == 0) ? "  ($value" : ", $value";
+        }
+        $sql .= ($rownum < $#$rows) ? "),\n" : ")\n";
+    }
+    &App::sub_exit($sql) if ($App::trace);
+    $sql;
+}
+
+# $nrows = $rep->_insert_rows ($table, [EMAIL PROTECTED], [EMAIL PROTECTED]);
+sub _insert_rows {
+    &App::sub_entry if ($App::trace);
+    my ($self, $table, $cols, $rows, $options) = @_;
+    $self->{error} = "";
+    my ($sql, $retval);
+   
+    my $dbh = $self->{dbh};
+    return 0 if (!defined $dbh);
+
+    my $nrows = 0;
+    my $ok = 1;
+    my $context_options = $self->{context}{options};
+    my $debug_sql = $context_options->{debug_sql};
+    my $explain_sql = $context_options->{explain_sql};
+    my ($timer, $elapsed_time);
+    if ($debug_sql) {
+        $timer = $self->_get_timer();
+    }
+    my $rows_ref = ref($rows);
+    if ($rows_ref eq "ARRAY") {
+        $sql = $self->_mk_insert_rows_sql($table, $cols, $rows);
+        if ($debug_sql) {
+            print "DEBUG_SQL: _insert_rows()\n";
+            print $sql;
+        }
+        $retval = $dbh->do($sql);
+        if ($debug_sql) {
+            print "DEBUG_SQL: retval [$retval] $DBI::errstr\n";
+            print "\n";
+        }
+
+        $nrows = $retval;
+        $self->{numrows} = $nrows;
+        if ($retval != $#$rows + 1) {
+            $ok = 0;
+        }
+    }
+    else {
+        my ($fh);
+        if (!$rows_ref) {
+            my $file = $rows;          # assume it is a file name
+            open(App::Repository::MySQL::FILE, $file) || die "Unable to open 
$file for reading: $!";
+            $fh = \*App::Repository::MySQL::FILE;
+        }
+        else {
+            $fh = $rows;               # assume it is a file handle
+        }
+        $rows = [];                    # we will be refilling this buffer
+        my %options = ( %$options );   # make a copy so it can be modified
+        $options{maxrows} = 100;
+        $sql = $self->_mk_insert_row_sql($table, $cols);
+        $nrows = 0;
+        while (1) {
+            $rows = $self->_read_rows_from_file($fh, $cols, \%options);
+            last if ($#$rows == -1);
+            $sql = $self->_mk_insert_rows_sql($table, $cols, $rows);
+            if ($debug_sql) {
+                print "DEBUG_SQL: _insert_rows()\n";
+                print $sql;
+            }
+            $retval = $dbh->do($sql);
+            if ($debug_sql) {
+                print "DEBUG_SQL: retval [$retval] $DBI::errstr\n";
+                print "\n";
+            }
+
+            $nrows += $retval;
+            if ($retval != $#$rows + 1) {
+                $ok = 0;
+                last;
+            }
+        }
+        $self->{numrows} = $nrows;
+        if (!$rows_ref) {
+            close(App::Repository::MySQL::FILE);
+        }
+    }
+    if ($debug_sql) {
+        $elapsed_time = $self->_read_timer($timer);
+        print "DEBUG_SQL: nrows [$nrows] ($elapsed_time sec)\n";
+    }
+    $self->{sql} = $sql;
+    $self->{numrows} = $nrows;
+    &App::sub_exit($nrows) if ($App::trace);
+    return($nrows);
 }
 
 sub _load_table_key_metadata {
@@ -224,7 +360,9 @@
     * Param:     $file         string
     * Param:     $options      named
     * Param:     columns       ARRAY     names of columns of the fields in the 
file
-    * Param:     method        string    [basic=invokes generic superclass to 
do work]
+    * Param:     import_method string    [basic=invokes generic superclass to 
do work,
+                                          insert=loads with multiple-row 
inserts,
+                                          <otherwise>=use "load data infile"]
     * Param:     local         boolean   file is on client machine rather than 
database server
     * Param:     replace       boolean   rows should replace existing rows 
based on unique indexes
     * Param:     field_sep     char      character which separates the fields 
in the file (can by "\t")
@@ -265,10 +403,19 @@
 
 sub import_rows {
     &App::sub_entry if ($App::trace);
-    my ($self, $table, $file, $options) = @_;
+    my ($self, $table, $columns, $file, $options) = @_;
+    $columns = $self->_get_default_columns($table) if (!$columns);
 
-    if ($options->{method} && $options->{method} eq "basic") {
-        $self->SUPER::import_rows($table, $file, $options);
+    my $nrows = 0;
+    my $import_method = $options->{import_method} || $self->{import_method} || 
"";
+    if ($import_method eq "basic") {
+        $nrows = $self->SUPER::import_rows($table, $columns, $file, $options);
+    }
+    elsif ($import_method eq "insert") {
+        $nrows = $self->insert_rows($table, $columns, $file, $options);
+        #open(App::Repository::MySQL::FILE, $file) || die "Unable to open 
$file for reading: $!";
+        #$nrows = $self->insert_rows($table, $columns, 
\*App::Repository::MySQL::FILE, $options);
+        #close(App::Repository::MySQL::FILE);
     }
     else {
         my $local = $options->{local};
@@ -281,9 +428,7 @@
             $sql .= "\n   optionally enclosed by '$options->{field_quote}'" if 
($options->{field_quote});
             $sql .= "\n   escaped by '$options->{field_escape}'" if 
($options->{field_escape});
         }
-        if ($options->{columns}) {
-            $sql .= "\n(" . join(",", @{$options->{columns}}) . ")";
-        }
+        $sql .= "\n(" . join(",", @$columns) . ")";
         my $context_options = $self->{context}{options};
         my $debug_sql = $context_options->{debug_sql};
         my ($timer, $elapsed_time);
@@ -292,18 +437,18 @@
             print "DEBUG_SQL: import_rows()\n";
             print $sql;
         }
-        my ($retval);
         eval {
-            $retval = $self->{dbh}->do($sql);
+            $nrows = $self->{dbh}->do($sql);
         };
         if ($debug_sql) {
             $elapsed_time = $self->_read_timer($timer);
-            print "DEBUG_SQL: import_rows=[$retval] ($elapsed_time sec) 
$DBI::errstr : [EMAIL PROTECTED]";
+            print "DEBUG_SQL: import_rows=[$nrows] ($elapsed_time sec) 
$DBI::errstr : [EMAIL PROTECTED]";
         }
         die $@ if ($@);
     }
 
-    &App::sub_exit() if ($App::trace);
+    &App::sub_exit($nrows) if ($App::trace);
+    return($nrows);
 }
 
 #############################################################################
@@ -318,7 +463,7 @@
     * Param:     $file         string
     * Param:     $options      named
     * Param:     columns       ARRAY     names of columns of the fields in the 
file
-    * Param:     method        string    [basic=invokes generic superclass to 
do work]
+    * Param:     export_method string    [basic=invokes generic superclass to 
do work]
     * Param:     field_sep     char      character which separates the fields 
in the file (can by "\t")
     * Param:     field_quote   char      character which optionally encloses 
the fields in the file (i.e. '"')
     * Param:     field_escape  char      character which escapes the quote 
chars within quotes (i.e. "\")
@@ -367,7 +512,7 @@
     &App::sub_entry if ($App::trace);
     my ($self, $table, $params, $file, $options) = @_;
 
-    if ($options->{method} && $options->{method} eq "basic") {
+    if ($options->{export_method} && $options->{export_method} eq "basic") {
         $self->SUPER::export_rows($table, $file, $options);
     }
     else {

Reply via email to