changeset 11407:f4098c7d5b35 octave-forge

Wrong implementation of copy-in from argument. Compiled, but not tested otherwise. Wanted to note this stage, but will be removed again since it can't work for composite types. Have to lookup composite types till end of any recursion before making the main connection. This is put off till later or till it is needed, for it is more work.
author i7tiol
date Tue, 22 Jan 2013 18:45:48 +0000
parents e29ecce18b3b
children 6c22f62f2b64
files main/database/src/command.cc main/database/src/command.h main/database/src/converters.cc main/database/src/converters.h main/database/src/converters_arr_comp.cc main/database/src/pq_exec.cc
diffstat 6 files changed, 302 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/main/database/src/command.cc	Tue Jan 22 17:27:26 2013 +0000
+++ b/main/database/src/command.cc	Tue Jan 22 18:45:48 2013 +0000
@@ -60,7 +60,7 @@
 command::command (octave_pq_connection &connection, std::string &cmd,
                   Cell &params, Cell &ptypes, Cell &rtypes, std::string &who)
   : valid (1), conn (connection), caller (who), res (NULL), all_fetched (1),
-  rettypes (rtypes)
+    rettypes (rtypes)
 {
   if (! (cptr = conn.octave_pq_get_conn ()))
     {
@@ -250,7 +250,9 @@
 octave_value command::process_single_result (const std::string &infile,
                                              const std::string &outfile,
                                              int nargout,
-                                             const Cell &data)
+                                             const Cell &data,
+                                             bool cin_oids,
+                                             const Cell &cin_types)
 {
   octave_value retval;
 
@@ -283,7 +285,7 @@
           retval = copy_out_handler (outfile, nargout);
           break;
         case PGRES_COPY_IN:
-          retval = copy_in_handler (infile, data);
+          retval = copy_in_handler (infile, data, cin_oids, cin_types);
           break;
         }
 
@@ -507,7 +509,9 @@
 }
 
 octave_value command::copy_in_handler (const std::string &infile,
-                                       const Cell &data)
+                                       const Cell &data,
+                                       bool oids,
+                                       const Cell &cin_types)
 {
   octave_value retval;
 
@@ -526,7 +530,7 @@
 
           PQputCopyEnd (cptr, "could not open input file");
 
-          error ("%s", PQerrorMessage (cptr));
+          error ("server error: %s", PQerrorMessage (cptr));
 
           valid = 0;
 
@@ -591,26 +595,225 @@
     {
       // read input from argument
 
-      error ("copy in from argument not yet implemented");
+      dim_vector dv = data.dims ();
+      octave_idx_type r = dv(0);
+      octave_idx_type c = dv(1);
+
+      octave_idx_type nf = PQnfields (res);
+      if (c != nf + oids)
+        {
+          error ("argument for copy-in has unexpected number of columns");
+
+          PQputCopyEnd
+            (cptr, "argument for copy-in has unexpected number of columns");
+        }
+      else if (! PQbinaryTuples (res))
+        {
+          error ("copy-in from argument must use binary mode");
 
-      if (data.dims ().length () > 2)
+          PQputCopyEnd (cptr, "copy-in from argument must use binary mode");
+        }
+      else
         {
-          error ("copy-in data must not be more than two-dimensional");
+          for (octave_idx_type j = 0; j < c; j++)
+            if (! PQfformat (res, j))
+              {
+                error ("copy-in from argument must use binary mode in all columns");
+
+                PQputCopyEnd (cptr, "copy-in from argument must use binary mode in all columns");
+
+                break;
+              }
+        }
+
+      if (error_state)
+        {
+          error ("server error: %s", PQerrorMessage (cptr));
 
           valid = 0;
 
           return retval;
         }
 
-      valid = 0;
+#define COPY_HEADER_SIZE 19
+      char header [COPY_HEADER_SIZE];
+      memset (header, 0, COPY_HEADER_SIZE);
+      strcpy (header, "PGCOPY\n\377\r\n\0");
+      *((uint32_t *) (&header[11])) = htobe32 (uint32_t (oids) << 16);
+
+      char trailer [2];
+      *((int16_t *) (&trailer)) = htobe16 (int16_t (-1));
+
+      if (PQputCopyData (cptr, header, COPY_HEADER_SIZE) == -1)
+        {
+          PQputCopyEnd (cptr, "could not send header");
+
+          error ("server error: %s", PQerrorMessage (cptr));
+        }
+      else
+        {
+          oct_type_t oct_types [c];
+          oct_pq_conv_t *convs [c];
+          // FIXME: this can't prevent repetition of lookups in recursive types
+          bool type_determined [c];
+          memset (type_determined, 0, sizeof (type_determined));
+
+          for (octave_idx_type i = 0; i < r; i++) // i is row
+            {
+              int16_t fc = htobe16 (int16_t (nf));
+              if (PQputCopyData (cptr, (char *) &fc, 2) == -1)
+                {
+                  error ("%s", PQerrorMessage (cptr));
+
+                  PQputCopyEnd (cptr, "error sending field count");
+
+                  error ("server error: %s", PQerrorMessage (cptr));
+
+                  break;
+                }
+
+              // j is column of argument data
+              for (octave_idx_type j = 0; j < c; j++)
+                {
+                  if (data(i, j).is_real_scalar () &&
+                      data(i, j).isna ().bool_value ())
+                    {
+                      int32_t t = htobe32 (int32_t (-1));
+                      if (PQputCopyData (cptr, (char *) &t, 4) == -1)
+                        {
+                          error ("could not send NULL in copy-in");
+
+                          break;
+                        }
+                    }
+                  else
+                    {
+                      if (! type_determined [j])
+                        {
+                          if ((j == 0) && oids)
+                            {
+                              std::string t ("oid");
+                              convs[0] = pgtype_from_spec (t, oct_types[0]);
+                            }
+                          else
+                            {
+                              if (cin_types(j).is_empty ())
+                                {
+                                  oct_types[j] = simple;
+
+                                  if (! (convs[j] =
+                                         pgtype_from_octtype (data(i, j))))
+                                    {
+                                      error ("could not determine type in column %i for copy-in",
+                                             j);
+
+                                      break;
+                                    }
+                                }
+                              else
+                                {
+                                  std::string s = cin_types(j).string_value ();
+                                  if (error_state)
+                                    {
+                                      error ("column type specification no string");
+
+                                      break;
+                                    }
+
+                                  if (! (convs[j] =
+                                         pgtype_from_spec (s, oct_types[j])))
+                                    {
+                                      error ("invalid column type specification");
+
+                                      break;
+                                    }
+                                }
+                            }
+
+                          type_determined [j] = true;
+                        } // ! type_determined [j]
+
+                      oct_pq_dynvec_t val;
+
+                      bool conversion_failed = false;
+                      switch (oct_types[j])
+                        {
+                        case simple:
+                          if (convs[j]->from_octave_bin (data(i, j), val))
+                            conversion_failed = true;
+                          break;
+
+                        case array:
+                          if (from_octave_bin_array (data(i, j), val, convs[j]))
+                            conversion_failed = true;
+
+                        case composite:
+                          if (from_octave_bin_composite (data(i, j), val,
+                                                         convs[j]))
+                            conversion_failed = true;
+
+                        default:
+                          // should not get here
+                          error ("internal error, undefined type identifier");
+                        }
+
+                      if (conversion_failed)
+                        error ("could not convert data(%i, %i) for copy-in",
+                               i, j);
+                      else
+                        if (PQputCopyData (cptr, &(val.front ()),
+                                           val.size ()) == -1)
+                          error ("could not send copy-in data");
+
+                      if (error_state) break;
+                    }
+                } // column of argument data
+
+              if (error_state)
+                {
+                  PQputCopyEnd (cptr, "error sending copy-in data");
+
+                  error ("server error: %s", PQerrorMessage (cptr));
+
+                  break;
+                }
+            } // row of argument data
+        }
+
+      if (! error_state)
+        if (PQputCopyData (cptr, trailer, 2) == -1)
+          {
+            PQputCopyEnd (cptr, "could not send trailer");
+
+            error ("%s", PQerrorMessage (cptr));
+          }
+
+      if (! error_state)
+        if (PQputCopyEnd (cptr, NULL) == -1)
+          error ("%s", PQerrorMessage (cptr));
+        else
+          {
+            PQclear (res);
+
+            if (res = PQgetResult (cptr))
+              {
+                if ((state = PQresultStatus (res)) == PGRES_FATAL_ERROR)
+                  error ("server error in copy-in: %s", PQerrorMessage (cptr));
+              }
+            else
+              error ("unexpectedly got no result information");
+          }
     }
   else
     error ("neither data nor filename given for copy-in");
 
+  if (error_state)
+    valid = 0;
+
   return retval;
 }
 
-oct_pq_conv_t *command::pgtype_from_octtype (octave_value &param)
+oct_pq_conv_t *command::pgtype_from_octtype (const octave_value &param)
 {
   // printf ("pgtype_from_octtype: ");
 
--- a/main/database/src/command.h	Tue Jan 22 17:27:26 2013 +0000
+++ b/main/database/src/command.h	Tue Jan 22 18:45:48 2013 +0000
@@ -72,13 +72,15 @@
   {
     Cell c;
     // inlining should prevent the additional copy
-    return process_single_result ("", "", 0, c);
+    return process_single_result ("", "", 0, c, false, c);
   }
 
   octave_value process_single_result (const std::string &infile,
                                       const std::string &outfile,
                                       int nargout,
-                                      const Cell &data);
+                                      const Cell &data,
+                                      bool cin_oids,
+                                      const Cell &cin_types);
 
   int good (void) {return valid;}
 
@@ -113,25 +115,26 @@
 
   octave_value copy_out_handler (const std::string &, int);
 
-  octave_value copy_in_handler (const std::string &, const Cell &);
+  octave_value copy_in_handler (const std::string &, const Cell &, bool oids,
+                                const Cell &cin_types);
 
-  oct_pq_conv_t *pgtype_from_octtype (octave_value &);
+  oct_pq_conv_t *pgtype_from_octtype (const octave_value &);
 
   oct_pq_conv_t *pgtype_from_spec (std::string &, oct_type_t &);
 
   oct_pq_conv_t *pgtype_from_spec (Oid, oct_type_t &);
 
-  int from_octave_bin_array (octave_value &oct_arr, oct_pq_dynvec_t &val,
+  int from_octave_bin_array (const octave_value &oct_arr, oct_pq_dynvec_t &val,
                              oct_pq_conv_t *);
 
-  int from_octave_bin_composite (octave_value &oct_comp, oct_pq_dynvec_t &val,
-                                 oct_pq_conv_t *);
+  int from_octave_bin_composite (const octave_value &oct_comp,
+                                 oct_pq_dynvec_t &val, oct_pq_conv_t *);
 
-  int from_octave_str_array (octave_value &oct_arr, oct_pq_dynvec_t &val,
+  int from_octave_str_array (const octave_value &oct_arr, oct_pq_dynvec_t &val,
                              octave_value &type);
 
-  int from_octave_str_composite (octave_value &oct_comp, oct_pq_dynvec_t &val,
-                                 octave_value &type);
+  int from_octave_str_composite (const octave_value &oct_comp,
+                                 oct_pq_dynvec_t &val, octave_value &type);
 
   int to_octave_bin_array (char *, octave_value &, int, oct_pq_conv_t *);
 
--- a/main/database/src/converters.cc	Tue Jan 22 17:27:26 2013 +0000
+++ b/main/database/src/converters.cc	Tue Jan 22 18:45:48 2013 +0000
@@ -55,7 +55,7 @@
   return 0;
 }
 
-int from_octave_str_bool (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_bool (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   bool b = ov.bool_value ();
 
@@ -71,7 +71,7 @@
   return 0;
 }
 
-int from_octave_bin_bool (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_bool (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   bool b = ov.bool_value ();
 
@@ -114,12 +114,12 @@
   return 0;
 }
 
-int from_octave_str_oid (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_oid (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_oid (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_oid (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   uint32_t oid = ov.uint_value ();
 
@@ -173,14 +173,14 @@
   return 0;
 }
 
-int from_octave_str_float8 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_float8 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   // not implemented
 
   return 1;
 }
 
-int from_octave_bin_float8 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_float8 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   double d = ov.double_value ();
 
@@ -243,14 +243,14 @@
   return 0;
 }
 
-int from_octave_str_float4 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_float4 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   // not implemented
 
   return 1;
 }
 
-int from_octave_bin_float4 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_float4 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   double f = ov.float_value ();
 
@@ -308,12 +308,12 @@
   return 0;
 }
 
-int from_octave_str_bytea (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_bytea (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_bytea (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_bytea (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   uint8NDArray b = ov.uint8_array_value ();
 
@@ -368,12 +368,12 @@
   return 0;
 }
 
-int from_octave_str_text (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_text (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_text (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_text (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   std::string s = ov.string_value ();
 
@@ -455,12 +455,12 @@
   return 0;
 }
 
-int from_octave_str_name (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_name (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_name (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_name (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   std::string s = ov.string_value ();
 
@@ -513,12 +513,12 @@
   return 0;
 }
 
-int from_octave_str_int2 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_int2 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_int2 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_int2 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   int16_t i2 = ov.int_value ();
 
@@ -562,12 +562,12 @@
   return 0;
 }
 
-int from_octave_str_int4 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_int4 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_int4 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_int4 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   int32_t i4 = ov.int_value ();
 
@@ -611,12 +611,12 @@
   return 0;
 }
 
-int from_octave_str_int8 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_str_int8 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   return 1;
 }
 
-int from_octave_bin_int8 (octave_value &ov, oct_pq_dynvec_t &val)
+int from_octave_bin_int8 (const octave_value &ov, oct_pq_dynvec_t &val)
 {
   int64_t i8 = ov.int64_scalar_value ();
 
--- a/main/database/src/converters.h	Tue Jan 22 17:27:26 2013 +0000
+++ b/main/database/src/converters.h	Tue Jan 22 18:45:48 2013 +0000
@@ -37,7 +37,7 @@
 
 typedef int (*oct_pq_to_octave_fp_t) (char *, octave_value &, int);
 
-typedef int (*oct_pq_from_octave_fp_t) (octave_value &, oct_pq_dynvec_t &);
+typedef int (*oct_pq_from_octave_fp_t) (const octave_value &, oct_pq_dynvec_t &);
 
 // some objects will be constants, some will be allocated
 typedef struct
--- a/main/database/src/converters_arr_comp.cc	Tue Jan 22 17:27:26 2013 +0000
+++ b/main/database/src/converters_arr_comp.cc	Tue Jan 22 18:45:48 2013 +0000
@@ -86,8 +86,8 @@
     }
 }
 
-int command::from_octave_bin_array (octave_value &oct_arr, oct_pq_dynvec_t &val,
-                                    oct_pq_conv_t *conv)
+int command::from_octave_bin_array (const octave_value &oct_arr,
+                                    oct_pq_dynvec_t &val, oct_pq_conv_t *conv)
 {
   octave_scalar_map m = oct_arr.scalar_map_value ();
   if (error_state)
@@ -194,7 +194,7 @@
   return 0;
 }
 
-int command::from_octave_bin_composite (octave_value &oct_comp,
+int command::from_octave_bin_composite (const octave_value &oct_comp,
                                         oct_pq_dynvec_t &val,
                                         oct_pq_conv_t *conv)
 {
@@ -269,8 +269,8 @@
   return 0;
 }
 
-int command::from_octave_str_array (octave_value &oct_arr, oct_pq_dynvec_t &val,
-                                    octave_value &type)
+int command::from_octave_str_array (const octave_value &oct_arr,
+                                    oct_pq_dynvec_t &val, octave_value &type)
 {
   // not implemented
   error ("not implemented");
@@ -279,7 +279,7 @@
   return 0;
 }
 
-int command::from_octave_str_composite (octave_value &oct_comp,
+int command::from_octave_str_composite (const octave_value &oct_comp,
                                         oct_pq_dynvec_t &val,
                                         octave_value &type)
 {
--- a/main/database/src/pq_exec.cc	Tue Jan 22 17:27:26 2013 +0000
+++ b/main/database/src/pq_exec.cc	Tue Jan 22 18:45:48 2013 +0000
@@ -181,7 +181,7 @@
   if (nargs == 1 && args(0).is_string () &&
       args(0).string_value () == "defaults")
     {
-      octave_value_list f_args (8);
+      octave_value_list f_args (12);
       Matrix a;
       Cell c;
 
@@ -193,6 +193,10 @@
       f_args(5) = octave_value ("");
       f_args(6) = octave_value ("copy_in_data");
       f_args(7) = octave_value (c);
+      f_args(8) = octave_value ("copy_in_oids");
+      f_args(9) = octave_value (false);
+      f_args(10) = octave_value ("copy_in_types");
+      f_args(11) = octave_value (c);
 
       return feval ("setdbopts", f_args, 1);
     }
@@ -345,6 +349,30 @@
       return retval;
     }
 
+  f_args(1) = octave_value ("copy_in_oids");
+  f_args(2) = octave_value (false);
+
+  f_ret = feval ("getdbopts", f_args, 1);
+  bool cin_oids = f_ret(0).bool_value ();
+  if (error_state)
+    {
+      error ("could not convert copy_in_oids to bool");
+
+      return retval;
+    }
+
+  f_args(1) = octave_value ("copy_in_types");
+  f_args(2) = octave_value (Cell ());
+
+  f_ret = feval ("getdbopts", f_args, 1);
+  Cell cin_types = f_ret(0).cell_value ();
+  if (error_state)
+    {
+      error ("could not convert copy_in_types to cell");
+
+      return retval;
+    }
+
   // check option settings
 
   if (ptypes.length () != nparams)
@@ -371,6 +399,24 @@
       return retval;
     }
 
+  dim_vector cind_dv = cin_data.dims ();
+  if (cind_dv.length () > 2)
+    {
+      error ("%s: copy-in data must not be more than two-dimensional",
+             fname.c_str ());
+
+      return retval;
+    }
+
+  if (cin_types.is_empty ())
+    cin_types.resize (dim_vector (1, cind_dv(1)));
+  if (cin_types.numel () != cind_dv(1))
+    {
+      error ("%s: copy_in_types has wrong number of elements");
+
+      return retval;
+    }
+
   //
 
   Cell rtypes;
@@ -378,7 +424,8 @@
   command c (oct_pq_conn, cmd, params, ptypes, rtypes, fname);
 
   if (c.good ())
-    retval = c.process_single_result (cin_path, cout_path, nargout, cin_data);
+    retval = c.process_single_result
+      (cin_path, cout_path, nargout, cin_data, cin_oids, cin_types);
 
   return retval;
 }