/* 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
#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)
#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"));
#include <libpq-fe.h>
+/* Default width of string variables. */
+#define PSQL_DEFAULT_WIDTH 8
+
/* These macros must be the same as in catalog/pg_types.h from the postgres source */
#define BOOLOID 16
#define BYTEAOID 17
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 =
{
double postgres_epoch;
- size_t value_cnt;
+ struct caseproto *proto;
struct dictionary *dict;
/* An array of ints, which maps psql column numbers into
};
-static bool set_value (struct psql_reader *r,
- struct ccase *cc);
+static struct ccase *set_value (struct psql_reader *r);
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);
/* 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 ");
n_tuples = PQntuples (qres);
n_fields = PQnfields (qres);
- r->value_cnt = 0;
+ r->proto = NULL;
r->vmap = NULL;
r->vmapsize = 0;
if ( n_tuples > 0 )
length = PQgetlength (qres, 0, i);
else
- length = MAX_SHORT_STRING;
+ length = PSQL_DEFAULT_WIDTH;
switch (type)
{
case BPCHAROID:
fmt.type = FMT_A;
width = (info->str_width == -1) ?
- ROUND_UP (length, MAX_SHORT_STRING) : info->str_width;
+ ROUND_UP (length, PSQL_DEFAULT_WIDTH) : info->str_width;
fmt.w = width;
fmt.d = 0;
break;
case BYTEAOID:
fmt.type = FMT_AHEX;
- width = length > 0 ? length : MAX_SHORT_STRING;
+ width = length > 0 ? length : PSQL_DEFAULT_WIDTH;
fmt.w = width * 2;
fmt.d = 0;
break;
default:
msg (MW, _("Unsupported OID %d. SYSMIS values will be inserted."), type);
fmt.type = FMT_A;
- width = length > 0 ? length : MAX_SHORT_STRING;
+ width = length > 0 ? length : PSQL_DEFAULT_WIDTH;
fmt.w = width ;
fmt.d = 0;
break;
}
+ if ( width == 0 && fmt_is_string (fmt.type))
+ fmt.w = width = PSQL_DEFAULT_WIDTH;
+
+
var = create_var (r, &fmt, width, PQfname (qres, i), i);
if ( type == NUMERICOID && n_tuples > 0)
{
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);
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_;
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 )
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:
r->tuple++;
- return true;
+ return c;
}
#endif