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
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
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
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
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
00138
00139 LayerDataHolder data;
00140
00141
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 }