diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 5c007b0ae43..8bdda60ed1a 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -1595,6 +1595,11 @@ Thu Jul 24 10:33:51 CEST 2003 Fri Jul 25 18:08:18 CEST 2003 - Added explicit casts for date/timestamp/interval. + +Fri Aug 1 08:54:02 CEST 2003 + + - Added some Informix error codes in Informix mode. + - Added just another pgtypeslib function. - Set ecpg version to 3.0.0 - Set ecpg library to 4.0.0 - Set pgtypes library to 1.0.0 diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c index 807349fd835..e1b073f4002 100644 --- a/src/interfaces/ecpg/compatlib/informix.c +++ b/src/interfaces/ecpg/compatlib/informix.c @@ -823,7 +823,7 @@ rtypwidth(int sqltype, int sqllen) int dtcvfmtasc (char *inbuf, char *fmtstr, dtime_t *dtvalue) { - return 0; + return PGTYPEStimestamp_defmt_asc(inbuf, fmtstr, dtvalue); } static struct var_list diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index d187d32f708..44b088481c7 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.12 2003/07/15 12:38:38 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.13 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -116,7 +116,7 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name) { if ((results = PQexec(con->connection, "begin transaction")) == NULL) { - ECPGraise(lineno, ECPG_TRANS, NULL); + ECPGraise(lineno, ECPG_TRANS, NULL, ECPG_COMPAT_PGSQL); return false; } PQclear(results); @@ -130,7 +130,7 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name) { if ((results = PQexec(con->connection, "commit")) == NULL) { - ECPGraise(lineno, ECPG_TRANS, NULL); + ECPGraise(lineno, ECPG_TRANS, NULL, ECPG_COMPAT_PGSQL); return false; } PQclear(results); @@ -406,7 +406,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p if (strncmp(dbname, "unix:", 5) != 0) { ECPGlog("connect: socketname %s given for TCP connection in line %d\n", host, lineno); - ECPGraise(lineno, ECPG_CONNECT, realname ? realname : ""); + ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "", ECPG_COMPAT_PGSQL); if (host) ECPGfree(host); if (port) @@ -429,7 +429,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0) { ECPGlog("connect: non-localhost access via sockets in line %d\n", lineno); - ECPGraise(lineno, ECPG_CONNECT, realname ? realname : ""); + ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "", ECPG_COMPAT_PGSQL); if (host) ECPGfree(host); if (port) @@ -497,7 +497,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p user ? "for user " : "", user ? user : "", lineno, errmsg); - ECPGraise(lineno, ECPG_CONNECT, db); + ECPGraise(lineno, ECPG_CONNECT, db, ECPG_COMPAT_PGSQL); if (host) ECPGfree(host); if (port) diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index e783e4f077b..361dfa73a4a 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.13 2003/07/18 14:32:56 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.14 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -34,7 +34,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, { if (*pval != '{') { - ECPGraise(lineno, ECPG_DATA_NOT_ARRAY, NULL); + ECPGraise(lineno, ECPG_DATA_NOT_ARRAY, NULL, compat); return (false); } @@ -90,13 +90,13 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, } else { - ECPGraise(lineno, ECPG_MISSING_INDICATOR, NULL); + ECPGraise(lineno, ECPG_MISSING_INDICATOR, NULL, compat); return (false); } } break; default: - ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(ind_type)); + ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(ind_type), compat); return (false); break; } @@ -126,7 +126,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_INT_FORMAT, pval); + ECPGraise(lineno, ECPG_INT_FORMAT, pval, compat); return (false); } } @@ -159,7 +159,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_UINT_FORMAT, pval); + ECPGraise(lineno, ECPG_UINT_FORMAT, pval, compat); return (false); } } @@ -192,7 +192,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_INT_FORMAT, pval); + ECPGraise(lineno, ECPG_INT_FORMAT, pval, compat); return (false); } } @@ -209,7 +209,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_UINT_FORMAT, pval); + ECPGraise(lineno, ECPG_UINT_FORMAT, pval, compat); return (false); } } @@ -235,7 +235,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_FLOAT_FORMAT, pval); + ECPGraise(lineno, ECPG_FLOAT_FORMAT, pval, compat); return (false); } } @@ -266,7 +266,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, else if (offset == sizeof(int)) *((int *) (var + offset * act_tuple)) = false; else - ECPGraise(lineno, ECPG_CONVERT_BOOL, "different size"); + ECPGraise(lineno, ECPG_CONVERT_BOOL, "different size", compat); break; } else if (pval[0] == 't' && pval[1] == '\0') @@ -276,7 +276,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, else if (offset == sizeof(int)) *((int *) (var + offset * act_tuple)) = true; else - ECPGraise(lineno, ECPG_CONVERT_BOOL, "different size"); + ECPGraise(lineno, ECPG_CONVERT_BOOL, "different size", compat); break; } else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field)) @@ -286,7 +286,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, } } - ECPGraise(lineno, ECPG_CONVERT_BOOL, pval); + ECPGraise(lineno, ECPG_CONVERT_BOOL, pval, compat); return (false); break; @@ -396,7 +396,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_NUMERIC_FORMAT, pval); + ECPGraise(lineno, ECPG_NUMERIC_FORMAT, pval, compat); return (false); } } @@ -423,7 +423,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_INTERVAL_FORMAT, pval); + ECPGraise(lineno, ECPG_INTERVAL_FORMAT, pval, compat); return (false); } } @@ -446,7 +446,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_DATE_FORMAT, pval); + ECPGraise(lineno, ECPG_DATE_FORMAT, pval, compat); return (false); } @@ -468,7 +468,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if ((isarray && *scan_length != ',' && *scan_length != '}') || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ { - ECPGraise(lineno, ECPG_TIMESTAMP_FORMAT, pval); + ECPGraise(lineno, ECPG_TIMESTAMP_FORMAT, pval, compat); return (false); } @@ -477,7 +477,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, break; default: - ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(type)); + ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(type), compat); return (false); break; } diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index ade737beeae..bdb308810da 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -1,6 +1,6 @@ /* dynamic SQL support routines * - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.3 2003/06/15 04:07:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.4 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL @@ -103,7 +103,7 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value) *(double *) var = (double) value; break; default: - ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, NULL); + ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, NULL, ECPG_COMPAT_PGSQL); return (false); } @@ -135,7 +135,7 @@ get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int va } break; default: - ECPGraise(lineno, ECPG_VAR_NOT_CHAR, NULL); + ECPGraise(lineno, ECPG_VAR_NOT_CHAR, NULL, ECPG_COMPAT_PGSQL); return (false); } @@ -162,13 +162,13 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) ntuples = PQntuples(ECPGresult); if (ntuples < 1) { - ECPGraise(lineno, ECPG_NOT_FOUND, NULL); + ECPGraise(lineno, ECPG_NOT_FOUND, NULL, ECPG_COMPAT_PGSQL); return (false); } if (index < 1 || index > PQnfields(ECPGresult)) { - ECPGraise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, NULL); + ECPGraise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, NULL, ECPG_COMPAT_PGSQL); return (false); } @@ -300,7 +300,7 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) { ECPGlog("ECPGget_desc line %d: Incorrect number of matches: %d don't fit into array of %d\n", lineno, ntuples, arrsize); - ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL); + ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL, ECPG_COMPAT_PGSQL); return false; } /* allocate storage if needed */ @@ -324,7 +324,7 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) default: snprintf(type_str, sizeof(type_str), "%d", type); - ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, type_str); + ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, type_str, ECPG_COMPAT_PGSQL); return (false); } @@ -361,7 +361,7 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) { ECPGlog("ECPGget_desc line %d: Incorrect number of matches (indicator): %d don't fit into array of %d\n", lineno, ntuples, data_var.ind_arrsize); - ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL); + ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL, ECPG_COMPAT_PGSQL); return false; } /* allocate storage if needed */ @@ -404,7 +404,7 @@ ECPGdeallocate_desc(int line, const char *name) return true; } } - ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, name); + ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, name, ECPG_COMPAT_PGSQL); return false; } @@ -430,7 +430,7 @@ ECPGallocate_desc(int line, const char *name) { ECPGfree(new->name); ECPGfree(new); - ECPGraise(line, ECPG_OUT_OF_MEMORY, NULL); + ECPGraise(line, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL); return false; } strcpy(new->name, name); @@ -449,7 +449,7 @@ ECPGdescriptor_lvalue(int line, const char *descriptor) return &i->result; } - ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, (char *) descriptor); + ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, (char *) descriptor, ECPG_COMPAT_PGSQL); return NULL; } diff --git a/src/interfaces/ecpg/ecpglib/error.c b/src/interfaces/ecpg/ecpglib/error.c index 5566c0edf66..0b4b563d85a 100644 --- a/src/interfaces/ecpg/ecpglib/error.c +++ b/src/interfaces/ecpg/ecpglib/error.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/error.c,v 1.3 2003/07/15 12:38:38 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/error.c,v 1.4 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -12,7 +12,7 @@ #include "sqlca.h" void -ECPGraise(int line, int code, const char *str) +ECPGraise(int line, int code, const char *str, int compat) { struct sqlca_t *sqlca = ECPGget_sqlca(); sqlca->sqlcode = code; @@ -139,9 +139,9 @@ ECPGraise(int line, int code, const char *str) snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "'%.*s' in line %d.", slen, str, line); if (strncmp(str, "ERROR: Cannot insert a duplicate key", strlen("ERROR: Cannot insert a duplicate key")) == 0) - sqlca->sqlcode = ECPG_DUPLICATE_KEY; + sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_DUPLICATE_KEY : ECPG_DUPLICATE_KEY; else if (strncmp(str, "ERROR: More than one tuple returned by a subselect", strlen("ERROR: More than one tuple returned by a subselect")) == 0) - sqlca->sqlcode = ECPG_SUBSELECT_NOT_ONE; + sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_SUBSELECT_NOT_ONE; break; } diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index f9557a861a4..8e9545f0ab4 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.20 2003/07/25 16:10:26 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.21 2003/08/01 08:21:04 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -124,7 +124,7 @@ create_statement(int lineno, int compat, int force_indicator, struct connection /* if variable is NULL, the statement hasn't been prepared */ if (var->pointer == NULL) { - ECPGraise(lineno, ECPG_INVALID_STMT, NULL); + ECPGraise(lineno, ECPG_INVALID_STMT, NULL, compat); ECPGfree(var); return false; } @@ -351,7 +351,7 @@ ECPGstore_result(const PGresult *results, int act_field, { ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n", stmt->lineno, ntuples, var->arrsize); - ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL); + ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL, ECPG_COMPAT_PGSQL); return false; } } @@ -362,7 +362,7 @@ ECPGstore_result(const PGresult *results, int act_field, */ if (var->arrsize == 0) { - ECPGraise(stmt->lineno, ECPG_NO_ARRAY, NULL); + ECPGraise(stmt->lineno, ECPG_NO_ARRAY, NULL, ECPG_COMPAT_PGSQL); return false; } } @@ -484,7 +484,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, /* if (var->arrsize > 1 && ...) { - ECPGraise(stmt->lineno, ECPG_ARRAY_INSERT, NULL); + ECPGraise(stmt->lineno, ECPG_ARRAY_INSERT, NULL, compat); return false; }*/ @@ -757,7 +757,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, for (element = 0; element < var->arrsize; element++) sprintf(mallocedval + strlen(mallocedval), "%c,", (((int *) var->value)[element]) ? 't' : 'f'); else - ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size"); + ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size", ECPG_COMPAT_PGSQL); strcpy(mallocedval + strlen(mallocedval) - 1, "]"); } @@ -768,7 +768,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, else if (var->offset == sizeof(int)) sprintf(mallocedval, "'%c'", (*((int *) var->value)) ? 't' : 'f'); else - ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size"); + ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size", ECPG_COMPAT_PGSQL); } *tobeinserted_p = mallocedval; @@ -1021,7 +1021,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, default: /* Not implemented yet */ - ECPGraise(stmt->lineno, ECPG_UNSUPPORTED, (char *) ECPGtype_name(var->type)); + ECPGraise(stmt->lineno, ECPG_UNSUPPORTED, (char *) ECPGtype_name(var->type), ECPG_COMPAT_PGSQL); return false; break; } @@ -1073,7 +1073,7 @@ ECPGexecute(struct statement * stmt) * We have an argument but we dont have the matched up string * in the string */ - ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, NULL); + ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, NULL, stmt->compat); return false; } else @@ -1111,7 +1111,7 @@ ECPGexecute(struct statement * stmt) /* Check if there are unmatched things left. */ if (next_insert(copiedquery) != NULL) { - ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL); + ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL, stmt->compat); return false; } @@ -1121,7 +1121,7 @@ ECPGexecute(struct statement * stmt) { if ((results = PQexec(stmt->connection->connection, "begin transaction")) == NULL) { - ECPGraise(stmt->lineno, ECPG_TRANS, NULL); + ECPGraise(stmt->lineno, ECPG_TRANS, NULL, stmt->compat); return false; } PQclear(results); @@ -1136,7 +1136,7 @@ ECPGexecute(struct statement * stmt) { errmsg = PQerrorMessage(stmt->connection->connection); ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno, errmsg); - ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg); + ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg, stmt->compat); } else @@ -1167,7 +1167,7 @@ ECPGexecute(struct statement * stmt) if (ntuples) ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n", stmt->lineno, ntuples); - ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL); + ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL, stmt->compat); status = false; break; } @@ -1198,21 +1198,21 @@ ECPGexecute(struct statement * stmt) } else if (!INFORMIX_MODE(stmt->compat)) { - ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL); + ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL, stmt->compat); return (false); } } if (status && var != NULL) { - ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, NULL); + ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, NULL, stmt->compat); status = false; } break; case PGRES_EMPTY_QUERY: /* do nothing */ - ECPGraise(stmt->lineno, ECPG_EMPTY, NULL); + ECPGraise(stmt->lineno, ECPG_EMPTY, NULL, stmt->compat); break; case PGRES_COMMAND_OK: status = true; @@ -1225,13 +1225,13 @@ ECPGexecute(struct statement * stmt) ( !strncmp(cmdstat, "UPDATE", 6) || !strncmp(cmdstat, "INSERT", 6) || !strncmp(cmdstat, "DELETE", 6))) - ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL); + ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL, stmt->compat); break; case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: ECPGlog("ECPGexecute line %d: Error: %s", stmt->lineno, errmsg); - ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg); + ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg, stmt->compat); status = false; break; case PGRES_COPY_OUT: @@ -1245,7 +1245,7 @@ ECPGexecute(struct statement * stmt) default: ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n", stmt->lineno); - ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg); + ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg, stmt->compat); status = false; break; } @@ -1300,7 +1300,7 @@ ECPGdo(int lineno, int compat, int force_indicator, const char *connection_name, if (con == NULL || con->connection == NULL) { free_statement(stmt); - ECPGraise(lineno, ECPG_NOT_CONN, (con) ? con->name : ""); + ECPGraise(lineno, ECPG_NOT_CONN, (con) ? con->name : "", stmt->compat); setlocale(LC_NUMERIC, oldlocale); ECPGfree(oldlocale); return false; diff --git a/src/interfaces/ecpg/ecpglib/memory.c b/src/interfaces/ecpg/ecpglib/memory.c index 1a5de833d1c..0a77da4f095 100644 --- a/src/interfaces/ecpg/ecpglib/memory.c +++ b/src/interfaces/ecpg/ecpglib/memory.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/memory.c,v 1.2 2003/06/15 04:07:58 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/memory.c,v 1.3 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -21,7 +21,7 @@ ECPGalloc(long size, int lineno) if (!new) { - ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL); + ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL); return NULL; } @@ -36,7 +36,7 @@ ECPGrealloc(void *ptr, long size, int lineno) if (!new) { - ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL); + ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL); return NULL; } @@ -50,7 +50,7 @@ ECPGstrdup(const char *string, int lineno) if (!new) { - ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL); + ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL); return NULL; } diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index b9e0c35d0ca..4334844d61d 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.10 2003/07/17 07:54:29 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.11 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -103,7 +103,7 @@ ECPGinit(const struct connection * con, const char *connection_name, const int l ECPGinit_sqlca(sqlca); if (con == NULL) { - ECPGraise(lineno, ECPG_NO_CONN, connection_name ? connection_name : "NULL"); + ECPGraise(lineno, ECPG_NO_CONN, connection_name ? connection_name : "NULL", ECPG_COMPAT_PGSQL); return (false); } @@ -150,7 +150,7 @@ ECPGstatus(int lineno, const char *connection_name) /* are we connected? */ if (con->connection == NULL) { - ECPGraise(lineno, ECPG_NOT_CONN, con->name); + ECPGraise(lineno, ECPG_NOT_CONN, con->name, ECPG_COMPAT_PGSQL); return false; } @@ -179,7 +179,7 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction) { if ((res = PQexec(con->connection, transaction)) == NULL) { - ECPGraise(lineno, ECPG_TRANS, NULL); + ECPGraise(lineno, ECPG_TRANS, NULL, ECPG_COMPAT_PGSQL); return FALSE; } PQclear(res); diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c index 8b0d523c6a3..76c58d1238c 100644 --- a/src/interfaces/ecpg/ecpglib/prepare.c +++ b/src/interfaces/ecpg/ecpglib/prepare.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.6 2003/07/14 10:16:44 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.7 2003/08/01 08:21:04 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -120,7 +120,7 @@ ECPGdeallocate(int lineno, int c, char *name) } if (!ret) - ECPGraise(lineno, ECPG_INVALID_STMT, name); + ECPGraise(lineno, ECPG_INVALID_STMT, name, ECPG_COMPAT_PGSQL); return ret; } diff --git a/src/interfaces/ecpg/include/ecpgerrno.h b/src/interfaces/ecpg/include/ecpgerrno.h index b78ecc634cf..eb1936beb18 100644 --- a/src/interfaces/ecpg/include/ecpgerrno.h +++ b/src/interfaces/ecpg/include/ecpgerrno.h @@ -50,6 +50,11 @@ #define ECPG_DUPLICATE_KEY -403 #define ECPG_SUBSELECT_NOT_ONE -404 +/* for compatibility we define some different error codes for the same error + * if adding a new one make sure to not double define it */ +#define ECPG_INFORMIX_DUPLICATE_KEY -239 +#define ECPG_INFORMIX_SUBSELECT_NOT_ONE -284 + /* backend WARNINGs, starting at 600 */ #define ECPG_WARNING_UNRECOGNIZED -600 /* WARNING: (transaction aborted): queries ignored until END */ diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h index 66985bf3b60..e99c50bc866 100644 --- a/src/interfaces/ecpg/include/ecpglib.h +++ b/src/interfaces/ecpg/include/ecpglib.h @@ -71,7 +71,7 @@ bool ECPGdo_descriptor(int line, const char *connection, const char *descriptor, const char *query); bool ECPGdeallocate_desc(int line, const char *name); bool ECPGallocate_desc(int line, const char *name); -void ECPGraise(int line, int code, const char *str); +void ECPGraise(int line, int code, const char *str, int); bool ECPGget_desc_header(int, char *, int *); bool ECPGget_desc(int, char *, int,...); diff --git a/src/interfaces/ecpg/include/pgtypes_timestamp.h b/src/interfaces/ecpg/include/pgtypes_timestamp.h index 189d09a2d23..9294e1d77a0 100644 --- a/src/interfaces/ecpg/include/pgtypes_timestamp.h +++ b/src/interfaces/ecpg/include/pgtypes_timestamp.h @@ -17,6 +17,6 @@ extern char *PGTYPEStimestamp_to_asc(Timestamp); extern int PGTYPEStimestamp_sub (Timestamp *, Timestamp *, Interval *); extern int PGTYPEStimestamp_fmt_asc (Timestamp *, char *, int, char *); extern void PGTYPEStimestamp_current (Timestamp *); - +extern int PGTYPEStimestamp_defmt_asc(char *, char *, Timestamp *); #endif /* PGTYPES_TIMESTAMP */ diff --git a/src/interfaces/ecpg/pgtypeslib/common.c b/src/interfaces/ecpg/pgtypeslib/common.c index 03a45870c02..d1202eb59a1 100644 --- a/src/interfaces/ecpg/pgtypeslib/common.c +++ b/src/interfaces/ecpg/pgtypeslib/common.c @@ -28,33 +28,33 @@ pgtypes_strdup(char *str) } int -pgtypes_fmt_replace(union un_fmt_replace replace_val, int replace_type, char** output, int *pstr_len) { +pgtypes_fmt_replace(union un_fmt_comb replace_val, int replace_type, char** output, int *pstr_len) { /* general purpose variable, set to 0 in order to fix compiler * warning */ int i = 0; switch(replace_type) { - case PGTYPES_REPLACE_NOTHING: + case PGTYPES_TYPE_NOTHING: break; - case PGTYPES_REPLACE_STRING_CONSTANT: - case PGTYPES_REPLACE_STRING_MALLOCED: - i = strlen(replace_val.replace_str); + case PGTYPES_TYPE_STRING_CONSTANT: + case PGTYPES_TYPE_STRING_MALLOCED: + i = strlen(replace_val.str_val); if (i + 1 <= *pstr_len) { /* copy over i + 1 bytes, that includes the * tailing terminator */ - strncpy(*output, replace_val.replace_str, i + 1); + strncpy(*output, replace_val.str_val, i + 1); *pstr_len -= i; *output += i; - if (replace_type == PGTYPES_REPLACE_STRING_MALLOCED) { - free(replace_val.replace_str); + if (replace_type == PGTYPES_TYPE_STRING_MALLOCED) { + free(replace_val.str_val); } return 0; } else { return -1; } break; - case PGTYPES_REPLACE_CHAR: + case PGTYPES_TYPE_CHAR: if (*pstr_len >= 2) { - (*output)[0] = replace_val.replace_char; + (*output)[0] = replace_val.char_val; (*output)[1] = '\0'; (*pstr_len)--; (*output)++; @@ -63,48 +63,48 @@ pgtypes_fmt_replace(union un_fmt_replace replace_val, int replace_type, char** o return -1; } break; - case PGTYPES_REPLACE_DOUBLE_NF: - case PGTYPES_REPLACE_INT64: - case PGTYPES_REPLACE_UINT: - case PGTYPES_REPLACE_UINT_2_LZ: - case PGTYPES_REPLACE_UINT_2_LS: - case PGTYPES_REPLACE_UINT_3_LZ: - case PGTYPES_REPLACE_UINT_4_LZ: + case PGTYPES_TYPE_DOUBLE_NF: + case PGTYPES_TYPE_INT64: + case PGTYPES_TYPE_UINT: + case PGTYPES_TYPE_UINT_2_LZ: + case PGTYPES_TYPE_UINT_2_LS: + case PGTYPES_TYPE_UINT_3_LZ: + case PGTYPES_TYPE_UINT_4_LZ: { char* t = pgtypes_alloc(PGTYPES_FMT_NUM_MAX_DIGITS); if (!t) { return ENOMEM; } switch (replace_type) { - case PGTYPES_REPLACE_DOUBLE_NF: + case PGTYPES_TYPE_DOUBLE_NF: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, - "%0.0g", replace_val.replace_double); + "%0.0g", replace_val.double_val); break; #ifdef HAVE_INT6 - case PGTYPES_REPLACE_INT64: + case PGTYPES_TYPE_INT64: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, INT64_FORMAT, replace_val.replace_int64); break; #endif - case PGTYPES_REPLACE_UINT: + case PGTYPES_TYPE_UINT: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, - "%u", replace_val.replace_uint); + "%u", replace_val.uint_val); break; - case PGTYPES_REPLACE_UINT_2_LZ: + case PGTYPES_TYPE_UINT_2_LZ: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, - "%02u", replace_val.replace_uint); + "%02u", replace_val.uint_val); break; - case PGTYPES_REPLACE_UINT_2_LS: + case PGTYPES_TYPE_UINT_2_LS: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, - "%2u", replace_val.replace_uint); + "%2u", replace_val.uint_val); break; - case PGTYPES_REPLACE_UINT_3_LZ: + case PGTYPES_TYPE_UINT_3_LZ: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, - "%03u", replace_val.replace_uint); + "%03u", replace_val.uint_val); break; - case PGTYPES_REPLACE_UINT_4_LZ: + case PGTYPES_TYPE_UINT_4_LZ: i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS, - "%04u", replace_val.replace_uint); + "%04u", replace_val.uint_val); break; } diff --git a/src/interfaces/ecpg/pgtypeslib/datetime.c b/src/interfaces/ecpg/pgtypeslib/datetime.c index 26afea2c646..789f8400fa7 100644 --- a/src/interfaces/ecpg/pgtypeslib/datetime.c +++ b/src/interfaces/ecpg/pgtypeslib/datetime.c @@ -168,10 +168,7 @@ PGTYPESdate_fmt_asc(Date dDate, char* fmtstring, char* outbuf) { { NULL, 0 } }; - union { - char* replace_str; - unsigned int replace_uint; - } replace_val; + union un_fmt_comb replace_val; int replace_type; int i; @@ -191,76 +188,76 @@ PGTYPESdate_fmt_asc(Date dDate, char* fmtstring, char* outbuf) { while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL) { switch(mapping[i].component) { case PGTYPES_FMTDATE_DOW_LITERAL_SHORT: - replace_val.replace_str = pgtypes_date_weekdays_short[dow]; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = pgtypes_date_weekdays_short[dow]; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case PGTYPES_FMTDATE_DAY_DIGITS_LZ: - replace_val.replace_uint = tm.tm_mday; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm.tm_mday; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT: - replace_val.replace_str = months[tm.tm_mon-1]; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = months[tm.tm_mon-1]; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case PGTYPES_FMTDATE_MONTH_DIGITS_LZ: - replace_val.replace_uint = tm.tm_mon; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm.tm_mon; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case PGTYPES_FMTDATE_YEAR_DIGITS_LONG: - replace_val.replace_uint = tm.tm_year; - replace_type = PGTYPES_REPLACE_UINT_4_LZ; + replace_val.uint_val = tm.tm_year; + replace_type = PGTYPES_TYPE_UINT_4_LZ; break; case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT: - replace_val.replace_uint = tm.tm_year % 1000; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm.tm_year % 1000; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; default: /* should not happen, set something * anyway */ - replace_val.replace_str = " "; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = " "; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; } switch(replace_type) { - case PGTYPES_REPLACE_STRING_MALLOCED: - case PGTYPES_REPLACE_STRING_CONSTANT: - strncpy(start_pattern, replace_val.replace_str, - strlen(replace_val.replace_str)); - if (replace_type == PGTYPES_REPLACE_STRING_MALLOCED) { - free(replace_val.replace_str); + case PGTYPES_TYPE_STRING_MALLOCED: + case PGTYPES_TYPE_STRING_CONSTANT: + strncpy(start_pattern, replace_val.str_val, + strlen(replace_val.str_val)); + if (replace_type == PGTYPES_TYPE_STRING_MALLOCED) { + free(replace_val.str_val); } break; - case PGTYPES_REPLACE_UINT: + case PGTYPES_TYPE_UINT: { char* t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); if (!t) { return -1; } snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, - "%u", replace_val.replace_uint); + "%u", replace_val.uint_val); strncpy(start_pattern, t, strlen(t)); free(t); } break; - case PGTYPES_REPLACE_UINT_2_LZ: + case PGTYPES_TYPE_UINT_2_LZ: { char* t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); if (!t) { return -1; } snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, - "%02u", replace_val.replace_uint); + "%02u", replace_val.uint_val); strncpy(start_pattern, t, strlen(t)); free(t); } break; - case PGTYPES_REPLACE_UINT_4_LZ: + case PGTYPES_TYPE_UINT_4_LZ: { char* t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); if (!t) { return -1; } snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, - "%04u", replace_val.replace_uint); + "%04u", replace_val.uint_val); strncpy(start_pattern, t, strlen(t)); free(t); } @@ -268,7 +265,7 @@ PGTYPESdate_fmt_asc(Date dDate, char* fmtstring, char* outbuf) { default: /* doesn't happen (we set * replace_type to - * PGTYPES_REPLACE_STRING_CONSTANT + * PGTYPES_TYPE_STRING_CONSTANT * in case of an error above) */ break; } diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c index 8d41d6f1e03..98761f59414 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt_common.c +++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c @@ -6,6 +6,7 @@ #include "extern.h" #include "dt.h" +#include "pgtypes_timestamp.h" static int day_tab[2][13] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, @@ -13,6 +14,8 @@ static int day_tab[2][13] = { typedef long AbsoluteTime; +int tm2timestamp(struct tm *, fsec_t, int *, Timestamp *); + #define ABS_SIGNBIT ((char) 0200) #define POS(n) (n) #define NEG(n) ((n)|ABS_SIGNBIT) @@ -2559,3 +2562,505 @@ DecodeDateTime(char **field, int *ftype, int nf, return 0; } /* DecodeDateTime() */ +/* Function works as follows: + * + * + * */ + +static char* find_end_token(char* str, char* fmt) { + /* str: here is28the day12the hour + * fmt: here is%dthe day%hthe hour + * + * we extract the 28, we read the percent sign and the type "d" + * then this functions gets called as + * find_end_token("28the day12the hour", "the day%hthehour") + * + * fmt points to "the day%hthehour", next_percent points to + * %hthehour and we have to find a match for everything between + * these positions ("the day"). We look for "the day" in str and + * know that the pattern we are about to scan ends where this string + * starts (right after the "28") + * + * At the end, *fmt is '\0' and *str isn't. end_position then is + * unchanged. + */ + char* end_position = NULL; + char* next_percent, *subst_location = NULL; + int scan_offset = 0; + char last_char; + + /* are we at the end? */ + if (!*fmt) { + end_position = fmt; + return end_position; + } + + /* not at the end */ + while (fmt[scan_offset] == '%' && fmt[scan_offset+1]) { + /* there is no delimiter, skip to the next delimiter + * if we're reading a number and then something that is not + * a number "9:15pm", we might be able to recover with the + * strtol end pointer. Go for the next percent sign */ + scan_offset += 2; + } + next_percent = strchr(fmt+scan_offset, '%'); + if (next_percent) { + /* we don't want to allocate extra memory, so we temporarily + * set the '%' sign to '\0' and call strstr + * However since we allow whitespace to float around + * everything, we have to shorten the pattern until we reach + * a non-whitespace character */ + + subst_location = next_percent; + while(*(subst_location-1) == ' ' && subst_location-1 > fmt+scan_offset) { + subst_location--; + } + last_char = *subst_location; + *subst_location = '\0'; + + /* the haystack is the str and the needle is the original + * fmt but it ends at the position where the next percent + * sign would be */ + /* There is one special case. Imagine: + * str = " 2", fmt = "%d %...", + * since we want to allow blanks as "dynamic" padding we + * have to accept this. Now, we are called with a fmt of + * " %..." and look for " " in str. We find it at the first + * position and never read the 2... */ + while (*str == ' ') { str++; } + end_position = strstr(str, fmt+scan_offset); + *subst_location = last_char; + } else { + /* there is no other percent sign. So everything up to + * the end has to match. */ + end_position = str + strlen(str); + } + if (!end_position) { + /* maybe we have the following case: + * + * str = "4:15am" + * fmt = "%M:%S %p" + * + * at this place we could have + * + * str = "15am" + * fmt = " %p" + * + * and have set fmt to " " because overwrote the % sign with + * a NULL + * + * In this case where we would have to match a space but + * can't find it, set end_position to the end of the string */ + if ((fmt+scan_offset)[0] == ' ' && fmt+scan_offset+1 == subst_location) { + end_position = str + strlen(str); + } + } + return end_position; +} + +static int pgtypes_defmt_scan(union un_fmt_comb* scan_val, int scan_type, char** pstr, char* pfmt) { + /* scan everything between pstr and pstr_end. + * This is not including the last character so we might set it to + * '\0' for the parsing */ + + char last_char; + int err = 0; + char* pstr_end; + char* strtol_end = NULL; + + while (**pstr == ' ') { pstr++; } + pstr_end = find_end_token(*pstr, pfmt); + if (!pstr_end) { + /* there was an error, no match */ + err = 1; + return err; + } + last_char = *pstr_end; + *pstr_end = '\0'; + + switch(scan_type) { + case PGTYPES_TYPE_UINT: + /* numbers may be blank-padded, this is the only + * deviation from the fmt-string we accept */ + while (**pstr == ' ') { (*pstr)++; } + errno = 0; + scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10); + if (errno) { err = 1; } + break; + case PGTYPES_TYPE_UINT_LONG: + while (**pstr == ' ') { (*pstr)++; } + errno = 0; + scan_val->uint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10); + if (errno) { err = 1; } + break; + case PGTYPES_TYPE_STRING_MALLOCED: + if (pstr) { + scan_val->str_val = pgtypes_strdup(*pstr); + } + } + if (strtol_end && *strtol_end) { + *pstr = strtol_end; + } else { + *pstr = pstr_end; + } + *pstr_end = last_char; + return err; +} + +/* XXX range checking */ +int PGTYPEStimestamp_defmt_scan(char**, char*, Timestamp *, int*, int*, int*, + int*, int*, int*, int*); + +int PGTYPEStimestamp_defmt_scan(char** str, char* fmt, Timestamp *d, + int* year, int* month, int* day, + int* hour, int* minute, int* second, + int* tz) { + union un_fmt_comb scan_val; + int scan_type; + + char *pstr, *pfmt, *tmp; + int err = 1; + int j; + struct tm tm; + + pfmt = fmt; + pstr = *str; + + while (*pfmt) { + err = 0; + while (*pfmt == ' ') { pfmt++; } + while (*pstr == ' ') { pstr++; } + if (*pfmt != '%') { + if (*pfmt == *pstr) { + pfmt++; + pstr++; + } else { + /* XXX Error: no match */ + err = 1; + return err; + } + continue; + } + /* here *pfmt equals '%' */ + pfmt++; + switch(*pfmt) { + case 'a': + pfmt++; + /* we parse the day and see if it is a week + * day but we do not check if the week day + * really matches the date + * */ + err = 1; j = 0; + while(pgtypes_date_weekdays_short[j]) { + if (strncmp(pgtypes_date_weekdays_short[j], pstr, + strlen(pgtypes_date_weekdays_short[j])) == 0) { + /* found it */ + err = 0; + pstr += strlen(pgtypes_date_weekdays_short[j]); + break; + } + j++; + } + break; + case 'A': + /* see note above */ + pfmt++; + err = 1; j = 0; + while(days[j]) { + if (strncmp(days[j], pstr, strlen(days[j])) == 0) { + /* found it */ + err = 0; + pstr += strlen(days[j]); + break; + } + j++; + } + break; + case 'b': + case 'h': + pfmt++; + err = 1; j = 0; + while(months[j]) { + if (strncmp(months[j], pstr, strlen(months[j])) == 0) { + /* found it */ + err = 0; + pstr += strlen(months[j]); + *month = j+1; + break; + } + j++; + } + break; + case 'B': + /* see note above */ + pfmt++; + err = 1; j = 0; + while(pgtypes_date_months[j]) { + if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0) { + /* found it */ + err = 0; + pstr += strlen(pgtypes_date_months[j]); + *month = j+1; + break; + } + j++; + } + break; + case 'c': + /* XXX */ + break; + case 'C': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *year = scan_val.uint_val * 100; + break; + case 'd': + case 'e': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *day = scan_val.uint_val; + break; + case 'D': + /* we have to concatenate the strings in + * order to be able to find the end of the + * substitution */ + pfmt++; + tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1); + strcpy(tmp, "%m/%d/%y"); + strcat(tmp, pfmt); + err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); + free(tmp); + return err; + case 'm': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *month = scan_val.uint_val; + break; + case 'y': + case 'g': /* XXX difference to y (ISO) */ + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (*year < 0) { + /* not yet set */ + *year = scan_val.uint_val; + } else { + *year += scan_val.uint_val; + } + if (*year < 100) { *year += 1900; } + break; + case 'G': + /* XXX difference to %V (ISO) */ + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *year = scan_val.uint_val; + break; + case 'H': + case 'I': + case 'k': + case 'l': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *hour += scan_val.uint_val; + break; + case 'j': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + /* XXX what should we do with that? + * We could say that it's sufficient if we + * have the year and the day within the year + * to get at least a specific day. */ + break; + case 'M': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *minute = scan_val.uint_val; + break; + case 'n': + pfmt++; + if (*pstr == '\n') { pstr++; } else { err = 1; } + break; + case 'p': + err = 1; + pfmt++; + if (strncmp(pstr, "am", 2) == 0) { *hour += 0; err = 0; pstr += 2; } + if (strncmp(pstr, "a.m.", 4) == 0) { *hour += 0; err = 0; pstr += 4; } + if (strncmp(pstr, "pm", 2) == 0) { *hour += 12; err = 0; pstr += 2; } + if (strncmp(pstr, "p.m.", 4) == 0) { *hour += 12; err = 0; pstr += 4; } + break; + case 'P': + err = 1; + pfmt++; + if (strncmp(pstr, "AM", 2) == 0) { *hour += 0; err = 0; pstr += 2; } + if (strncmp(pstr, "A.M.", 4) == 0) { *hour += 0; err = 0; pstr += 4; } + if (strncmp(pstr, "PM", 2) == 0) { *hour += 12; err = 0; pstr += 2; } + if (strncmp(pstr, "P.M.", 4) == 0) { *hour += 12; err = 0; pstr += 4; } + break; + case 'r': + pfmt++; + tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1); + strcpy(tmp, "%I:%M:%S %p"); + strcat(tmp, pfmt); + err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); + free(tmp); + return err; + case 'R': + pfmt++; + tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1); + strcpy(tmp, "%H:%M"); + strcat(tmp, pfmt); + err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); + free(tmp); + return err; + case 's': + pfmt++; + scan_type = PGTYPES_TYPE_UINT_LONG; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + /* number of seconds in scan_val.luint_val */ + { + struct tm *tms; + time_t et = (time_t) scan_val.luint_val; + tms = gmtime(&et); + *year = tms->tm_year; + *month = tms->tm_mon; + *day = tms->tm_mday; + *hour = tms->tm_hour; + *minute = tms->tm_min; + *second = tms->tm_sec; + } + break; + case 'S': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *second = scan_val.uint_val; + break; + case 't': + pfmt++; + if (*pstr == '\t') { pstr++; } else { err = 1; } + break; + case 'T': + pfmt++; + tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1); + strcpy(tmp, "%H:%M:%S"); + strcat(tmp, pfmt); + err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); + free(tmp); + return err; + case 'u': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (scan_val.uint_val < 1 || scan_val.uint_val > 7) { err = 1; } + break; + case 'U': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (scan_val.uint_val < 0 || scan_val.uint_val > 53) { err = 1; } + break; + case 'V': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (scan_val.uint_val < 1 || scan_val.uint_val > 53) { err = 1; } + break; + case 'w': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (scan_val.uint_val < 0 || scan_val.uint_val > 6) { err = 1; } + break; + case 'W': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (scan_val.uint_val < 0 || scan_val.uint_val > 53) { err = 1; } + break; + case 'x': + case 'X': + /* XXX */ + break; + case 'Y': + pfmt++; + scan_type = PGTYPES_TYPE_UINT; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + *year = scan_val.uint_val; + break; + case 'z': + pfmt++; + scan_type = PGTYPES_TYPE_STRING_MALLOCED; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + if (!err) { + err = DecodeTimezone(scan_val.str_val, tz); + free(scan_val.str_val); + } + break; + case 'Z': + pfmt++; + scan_type = PGTYPES_TYPE_STRING_MALLOCED; + err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); + /* XXX use DecodeSpecial instead ? - it's + * declared static but the arrays as well. + * :-( */ + for (j = 0; !err && j < szdatetktbl; j++) { + if (strcasecmp(datetktbl[j].token, scan_val.str_val) == 0) { + /* tz calculates the offset + * for the seconds, the + * timezone value of the + * datetktbl table is in + * quarter hours */ + *tz = -15 * 60 * datetktbl[j].value; + break; + } + } + free(scan_val.str_val); + break; + case '+': + /* XXX */ + break; + case '%': + pfmt++; + if (*pstr == '%') { pstr++; } else { err = 1; } + break; + default: + err = 1; + } + } + if (!err) { + if (*second < 0) { *second = 0; } + if (*minute < 0) { *minute = 0; } + if (*hour < 0) { *hour = 0; } + if (*day < 0) { err = 1; *day = 1; } + if (*month < 0) { err = 1; *month = 1; } + if (*year < 0) { err = 1; *year = 1970; } + + if (*second > 59) { err = 1; *second = 0; } + if (*minute > 59) { err = 1; *minute = 0; } + if (*hour > 23) { err = 1; *hour = 0; } + if (*month > 12) { err = 1; *month = 1; } + if (*day > day_tab[isleap(*year)][*month-1]) { + *day = day_tab[isleap(*year)][*month-1]; + err = 1; + } + + tm.tm_sec = *second; + tm.tm_min = *minute; + tm.tm_hour = *hour; + tm.tm_mday = *day; + tm.tm_mon = *month; + tm.tm_year = *year; + + tm2timestamp(&tm, 0, tz, d); + } + return err; +} + +/* XXX: 1900 is compiled in as the base for years */ diff --git a/src/interfaces/ecpg/pgtypeslib/extern.h b/src/interfaces/ecpg/pgtypeslib/extern.h index 90125ffd452..8004e3d4216 100644 --- a/src/interfaces/ecpg/pgtypeslib/extern.h +++ b/src/interfaces/ecpg/pgtypeslib/extern.h @@ -5,32 +5,33 @@ /* These are the constants that decide which printf() format we'll use in * order to get a string representation of the value */ -#define PGTYPES_REPLACE_NOTHING 0 -#define PGTYPES_REPLACE_STRING_MALLOCED 1 -#define PGTYPES_REPLACE_STRING_CONSTANT 2 -#define PGTYPES_REPLACE_CHAR 3 -#define PGTYPES_REPLACE_DOUBLE_NF 4 /* no fractional part */ -#define PGTYPES_REPLACE_INT64 5 -#define PGTYPES_REPLACE_UINT 6 -#define PGTYPES_REPLACE_UINT_2_LZ 7 /* 2 digits, pad with leading zero */ -#define PGTYPES_REPLACE_UINT_2_LS 8 /* 2 digits, pad with leading space */ -#define PGTYPES_REPLACE_UINT_3_LZ 9 -#define PGTYPES_REPLACE_UINT_4_LZ 10 +#define PGTYPES_TYPE_NOTHING 0 +#define PGTYPES_TYPE_STRING_MALLOCED 1 +#define PGTYPES_TYPE_STRING_CONSTANT 2 +#define PGTYPES_TYPE_CHAR 3 +#define PGTYPES_TYPE_DOUBLE_NF 4 /* no fractional part */ +#define PGTYPES_TYPE_INT64 5 +#define PGTYPES_TYPE_UINT 6 +#define PGTYPES_TYPE_UINT_2_LZ 7 /* 2 digits, pad with leading zero */ +#define PGTYPES_TYPE_UINT_2_LS 8 /* 2 digits, pad with leading space */ +#define PGTYPES_TYPE_UINT_3_LZ 9 +#define PGTYPES_TYPE_UINT_4_LZ 10 +#define PGTYPES_TYPE_UINT_LONG 11 #define PGTYPES_FMT_NUM_MAX_DIGITS 40 -union un_fmt_replace { - char* replace_str; - unsigned int replace_uint; - char replace_char; - unsigned long int replace_luint; - double replace_double; +union un_fmt_comb { + char* str_val; + unsigned int uint_val; + char char_val; + unsigned long int luint_val; + double double_val; #ifdef HAVE_INT64_TIMESTAMP - int64 replace_int64; + int64 int64_val; #endif }; -int pgtypes_fmt_replace(union un_fmt_replace, int, char**, int*); +int pgtypes_fmt_replace(union un_fmt_comb, int, char**, int*); char *pgtypes_alloc(long); char *pgtypes_strdup(char *); diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c index 564e1f83c6b..a0b4626bf06 100644 --- a/src/interfaces/ecpg/pgtypeslib/timestamp.c +++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c @@ -13,6 +13,9 @@ #include "pgtypes_date.h" #include "datetime.h" +int PGTYPEStimestamp_defmt_scan(char**, char*, Timestamp *, int*, int*, int*, + int*, int*, int*, int*); + #ifdef HAVE_INT64_TIMESTAMP static int64 time2t(const int hour, const int min, const int sec, const fsec_t fsec) @@ -47,7 +50,7 @@ dt2local(Timestamp dt, int tz) * * Returns -1 on failure (overflow). */ -static int +int tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *result) { #ifdef HAVE_INT64_TIMESTAMP @@ -372,7 +375,7 @@ static int dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, char* output, int *pstr_len, char *fmtstr) { - union un_fmt_replace replace_val; + union un_fmt_comb replace_val; int replace_type; int i; char* p = fmtstr; @@ -382,35 +385,35 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, if (*p == '%') { p++; /* fix compiler warning */ - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; switch (*p) { case 'a': - replace_val.replace_str = pgtypes_date_weekdays_short[dow]; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = pgtypes_date_weekdays_short[dow]; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'A': - replace_val.replace_str = days[dow]; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = days[dow]; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'b': case 'h': - replace_val.replace_str = months[tm->tm_mon]; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = months[tm->tm_mon]; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'B': - replace_val.replace_str = pgtypes_date_months[tm->tm_mon]; - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_val.str_val = pgtypes_date_months[tm->tm_mon]; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'c': /* XXX */ break; case 'C': - replace_val.replace_uint = (tm->tm_year + 1900) / 100; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = (tm->tm_year + 1900) / 100; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'd': - replace_val.replace_uint = tm->tm_mday; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm->tm_mday; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'D': /* ts, dDate, dow, tm is @@ -428,8 +431,8 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, if (i) { return i; } break; case 'e': - replace_val.replace_uint = tm->tm_mday; - replace_type = PGTYPES_REPLACE_UINT_2_LS; + replace_val.uint_val = tm->tm_mday; + replace_type = PGTYPES_TYPE_UINT_2_LS; break; case 'E': { @@ -450,7 +453,7 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; } case 'G': @@ -463,7 +466,7 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case 'g': /* XXX: fall back to strftime */ @@ -478,56 +481,56 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; } break; case 'H': - replace_val.replace_uint = tm->tm_hour; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm->tm_hour; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'I': - replace_val.replace_uint = tm->tm_hour % 12; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm->tm_hour % 12; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'j': - replace_val.replace_uint = tm->tm_yday; - replace_type = PGTYPES_REPLACE_UINT_3_LZ; + replace_val.uint_val = tm->tm_yday; + replace_type = PGTYPES_TYPE_UINT_3_LZ; break; case 'k': - replace_val.replace_uint = tm->tm_hour; - replace_type = PGTYPES_REPLACE_UINT_2_LS; + replace_val.uint_val = tm->tm_hour; + replace_type = PGTYPES_TYPE_UINT_2_LS; break; case 'l': - replace_val.replace_uint = tm->tm_hour % 12; - replace_type = PGTYPES_REPLACE_UINT_2_LS; + replace_val.uint_val = tm->tm_hour % 12; + replace_type = PGTYPES_TYPE_UINT_2_LS; break; case 'm': - replace_val.replace_uint = tm->tm_mon; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm->tm_mon; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'M': - replace_val.replace_uint = tm->tm_min; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm->tm_min; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'n': - replace_val.replace_char = '\n'; - replace_type = PGTYPES_REPLACE_CHAR; + replace_val.char_val = '\n'; + replace_type = PGTYPES_TYPE_CHAR; break; case 'p': if (tm->tm_hour < 12) { - replace_val.replace_str = "AM"; + replace_val.str_val = "AM"; } else { - replace_val.replace_str = "PM"; + replace_val.str_val = "PM"; } - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'P': if (tm->tm_hour < 12) { - replace_val.replace_str = "am"; + replace_val.str_val = "am"; } else { - replace_val.replace_str = "pm"; + replace_val.str_val = "pm"; } - replace_type = PGTYPES_REPLACE_STRING_CONSTANT; + replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'r': i = dttofmtasc_replace(ts, dDate, dow, tm, @@ -544,19 +547,19 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, case 's': #ifdef HAVE_INT64_TIMESTAMP replace_val.replace_int64 = ((*ts - SetEpochTimestamp()) / 1000000e0); - replace_type = PGTYPES_REPLACE_INT64; + replace_type = PGTYPES_TYPE_INT64; #else - replace_val.replace_double = *ts - SetEpochTimestamp(); - replace_type = PGTYPES_REPLACE_DOUBLE_NF; + replace_val.double_val = *ts - SetEpochTimestamp(); + replace_type = PGTYPES_TYPE_DOUBLE_NF; #endif break; case 'S': - replace_val.replace_uint = tm->tm_sec; - replace_type = PGTYPES_REPLACE_UINT; + replace_val.uint_val = tm->tm_sec; + replace_type = PGTYPES_TYPE_UINT; break; case 't': - replace_val.replace_char = '\t'; - replace_type = PGTYPES_REPLACE_CHAR; + replace_val.char_val = '\t'; + replace_type = PGTYPES_TYPE_CHAR; break; case 'T': i = dttofmtasc_replace(ts, dDate, dow, tm, @@ -566,8 +569,8 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, break; case 'u': if (dow == 0) { dow = 7; } - replace_val.replace_uint = dow; - replace_type = PGTYPES_REPLACE_UINT; + replace_val.uint_val = dow; + replace_type = PGTYPES_TYPE_UINT; break; case 'U': /* XXX: fall back to strftime */ @@ -579,7 +582,7 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case 'V': /* XXX: fall back to strftime */ @@ -589,11 +592,11 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, q++; (*pstr_len)--; } - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case 'w': - replace_val.replace_uint = dow; - replace_type = PGTYPES_REPLACE_UINT; + replace_val.uint_val = dow; + replace_type = PGTYPES_TYPE_UINT; break; case 'W': /* XXX: fall back to strftime */ @@ -605,7 +608,7 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case 'x': /* XXX: fall back to strftime */ @@ -620,7 +623,7 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; } break; case 'X': @@ -633,15 +636,15 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case 'y': - replace_val.replace_uint = tm->tm_year % 100; - replace_type = PGTYPES_REPLACE_UINT_2_LZ; + replace_val.uint_val = tm->tm_year % 100; + replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'Y': - replace_val.replace_uint = tm->tm_year + 1900; - replace_type = PGTYPES_REPLACE_UINT; + replace_val.uint_val = tm->tm_year + 1900; + replace_type = PGTYPES_TYPE_UINT; break; case 'z': /* XXX: fall back to strftime */ @@ -653,7 +656,7 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case 'Z': /* XXX: fall back to strftime */ @@ -665,11 +668,11 @@ dttofmtasc_replace (Timestamp *ts, Date dDate, int dow, struct tm* tm, (*pstr_len)--; } tm->tm_mon += 1; - replace_type = PGTYPES_REPLACE_NOTHING; + replace_type = PGTYPES_TYPE_NOTHING; break; case '%': - replace_val.replace_char = '%'; - replace_type = PGTYPES_REPLACE_CHAR; + replace_val.char_val = '%'; + replace_type = PGTYPES_TYPE_CHAR; break; case '\0': /* fmtstr: blabla%' */ @@ -749,3 +752,33 @@ PGTYPEStimestamp_sub (Timestamp *ts1, Timestamp *ts2, Interval *iv) return 0; } +int PGTYPEStimestamp_defmt_asc(char* str, char *fmt, Timestamp *d) { + int year, month, day; + int hour, minute, second; + int tz; + + int i; + char* mstr; + char* mfmt; + + if (!fmt) { + fmt = "%Y-%m-%d %H:%M:%S"; + } + if (!fmt[0]) { + return 1; + } + + mstr = pgtypes_strdup(str); + mfmt = pgtypes_strdup(fmt); + /* initialize with impossible values so that we can see if the + * fields where specified at all */ + /* XXX ambiguity with 1 BC for year? */ + year = -1; month = -1; day = -1; hour = 0; minute = -1; second = -1; + tz = 0; + + i = PGTYPEStimestamp_defmt_scan(&mstr, mfmt, d, &year, &month, &day, &hour, &minute, &second, &tz); + free(mstr); + free(mfmt); + return i; +} + diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index 42f278057ce..fb0f6dcb859 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.75 2003/06/26 11:37:05 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.76 2003/08/01 08:21:04 meskes Exp $ */ /* New main for ecpg, the PostgreSQL embedded SQL precompiler. */ /* (C) Michael Meskes Feb 5th, 1998 */ @@ -382,11 +382,13 @@ main(int argc, char *const argv[]) lex_init(); /* we need several includes */ - fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/* These four include files are added by the preprocessor */\n#include \n#include \n#include \n#include \n#line 1 \"%s\"\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL, input_filename); + fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/* These include files are added by the preprocessor */\n#include \n#include \n#include \n#include \n#line 1 \"%s\"\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL, input_filename); /* add some compatibility headers */ if (INFORMIX_MODE) fprintf(yyout, "/* Needed for informix compatibility */\n#include \n"); + + fprintf(yyout, "/* End of automatic include section */\n"); /* and parse the source */ yyparse(); diff --git a/src/interfaces/ecpg/test/dt_test.pgc b/src/interfaces/ecpg/test/dt_test.pgc index ef8ebbca126..df6edc30a82 100644 --- a/src/interfaces/ecpg/test/dt_test.pgc +++ b/src/interfaces/ecpg/test/dt_test.pgc @@ -19,7 +19,7 @@ main() char *fmt, *out, *in; char *d1 = "Mon Jan 17 1966"; char *t1 = "2000-7-12 17:34:29"; - + int i; FILE *dbgs; if ((dbgs = fopen("log", "w")) != NULL) @@ -71,7 +71,7 @@ main() printf("Today in format \"%s\" is \"%s\"\n", fmt, out); free(out); - /* rdefmtdate() */ + /* rdate_defmt_asc() */ date1 = 0; text = ""; fmt = "yy/mm/dd"; @@ -81,78 +81,232 @@ main() */ PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate1: %s\n", text); + printf("date_defmt_asc1: %s\n", text); date1 = 0; text = ""; fmt = "mmmm. dd. yyyy"; in = "12/25/95"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate2: %s\n", text); + printf("date_defmt_asc2: %s\n", text); date1 = 0; text = ""; fmt = "yy/mm/dd"; in = "95/12/25"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate3: %s\n", text); + printf("date_defmt_asc3: %s\n", text); date1 = 0; text = ""; fmt = "yy/mm/dd"; in = "1995, December 25th"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate4: %s\n", text); + printf("date_defmt_asc4: %s\n", text); date1 = 0; text = ""; fmt = "dd-mm-yy"; in = "This is 25th day of December, 1995"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate5: %s\n", text); + printf("date_defmt_asc5: %s\n", text); date1 = 0; text = ""; fmt = "mmddyy"; in = "Dec. 25th, 1995"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate6: %s\n", text); + printf("date_defmt_asc6: %s\n", text); date1 = 0; text = ""; fmt = "mmm. dd. yyyy"; in = "dec 25th 1995"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate7: %s\n", text); + printf("date_defmt_asc7: %s\n", text); date1 = 0; text = ""; fmt = "mmm. dd. yyyy"; in = "DEC-25-1995"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate8: %s\n", text); + printf("date_defmt_asc8: %s\n", text); date1 = 0; text = ""; fmt = "mm yy dd."; in = "12199525"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate9: %s\n", text); + printf("date_defmt_asc9: %s\n", text); date1 = 0; text = ""; fmt = "yyyy fierj mm dd."; in = "19951225"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate10: %s\n", text); + printf("date_defmt_asc10: %s\n", text); date1 = 0; text = ""; fmt = "mm/dd/yy"; in = "122595"; PGTYPESdate_defmt_asc(&date1, fmt, in); text = PGTYPESdate_to_asc(date1); - printf("defmtdate12: %s\n", text); + printf("date_defmt_asc12: %s\n", text); + PGTYPEStimestamp_current(&ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_current: Now: %s\n", text); + + ts1 = PGTYPEStimestamp_from_asc("96-02-29", NULL); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_to_asc1: %s\n", text); + + ts1 = PGTYPEStimestamp_from_asc("1994-02-11 3:10:35", NULL); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_to_asc2: %s\n", text); + + ts1 = PGTYPEStimestamp_from_asc("1994-02-11 26:10:35", NULL); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_to_asc3: %s\n", text); + +/* abc-03:10:35-def-02/11/94-gh */ +/* 12345678901234567890123456789 */ + + out = (char*) malloc(32); + i = PGTYPEStimestamp_fmt_asc(&ts1, out, 31, "abc-%X-def-%x-ghi%%"); + printf("timestamp_fmt_asc: %d: %s\n", i, out); + + fmt = "This is a %m/%d/%y %H-%Ml%Stest"; + in = "This is a 4/12/80 3-39l12test"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%a %b %d %H:%M:%S %z %Y"; + in = "Tue Jul 22 17:28:44 +0200 2003"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%a %b %d %H:%M:%S %z %Y"; + in = "Tue Feb 29 17:28:44 +0200 2000"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%a %b %d %H:%M:%S %z %Y"; + in = "Tue Feb 29 17:28:44 +0200 1900"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = "%a %b %d %H:%M:%S %z %Y"; + in = "Tue Feb 29 17:28:44 +0200 1996"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%b %d %H:%M:%S %z %Y"; + in = " Jul 31 17:28:44 +0200 1996"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%b %d %H:%M:%S %z %Y"; + in = " Jul 32 17:28:44 +0200 1996"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = "%a %b %d %H:%M:%S %z %Y"; + in = "Tue Feb 29 17:28:44 +0200 1997"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = "%"; + in = "Tue Jul 22 17:28:44 +0200 2003"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = "a %"; + in = "Tue Jul 22 17:28:44 +0200 2003"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = "%b, %d %H_%M`%S %z %Y"; + in = " Jul, 22 17_28 `44 +0200 2003 "; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%a %b %%%d %H:%M:%S %Z %Y"; + in = "Tue Jul %22 17:28:44 CEST 2003"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%a %b %%%d %H:%M:%S %Z %Y"; + in = "Tue Jul %22 17:28:44 CEST 2003"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "abc%n %C %B %%%d %H:%M:%S %Z %Y"; + in = "abc\n 19 October %22 17:28:44 CEST 2003"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "abc%n %C %B %%%d %H:%M:%S %Z %y"; + in = "abc\n 18 October %34 17:28:44 CEST 80"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = ""; + in = "abc\n 18 October %34 17:28:44 CEST 80"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i); + + fmt = NULL; + in = "1980-04-12 3:49:44 "; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + fmt = "%B %d, %Y. Time: %I:%M%p"; + in = "July 14, 1988. Time: 9:15am"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + in = "September 6 at 01:30 pm in the year 1983"; + fmt = "%B %d at %I:%M %p in the year %Y"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + in = " 1976, July 14. Time: 9:15am"; + fmt = "%Y, %B %d. Time: %I:%M %p"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + in = " 1976, July 14. Time: 9:15 am"; + fmt = "%Y, %B %d. Time: %I:%M%p"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); + + in = " 1976, P.M. July 14. Time: 9:15"; + fmt = "%Y, %P %B %d. Time: %I:%M"; + i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); + text = PGTYPEStimestamp_to_asc(ts1); + printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); exec sql rollback; exec sql disconnect;