read_pg.c 29 KB

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