read_pg.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. /*!
  2. \file lib/vector/Vlib/read_pg.c
  3. \brief Vector library - reading features (PostGIS format)
  4. Higher level functions for reading/writing/manipulating vectors.
  5. \todo Currently only points, linestrings and polygons are supported,
  6. implement also other types
  7. (C) 2011-2012 by the GRASS Development Team
  8. This program is free software under the GNU General Public License
  9. (>=v2). Read the file COPYING that comes with GRASS for details.
  10. \author Martin Landa <landa.martin gmail.com>
  11. */
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <limits.h>
  15. #include <grass/vector.h>
  16. #include <grass/dbmi.h>
  17. #include <grass/glocale.h>
  18. #ifdef HAVE_POSTGRES
  19. #include "pg_local_proto.h"
  20. static int read_next_line_pg(struct Map_info *,
  21. struct line_pnts *, struct line_cats *, int);
  22. SF_FeatureType get_feature(struct Format_info_pg *, int);
  23. static unsigned char *hex_to_wkb(const char *, int *);
  24. static int point_from_wkb(const unsigned char *, int, int, int,
  25. struct line_pnts *);
  26. static int linestring_from_wkb(const unsigned char *, int, int, int,
  27. struct line_pnts *, int);
  28. static int polygon_from_wkb(const unsigned char *, int, int, int,
  29. struct Format_info_cache *);
  30. static int geometry_collection_from_wkb(const unsigned char *, int, int, int,
  31. struct Format_info_cache *,
  32. struct feat_parts *);
  33. static int error_corrupted_data(const char *);
  34. static int set_initial_query();
  35. static void reallocate_cache(struct Format_info_cache *, int);
  36. static void add_fpart(struct feat_parts *, SF_FeatureType, int, int);
  37. #endif
  38. /*!
  39. \brief Read next feature from PostGIS layer. Skip
  40. empty features (level 1 without topology).
  41. t
  42. This function implements sequential access.
  43. The action of this routine can be modified by:
  44. - Vect_read_constraint_region()
  45. - Vect_read_constraint_type()
  46. - Vect_remove_constraints()
  47. \param Map pointer to Map_info structure
  48. \param[out] line_p container used to store line points within
  49. (pointer to line_pnts struct)
  50. \param[out] line_c container used to store line categories within
  51. (pointer line_cats struct)
  52. \return feature type
  53. \return -2 no more features (EOF)
  54. \return -1 out of memory
  55. */
  56. int V1_read_next_line_pg(struct Map_info *Map,
  57. struct line_pnts *line_p,
  58. struct line_cats *line_c)
  59. {
  60. #ifdef HAVE_POSTGRES
  61. G_debug(3, "V1_read_next_line_pg()");
  62. /* constraints not ignored */
  63. return read_next_line_pg(Map, line_p, line_c, FALSE);
  64. #else
  65. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  66. return -1;
  67. #endif
  68. }
  69. /*!
  70. \brief Read next feature from PostGIS layer on topological level.
  71. This function implements sequential access.
  72. \param Map pointer to Map_info structure
  73. \param[out] line_p container used to store line points within
  74. (pointer to line_pnts struct)
  75. \param[out] line_c container used to store line categories within
  76. (pointer to line_cats struct)
  77. \return feature type
  78. \return -2 no more features (EOF)
  79. \return -1 on failure
  80. */
  81. int V2_read_next_line_pg(struct Map_info *Map, struct line_pnts *line_p,
  82. struct line_cats *line_c)
  83. {
  84. #ifdef HAVE_POSTGRES
  85. int line, ret;
  86. struct P_line *Line;
  87. struct bound_box lbox, mbox;
  88. G_debug(3, "V2_read_next_line_pg()");
  89. if (Map->constraint.region_flag)
  90. Vect_get_constraint_box(Map, &mbox);
  91. ret = -1;
  92. while(TRUE) {
  93. line = Map->next_line;
  94. if (Map->next_line > Map->plus.n_lines)
  95. return -2;
  96. Line = Map->plus.Line[line];
  97. if (Line == NULL) { /* skip dead features */
  98. Map->next_line++;
  99. continue;
  100. }
  101. if (Map->constraint.type_flag) {
  102. /* skip by type */
  103. if (!(Line->type & Map->constraint.type)) {
  104. Map->next_line++;
  105. continue;
  106. }
  107. }
  108. if (Line->type == GV_CENTROID) {
  109. G_debug(4, "Centroid");
  110. Map->next_line++;
  111. if (line_p != NULL) {
  112. int i, found;
  113. struct bound_box box;
  114. struct boxlist list;
  115. struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
  116. /* get area bbox */
  117. Vect_get_area_box(Map, topo->area, &box);
  118. /* search in spatial index for centroid with area bbox */
  119. dig_init_boxlist(&list, TRUE);
  120. Vect_select_lines_by_box(Map, &box, Line->type, &list);
  121. found = -1;
  122. for (i = 0; i < list.n_values; i++) {
  123. if (list.id[i] == line) {
  124. found = i;
  125. break;
  126. }
  127. }
  128. if (found > -1) {
  129. Vect_reset_line(line_p);
  130. Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
  131. }
  132. }
  133. if (line_c != NULL) {
  134. /* cat = FID and offset = FID for centroid */
  135. Vect_reset_cats(line_c);
  136. Vect_cat_set(line_c, 1, (int) Line->offset);
  137. }
  138. ret = GV_CENTROID;
  139. }
  140. else {
  141. /* ignore constraints, Map->next_line incremented */
  142. ret = read_next_line_pg(Map, line_p, line_c, TRUE);
  143. }
  144. if (Map->constraint.region_flag) {
  145. /* skip by region */
  146. Vect_line_box(line_p, &lbox);
  147. if (!Vect_box_overlap(&lbox, &mbox)) {
  148. continue;
  149. }
  150. }
  151. /* skip by field ignored */
  152. return ret;
  153. }
  154. #else
  155. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  156. #endif
  157. return -1; /* not reached */
  158. }
  159. /*!
  160. \brief Read feature from PostGIS layer at given offset (level 1 without topology)
  161. This function implements random access on level 1.
  162. \param Map pointer to Map_info structure
  163. \param[out] line_p container used to store line points within
  164. (pointer line_pnts struct)
  165. \param[out] line_c container used to store line categories within
  166. (pointer line_cats struct)
  167. \param offset given offset
  168. \return line type
  169. \return 0 dead line
  170. \return -2 no more features
  171. \return -1 out of memory
  172. */
  173. int V1_read_line_pg(struct Map_info *Map,
  174. struct line_pnts *line_p, struct line_cats *line_c, off_t offset)
  175. {
  176. #ifdef HAVE_POSTGRES
  177. long fid;
  178. int i, ipart, type;
  179. SF_FeatureType sf_type;
  180. struct line_pnts *line_i;
  181. struct Format_info_pg *pg_info;
  182. pg_info = &(Map->fInfo.pg);
  183. G_debug(3, "V1_read_line_pg(): offset = %lu offset_num = %lu",
  184. (long) offset, (long) pg_info->offset.array_num);
  185. if (offset >= pg_info->offset.array_num)
  186. return -2; /* nothing to read */
  187. if (line_p != NULL)
  188. Vect_reset_line(line_p);
  189. if (line_c != NULL)
  190. Vect_reset_cats(line_c);
  191. fid = pg_info->offset.array[offset];
  192. G_debug(4, " fid = %ld", fid);
  193. /* read feature to cache if necessary */
  194. if (pg_info->cache.fid != fid) {
  195. G_debug(4, "read feature (fid = %ld) to cache", fid);
  196. sf_type = (int) get_feature(pg_info, fid);
  197. if ((int) sf_type < 0)
  198. return (int) sf_type;
  199. }
  200. /* get data from cache */
  201. ipart = pg_info->offset.array[offset + 1];
  202. type = pg_info->cache.lines_types[ipart];
  203. G_debug(4, "read feature part: %d -> type = %d",
  204. ipart, type);
  205. if (line_p != NULL) {
  206. /* coordinates */
  207. line_i = pg_info->cache.lines[ipart];
  208. for (i = 0; i < line_i->n_points; i++) {
  209. Vect_append_point(line_p,
  210. line_i->x[i], line_i->y[i], line_i->z[i]);
  211. }
  212. }
  213. if (line_c != NULL) {
  214. /* category */
  215. Vect_cat_set(line_c, 1, (int) fid);
  216. }
  217. return type;
  218. #else
  219. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  220. return -1;
  221. #endif
  222. }
  223. #ifdef HAVE_POSTGRES
  224. /*!
  225. \brief Read next feature from PostGIS layer.
  226. \param Map pointer to Map_info structure
  227. \param[out] line_p container used to store line points within
  228. (pointer to line_pnts struct)
  229. \param[out] line_c container used to store line categories within
  230. (pointer line_cats struct)
  231. \param ignore_constraints TRUE to ignore constraints (type, region)
  232. \return feature type
  233. \return -2 no more features (EOF)
  234. \return -1 out of memory
  235. */
  236. int read_next_line_pg(struct Map_info *Map,
  237. struct line_pnts *line_p, struct line_cats *line_c,
  238. int ignore_constraints)
  239. {
  240. int i, ltype;
  241. SF_FeatureType sf_type;
  242. struct Format_info_pg *pg_info;
  243. struct bound_box mbox, lbox;
  244. struct line_pnts *line_i;
  245. pg_info = &(Map->fInfo.pg);
  246. if (Map->constraint.region_flag && !ignore_constraints)
  247. Vect_get_constraint_box(Map, &mbox);
  248. while (TRUE) {
  249. Map->next_line++; /* level 2 only */
  250. /* reset data structures */
  251. if (line_p != NULL)
  252. Vect_reset_line(line_p);
  253. if (line_c != NULL)
  254. Vect_reset_cats(line_c);
  255. /* read feature to cache if necessary */
  256. while (pg_info->cache.lines_next == pg_info->cache.lines_num) {
  257. pg_info->cache.lines_next = pg_info->cache.lines_num = 0;
  258. /* cache feature -> line_p & line_c */
  259. sf_type = get_feature(pg_info, -1);
  260. if ((int) sf_type < 0) /* -1 || - 2 */
  261. return (int) sf_type;
  262. if (sf_type == SF_UNKNOWN || sf_type == SF_NONE) {
  263. G_warning(_("Feature without geometry. Skipped."));
  264. pg_info->cache.lines_next = pg_info->cache.lines_num = 0;
  265. continue;
  266. }
  267. G_debug(4, "%d lines read to cache", pg_info->cache.lines_num);
  268. }
  269. /* get data from cache */
  270. ltype = pg_info->cache.lines_types[pg_info->cache.lines_next];
  271. if (line_p) {
  272. line_i = pg_info->cache.lines[pg_info->cache.lines_next];
  273. for (i = 0; i < line_i->n_points; i++) {
  274. Vect_append_point(line_p,
  275. line_i->x[i], line_i->y[i], line_i->z[i]);
  276. }
  277. }
  278. if (line_c) {
  279. Vect_cat_set(line_c, 1, (int) pg_info->cache.fid);
  280. }
  281. pg_info->cache.lines_next++;
  282. /* apply constraints */
  283. if (Map->constraint.type_flag && !ignore_constraints) {
  284. /* skip feature by type */
  285. if (!(ltype & Map->constraint.type))
  286. continue;
  287. }
  288. if (line_p && Map->constraint.region_flag &&
  289. !ignore_constraints) {
  290. /* skip feature by region */
  291. Vect_line_box(line_p, &lbox);
  292. if (!Vect_box_overlap(&lbox, &mbox))
  293. continue;
  294. }
  295. /* skip feature by field ignored */
  296. return ltype;
  297. }
  298. return -1; /* not reached */
  299. }
  300. /*!
  301. \brief Read feature geometry
  302. Geometry is stored in lines cache.
  303. \param[in,out] pg_info pointer to Format_info_pg struct
  304. \param fid feature id to be read (-1 for next)
  305. \param[out] line_c pointer to line_cats structure (or NULL)
  306. \return simple feature type (SF_POINT, SF_LINESTRING, ...)
  307. \return -1 on error
  308. */
  309. SF_FeatureType get_feature(struct Format_info_pg *pg_info, int fid)
  310. {
  311. char *data;
  312. char stmt[DB_SQL_MAX];
  313. SF_FeatureType ftype;
  314. if (!pg_info->geom_column) {
  315. G_warning(_("No geometry column defined"));
  316. return -1;
  317. }
  318. if (fid < 1) {
  319. /* next (read n features) */
  320. if (!pg_info->res) {
  321. if (set_initial_query(pg_info) == -1)
  322. return -1;
  323. }
  324. }
  325. else {
  326. if (!pg_info->fid_column) {
  327. G_warning(_("Random access not supported. "
  328. "Primary key not defined."));
  329. return -1;
  330. }
  331. if (execute(pg_info->conn, "BEGIN") == -1)
  332. return -1;
  333. sprintf(stmt, "DECLARE %s%p CURSOR FOR SELECT %s FROM %s "
  334. "WHERE %s = %d",
  335. pg_info->table_name, pg_info->conn,
  336. pg_info->geom_column,
  337. pg_info->table_name, pg_info->fid_column, fid);
  338. if (execute(pg_info->conn, stmt) == -1)
  339. return -1;
  340. sprintf(stmt, "FETCH ALL in %s%p",
  341. pg_info->table_name, pg_info->conn);
  342. pg_info->res = PQexec(pg_info->conn, stmt);
  343. pg_info->next_line = 0;
  344. }
  345. if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
  346. PQclear(pg_info->res);
  347. pg_info->res = NULL;
  348. return -1; /* reading failed */
  349. }
  350. /* do we need to fetch more records ? */
  351. if (PQntuples(pg_info->res) == CURSOR_PAGE &&
  352. PQntuples(pg_info->res) == pg_info->next_line) {
  353. char stmt[DB_SQL_MAX];
  354. PQclear(pg_info->res);
  355. sprintf(stmt, "FETCH %d in %s%p", CURSOR_PAGE,
  356. pg_info->table_name, pg_info->conn);
  357. pg_info->res = PQexec(pg_info->conn, stmt);
  358. pg_info->next_line = 0;
  359. }
  360. /* out of results ? */
  361. if (PQntuples(pg_info->res) == pg_info->next_line) {
  362. if (pg_info->res) {
  363. PQclear(pg_info->res);
  364. pg_info->res = NULL;
  365. sprintf(stmt, "CLOSE %s%p",
  366. pg_info->table_name, pg_info->conn);
  367. if (execute(pg_info->conn, stmt) == -1) {
  368. G_warning(_("Unable to close cursor"));
  369. return -1;
  370. }
  371. execute(pg_info->conn, "COMMIT");
  372. }
  373. return -2;
  374. }
  375. data = (char *)PQgetvalue(pg_info->res, pg_info->next_line, 0);
  376. ftype = cache_feature(data, FALSE, &(pg_info->cache), NULL);
  377. if (fid < 0) {
  378. pg_info->cache.fid = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 1));
  379. pg_info->next_line++;
  380. }
  381. else {
  382. pg_info->cache.fid = fid;
  383. PQclear(pg_info->res);
  384. pg_info->res = NULL;
  385. sprintf(stmt, "CLOSE %s%p",
  386. pg_info->table_name, pg_info->conn);
  387. if (execute(pg_info->conn, stmt) == -1) {
  388. G_warning(_("Unable to close cursor"));
  389. return -1;
  390. }
  391. if (execute(pg_info->conn, "COMMIT") == -1)
  392. return -1;
  393. }
  394. return ftype;
  395. }
  396. /*!
  397. \brief Convert HEX to WKB data
  398. This function is based on CPLHexToBinary() from GDAL/OGR library
  399. \param hex_data HEX data
  400. \param[out] nbytes number of bytes in output buffer
  401. \return pointer to WKB data buffer
  402. */
  403. static unsigned char *hex_to_wkb(const char *hex_data, int *nbytes)
  404. {
  405. unsigned char *wkb_data;
  406. unsigned int length, i_src, i_dst;
  407. i_src = i_dst = 0;
  408. length = strlen(hex_data);
  409. wkb_data = G_malloc(length / 2 + 2);
  410. while (hex_data[i_src] != '\0' ) {
  411. if (hex_data[i_src] >= '0' && hex_data[i_src] <= '9')
  412. wkb_data[i_dst] = hex_data[i_src] - '0';
  413. else if (hex_data[i_src] >= 'A' && hex_data[i_src] <= 'F')
  414. wkb_data[i_dst] = hex_data[i_src] - 'A' + 10;
  415. else if (hex_data[i_src] >= 'a' && hex_data[i_src] <= 'f')
  416. wkb_data[i_dst] = hex_data[i_src] - 'a' + 10;
  417. else
  418. break;
  419. wkb_data[i_dst] *= 16;
  420. i_src++;
  421. if (hex_data[i_src] >= '0' && hex_data[i_src] <= '9')
  422. wkb_data[i_dst] += hex_data[i_src] - '0';
  423. else if(hex_data[i_src] >= 'A' && hex_data[i_src] <= 'F')
  424. wkb_data[i_dst] += hex_data[i_src] - 'A' + 10;
  425. else if(hex_data[i_src] >= 'a' && hex_data[i_src] <= 'f')
  426. wkb_data[i_dst] += hex_data[i_src] - 'a' + 10;
  427. else
  428. break;
  429. i_src++;
  430. i_dst++;
  431. }
  432. wkb_data[i_dst] = 0;
  433. *nbytes = i_dst;
  434. return wkb_data;
  435. }
  436. /*!
  437. \brief Read geometry from HEX data
  438. This code is inspired by OGRGeometryFactory::createFromWkb() from
  439. GDAL/OGR library.
  440. \param data HEX data
  441. \param skip_polygon skip polygons (level 1)
  442. \param[out] cache lines cache
  443. \param[out] fparts used for building pseudo-topology (or NULL)
  444. \return simple feature type
  445. \return SF_UNKNOWN on error
  446. */
  447. SF_FeatureType cache_feature(const char *data, int skip_polygon,
  448. struct Format_info_cache *cache,
  449. struct feat_parts *fparts)
  450. {
  451. int ret, byte_order, nbytes, is3D;
  452. unsigned char *wkb_data;
  453. unsigned int wkb_flags;
  454. SF_FeatureType ftype;
  455. wkb_flags = 0;
  456. wkb_data = hex_to_wkb(data, &nbytes);
  457. if (nbytes < 5) {
  458. G_warning(_("Invalid WKB content: %d bytes"), nbytes);
  459. G_free(wkb_data);
  460. return SF_UNKNOWN;
  461. }
  462. /* parsing M coordinate not supported */
  463. memcpy(&wkb_flags, wkb_data + 1, 4);
  464. byte_order = (wkb_data[0] == 0 ? ENDIAN_BIG : ENDIAN_LITTLE);
  465. if (byte_order == ENDIAN_BIG)
  466. wkb_flags = SWAP32(wkb_flags);
  467. if (wkb_flags & 0x40000000) {
  468. G_warning(_("Reading EWKB with 4-dimensional coordinates (XYZM) "
  469. "is not supported"));
  470. G_free(wkb_data);
  471. return SF_UNKNOWN;
  472. }
  473. /* PostGIS EWKB format includes an SRID, but this won't be
  474. understood by OGR, so if the SRID flag is set, we remove the
  475. SRID (bytes at offset 5 to 8).
  476. */
  477. if (nbytes > 9 &&
  478. ((byte_order == ENDIAN_BIG && (wkb_data[1] & 0x20)) ||
  479. (byte_order == ENDIAN_LITTLE && (wkb_data[4] & 0x20)))) {
  480. memmove(wkb_data + 5, wkb_data + 9, nbytes -9);
  481. nbytes -= 4;
  482. if(byte_order == ENDIAN_BIG)
  483. wkb_data[1] &= (~0x20);
  484. else
  485. wkb_data[4] &= (~0x20);
  486. }
  487. if (nbytes < 9 && nbytes != -1) {
  488. G_free(wkb_data);
  489. return SF_UNKNOWN;
  490. }
  491. /* Get the geometry feature type. For now we assume that geometry
  492. type is between 0 and 255 so we only have to fetch one byte.
  493. */
  494. if (byte_order == ENDIAN_LITTLE) {
  495. ftype = (SF_FeatureType) wkb_data[1];
  496. is3D = wkb_data[4] & 0x80 || wkb_data[2] & 0x80;
  497. }
  498. else {
  499. ftype = (SF_FeatureType) wkb_data[4];
  500. is3D = wkb_data[1] & 0x80 || wkb_data[3] & 0x80;
  501. }
  502. G_debug(5, "cache_feature(): sf_type = %d", ftype);
  503. /* allocate space in lines cache - be minimalistic
  504. more lines require eg. polygon with more rings, multi-features
  505. or geometry collections
  506. */
  507. if (!cache->lines) {
  508. reallocate_cache(cache, 1);
  509. }
  510. cache->lines_num = 0;
  511. if (fparts)
  512. fparts->n_parts = 0;
  513. ret = -1;
  514. if (ftype == SF_POINT) {
  515. cache->lines_num = 1;
  516. cache->lines_types[0] = GV_POINT;
  517. ret = point_from_wkb(wkb_data, nbytes, byte_order,
  518. is3D, cache->lines[0]);
  519. add_fpart(fparts, ftype, 0, 1);
  520. }
  521. else if (ftype == SF_LINESTRING) {
  522. cache->lines_num = 1;
  523. cache->lines_types[0] = GV_LINE;
  524. ret = linestring_from_wkb(wkb_data, nbytes, byte_order,
  525. is3D, cache->lines[0], FALSE);
  526. add_fpart(fparts, ftype, 0, 1);
  527. }
  528. else if (ftype == SF_POLYGON && !skip_polygon) {
  529. ret = polygon_from_wkb(wkb_data, nbytes, byte_order,
  530. is3D, cache);
  531. add_fpart(fparts, ftype, 0, 1);
  532. }
  533. else if (ftype == SF_MULTIPOINT ||
  534. ftype == SF_MULTILINESTRING ||
  535. ftype == SF_MULTIPOLYGON ||
  536. ftype == SF_GEOMETRYCOLLECTION) {
  537. ret = geometry_collection_from_wkb(wkb_data, nbytes, byte_order,
  538. is3D, cache, fparts);
  539. }
  540. else {
  541. G_warning(_("Unsupported feature type %d"), ftype);
  542. }
  543. G_free(wkb_data);
  544. return ret > 0 ? ftype : SF_UNKNOWN;
  545. }
  546. /*!
  547. \brief Read point for WKB data
  548. See OGRPoint::importFromWkb() from GDAL/OGR library
  549. \param wkb_data WKB data
  550. \param nbytes number of bytes (WKB data buffer)
  551. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  552. \param with_z WITH_Z for 3D data
  553. \param[out] line_p point geometry (pointer to line_pnts struct)
  554. \return wkb size
  555. \return -1 on error
  556. */
  557. int point_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  558. int with_z, struct line_pnts *line_p)
  559. {
  560. double x, y, z;
  561. if (nbytes < 21 && nbytes != -1 )
  562. return -1;
  563. /* get vertex */
  564. memcpy(&x, wkb_data + 5, 8);
  565. memcpy(&y, wkb_data + 5 + 8, 8);
  566. if (byte_order == ENDIAN_BIG) {
  567. SWAPDOUBLE(&x);
  568. SWAPDOUBLE(&y);
  569. }
  570. if (with_z) {
  571. if (nbytes < 29 && nbytes != -1 )
  572. return -1;
  573. memcpy(&z, wkb_data + 5 + 16, 8);
  574. if (byte_order == ENDIAN_BIG) {
  575. SWAPDOUBLE(&z);
  576. }
  577. }
  578. else {
  579. z = 0.0;
  580. }
  581. if (line_p) {
  582. Vect_reset_line(line_p);
  583. Vect_append_point(line_p, x, y, z);
  584. }
  585. return 5 + 8 * (with_z == WITH_Z ? 3 : 2);
  586. }
  587. /*!
  588. \brief Read line for WKB data
  589. See OGRLineString::importFromWkb() from GDAL/OGR library
  590. \param wkb_data WKB data
  591. \param nbytes number of bytes (WKB data buffer)
  592. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  593. \param with_z WITH_Z for 3D data
  594. \param[out] line_p line geometry (pointer to line_pnts struct)
  595. \return wkb size
  596. \return -1 on error
  597. */
  598. int linestring_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  599. int with_z, struct line_pnts *line_p, int is_ring)
  600. {
  601. int npoints, point_size, buff_min_size, offset;
  602. int i;
  603. double x, y, z;
  604. if (is_ring)
  605. offset = 5;
  606. else
  607. offset = 0;
  608. if (is_ring && nbytes < 4 && nbytes != -1)
  609. return error_corrupted_data(NULL);
  610. /* get the vertex count */
  611. memcpy(&npoints, wkb_data + (5 - offset), 4);
  612. if (byte_order == ENDIAN_BIG) {
  613. npoints = SWAP32(npoints);
  614. }
  615. /* check if the wkb stream buffer is big enough to store fetched
  616. number of points. 16 or 24 - size of point structure
  617. */
  618. point_size = with_z ? 24 : 16;
  619. if (npoints < 0 || npoints > INT_MAX / point_size)
  620. return error_corrupted_data(NULL);
  621. buff_min_size = point_size * npoints;
  622. if (nbytes != -1 && buff_min_size > nbytes - (9 - offset))
  623. return error_corrupted_data(_("Length of input WKB is too small"));
  624. if (line_p)
  625. Vect_reset_line(line_p);
  626. /* get the vertex */
  627. for (i = 0; i < npoints; i++) {
  628. memcpy(&x, wkb_data + (9 - offset) + i * point_size, 8);
  629. memcpy(&y, wkb_data + (9 - offset) + 8 + i * point_size, 8);
  630. if (with_z)
  631. memcpy(&z, wkb_data + (9 - offset) + 16 + i * point_size, 8);
  632. else
  633. z = 0.0;
  634. if (byte_order == ENDIAN_BIG) {
  635. SWAPDOUBLE(&x);
  636. SWAPDOUBLE(&y);
  637. if (with_z)
  638. SWAPDOUBLE(&z);
  639. }
  640. if (line_p)
  641. Vect_append_point(line_p, x, y, z);
  642. }
  643. return (9 - offset) + (with_z == WITH_Z ? 3 : 2) * 8 * line_p->n_points;
  644. }
  645. /*!
  646. \brief Read polygon for WKB data
  647. See OGRPolygon::importFromWkb() from GDAL/OGR library
  648. \param wkb_data WKB data
  649. \param nbytes number of bytes (WKB data buffer)
  650. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  651. \param with_z WITH_Z for 3D data
  652. \param[out] line_p array of rings (pointer to line_pnts struct)
  653. \return wkb size
  654. \return -1 on error
  655. */
  656. int polygon_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  657. int with_z, struct Format_info_cache *cache)
  658. {
  659. int nrings, data_offset, i, nsize, isize;
  660. struct line_pnts *line_i;
  661. if (nbytes < 9 && nbytes != -1)
  662. return -1;
  663. /* get the ring count */
  664. memcpy(&nrings, wkb_data + 5, 4);
  665. if (byte_order == ENDIAN_BIG) {
  666. nrings = SWAP32(nrings);
  667. }
  668. if (nrings < 0) {
  669. return -1;
  670. }
  671. /* reallocate space for islands if needed */
  672. reallocate_cache(cache, nrings);
  673. cache->lines_num += nrings;
  674. /* each ring has a minimum of 4 bytes (point count) */
  675. if (nbytes != -1 && nbytes - 9 < nrings * 4) {
  676. return error_corrupted_data(_("Length of input WKB is too small"));
  677. }
  678. data_offset = 9;
  679. if (nbytes != -1)
  680. nbytes -= data_offset;
  681. /* get the rings */
  682. nsize = 9;
  683. for (i = 0; i < nrings; i++ ) {
  684. line_i = cache->lines[cache->lines_next];
  685. cache->lines_types[cache->lines_next++] = GV_BOUNDARY;
  686. linestring_from_wkb(wkb_data + data_offset, nbytes, byte_order,
  687. with_z, line_i, TRUE);
  688. if (nbytes != -1) {
  689. isize = 4 + 8 * (with_z == WITH_Z ? 3 : 2) * line_i->n_points;
  690. nbytes -= isize;
  691. }
  692. nsize += isize;
  693. data_offset += isize;
  694. }
  695. return nsize;
  696. }
  697. /*!
  698. \brief Read geometry collection for WKB data
  699. See OGRGeometryCollection::importFromWkbInternal() from GDAL/OGR library
  700. \param wkb_data WKB data
  701. \param nbytes number of bytes (WKB data buffer)
  702. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  703. \param with_z WITH_Z for 3D data
  704. \param ipart part to cache (starts at 0)
  705. \param[out] cache lines cache
  706. \param[in,out] fparts feature parts (required for building pseudo-topology)
  707. \return number of parts
  708. \return -1 on error
  709. */
  710. int geometry_collection_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  711. int with_z, struct Format_info_cache *cache,
  712. struct feat_parts *fparts)
  713. {
  714. int ipart, nparts, data_offset, nsize;
  715. unsigned char *wkb_subdata;
  716. SF_FeatureType ftype;
  717. if (nbytes < 9 && nbytes != -1)
  718. return error_corrupted_data(NULL);
  719. /* get the geometry count */
  720. memcpy(&nparts, wkb_data + 5, 4 );
  721. if (byte_order == ENDIAN_BIG) {
  722. nparts = SWAP32(nparts);
  723. }
  724. if (nparts < 0 || nparts > INT_MAX / 9) {
  725. return error_corrupted_data(NULL);
  726. }
  727. G_debug(5, "\t(geometry collections) parts: %d", nparts);
  728. /* each geometry has a minimum of 9 bytes */
  729. if (nbytes != -1 && nbytes - 9 < nparts * 9) {
  730. return error_corrupted_data(_("Length of input WKB is too small"));
  731. }
  732. data_offset = 9;
  733. if (nbytes != -1)
  734. nbytes -= data_offset;
  735. /* reallocate space for parts if needed */
  736. reallocate_cache(cache, nparts);
  737. /* get parts */
  738. cache->lines_next = cache->lines_num = 0;
  739. for (ipart = 0; ipart < nparts; ipart++) {
  740. wkb_subdata = (unsigned char *)wkb_data + data_offset;
  741. if (nbytes < 9 && nbytes != -1)
  742. return error_corrupted_data(NULL);
  743. if (byte_order == ENDIAN_LITTLE) {
  744. ftype = (SF_FeatureType) wkb_subdata[1];
  745. }
  746. else {
  747. ftype = (SF_FeatureType) wkb_subdata[4];
  748. }
  749. if (ftype == SF_POINT) {
  750. cache->lines_types[cache->lines_next] = GV_POINT;
  751. nsize = point_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
  752. cache->lines[cache->lines_next]);
  753. cache->lines_num++;
  754. add_fpart(fparts, ftype, cache->lines_next, 1);
  755. cache->lines_next++;
  756. }
  757. else if (ftype == SF_LINESTRING) {
  758. cache->lines_types[cache->lines_next] = GV_LINE;
  759. nsize = linestring_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
  760. cache->lines[cache->lines_next],
  761. FALSE);
  762. cache->lines_num++;
  763. add_fpart(fparts, ftype, cache->lines_next, 1);
  764. cache->lines_next++;
  765. }
  766. else if (ftype == SF_POLYGON) {
  767. int idx = cache->lines_next;
  768. nsize = polygon_from_wkb(wkb_subdata, nbytes, byte_order,
  769. with_z, cache);
  770. add_fpart(fparts, ftype, idx, cache->lines_num - idx);
  771. }
  772. else if (ftype == SF_GEOMETRYCOLLECTION ||
  773. ftype == SF_MULTIPOLYGON ||
  774. ftype == SF_MULTILINESTRING ||
  775. ftype == SF_MULTIPOLYGON) {
  776. // geometry_collection_from_wkb();
  777. }
  778. else {
  779. G_warning(_("Unsupported feature type %d"), ftype);
  780. }
  781. if (nbytes != -1) {
  782. nbytes -= nsize;
  783. }
  784. data_offset += nsize;
  785. }
  786. cache->lines_next = 0;
  787. return nparts;
  788. }
  789. /*!
  790. \brief Report error message
  791. \param msg message (NULL)
  792. \return -1
  793. */
  794. int error_corrupted_data(const char *msg)
  795. {
  796. if (msg)
  797. G_warning(_("Corrupted data. %s."), msg);
  798. else
  799. G_warning(_("Corrupted data"));
  800. return -1;
  801. }
  802. /*!
  803. \brief Set initial SQL query for sequential access
  804. \param pg_info pointer to Format_info_pg struct
  805. \return 0 on success
  806. \return -1 on error
  807. */
  808. int set_initial_query(struct Format_info_pg *pg_info)
  809. {
  810. char stmt[DB_SQL_MAX];
  811. if (execute(pg_info->conn, "BEGIN") == -1)
  812. return -1;
  813. sprintf(stmt, "DECLARE %s%p CURSOR FOR SELECT %s,%s FROM %s",
  814. pg_info->table_name, pg_info->conn,
  815. pg_info->geom_column, pg_info->fid_column,
  816. pg_info->table_name);
  817. if (execute(pg_info->conn, stmt) == -1)
  818. return -1;
  819. sprintf(stmt, "FETCH %d in %s%p", CURSOR_PAGE,
  820. pg_info->table_name, pg_info->conn);
  821. pg_info->res = PQexec(pg_info->conn, stmt);
  822. pg_info->next_line = 0;
  823. return 0;
  824. }
  825. /*!
  826. \brief Execute SQL statement
  827. See pg_local_proto.h
  828. \param conn pointer to PGconn
  829. \param stmt query
  830. \return 0 on success
  831. \return -1 on error
  832. */
  833. int execute(PGconn *conn, const char *stmt)
  834. {
  835. PGresult *result;
  836. result = NULL;
  837. G_debug(3, "execute(): %s", stmt);
  838. result = PQexec(conn, stmt);
  839. if (!result || PQresultStatus(result) != PGRES_COMMAND_OK) {
  840. PQclear(result);
  841. G_warning(_("Execution failed: %s"), PQerrorMessage(conn));
  842. return -1;
  843. }
  844. PQclear(result);
  845. return 0;
  846. }
  847. /*!
  848. \brief Reallocate lines cache
  849. */
  850. void reallocate_cache(struct Format_info_cache *cache, int num)
  851. {
  852. int i;
  853. if (cache->lines_alloc >= num)
  854. return;
  855. if (!cache->lines) {
  856. /* most of features requires only one line cache */
  857. cache->lines_alloc = 1;
  858. }
  859. else {
  860. cache->lines_alloc += 20;
  861. }
  862. cache->lines = (struct line_pnts **) G_realloc(cache->lines,
  863. cache->lines_alloc *
  864. sizeof(struct line_pnts *));
  865. cache->lines_types = (int *) G_realloc(cache->lines_types,
  866. cache->lines_alloc *
  867. sizeof(int));
  868. if (cache->lines_alloc > 1) {
  869. for (i = cache->lines_alloc - 20; i < cache->lines_alloc; i++) {
  870. cache->lines[i] = Vect_new_line_struct();
  871. cache->lines_types[i] = -1;
  872. }
  873. }
  874. else {
  875. cache->lines[0] = Vect_new_line_struct();
  876. cache->lines_types[0] = -1;
  877. }
  878. }
  879. void add_fpart(struct feat_parts *fparts, SF_FeatureType ftype,
  880. int idx, int nlines)
  881. {
  882. if (!fparts)
  883. return;
  884. if (fparts->a_parts == 0 || fparts->n_parts >= fparts->a_parts) {
  885. if (fparts->a_parts == 0)
  886. fparts->a_parts = 1;
  887. else
  888. fparts->a_parts += 20;
  889. fparts->ftype = (SF_FeatureType *) G_realloc(fparts->ftype,
  890. fparts->a_parts * sizeof(SF_FeatureType));
  891. fparts->nlines = (int *) G_realloc(fparts->nlines,
  892. fparts->a_parts * sizeof(int));
  893. fparts->idx = (int *) G_realloc(fparts->idx,
  894. fparts->a_parts * sizeof(int));
  895. }
  896. fparts->ftype[fparts->n_parts] = ftype;
  897. fparts->idx[fparts->n_parts] = idx;
  898. fparts->nlines[fparts->n_parts] = nlines;
  899. fparts->n_parts++;
  900. }
  901. #endif