read_pg.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  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. fparts->n_parts = 0;
  605. ret = -1;
  606. if (ftype == SF_POINT) {
  607. cache->lines_num = 1;
  608. cache->lines_types[0] = GV_POINT;
  609. ret = point_from_wkb(wkb_data, nbytes, byte_order,
  610. is3D, cache->lines[0]);
  611. add_fpart(fparts, ftype, 0, 1);
  612. }
  613. else if (ftype == SF_LINESTRING) {
  614. cache->lines_num = 1;
  615. cache->lines_types[0] = GV_LINE;
  616. ret = linestring_from_wkb(wkb_data, nbytes, byte_order,
  617. is3D, cache->lines[0], FALSE);
  618. add_fpart(fparts, ftype, 0, 1);
  619. }
  620. else if (ftype == SF_POLYGON && !skip_polygon) {
  621. ret = polygon_from_wkb(wkb_data, nbytes, byte_order,
  622. is3D, cache);
  623. add_fpart(fparts, ftype, 0, 1);
  624. }
  625. else if (ftype == SF_MULTIPOINT ||
  626. ftype == SF_MULTILINESTRING ||
  627. ftype == SF_MULTIPOLYGON ||
  628. ftype == SF_GEOMETRYCOLLECTION) {
  629. ret = geometry_collection_from_wkb(wkb_data, nbytes, byte_order,
  630. is3D, cache, fparts);
  631. }
  632. else {
  633. G_warning(_("Unsupported feature type %d"), ftype);
  634. }
  635. G_free(wkb_data);
  636. return ret > 0 ? ftype : SF_UNKNOWN;
  637. }
  638. /*!
  639. \brief Read point for WKB data
  640. See OGRPoint::importFromWkb() from GDAL/OGR library
  641. \param wkb_data WKB data
  642. \param nbytes number of bytes (WKB data buffer)
  643. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  644. \param with_z WITH_Z for 3D data
  645. \param[out] line_p point geometry (pointer to line_pnts struct)
  646. \return wkb size
  647. \return -1 on error
  648. */
  649. int point_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  650. int with_z, struct line_pnts *line_p)
  651. {
  652. double x, y, z;
  653. if (nbytes < 21 && nbytes != -1 )
  654. return -1;
  655. /* get vertex */
  656. memcpy(&x, wkb_data + 5, 8);
  657. memcpy(&y, wkb_data + 5 + 8, 8);
  658. if (byte_order == ENDIAN_BIG) {
  659. SWAPDOUBLE(&x);
  660. SWAPDOUBLE(&y);
  661. }
  662. if (with_z) {
  663. if (nbytes < 29 && nbytes != -1 )
  664. return -1;
  665. memcpy(&z, wkb_data + 5 + 16, 8);
  666. if (byte_order == ENDIAN_BIG) {
  667. SWAPDOUBLE(&z);
  668. }
  669. }
  670. else {
  671. z = 0.0;
  672. }
  673. if (line_p) {
  674. Vect_reset_line(line_p);
  675. Vect_append_point(line_p, x, y, z);
  676. }
  677. return 5 + 8 * (with_z == WITH_Z ? 3 : 2);
  678. }
  679. /*!
  680. \brief Read line for WKB data
  681. See OGRLineString::importFromWkb() from GDAL/OGR library
  682. \param wkb_data WKB data
  683. \param nbytes number of bytes (WKB data buffer)
  684. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  685. \param with_z WITH_Z for 3D data
  686. \param[out] line_p line geometry (pointer to line_pnts struct)
  687. \return wkb size
  688. \return -1 on error
  689. */
  690. int linestring_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  691. int with_z, struct line_pnts *line_p, int is_ring)
  692. {
  693. int npoints, point_size, buff_min_size, offset;
  694. int i;
  695. double x, y, z;
  696. if (is_ring)
  697. offset = 5;
  698. else
  699. offset = 0;
  700. if (is_ring && nbytes < 4 && nbytes != -1)
  701. return error_corrupted_data(NULL);
  702. /* get the vertex count */
  703. memcpy(&npoints, wkb_data + (5 - offset), 4);
  704. if (byte_order == ENDIAN_BIG) {
  705. npoints = SWAP32(npoints);
  706. }
  707. /* check if the wkb stream buffer is big enough to store fetched
  708. number of points. 16 or 24 - size of point structure
  709. */
  710. point_size = with_z ? 24 : 16;
  711. if (npoints < 0 || npoints > INT_MAX / point_size)
  712. return error_corrupted_data(NULL);
  713. buff_min_size = point_size * npoints;
  714. if (nbytes != -1 && buff_min_size > nbytes - (9 - offset))
  715. return error_corrupted_data(_("Length of input WKB is too small"));
  716. if (line_p)
  717. Vect_reset_line(line_p);
  718. /* get the vertex */
  719. for (i = 0; i < npoints; i++) {
  720. memcpy(&x, wkb_data + (9 - offset) + i * point_size, 8);
  721. memcpy(&y, wkb_data + (9 - offset) + 8 + i * point_size, 8);
  722. if (with_z)
  723. memcpy(&z, wkb_data + (9 - offset) + 16 + i * point_size, 8);
  724. else
  725. z = 0.0;
  726. if (byte_order == ENDIAN_BIG) {
  727. SWAPDOUBLE(&x);
  728. SWAPDOUBLE(&y);
  729. if (with_z)
  730. SWAPDOUBLE(&z);
  731. }
  732. if (line_p)
  733. Vect_append_point(line_p, x, y, z);
  734. }
  735. return (9 - offset) + (with_z == WITH_Z ? 3 : 2) * 8 * line_p->n_points;
  736. }
  737. /*!
  738. \brief Read polygon for WKB data
  739. See OGRPolygon::importFromWkb() from GDAL/OGR library
  740. \param wkb_data WKB data
  741. \param nbytes number of bytes (WKB data buffer)
  742. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  743. \param with_z WITH_Z for 3D data
  744. \param[out] line_p array of rings (pointer to line_pnts struct)
  745. \return wkb size
  746. \return -1 on error
  747. */
  748. int polygon_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  749. int with_z, struct Format_info_cache *cache)
  750. {
  751. int nrings, data_offset, i, nsize, isize;
  752. struct line_pnts *line_i;
  753. if (nbytes < 9 && nbytes != -1)
  754. return -1;
  755. /* get the ring count */
  756. memcpy(&nrings, wkb_data + 5, 4);
  757. if (byte_order == ENDIAN_BIG) {
  758. nrings = SWAP32(nrings);
  759. }
  760. if (nrings < 0) {
  761. return -1;
  762. }
  763. /* reallocate space for islands if needed */
  764. reallocate_cache(cache, nrings);
  765. cache->lines_num += nrings;
  766. /* each ring has a minimum of 4 bytes (point count) */
  767. if (nbytes != -1 && nbytes - 9 < nrings * 4) {
  768. return error_corrupted_data(_("Length of input WKB is too small"));
  769. }
  770. data_offset = 9;
  771. if (nbytes != -1)
  772. nbytes -= data_offset;
  773. /* get the rings */
  774. nsize = 9;
  775. for (i = 0; i < nrings; i++ ) {
  776. line_i = cache->lines[cache->lines_next];
  777. cache->lines_types[cache->lines_next++] = GV_BOUNDARY;
  778. linestring_from_wkb(wkb_data + data_offset, nbytes, byte_order,
  779. with_z, line_i, TRUE);
  780. if (nbytes != -1) {
  781. isize = 4 + 8 * (with_z == WITH_Z ? 3 : 2) * line_i->n_points;
  782. nbytes -= isize;
  783. }
  784. nsize += isize;
  785. data_offset += isize;
  786. }
  787. return nsize;
  788. }
  789. /*!
  790. \brief Read geometry collection for WKB data
  791. See OGRGeometryCollection::importFromWkbInternal() from GDAL/OGR library
  792. \param wkb_data WKB data
  793. \param nbytes number of bytes (WKB data buffer)
  794. \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
  795. \param with_z WITH_Z for 3D data
  796. \param ipart part to cache (starts at 0)
  797. \param[out] cache lines cache
  798. \param[in,out] fparts feature parts (required for building pseudo-topology)
  799. \return number of parts
  800. \return -1 on error
  801. */
  802. int geometry_collection_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
  803. int with_z, struct Format_info_cache *cache,
  804. struct feat_parts *fparts)
  805. {
  806. int ipart, nparts, data_offset, nsize;
  807. unsigned char *wkb_subdata;
  808. SF_FeatureType ftype;
  809. if (nbytes < 9 && nbytes != -1)
  810. return error_corrupted_data(NULL);
  811. /* get the geometry count */
  812. memcpy(&nparts, wkb_data + 5, 4 );
  813. if (byte_order == ENDIAN_BIG) {
  814. nparts = SWAP32(nparts);
  815. }
  816. if (nparts < 0 || nparts > INT_MAX / 9) {
  817. return error_corrupted_data(NULL);
  818. }
  819. G_debug(5, "\t(geometry collections) parts: %d", nparts);
  820. /* each geometry has a minimum of 9 bytes */
  821. if (nbytes != -1 && nbytes - 9 < nparts * 9) {
  822. return error_corrupted_data(_("Length of input WKB is too small"));
  823. }
  824. data_offset = 9;
  825. if (nbytes != -1)
  826. nbytes -= data_offset;
  827. /* reallocate space for parts if needed */
  828. reallocate_cache(cache, nparts);
  829. /* get parts */
  830. cache->lines_next = cache->lines_num = 0;
  831. for (ipart = 0; ipart < nparts; ipart++) {
  832. wkb_subdata = (unsigned char *)wkb_data + data_offset;
  833. if (nbytes < 9 && nbytes != -1)
  834. return error_corrupted_data(NULL);
  835. if (byte_order == ENDIAN_LITTLE) {
  836. ftype = (SF_FeatureType) wkb_subdata[1];
  837. }
  838. else {
  839. ftype = (SF_FeatureType) wkb_subdata[4];
  840. }
  841. if (ftype == SF_POINT) {
  842. cache->lines_types[cache->lines_next] = GV_POINT;
  843. nsize = point_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
  844. cache->lines[cache->lines_next]);
  845. cache->lines_num++;
  846. add_fpart(fparts, ftype, cache->lines_next, 1);
  847. cache->lines_next++;
  848. }
  849. else if (ftype == SF_LINESTRING) {
  850. cache->lines_types[cache->lines_next] = GV_LINE;
  851. nsize = linestring_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
  852. cache->lines[cache->lines_next],
  853. FALSE);
  854. cache->lines_num++;
  855. add_fpart(fparts, ftype, cache->lines_next, 1);
  856. cache->lines_next++;
  857. }
  858. else if (ftype == SF_POLYGON) {
  859. int idx = cache->lines_next;
  860. nsize = polygon_from_wkb(wkb_subdata, nbytes, byte_order,
  861. with_z, cache);
  862. add_fpart(fparts, ftype, idx, cache->lines_num - idx);
  863. }
  864. else if (ftype == SF_GEOMETRYCOLLECTION ||
  865. ftype == SF_MULTIPOLYGON ||
  866. ftype == SF_MULTILINESTRING ||
  867. ftype == SF_MULTIPOLYGON) {
  868. // geometry_collection_from_wkb();
  869. }
  870. else {
  871. G_warning(_("Unsupported feature type %d"), ftype);
  872. }
  873. if (nbytes != -1) {
  874. nbytes -= nsize;
  875. }
  876. data_offset += nsize;
  877. }
  878. cache->lines_next = 0;
  879. return nparts;
  880. }
  881. /*!
  882. \brief Report error message
  883. \param msg message (NULL)
  884. \return -1
  885. */
  886. int error_corrupted_data(const char *msg)
  887. {
  888. if (msg)
  889. G_warning(_("Corrupted data. %s."), msg);
  890. else
  891. G_warning(_("Corrupted data"));
  892. return -1;
  893. }
  894. /*!
  895. \brief Set initial SQL query for sequential access
  896. \param pg_info pointer to Format_info_pg struct
  897. \return 0 on success
  898. \return -1 on error
  899. */
  900. int set_initial_query(struct Format_info_pg *pg_info)
  901. {
  902. char stmt[DB_SQL_MAX];
  903. if (execute(pg_info->conn, "BEGIN") == -1)
  904. return -1;
  905. sprintf(stmt, "DECLARE %s%p CURSOR FOR SELECT %s,%s FROM %s",
  906. pg_info->table_name, pg_info->conn,
  907. pg_info->geom_column, pg_info->fid_column,
  908. pg_info->table_name);
  909. if (execute(pg_info->conn, stmt) == -1)
  910. return -1;
  911. sprintf(stmt, "FETCH %d in %s%p", CURSOR_PAGE,
  912. pg_info->table_name, pg_info->conn);
  913. pg_info->res = PQexec(pg_info->conn, stmt);
  914. pg_info->next_line = 0;
  915. return 0;
  916. }
  917. /*!
  918. \brief Execute SQL statement
  919. See pg_local_proto.h
  920. \param conn pointer to PGconn
  921. \param stmt query
  922. \return 0 on success
  923. \return -1 on error
  924. */
  925. int execute(PGconn *conn, const char *stmt)
  926. {
  927. PGresult *result;
  928. result = NULL;
  929. G_debug(3, "execute(): %s", stmt);
  930. result = PQexec(conn, stmt);
  931. if (!result || PQresultStatus(result) != PGRES_COMMAND_OK) {
  932. PQclear(result);
  933. G_warning(_("Execution failed: %s"), PQerrorMessage(conn));
  934. return -1;
  935. }
  936. PQclear(result);
  937. return 0;
  938. }
  939. /*!
  940. \brief Reallocate lines cache
  941. */
  942. void reallocate_cache(struct Format_info_cache *cache, int num)
  943. {
  944. int i;
  945. if (cache->lines_alloc >= num)
  946. return;
  947. if (!cache->lines) {
  948. /* most of features requires only one line cache */
  949. cache->lines_alloc = 1;
  950. }
  951. else {
  952. cache->lines_alloc += 20;
  953. }
  954. cache->lines = (struct line_pnts **) G_realloc(cache->lines,
  955. cache->lines_alloc *
  956. sizeof(struct line_pnts *));
  957. cache->lines_types = (int *) G_realloc(cache->lines_types,
  958. cache->lines_alloc *
  959. sizeof(int));
  960. if (cache->lines_alloc > 1) {
  961. for (i = cache->lines_alloc - 20; i < cache->lines_alloc; i++) {
  962. cache->lines[i] = Vect_new_line_struct();
  963. cache->lines_types[i] = -1;
  964. }
  965. }
  966. else {
  967. cache->lines[0] = Vect_new_line_struct();
  968. cache->lines_types[0] = -1;
  969. }
  970. }
  971. void add_fpart(struct feat_parts *fparts, SF_FeatureType ftype,
  972. int idx, int nlines)
  973. {
  974. if (!fparts)
  975. return;
  976. if (fparts->a_parts == 0 || fparts->n_parts >= fparts->a_parts) {
  977. if (fparts->a_parts == 0)
  978. fparts->a_parts = 1;
  979. else
  980. fparts->a_parts += 20;
  981. fparts->ftype = (SF_FeatureType *) G_realloc(fparts->ftype,
  982. fparts->a_parts * sizeof(SF_FeatureType));
  983. fparts->nlines = (int *) G_realloc(fparts->nlines,
  984. fparts->a_parts * sizeof(int));
  985. fparts->idx = (int *) G_realloc(fparts->idx,
  986. fparts->a_parts * sizeof(int));
  987. }
  988. fparts->ftype[fparts->n_parts] = ftype;
  989. fparts->idx[fparts->n_parts] = idx;
  990. fparts->nlines[fparts->n_parts] = nlines;
  991. fparts->n_parts++;
  992. }
  993. #endif