Skip to content

Commit

Permalink
Correct a problem where SELECT operations returning bytearrays yield …
Browse files Browse the repository at this point in the history
…corrupted data from PostgreSQL servers at version 9.0 and beyond.
  • Loading branch information
kennykb committed Jul 13, 2012
1 parent 29fc64f commit 5948b86
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
8 changes: 8 additions & 0 deletions tdbcpostgres/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
2012-07-13 Kevin B. Kenny <[email protected]>

* generic/tdbcpostgres.c: Corrected a problem where PostgreSQL 9.0
and beyond return byte arrays in an
incompatible format, yielding silent
data corruption in SELECT operations.
(Bug [4357c31d89])

2012-07-10 Kevin B. Kenny <[email protected]>

* generic/tdbcpostgres.c: Fixed a non-static table argument to
Expand Down
70 changes: 70 additions & 0 deletions tdbcpostgres/generic/tdbcpostgres.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ enum IsolationLevel {

/* Static functions defined within this file */

static int DeterminePostgresMajorVersion(Tcl_Interp* interp,
ConnectionData* cdata,
int* versionPtr);
static void DummyNoticeProcessor(void*, const PGresult*);
static int ExecSimpleQuery(Tcl_Interp* interp, PGconn * pgPtr,
const char * query, PGresult** resOut);
Expand Down Expand Up @@ -846,6 +849,53 @@ static int TransferResultError(
}
}

/*
*-----------------------------------------------------------------------------
*
* DeterminePostgresMajorVersion --
*
* Determine the major version of the PostgreSQL server at the
* other end of a connection.
*
* Results:
* Returns a standard Tcl error code.
*
* Side effects:
* Stores the version number in '*versionPtr' if successful.
*
*-----------------------------------------------------------------------------
*/

static int
DeterminePostgresMajorVersion(Tcl_Interp* interp,
/* Tcl interpreter */
ConnectionData* cdata,
/* Connection data */
int* versionPtr)
/* OUTPUT: PostgreSQL server version */
{
PGresult* res; /* Result of a Postgres query */
int status = TCL_ERROR; /* Status return */
char* versionStr; /* Version information from server */

if (ExecSimpleQuery(interp, cdata->pgPtr,
"SELECT version()", &res) == TCL_OK) {
versionStr = PQgetvalue(res, 0, 0);
if (sscanf(versionStr, " PostgreSQL %d", versionPtr) == 1) {
status = TCL_OK;
} else {
Tcl_Obj* result = Tcl_NewStringObj("unable to parse PostgreSQL "
"version: \"", -1);
Tcl_AppendToObj(result, versionStr, -1);
Tcl_AppendToObj(result, "\"", -1);
Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY000",
"POSTGRES", "-1", NULL);
}
PQclear(res);
}
return status;
}

/*
*-----------------------------------------------------------------------------
*
Expand Down Expand Up @@ -991,6 +1041,7 @@ ConfigureConnection(

Tcl_Obj* retval;
Tcl_Obj* optval;
int vers; /* PostgreSQL major version */

if (cdata->pgPtr != NULL) {

Expand Down Expand Up @@ -1176,6 +1227,25 @@ ConfigureConnection(
}
cdata->readOnly = readOnly;
}

/* Determine the PostgreSQL version in use */

if (DeterminePostgresMajorVersion(interp, cdata, &vers) != TCL_OK) {
return TCL_ERROR;
}

/*
* On PostgreSQL 9.0 and later, change 'bytea_output' to the
* backward-compatible 'escape' setting, so that the code in
* ResultSetNextrowMethod will retrieve byte array values correctly
* on either 8.x or 9.x servers.
*/
if (vers >= 9) {
if (ExecSimpleQuery(interp, cdata->pgPtr,
"SET bytea_output = 'escape'", NULL) != TCL_OK) {
return TCL_ERROR;
}
}
return TCL_OK;
}

Expand Down

0 comments on commit 5948b86

Please sign in to comment.