dbconn.cc

00001 #include <cstdio>
00002 #include <cstddef>
00003 #include <cstdlib>
00004 #include <iostream>
00005 #include <cassert>
00006 #include <cctype>
00007 #include "dbconn.h"
00008 #ifdef HAVE_GEOS
00009 #ifndef GEOS_VERSION_MAJOR
00010 #include <geos_c.h>
00011 #endif
00012 #endif
00013 
00014 using namespace std;
00015 
00016 bool PostgresConn::Connect(const char* dbname, const char* host, const char* user, const char* password, const char* port)
00017 {
00018   conn = PQsetdbLogin(host, port, NULL, NULL, dbname, user, password);
00019   return (PQstatus(conn) != CONNECTION_BAD);
00020 }
00021 
00022 bool PostgresConn::Disconnect()
00023 {
00024   PQfinish(conn);
00025   conn = NULL;
00026   //return (PQstatus(conn) == CONNECTION_BAD);
00027   return true;
00028 }
00029 
00030 uint32_t PostgresConn::Text2Bin(const char * text, unsigned char * bin, uint32_t maxlen)
00031 {
00032     char numbuff[5];
00033     uint32_t i;
00034 
00035     for (i = 0; i < maxlen; i++)
00036     {
00037         if (!(text[0])) break;
00038         strcpy(numbuff, "0x");
00039         strncat(numbuff, text, 2);
00040         bin[i] = strtoul(numbuff, NULL, 0);
00041         text += 2;
00042     }
00043     return i;
00044 }
00045 
00046 VectorMapInfoHolder PostgresConn::GetVectorMapInfo(vector<string> layerNames)
00047 {
00048   // Get the extent in the first query
00049   string query_string = "SELECT GeometryFromText(astext(extent(geom))) FROM (SELECT geom FROM ";
00050 
00051   for (uint32_t ii=0; ii<layerNames.size(); ++ii)
00052   {
00053     if (ii == 0)
00054     {
00055       query_string += layerNames[ii];
00056     }
00057     else
00058     {
00059       query_string += " UNION SELECT geom FROM " + string(layerNames[ii]);
00060     }
00061   }
00062   query_string += ") AS layer_extent;";
00063 
00064   PGresult * res = PQexec(conn, query_string.c_str());
00065 
00066   if (PQresultStatus(res) != PGRES_TUPLES_OK)
00067   {
00068     cerr << "Error performing select query on database!" << endl;
00069     cerr << "No extent value found." << endl;
00070     cerr << "GetVectorMapInfo() failed" << endl;
00071   }
00072  
00073   uint32_t length = PQgetlength(res, 0, 0);
00074   uint8_t * wkb = new uint8_t[length];
00075   assert(wkb);
00076   length = Text2Bin(PQgetvalue(res, 0, 0), wkb, length);
00077   BoundingBox extent = BinaryToBBox(wkb, length);
00078   delete []wkb;
00079   PQclear(res);
00080 
00081   // Get the srid in the second query
00082   res = PQexec(conn, "SELECT srid FROM geometry_columns LIMIT 1;");
00083   if (PQresultStatus(res) != PGRES_TUPLES_OK)
00084   {
00085     cerr << "Error performing select query on database!" << endl;
00086     cerr << "No srid value found." << endl;
00087     cerr << "GetVectorMapInfo() failed" << endl;
00088   }
00089 
00090   uint32_t srid = atoi(PQgetvalue(res, 0, 0));
00091   PQclear(res);
00092 
00093   VectorMapInfoHolder info(srid, extent);
00094   for (uint32_t i=0; i<layerNames.size(); ++i)
00095   {
00096     info.layers.push_back(GetLayerInfo(layerNames[i].c_str()));
00097   }
00098 
00099   return info;
00100 }
00101 
00102 LayerInfoHolder PostgresConn::GetLayerInfo(const char* layer_name)
00103 {
00104   LayerInfoHolder info;
00105 
00106   // Retrieve the extent of the layer in binary form
00107   const char* query_template = "SELECT GeometryFromText(astext(extent(geom))) AS extent FROM %s;";
00108 
00109   char query_string[MAX_PSQL_STRING];
00110   memset(query_string, 0, MAX_PSQL_STRING);
00111   snprintf(query_string, MAX_PSQL_STRING, query_template, layer_name);
00112 
00113   PGresult* res = PQexec(conn, query_string);
00114 
00115   if (PQresultStatus(res) != PGRES_TUPLES_OK)
00116   {
00117     cerr << "Error performing select query on database!" << endl;
00118     cerr << "GetLayerInfo() failed" << endl;
00119   }
00120 
00121   info.name = layer_name;
00122 
00123   uint32_t length = PQgetlength(res, 0, 0);
00124   uint8_t * wkb = new uint8_t[length];
00125   assert(wkb);
00126   length = Text2Bin(PQgetvalue(res, 0, 0), wkb, length);
00127   info.extent = BinaryToBBox(wkb, length);
00128   delete []wkb;
00129 
00130   PQclear(res);
00131 
00132   return info;
00133 }
00134 
00135 LayerDataHolder PostgresConn::GetLayerData(const char* layer_name)
00136 {
00137   // Split into two queries. First get the layer meta-data, then get the feature data.
00138   // need to get layer name count, layer name, feature count and exteny
00139   LayerDataHolder data;
00140 
00141   // need to get name count, name, wkb count, wkb
00142   const char* template_data = "SELECT name, geom, attrib FROM %s ORDER BY id;";
00143   char query_data[MAX_PSQL_STRING];
00144   memset(query_data, 0, sizeof(MAX_PSQL_STRING));
00145   snprintf(query_data, MAX_PSQL_STRING, template_data, layer_name);
00146 
00147   PGresult* res = PQexec(conn, query_data);
00148 
00149   if (PQresultStatus(res) != PGRES_TUPLES_OK)
00150   {
00151     cerr << "Error performing select query on database!" << endl;
00152     cerr << "GetLayerData() data failed, returned NULL" << endl;
00153   }
00154 
00155   int num_rows = PQntuples(res);
00156   data.name = layer_name;
00157   for (int i=0; i<num_rows; ++i)
00158   {
00159     FeatureDataHolder * fd = new FeatureDataHolder(string(PQgetvalue(res, i, 0)));
00160     assert(fd);
00161     uint32_t length = PQgetlength(res, i, 1);
00162     uint8_t * wkb = new uint8_t[length];
00163     assert(wkb);
00164     length = Text2Bin(PQgetvalue(res, i, 1), wkb, length);
00165     fd->wkb.assign(wkb, wkb + length);
00166     delete []wkb;
00167     fd->attrib = string(PQgetvalue(res, i, 2));
00168 
00169     data.features.push_back(*fd);
00170     delete fd;
00171   }
00172 
00173   PQclear(res);
00174 
00175   return data;
00176 }
00177 
00178 int PostgresConn::WriteLayerData(LayerDataHolder & data)
00179 {
00180 
00181   const string delcmd = string("DELETE FROM ") + data.name + string(";");
00182   const string inscmd = string("INSERT INTO ") + data.name + string(" (id, name, geom, attrib) VALUES ($1::integer, $2, $3, $4);");
00183   PGresult * res;
00184   const player_vectormap_feature_data_t * feature;
00185   char numbuff[16];
00186   const char * params[4];
00187 
00188   res = PQexec(conn, "BEGIN TRANSACTION;");
00189   if (!res)
00190   {
00191     PLAYER_ERROR("Couldn't delete layer features");
00192     return -1;
00193   }
00194   if (PQresultStatus(res) != PGRES_COMMAND_OK)
00195   {
00196     PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00197     PQclear(res);
00198     return -1;
00199   }
00200   PQclear(res);
00201   PLAYER_WARN1("[%s]", delcmd.c_str());
00202   res = PQexec(conn, delcmd.c_str());
00203   if (!res)
00204   {
00205     PLAYER_ERROR("Couldn't delete layer features");
00206     res = PQexec(conn, "ROLLBACK;");
00207     if (!res)
00208     {
00209       PLAYER_ERROR("Couldn't rollback transaction");
00210       return -1;
00211     }
00212     if (PQresultStatus(res) != PGRES_COMMAND_OK) PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00213     PQclear(res);
00214     return -1;
00215   }
00216   if (PQresultStatus(res) != PGRES_COMMAND_OK)
00217   {
00218     PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00219     PQclear(res);
00220     res = PQexec(conn, "ROLLBACK;");
00221     if (!res)
00222     {
00223       PLAYER_ERROR("Couldn't rollback transaction");
00224       return -1;
00225     }
00226     if (PQresultStatus(res) != PGRES_COMMAND_OK) PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00227     PQclear(res);
00228     return -1;
00229   }
00230   PQclear(res);
00231   for (int i = 0; i < (int)(data.features.size()); i++)
00232   {
00233     feature = data.features[i].Convert();
00234     char * wkb_buff = new char[((feature->wkb_count) * 2) + 1];
00235     assert(wkb_buff);
00236     char * ptr = wkb_buff;
00237     for (uint32_t j = 0; j < (feature->wkb_count); j++)
00238     {
00239       snprintf(ptr, 3, "%02x", feature->wkb[j]);
00240       ptr += 2;
00241     }
00242     for (int j = 0; wkb_buff[j]; j++) wkb_buff[j] = toupper(wkb_buff[j]);
00243     snprintf(numbuff, sizeof numbuff, "%d", i + 1);
00244     params[0] = numbuff;
00245     params[1] = (feature->name[0]) ? feature->name : NULL;
00246     params[2] = wkb_buff;
00247     params[3] = (feature->attrib[0]) ? feature->attrib : NULL;
00248     PLAYER_WARN5("[%s] [%s] [%s] [%s] [%s]", inscmd.c_str(), params[0], ((params[1]) ? (params[1]) : ""), params[2], ((params[3]) ? (params[3]) : ""));
00249     PGresult * res = PQexecParams(conn,
00250                                   inscmd.c_str(),
00251                                   4,
00252                                   NULL,
00253                                   params,
00254                                   NULL,
00255                                   NULL,
00256                                   0);
00257     delete []wkb_buff;
00258     if (!res)
00259     {
00260       PLAYER_ERROR("Couldn't insert layer feature to the database");
00261       res = PQexec(conn, "ROLLBACK;");
00262       if (!res)
00263       {
00264         PLAYER_ERROR("Couldn't rollback transaction");
00265         return -1;
00266       }
00267       if (PQresultStatus(res) != PGRES_COMMAND_OK) PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00268       PQclear(res);
00269       return -1;
00270     }
00271     if (PQresultStatus(res) != PGRES_COMMAND_OK)
00272     {
00273       PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00274       PQclear(res);
00275       res = PQexec(conn, "ROLLBACK;");
00276       if (!res)
00277       {
00278         PLAYER_ERROR("Couldn't rollback transaction");
00279         return -1;
00280       }
00281       if (PQresultStatus(res) != PGRES_COMMAND_OK) PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00282       PQclear(res);
00283       return -1;      
00284     }
00285     PQclear(res);
00286   }
00287   res = PQexec(conn, "COMMIT TRANSACTION;");
00288   if (!res)
00289   {
00290     PLAYER_ERROR("Couldn't commit transaction");
00291     return -1;
00292   }
00293   if (PQresultStatus(res) != PGRES_COMMAND_OK)
00294   {
00295     PLAYER_ERROR1("%s", PQresultErrorMessage(res));
00296     PQclear(res);
00297     return -1;
00298   }
00299   PQclear(res);
00300   return 0;
00301 }
00302 
00303 BoundingBox PostgresConn::BinaryToBBox(const uint8_t* wkb, uint32_t length)
00304 {
00305   BoundingBox res;
00306   memset(&res, 0, sizeof(BoundingBox));
00307   if (length == 0)
00308     return res;
00309 #ifdef HAVE_GEOS
00310   GEOSGeom polygon;
00311   polygon = GEOSGeomFromWKB_buf(wkb, length);
00312   if (polygon == NULL)
00313   {
00314     printf("GEOSGeomFromWKB_buf returned NULL!\n");
00315     return res;
00316   }
00317   GEOSGeom linestring = GEOSGetExteriorRing(polygon);
00318   if (linestring == NULL)
00319   {
00320     printf("GEOSGetExteriorRing returned NULL!\n");
00321     return res;
00322   }
00323   GEOSCoordSeq coords = GEOSGeom_getCoordSeq(linestring);
00324   if (coords == NULL)
00325   {
00326     printf("GEOSGeom_getCoordSeq returned NULL!\n");
00327     return res;
00328   }
00329 
00330   double xmin = INT_MAX, ymin = INT_MAX;
00331   double xmax = INT_MIN, ymax = INT_MIN;
00332   double tempX, tempY = 0;
00333 
00334   for (int ii=0; ii<GEOSGetNumCoordinates(linestring); ++ii)
00335   {
00336     GEOSCoordSeq_getX(coords, ii, &tempX);
00337     GEOSCoordSeq_getY(coords, ii, &tempY);
00338     if (tempX > xmax)
00339       xmax = tempX;
00340     if (tempX < xmin)
00341       xmin = tempX;
00342     if (tempY > ymax)
00343       ymax = tempY;
00344     if (tempY < ymin)
00345       ymin = tempY;
00346   }
00347 
00348   res.x0 = xmin;
00349   res.y0 = ymin;
00350   res.x1 = xmax;
00351   res.y1 = ymax;
00352   GEOSGeom_destroy(polygon);
00353 #endif
00354   return res;
00355 }
00356 
00357 const player_vectormap_info_t* VectorMapInfoHolder::Convert()
00358 {
00359   info.srid = srid;
00360   info.extent.x0 = extent.x0;
00361   info.extent.y0 = extent.y0;
00362   info.extent.x1 = extent.x1;
00363   info.extent.y1 = extent.y1;
00364   info.layers_count = layers.size();
00365   if (info.layers) delete [](info.layers);
00366   info.layers = new player_vectormap_layer_info_t[layers.size()];
00367   assert(info.layers);
00368   for (uint32_t ii=0; ii<layers.size(); ++ii)
00369   {
00370     info.layers[ii] = *(layers[ii].Convert());
00371   }
00372   return &info;
00373 }
00374 
00375 VectorMapInfoHolder::~VectorMapInfoHolder()
00376 {
00377    if (info.layers)
00378    {
00379      delete[] info.layers;
00380    }
00381 }
00382 
00383 const player_vectormap_layer_info_t* LayerInfoHolder::Convert()
00384 {
00385   if (layer_info.name) free(layer_info.name);
00386   layer_info.name = strdup(name.c_str());
00387   assert(layer_info.name);
00388   layer_info.name_count = name.size() + 1;
00389   layer_info.extent.x0 = extent.x0;
00390   layer_info.extent.y0 = extent.y0;
00391   layer_info.extent.x1 = extent.x1;
00392   layer_info.extent.y1 = extent.y1;
00393   return &layer_info;
00394 }
00395 
00396 const player_vectormap_feature_data_t* FeatureDataHolder::Convert()
00397 {
00398   if (feature_data.name) free(feature_data.name);
00399   feature_data.name = strdup(name.c_str());
00400   assert(feature_data.name);
00401   feature_data.name_count = name.size() + 1;
00402   if (feature_data.wkb) delete [](feature_data.wkb);
00403   feature_data.wkb = new uint8_t[wkb.size()];
00404   assert(feature_data.wkb);
00405   feature_data.wkb_count = wkb.size();
00406   if (feature_data.attrib) free(feature_data.attrib);
00407   feature_data.attrib = strdup(attrib.c_str());
00408   assert(feature_data.attrib);
00409   feature_data.attrib_count = attrib.size() + 1;
00411   for (uint32_t ii=0; ii<wkb.size(); ++ii)
00412   {
00413     feature_data.wkb[ii] = wkb[ii];
00414   }
00415   return &feature_data;
00416 }
00417 
00418 FeatureDataHolder::~FeatureDataHolder()
00419 {
00420    if (feature_data.name) free(feature_data.name);
00421    if (feature_data.attrib) free(feature_data.attrib);
00422    if (feature_data.wkb)
00423    {
00424      delete[] feature_data.wkb;
00425    }
00426 }
00427 
00428 const player_vectormap_layer_data_t* LayerDataHolder::Convert()
00429 {
00430   if (layer_data.name) free(layer_data.name);
00431   layer_data.name = strdup(name.c_str());
00432   assert(layer_data.name);
00433   layer_data.name_count = name.size()+1;
00434   layer_data.features_count = features.size();
00435   if (layer_data.features) delete [](layer_data.features);
00436   layer_data.features = NULL;
00437   if (layer_data.features_count > 0)
00438   {
00439     layer_data.features = new player_vectormap_feature_data_t[layer_data.features_count];
00440     assert(layer_data.features);
00441     for (uint32_t ii=0; ii<layer_data.features_count; ++ii)
00442     {
00443       layer_data.features[ii] = *(features[ii].Convert());
00444     }
00445   }
00446   return &layer_data;
00447 }
00448 
00449 LayerDataHolder::~LayerDataHolder()
00450 {
00451   if (layer_data.name) free(layer_data.name);
00452   if (layer_data.features)
00453   {
00454      delete[] layer_data.features;
00455   }
00456 }

Last updated 12 September 2005 21:38:45