read_pg.c 30 KB

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