Monday, October 25, 2010

Making Slony source compatible with EnterpriseDB Advanced Server

Since, edb-replication which comes with advanced Server is more compactly build with one particular version, therefore some times user does not able to replicate the data between two different version of Advanced Servers.

For replicating data between two advanced Server versions, it is important to have same version of Slony on Source and target database.

I did research around the slony source code and tried to make it compatible with Advanced Server.

If user plainly comile the slony source code against the Advanced Server database, then user will start to get messages like : version/ while configuring the Replication.

Reason for such messages is that slony did not able to parse the Advanced Server version, therefore it would not be able to continue further for replication.

I did some research and gone through the slony source code.
Slony uses a program called dbutil*.c for finding the version of PostgreSQL or checking the compatibility of PostgreSQL version with Slony.

Following are the main programs which calls the dbutil*.c
1. slon
2. slonik

Following are the changes if user makes in slony source code then user would be able to compile the source code against the Advanced Server different versions for replication:
Changes which is require are given below:
File: src/slon/dbutils.c 

static int db_get_version(PGconn *conn)
{
 PGresult    *res;
 SlonDString query;
 char     versionstr[7];
 int     version=0;
 int     major=0;
 int     minor=0;
 int     patch=0;
 dstring_init(&query);
 slon_mkquery(&query, "SELECT version();");
 res = PQexec(conn, dstring_data(&query));

 if ( !res || PQresultStatus(res) != PGRES_TUPLES_OK )
        {
  PQclear(res);
  return -1;
 }
 if (sscanf(PQgetvalue(res, 0, 0), "PostgreSQL %d.%d.%d", &major, &minor, &patch) < 2)
 {
  PQclear(res);
  return -1;
 }
 PQclear(res);
 snprintf(versionstr, 7, "%.2d%.2d%.2d", major, minor, patch);
 version=atoi(versionstr);
 dstring_free(&query);
 return version;
}
Replace the above function with following function:
static int db_get_version(PGconn *conn)
{
 PGresult    *res;
 SlonDString query;
 char     versionstr[7];
 int     version=0;
 int     major=0;
 int     minor=0;
 int     patch=0;
 int     dummy=0;
 dstring_init(&query);
 slon_mkquery(&query, "SELECT version();");
 res = PQexec(conn, dstring_data(&query));

 if ( !res || PQresultStatus(res) != PGRES_TUPLES_OK )
        {
  PQclear(res);
  return -1;
 }
 if (sscanf(PQgetvalue(res, 0, 0), "EnterpriseDB %d.%d.%d.%d", &major, &minor, &patch, &dummy) < 2)
 {
  PQclear(res);
  return -1;
 }
 PQclear(res);
 snprintf(versionstr, 7, "%.2d%.2d%.2d", major, minor, patch);
 version=atoi(versionstr);
 dstring_free(&query);
 return version;
}
File:src/slonik/dbutils.c

db_get_version(SlonikStmt * stmt, SlonikAdmInfo * adminfo)
{
 PGresult   *res;
 SlonDString query;
 char        versionstr[7];
 int     major=0;
 int     minor=0;
 int         patch=0;
 int         version=0;

 if (db_begin_xact(stmt, adminfo) < 0)
  return -1;

 dstring_init(&query);
 slon_mkquery(&query, "select version();");
 res = db_exec_select(stmt, adminfo, &query);
 dstring_free(&query);

 if (res == NULL)
  return -1;

 if (sscanf(PQgetvalue(res, 0, 0), "PostgreSQL %d.%d.%d", &major, &minor, &patch) < 2)
 {
  fprintf(stderr, "%s:%d: failed to parse %s for DB version\n",
    stmt->stmt_filename, stmt->stmt_lno,
    PQgetvalue(res, 0, 0));
  PQclear(res);
  return -1;
 }
 PQclear(res);
 snprintf(versionstr, 7, "%.2d%.2d%.2d", major, minor, patch);
 version=atoi(versionstr);
 return version;
}
Replace Above function with Following function:
db_get_version(SlonikStmt * stmt, SlonikAdmInfo * adminfo)
{
 PGresult   *res;
 SlonDString query;
 char        versionstr[7];
 int     major=0;
 int     minor=0;
 int         patch=0;
 int         version=0;
 int      dummy=0;

 if (db_begin_xact(stmt, adminfo) < 0)
  return -1;

 dstring_init(&query);
 slon_mkquery(&query, "select version();");
 res = db_exec_select(stmt, adminfo, &query);
 dstring_free(&query);

 if (res == NULL)
  return -1;

 if (sscanf(PQgetvalue(res, 0, 0), "EnterpriseDB %d.%d.%d.%d", &major, &minor, &patch, &dummy) < 2)
 {
  fprintf(stderr, "%s:%d: failed to parse %s for DB version\n",
    stmt->stmt_filename, stmt->stmt_lno,
    PQgetvalue(res, 0, 0));
  PQclear(res);
  return -1;
 }
 PQclear(res);
 snprintf(versionstr, 7, "%.2d%.2d%.2d", major, minor, patch);
 version=atoi(versionstr);
 return version;
}

Now, if you have made the above changes you would be able to compile the slony with advanced Server and would be able to use the slony. Please Note:: I have tested above changes with Slony version 1.2.21 for replicating data between databases of version "EnterpriseDB 8.3.0.112" and EnterpriseDB 8.4.5.16

Interesting !! :)

No comments:

Post a Comment