X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fpsql-reader.c;h=4a49ba0cf92c413c551811b1ce1a87dd9e64c062;hb=8d6bfdd2a100bf8166b3b0b3f006d46f3e7a59e9;hp=a54b9f8b3888c58320623ea1d53086bc8650a155;hpb=cc57a28ef6796ae9a64ef80d453f72126956d49d;p=pspp diff --git a/src/data/psql-reader.c b/src/data/psql-reader.c index a54b9f8b38..4a49ba0cf9 100644 --- a/src/data/psql-reader.c +++ b/src/data/psql-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2008, 2009, 2010, 2011, 2012 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 @@ -16,19 +16,25 @@ #include -#include -#include -#include -#include +#include "data/psql-reader.h" + +#include +#include #include -#include "psql-reader.h" -#include "variable.h" -#include "format.h" -#include "calendar.h" +#include "data/calendar.h" +#include "data/casereader-provider.h" +#include "data/dictionary.h" +#include "data/format.h" +#include "data/variable.h" +#include "libpspp/i18n.h" +#include "libpspp/message.h" +#include "libpspp/misc.h" +#include "libpspp/str.h" -#include -#include +#include "gl/c-strcase.h" +#include "gl/minmax.h" +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -50,6 +56,9 @@ psql_open_reader (struct psql_read_info *info UNUSED, struct dictionary **dict U #include +/* 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 @@ -95,7 +104,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 @@ -173,17 +182,12 @@ create_var (struct psql_reader *r, const struct fmt_spec *fmt, { unsigned long int vx = 0; 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); - return NULL; - } + char *name; + name = dict_make_unique_var_name (r->dict, suggested_name, &vx); var = dict_create_var (r->dict, name, width); + free (name); + var_set_both_formats (var, fmt); if ( col != -1) @@ -227,6 +231,7 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) int n_fields, n_tuples; PGresult *qres = NULL; casenumber n_cases = CASENUMBER_MAX; + const char *encoding; struct psql_reader *r = xzalloc (sizeof *r); struct string query ; @@ -247,7 +252,7 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) } { - int ver_num; + int ver_num = 0; const char *vers = PQparameterStatus (r->conn, "server_version"); sscanf (vers, "%d", &ver_num); @@ -266,7 +271,7 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) { const char *dt = PQparameterStatus (r->conn, "integer_datetimes"); - r->integer_datetimes = ( 0 == strcasecmp (dt, "on")); + r->integer_datetimes = ( 0 == c_strcasecmp (dt, "on")); } #if USE_SSL @@ -281,20 +286,34 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) } } - r->postgres_epoch = - calendar_gregorian_to_offset (2000, 1, 1, NULL, NULL); + r->postgres_epoch = calendar_gregorian_to_offset (2000, 1, 1, NULL); + { + 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 use the default encoding + if we find this value. + */ + encoding = enc ? pg_encoding_to_char (enc) : get_default_encoding (); + + /* Create the dictionary and populate it */ + *dict = r->dict = dict_create (encoding); + } - /* Create the dictionary and populate it */ - *dict = r->dict = dict_create (); - + const int version = PQserverVersion (r->conn); + ds_init_empty (&query); /* - select count (*) from (select * from medium) stupid_sql_standard; - */ - - ds_init_cstr (&query, - "BEGIN READ ONLY ISOLATION LEVEL SERIALIZABLE; " - "DECLARE pspp BINARY CURSOR FOR "); + Versions before 9.1 don't have the REPEATABLE READ isolation level. + However according to if the server is in the + "hot standby" mode then SERIALIZABLE won't work. + */ + ds_put_c_format (&query, + "BEGIN READ ONLY ISOLATION LEVEL %s; " + "DECLARE pspp BINARY CURSOR FOR ", + (version < 90100) ? "SERIALIZABLE" : "REPEATABLE READ"); ds_put_substring (&query, info->sql.ss); @@ -345,7 +364,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; @@ -357,12 +376,12 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) int width = 0; int length ; - /* If there are no data then make a finger in the air + /* If there are no data then make a finger in the air guess at the contents */ if ( n_tuples > 0 ) length = PQgetlength (qres, 0, i); - else - length = MAX_SHORT_STRING; + else + length = PSQL_DEFAULT_WIDTH; switch (type) { @@ -389,13 +408,13 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) 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; @@ -434,12 +453,16 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict) 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) { @@ -512,15 +535,16 @@ 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); error: - dict_destroy (*dict); + dict_unref (*dict); psql_casereader_destroy (NULL, r); return NULL; @@ -538,6 +562,7 @@ 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); } @@ -572,8 +597,8 @@ set_value (struct psql_reader *r) if ( r->tuple >= PQntuples (r->res)) return NULL; - c = case_create (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 ) @@ -815,7 +840,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), vptr, + MIN (length, var_width)); break; case NUMERICOID: