Change "union value" to dynamically allocate long strings.
[pspp-builds.git] / src / data / psql-reader.c
index 72e14be4fce9542eb8f7c92b6a21563fc2842f0c..741bf36e44c079196d608df94c1a6b5f6ee7a9e4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
 #include <libpspp/message.h>
 #include <gl/xalloc.h>
 #include <data/dictionary.h>
+#include <math.h>
 #include <stdlib.h>
 
 #include "psql-reader.h"
 #include "calendar.h"
 
 #include <inttypes.h>
+#include <libpspp/misc.h>
 #include <libpspp/str.h>
 
+#include "minmax.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) (msgid)
@@ -37,7 +41,7 @@
 
 #if !PSQL_SUPPORT
 struct casereader *
-psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
+psql_open_reader (struct psql_read_info *info UNUSED, struct dictionary **dict UNUSED)
 {
   msg (ME, _("Support for reading postgres databases was not compiled into this installation of PSPP"));
 
@@ -75,8 +79,7 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
 
 static void psql_casereader_destroy (struct casereader *reader UNUSED, void *r_);
 
-static bool psql_casereader_read (struct casereader *, void *,
-                                 struct ccase *);
+static struct ccase *psql_casereader_read (struct casereader *, void *);
 
 static const struct casereader_class psql_casereader_class =
   {
@@ -96,7 +99,7 @@ struct psql_reader
 
   double postgres_epoch;
 
-  size_t value_cnt;
+  struct caseproto *proto;
   struct dictionary *dict;
 
   /* An array of ints, which maps psql column numbers into
@@ -109,8 +112,7 @@ struct psql_reader
 };
 
 
-static bool set_value (struct psql_reader *r,
-                      struct ccase *cc);
+static struct ccase *set_value (struct psql_reader *r);
 
 
 
@@ -177,8 +179,6 @@ create_var (struct psql_reader *r, const struct fmt_spec *fmt,
   struct variable *var;
   char name[VAR_NAME_LEN + 1];
 
-  r->value_cnt += value_cnt_from_width (width);
-
   if ( ! dict_make_unique_var_name (r->dict, suggested_name, &vx, name))
     {
       msg (ME, _("Cannot create variable name from %s"), suggested_name);
@@ -290,10 +290,22 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
   /* Create the dictionary and populate it */
   *dict = r->dict = dict_create ();
 
+  {
+    const int enc = PQclientEncoding (r->conn);
+
+    /* According to section 22.2 of the Postgresql manual
+       a value of zero (SQL_ASCII) indicates
+       "a declaration of ignorance about the encoding".
+       Accordingly, we don't set the dictionary's encoding
+       if we find this value.
+    */
+    if ( enc != 0 )
+      dict_set_encoding (r->dict, pg_encoding_to_char (enc));
+  }
+
   /*
     select count (*) from (select * from medium) stupid_sql_standard;
   */
-
   ds_init_cstr (&query,
                "BEGIN READ ONLY ISOLATION LEVEL SERIALIZABLE; "
                "DECLARE  pspp BINARY CURSOR FOR ");
@@ -347,7 +359,7 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
   n_tuples = PQntuples (qres);
   n_fields = PQnfields (qres);
 
-  r->value_cnt = 0;
+  r->proto = NULL;
   r->vmap = NULL;
   r->vmapsize = 0;
 
@@ -442,6 +454,10 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
          break;
        }
 
+      if ( width == 0 && fmt_is_string (fmt.type))
+       fmt.w = width = MAX_SHORT_STRING;
+
+
       var = create_var (r, &fmt, width, PQfname (qres, i), i);
       if ( type == NUMERICOID && n_tuples > 0)
        {
@@ -514,10 +530,11 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
   ds_put_format (&r->fetch_cmd,  "FETCH FORWARD %d FROM pspp", r->cache_size);
 
   reload_cache (r);
+  r->proto = caseproto_ref (dict_get_proto (*dict));
 
   return casereader_create_sequential
     (NULL,
-     r->value_cnt,
+     r->proto,
      n_cases,
      &psql_casereader_class, r);
 
@@ -540,15 +557,15 @@ psql_casereader_destroy (struct casereader *reader UNUSED, void *r_)
   free (r->vmap);
   if (r->res) PQclear (r->res);
   PQfinish (r->conn);
+  caseproto_unref (r->proto);
 
   free (r);
 }
 
 
 
-static bool
-psql_casereader_read (struct casereader *reader UNUSED, void *r_,
-                     struct ccase *cc)
+static struct ccase *
+psql_casereader_read (struct casereader *reader UNUSED, void *r_)
 {
   struct psql_reader *r = r_;
 
@@ -558,25 +575,25 @@ psql_casereader_read (struct casereader *reader UNUSED, void *r_,
        return false;
     }
 
-  return set_value (r, cc);
+  return set_value (r);
 }
 
-static bool
-set_value (struct psql_reader *r,
-          struct ccase *c)
+static struct ccase *
+set_value (struct psql_reader *r)
 {
-  int i;
+  struct ccase *c;
   int n_vars;
+  int i;
 
   assert (r->res);
 
   n_vars = PQnfields (r->res);
 
   if ( r->tuple >= PQntuples (r->res))
-    return false;
+    return NULL;
 
-  case_create (c, r->value_cnt);
-  memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt);
+  c = case_create (r->proto);
+  case_set_missing (c);
 
 
   for (i = 0 ; i < n_vars ; ++i )
@@ -818,7 +835,8 @@ set_value (struct psql_reader *r,
            case VARCHAROID:
            case BPCHAROID:
            case BYTEAOID:
-             memcpy (val->s, (char *) vptr, MIN (length, var_width));
+             memcpy (value_str_rw (val, var_width), (char *) vptr,
+                      MIN (length, var_width));
              break;
 
            case NUMERICOID:
@@ -870,7 +888,7 @@ set_value (struct psql_reader *r,
 
   r->tuple++;
 
-  return true;
+  return c;
 }
 
 #endif