read_pg.c 32 KB

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