28 #include "local_proto.h"
31 #include "pg_local_proto.h"
33 #define WKBSRIDFLAG 0x20000000
35 #define TOPOGEOM_COLUMN "topo"
40 #define USE_TOPO_STMT 0
45 static int create_pg_layer(
struct Map_info *,
int);
49 static off_t write_line_tp(
struct Map_info *,
int,
int,
51 static char *binary_to_hex(
int,
const unsigned char *);
52 static unsigned char *point_to_wkb(
int,
const struct line_pnts *,
int,
int *);
53 static unsigned char *linestring_to_wkb(
int,
const struct line_pnts *,
int,
55 static unsigned char *polygon_to_wkb(
int,
const struct line_pnts **,
int,
int,
61 static char *build_insert_stmt(
const struct Format_info_pg *,
const char *,
int,
63 static int insert_topo_element(
struct Map_info *,
int,
int,
const char *);
65 static int update_next_edge(
struct Map_info *,
int,
int);
68 static int delete_face(
struct Map_info *,
int);
69 static int update_topo_edge(
struct Map_info *,
int);
71 static int update_topo_face(
struct Map_info *,
int);
72 static int add_line_to_topo_pg(
struct Map_info *, off_t,
int,
74 static int delete_line_from_topo_pg(
struct Map_info *,
int,
int,
76 static int set_constraint_to_deferrable(
struct Format_info_pg *,
const char *,
77 const char *,
const char *,
78 const char *,
const char *);
85 #define NOPG_UNUSED UNUSED
116 pg_info = &(Map->fInfo.pg);
120 if (create_pg_layer(Map, type) < 0)
128 return write_line_sf(Map, type, &points, 1, cats);
132 return write_line_tp(Map, type,
FALSE, points, cats);
134 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
159 pg_info = &(Map->fInfo.pg);
166 return write_line_tp(Map, type,
FALSE, points, cats);
168 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
194 G_debug(3,
"V1_rewrite_line_pg(): type=%d offset=%" PRId64, type,
offset);
197 G_warning(
_(
"Unable to rewrite feature (incompatible feature types)"));
206 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
233 G_debug(3,
"V2_rewrite_line_pg(): line=%d type=%d", (
int)line, type);
236 char *stmt, *geom_data;
244 pg_info = &(Map->fInfo.pg);
246 if (line < 1 || line > Map->plus.n_lines) {
247 G_warning(
_(
"Attempt to access feature with invalid id (%d)"),
252 Line = Map->plus.Line[line];
254 G_warning(
_(
"Attempt to access dead feature %d"), (
int)line);
259 if (!(Map->plus.update_cidx)) {
260 Map->plus.cidx_up_to_date =
FALSE;
267 G_warning(
_(
"Unable to rewrite feature (incompatible feature types)"));
272 if (0 != delete_line_from_topo_pg(Map, line,
type, Points))
278 table_name = keycolumn =
"node";
281 table_name =
"edge_data";
291 geom_data = line_to_wkb(pg_info, &points, 1,
type, Map->head.with_z);
293 "UPDATE \"%s\".\"%s\" SET geom = '%s'::GEOMETRY WHERE %s_id = "
295 schema_name, table_name, geom_data, keycolumn, line);
299 G_warning(
_(
"Unable to rewrite feature %d"), (
int)line);
306 return add_line_to_topo_pg(Map,
offset,
type, points);
308 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
333 pg_info = &(Map->fInfo.pg);
347 G_debug(3,
"V1_delete_line_pg(): offset = %lu -> fid = %ld",
348 (
unsigned long)
offset, fid);
357 snprintf(stmt,
sizeof(stmt),
"DELETE FROM %s WHERE %s = %ld",
369 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
393 pg_info = &(Map->fInfo.pg);
395 if (line < 1 || line > Map->plus.n_lines) {
396 G_warning(
_(
"Attempt to access feature with invalid id (%d)"),
411 if (line < 1 || line > Map->plus.n_lines) {
412 G_warning(
_(
"Attempt to access feature with invalid id (%d)"),
417 Line = Map->plus.Line[line];
419 G_warning(
_(
"Attempt to access dead feature %d"), (
int)line);
423 if (!(Map->plus.update_cidx)) {
424 Map->plus.cidx_up_to_date =
431 table_name = keycolumn =
"node";
434 table_name =
"edge_data";
439 snprintf(stmt,
sizeof(stmt),
440 "UPDATE \"%s\".\"%s\" SET abs_next_left_edge = edge_id, "
441 "next_left_edge = -edge_id WHERE abs_next_left_edge = %d",
449 snprintf(stmt,
sizeof(stmt),
450 "UPDATE \"%s\".\"%s\" SET abs_next_right_edge = edge_id, "
451 "next_right_edge = edge_id WHERE abs_next_right_edge = %d",
469 stmt,
sizeof(stmt),
"DELETE FROM \"%s\".\"%s\" WHERE %s_id = %d",
472 G_warning(
_(
"Unable to delete feature (%s) %d"), keycolumn,
488 ret = delete_line_from_topo_pg(Map, line,
type, Points);
496 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
541 int nparts,
const struct line_cats *cats)
543 return write_line_sf(Map,
GV_BOUNDARY, points, nparts, cats);
561 char *stmt, *geom_data;
567 for (part = 0; part < nparts; part++) {
568 npoints = points[part]->
n_points - 1;
569 if (points[part]->
x[0] != points[part]->
x[npoints] ||
570 points[part]->y[0] != points[part]->y[npoints] ||
571 points[part]->z[0] != points[part]->z[npoints]) {
572 G_warning(
_(
"Boundary is not closed. Skipping."));
583 "UPDATE \"%s\".\"%s\" SET %s = '%s'::GEOMETRY WHERE %s = %d",
612 char *geom_type, *def_file;
618 def_file = getenv(
"GRASS_VECTOR_PGFILE");
652 if (check_schema(pg_info) != 0)
657 snprintf(stmt,
sizeof(stmt),
658 "CREATE TABLE \"%s\".\"%s\" (%s SERIAL%s, %s INTEGER",
666 int col, ncols, sqltype, length;
678 driver = open_db(pg_info);
693 "copying attributes: driver = %s database = %s table = %s cols "
697 for (col = 0; col < ncols; col++) {
703 G_debug(3,
"\tcolumn = %d name = %s type = %d length = %d", col,
704 colname, sqltype, length);
709 G_debug(3,
"\t%s skipped", colname);
714 snprintf(stmt_col,
sizeof(stmt_col),
",\"%s\" %s", colname,
716 strcat(stmt, stmt_col);
719 snprintf(stmt_col,
sizeof(stmt_col),
"(%d)", length);
720 strcat(stmt, stmt_col);
745 geom_type =
"LINESTRING";
748 geom_type =
"POLYGON";
751 geom_type =
"POLYGONZ";
754 geom_type =
"GEOMETRY";
763 snprintf(stmt,
sizeof(stmt),
764 "SELECT AddGeometryColumn('%s', '%s', "
765 "'%s', %d, '%s', %d)",
769 result = PQexec(pg_info->
conn, stmt);
771 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
772 G_warning(
"%s", PQresultErrorMessage(result));
782 snprintf(stmt,
sizeof(stmt),
"CREATE INDEX %s_%s_idx ON \"%s\".\"%s\" (%s)",
793 snprintf(stmt,
sizeof(stmt),
794 "CREATE INDEX %s_%s_idx ON \"%s\".\"%s\" USING GIST (%s)",
823 int i, found, nschema;
834 snprintf(stmt,
sizeof(stmt),
"SELECT nspname FROM pg_namespace");
836 result = PQexec(pg_info->
conn, stmt);
838 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
845 nschema = PQntuples(result);
846 for (i = 0; i < nschema && !found; i++) {
847 if (strcmp(pg_info->
schema_name, PQgetvalue(result, i, 0)) == 0)
854 snprintf(stmt,
sizeof(stmt),
"CREATE SCHEMA %s", pg_info->
schema_name);
859 G_warning(
_(
"Schema <%s> doesn't exist, created"),
880 int create_topo_schema(
struct Format_info_pg *pg_info,
int with_z)
886 def_file = getenv(
"GRASS_VECTOR_PGFILE");
907 G_debug(1,
"PG: tolerance: %f", tolerance);
940 snprintf(stmt,
sizeof(stmt),
941 "SELECT topology.createtopology('%s', "
942 "find_srid('%s', '%s', '%s'), %f, '%s')",
945 with_z ==
WITH_Z ?
"t" :
"f");
955 snprintf(stmt,
sizeof(stmt),
956 "SELECT topology.AddTopoGeometryColumn('%s', '%s', '%s', "
967 snprintf(stmt,
sizeof(stmt),
968 "CREATE INDEX \"%s_%s_%s_idx\" ON \"%s\".\"%s\" (((%s).id))",
979 if (-1 == set_constraint_to_deferrable(pg_info,
"node",
"face_exists",
980 "containing_face",
"face",
982 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
983 "end_node_exists",
"end_node",
984 "node",
"node_id") ||
985 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
986 "left_face_exists",
"left_face",
987 "face",
"face_id") ||
988 -1 == set_constraint_to_deferrable(
989 pg_info,
"edge_data",
"right_face_exists",
"right_face",
990 "face",
"face_id") ||
991 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
993 "start_node",
"node",
"node_id"))
1004 snprintf(stmt,
sizeof(stmt),
1005 "CREATE TABLE \"%s\".%s (node_id SERIAL PRIMARY KEY, "
1006 "lines integer[], angles float[])",
1013 snprintf(stmt,
sizeof(stmt),
1014 "ALTER TABLE \"%s\".%s ADD CONSTRAINT node_exists "
1015 "FOREIGN KEY (node_id) REFERENCES \"%s\".node (node_id) "
1016 "DEFERRABLE INITIALLY DEFERRED",
1027 snprintf(stmt,
sizeof(stmt),
1028 "CREATE TABLE \"%s\".%s (line_id SERIAL PRIMARY KEY, "
1029 "left_area integer, right_area integer)",
1036 snprintf(stmt,
sizeof(stmt),
1037 "ALTER TABLE \"%s\".%s ADD CONSTRAINT line_exists "
1038 "FOREIGN KEY (line_id) REFERENCES \"%s\".edge_data (edge_id) "
1039 "DEFERRABLE INITIALLY DEFERRED",
1051 snprintf(stmt,
sizeof(stmt),
1052 "CREATE TABLE \"%s\".%s (area_id SERIAL PRIMARY KEY, "
1053 "lines integer[], centroid integer, isles integer[])",
1064 snprintf(stmt,
sizeof(stmt),
1065 "CREATE TABLE \"%s\".%s (isle_id SERIAL PRIMARY KEY, "
1066 "lines integer[], area integer)",
1101 int create_pg_layer(
struct Map_info *Map,
int type)
1109 G_warning(
_(
"Connection string not defined"));
1114 G_warning(
_(
"PostGIS feature table not defined"));
1118 G_debug(1,
"Vect__open_new_pg(): conninfo='%s' table='%s' -> type = %d",
1142 G_warning(
_(
"Unsupported geometry type (%d)"), type);
1155 G_warning(
_(
"More layers defined, using driver <%s> and "
1160 G_warning(
_(
"Database connection not defined. "
1161 "Unable to write attributes."));
1166 if (create_table(pg_info) == -1) {
1167 G_warning(
_(
"Unable to create new PostGIS feature table"));
1180 if (create_topo_schema(pg_info,
Vect_is_3d(Map)) == -1) {
1181 G_warning(
_(
"Unable to create new PostGIS topology schema"));
1211 return "COLLECTION";
1213 G_warning(
_(
"Unsupported feature type %d"), sftype);
1230 off_t write_line_sf(
struct Map_info *Map,
int type,
1231 const struct line_pnts **points,
int nparts,
1243 offset_info = &(pg_info->
offset);
1249 if (!pg_info->
conn) {
1254 G_warning(
_(
"PostGIS feature table not defined"));
1260 if (create_pg_layer(Map, type) < 0)
1275 G_warning(
_(
"No category defined for layer %d"), field);
1277 G_warning(
_(
"Feature has more categories, using "
1278 "category %d (from layer %d)"),
1288 G_warning(
_(
"Point skipped (output feature type: %s)"),
1295 G_warning(
_(
"Line skipped (output feature type: %s)"),
1302 G_warning(
_(
"Centroid skipped (output feature type: %s)"),
1309 G_warning(
_(
"Boundary skipped (output feature type: %s)"),
1316 G_warning(
_(
"Face skipped (output feature type: %s)"),
1322 G_warning(
_(
"Unsupported feature type %d"), type);
1326 G_debug(3,
"write_line_sf(): type = %d n_points = %d cat = %d", type,
1327 points[0]->n_points, cat);
1333 for (part = 0; part < nparts; part++) {
1334 npoints = points[part]->
n_points - 1;
1335 if (points[part]->
x[0] != points[part]->
x[npoints] ||
1336 points[part]->y[0] != points[part]->y[npoints] ||
1337 points[part]->z[0] != points[part]->z[npoints]) {
1338 G_warning(
_(
"Boundary is not closed. Skipping."));
1345 if (-1 == write_feature(Map, -1, type, points, nparts, cat)) {
1363 G_debug(3,
"write_line_sf(): -> offset = %lu offset_num = %d cat = %d",
1364 (
unsigned long)offset, offset_info->
array_num, cat);
1382 off_t write_line_tp(
struct Map_info *Map,
int type,
int is_node,
1386 int line, cat, line_id;
1393 plus = &(Map->
plus);
1401 G_warning(
_(
"Invalid feature type (%d) for nodes"), type);
1406 if (!pg_info->
conn) {
1411 G_warning(
_(
"PostGIS feature table not defined"));
1415 G_warning(
_(
"PostGIS topology schema not defined"));
1421 if (create_pg_layer(Map, type) < 0)
1428 G_debug(3,
"write_line_pg(): type = %d n_points = %d", type,
1434 if (cats && cats->
n_cats > 0) {
1441 G_warning(
_(
"Feature has more categories, using "
1442 "category %d (from layer %d)"),
1443 cat, cats->
field[0]);
1471 line = add_line_to_topo_pg(Map, offset, type, points);
1479 line_id = write_feature(Map, line, type, &points, 1, cat);
1499 offset = &(pg_info->
offset);
1509 offset->
array[node - 1] = (int)line_id;
1514 update_topo_face(Map, line);
1516 return !is_node ? line : 0;
1529 char *binary_to_hex(
int nbytes,
const unsigned char *wkb_data)
1533 static const char ach_hex[] =
"0123456789ABCDEF";
1535 hex_data = (
char *)
G_malloc(nbytes * 2 + 1);
1536 hex_data[nbytes * 2] =
'\0';
1538 for (i = 0; i < nbytes; i++) {
1539 nlow = wkb_data[i] & 0x0f;
1540 nhigh = (wkb_data[i] & 0xf0) >> 4;
1542 hex_data[i * 2] = ach_hex[nhigh];
1543 hex_data[i * 2 + 1] = ach_hex[nlow];
1562 unsigned char *point_to_wkb(
int byte_order,
const struct line_pnts *points,
1563 int with_z,
int *nsize)
1565 unsigned char *wkb_data;
1566 unsigned int sf_type;
1572 *nsize = with_z ? 29 : 21;
1574 G_zero(wkb_data, *nsize);
1576 G_debug(5,
"\t->point size=%d (with_z = %d)", *nsize, with_z);
1580 wkb_data[0] =
'\001';
1582 wkb_data[0] =
'\000';
1588 sf_type = LSBWORD32(sf_type);
1590 sf_type = MSBWORD32(sf_type);
1591 memcpy(wkb_data + 1, &sf_type, 4);
1594 memcpy(wkb_data + 5, &(points->
x[0]), 8);
1595 memcpy(wkb_data + 5 + 8, &(points->
y[0]), 8);
1598 memcpy(wkb_data + 5 + 16, &(points->
z[0]), 8);
1603 SWAPDOUBLE(wkb_data + 5);
1604 SWAPDOUBLE(wkb_data + 5 + 8);
1607 SWAPDOUBLE(wkb_data + 5 + 16);
1626 unsigned char *linestring_to_wkb(
int byte_order,
const struct line_pnts *points,
1627 int with_z,
int *nsize)
1630 unsigned char *wkb_data;
1631 unsigned int sf_type;
1637 point_size = 8 * (with_z ? 3 : 2);
1638 *nsize = 5 + 4 + points->
n_points * point_size;
1640 G_zero(wkb_data, *nsize);
1642 G_debug(5,
"\t->linestring size=%d (with_z = %d)", *nsize, with_z);
1646 wkb_data[0] =
'\001';
1648 wkb_data[0] =
'\000';
1654 sf_type = LSBWORD32(sf_type);
1656 sf_type = MSBWORD32(sf_type);
1657 memcpy(wkb_data + 1, &sf_type, 4);
1660 memcpy(wkb_data + 5, &(points->
n_points), 4);
1663 for (i = 0; i < points->
n_points; i++) {
1664 memcpy(wkb_data + 9 + point_size * i, &(points->
x[i]), 8);
1665 memcpy(wkb_data + 9 + 8 + point_size * i, &(points->
y[i]), 8);
1668 memcpy(wkb_data + 9 + 16 + point_size * i, &(points->
z[i]), 8);
1674 int npoints, nitems;
1676 npoints = SWAP32(points->
n_points);
1677 memcpy(wkb_data + 5, &npoints, 4);
1679 nitems = (with_z ? 3 : 2) * points->
n_points;
1680 for (i = 0; i < nitems; i++) {
1681 SWAPDOUBLE(wkb_data + 9 + 4 + 8 * i);
1702 unsigned char *polygon_to_wkb(
int byte_order,
const struct line_pnts **points,
1703 int nrings,
int with_z,
int *nsize)
1705 int i, ring, point_size, offset;
1706 unsigned char *wkb_data;
1707 unsigned int sf_type;
1712 for (ring = 0; ring < nrings; ring++) {
1713 if (points[ring]->n_points < 3)
1718 point_size = 8 * (with_z ? 3 : 2);
1720 for (ring = 0; ring < nrings; ring++)
1721 *nsize += 4 + point_size * points[ring]->n_points;
1723 G_zero(wkb_data, *nsize);
1725 G_debug(5,
"\t->polygon size=%d (with_z = %d)", *nsize, with_z);
1729 wkb_data[0] =
'\001';
1731 wkb_data[0] =
'\000';
1737 sf_type = LSBWORD32(sf_type);
1739 sf_type = MSBWORD32(sf_type);
1740 memcpy(wkb_data + 1, &sf_type, 4);
1746 ncount = SWAP32(nrings);
1747 memcpy(wkb_data + 5, &ncount, 4);
1750 memcpy(wkb_data + 5, &nrings, 4);
1755 for (ring = 0; ring < nrings; ring++) {
1756 memcpy(wkb_data + offset, &(points[ring]->n_points), 4);
1757 for (i = 0; i < points[ring]->
n_points; i++) {
1758 memcpy(wkb_data + offset + 4 + point_size * i,
1759 &(points[ring]->
x[i]), 8);
1760 memcpy(wkb_data + offset + 4 + 8 + point_size * i,
1761 &(points[ring]->y[i]), 8);
1764 memcpy(wkb_data + offset + 4 + 16 + point_size * i,
1765 &(points[ring]->z[i]), 8);
1769 offset += 4 + point_size * points[ring]->
n_points;
1773 int npoints, nitems;
1775 npoints = SWAP32(points[ring]->n_points);
1776 memcpy(wkb_data + 5, &npoints, 4);
1778 nitems = (with_z ? 3 : 2) * points[ring]->n_points;
1779 for (i = 0; i < nitems; i++) {
1780 SWAPDOUBLE(wkb_data + offset + 4 + 8 * i);
1803 const struct line_pnts **points,
int nparts,
int type,
1806 int byte_order, nbytes, nsize;
1807 unsigned int sf_type;
1809 unsigned char *wkb_data;
1810 char *text_data, *text_data_p, *hex_data;
1818 wkb_data = point_to_wkb(byte_order, points[0], with_z, &nbytes);
1821 wkb_data = linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
1826 polygon_to_wkb(byte_order, points, nparts, with_z, &nbytes);
1831 linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
1835 if (!wkb_data || nbytes < 1) {
1836 G_warning(
_(
"Unsupported feature type %d"), type);
1843 nsize = nbytes * 2 + 8 + 1;
1844 text_data = text_data_p = (
char *)
G_malloc(nsize);
1847 hex_data = binary_to_hex(1, wkb_data);
1848 strcpy(text_data_p, hex_data);
1853 memcpy(&sf_type, wkb_data + 1, 4);
1856 if (pg_info->
srid > 0) {
1857 unsigned int srs_flag;
1862 sf_type = sf_type | srs_flag;
1866 hex_data = binary_to_hex(4, (
unsigned char *)&sf_type);
1867 strcpy(text_data_p, hex_data);
1872 if (pg_info->
srid > 0) {
1873 unsigned int srs_id;
1876 srs_id = LSBWORD32(pg_info->
srid);
1877 hex_data = binary_to_hex(
sizeof(srs_id), (
unsigned char *)&srs_id);
1878 strcpy(text_data_p, hex_data);
1885 hex_data = binary_to_hex(nbytes - 5, wkb_data + 5);
1886 strcpy(text_data_p, hex_data);
1906 int write_feature(
struct Map_info *Map,
int line,
int type,
1907 const struct line_pnts **points,
int nparts,
int cat)
1909 int with_z, topo_id;
1910 char *stmt, *geom_data;
1917 if (with_z && pg_info->
coor_dim != 3) {
1918 G_warning(
_(
"Trying to insert 3D data into feature table "
1919 "which store 2D data only"));
1922 if (!with_z && pg_info->
coor_dim != 2) {
1923 G_warning(
_(
"Trying to insert 2D data into feature table "
1924 "which store 3D data only"));
1929 geom_data = line_to_wkb(pg_info, points, nparts, type, with_z);
1946 topo_id = insert_topo_element(Map, line, type, geom_data);
1948 G_warning(
_(
"Unable to insert topological element into PostGIS "
1949 "Topology schema"));
1964 stmt = build_insert_stmt(pg_info, geom_data, topo_id, cat);
1998 const char *geom_data,
int topo_id,
int cat)
2008 topogeom_type = type_to_topogeom(pg_info);
2009 if (topogeom_type < 0)
2016 if (Fi && cat > -1) {
2018 int col, ncol, more;
2019 int sqltype, ctype, is_fid;
2022 const char *colname;
2034 snprintf(buf,
sizeof(buf),
"SELECT * FROM %s WHERE %s = %d", Fi->
table,
2040 snprintf(buf,
sizeof(buf),
"INSERT INTO \"%s\".\"%s\" (",
2046 G_warning(
_(
"Unable to select attributes for category %d"), cat);
2054 G_warning(
_(
"No database record for category %d, "
2055 "no attributes will be written"),
2062 for (col = 0; col < ncol; col++) {
2070 G_debug(3,
"col %d : val = %s", col,
2076 is_fid = strcmp(pg_info->
fid_column, colname) == 0;
2080 G_warning(
_(
"FID column must be integer, column <%s> "
2087 snprintf(buf_tmp,
sizeof(buf_tmp),
"\"%s\"", colname);
2088 strcat(buf, buf_tmp);
2096 snprintf(buf_tmp,
sizeof(buf_tmp),
"%d",
2100 snprintf(buf_tmp,
sizeof(buf_tmp),
"%.14f",
2108 snprintf(buf_tmp,
sizeof(buf_tmp),
"'%s'",
2115 snprintf(buf_tmp,
sizeof(buf_tmp),
"%s",
2119 G_warning(
_(
"Unsupported column type %d"), ctype);
2120 snprintf(buf_tmp,
sizeof(buf_tmp),
"NULL");
2126 G_warning(
_(
"Invalid value for FID column: NULL"));
2127 snprintf(buf_tmp,
sizeof(buf_tmp),
"NULL");
2129 strcat(buf_val, buf_tmp);
2131 strcat(buf_val,
",");
2136 G_asprintf(&stmt,
"%s,%s) VALUES (%s,'%s'::GEOMETRY)", buf,
2142 if (buf[strlen(buf) - 1] ==
',') {
2143 buf[strlen(buf) - 1] =
'\0';
2144 buf_val[strlen(buf_val) - 1] =
'\0';
2147 "%s, %s) VALUES (%s, '(%d, 1, %d, "
2148 "%d)'::topology.TopoGeometry)",
2162 "INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES "
2163 "(%d, '%s'::GEOMETRY)",
2170 "INSERT INTO \"%s\".\"%s\" (%s) VALUES "
2180 "INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES "
2181 "(%d, '(%d, 1, %d, %d)'::topology.TopoGeometry)",
2205 int insert_topo_element(
struct Map_info *Map,
int id,
int type,
2206 const char *geom_data)
2215 plus = &(Map->
plus);
2222 G_warning(
_(
"Invalid feature %d (max: %d)"), topo_id,
2241 G_warning(
_(
"Invalid node %d (%d)"), topo_id,
2257 G_asprintf(&stmt,
"SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
2262 snprintf(stmt_id,
sizeof(stmt_id),
2263 "SELECT nextval('\"%s\".node_node_id_seq')",
2270 "INSERT INTO \"%s\".node (node_id, geom) VALUES "
2271 "(%d, '%s'::GEOMETRY)",
2280 G_asprintf(&stmt,
"SELECT topology.AddEdge('%s', '%s'::GEOMETRY)",
2283 int n1, n2, nle, nre;
2287 offset = &(pg_info->
offset);
2291 snprintf(stmt_id,
sizeof(stmt_id),
2292 "SELECT nextval('\"%s\".edge_data_edge_id_seq')",
2301 int i, n, next_edge;
2304 topo_id = (
int)Line->
offset;
2310 for (i = 0; i < 2; i++) {
2316 update_next_edge(Map, n, i == 0 ? topo_id : -topo_id);
2317 if (next_edge != 0) {
2326 G_warning(
_(
"Unable to determine next left/right edge for "
2333 G_warning(
_(
"Unable to insert new edge. Topology not available."));
2337 G_debug(3,
"new edge: id=%d next_left_edge=%d next_right_edge=%d",
2347 "INSERT INTO \"%s\".edge_data (edge_id, start_node, end_node, "
2348 "next_left_edge, abs_next_left_edge, next_right_edge, "
2349 "abs_next_right_edge, "
2350 "left_face, right_face, geom) VALUES "
2351 "(%d, %d, %d, %d, %d, %d, %d, 0, 0, '%s'::GEOMETRY)",
2353 offset->
array[n2 - 1], nle, abs(nle), nre, abs(nre), geom_data);
2360 G_asprintf(&stmt,
"SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
2367 snprintf(stmt_id,
sizeof(stmt_id),
2368 "SELECT nextval('\"%s\".node_node_id_seq')",
2384 "INSERT INTO \"%s\".node (node_id, containing_face, geom) VALUES "
2385 "(%d, %d, '%s'::GEOMETRY)",
2391 G_warning(
_(
"Unsupported feature type %d"), type);
2427 return topogeom_type;
2431 int topo_id,
int element_id)
2436 topogeom_type = type_to_topogeom(pg_info);
2437 if (topogeom_type < 0)
2440 snprintf(stmt,
sizeof(stmt),
2441 "INSERT into \"%s\".relation VALUES(%d, 1, %d, %d)",
2465 int update_next_edge(
struct Map_info *Map,
int nlines,
int line)
2467 int ret, next_line, edge;
2471 struct P_line *Line_next, *Line;
2473 Line = Line_next =
NULL;
2483 G_debug(3,
"line=%d next_line=%d", line, next_line);
2484 if (next_line == 0) {
2490 Line_next = Map->
plus.
Line[abs(next_line)];
2491 if (!Line || !Line_next) {
2498 ret = next_line > 0 ? Line_next->
offset : -Line_next->
offset;
2502 ret = next_line > 0 ? Line_next->
offset : -Line_next->
offset;
2505 if (next_line < 0) {
2506 snprintf(stmt,
sizeof(stmt),
2507 "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
2508 "abs_next_left_edge = %d WHERE edge_id = %d AND "
2509 "abs_next_left_edge = %d",
2512 G_debug(3,
"update edge=%d next_left_edge=%d (?)",
2513 (
int)Line_next->
offset, edge);
2516 snprintf(stmt,
sizeof(stmt),
2517 "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
2518 "abs_next_right_edge = %d WHERE edge_id = %d AND "
2519 "abs_next_right_edge = %d",
2522 G_debug(3,
"update edge=%d next_right_edge=%d (?)",
2523 (
int)Line_next->
offset, edge);
2539 Line_next = Map->
plus.
Line[abs(next_line)];
2541 if (next_line < 0) {
2542 snprintf(stmt,
sizeof(stmt),
2543 "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
2544 "abs_next_left_edge = %d WHERE edge_id = %d",
2547 G_debug(3,
"update edge=%d next_left_edge=%d",
2548 (
int)Line_next->
offset, edge);
2551 snprintf(stmt,
sizeof(stmt),
2552 "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
2553 "abs_next_right_edge = %d WHERE edge_id = %d",
2556 G_debug(3,
"update edge=%d next_right_edge=%d",
2557 (
int)Line_next->
offset, edge);
2601 "INSERT INTO \"%s\".face (face_id, mbr) VALUES "
2602 "(%d, ST_GeomFromText('POLYGON((%.12f %.12f, %.12f %.12f, %.12f "
2603 "%.12f, %.12f %.12f, "
2604 "%.12f %.12f))', %d))",
2606 box.
E, box.
N, box.
E, box.
S, box.
W, box.
S, pg_info->
srid);
2607 G_debug(3,
"new face id=%d", area);
2630 int delete_face(
struct Map_info *Map,
int area)
2639 snprintf(stmt,
sizeof(stmt),
"UPDATE \"%s\".node SET containing_face = 0 "
2648 snprintf(stmt,
sizeof(stmt),
"UPDATE \"%s\".edge_data SET left_face = 0 "
2657 snprintf(stmt,
sizeof(stmt),
"UPDATE \"%s\".edge_data SET right_face = 0 "
2666 snprintf(stmt,
sizeof(stmt),
"DELETE FROM \"%s\".face WHERE face_id = %d",
2668 G_debug(3,
"delete face id=%d", area);
2694 int update_topo_edge(
struct Map_info *Map,
int line)
2697 int nle, nre, next_edge;
2706 G_warning(
_(
"Attempt to access non-existing feature %d"), line);
2711 G_warning(
_(
"Attempt to access dead feature %d"), line);
2720 for (i = 0; i < 2; i++) {
2728 next_edge = update_next_edge(Map, n, i == 0 ? line : -line);
2729 if (next_edge != 0) {
2736 G_warning(
_(
"Unable to determine next left/right edge"));
2741 if (nle == 0 && nre == 0)
2744 if (nle != 0 && nre != 0) {
2746 snprintf(stmt,
sizeof(stmt),
"UPDATE \"%s\".edge_data SET "
2747 "next_left_edge = %d, abs_next_left_edge = %d, "
2748 "next_right_edge = %d, abs_next_right_edge = %d "
2750 nle, abs(nle), nre, abs(nre), (
int)Line->
offset);
2752 else if (nle != 0) {
2754 snprintf(stmt,
sizeof(stmt),
"UPDATE \"%s\".edge_data SET "
2755 "next_left_edge = %d, abs_next_left_edge = %d "
2757 nle, abs(nle), (
int)Line->
offset);
2761 snprintf(stmt,
sizeof(stmt),
"UPDATE \"%s\".edge_data SET "
2762 "next_right_edge = %d, abs_next_right_edge = %d "
2764 nre, abs(nre), (
int)Line->
offset);
2766 G_debug(3,
"update edge=%d next_left_edge=%d next_right_edge=%d",
2767 (
int)Line->
offset, nle, nre);
2790 int update_topo_face(
struct Map_info *Map,
int line)
2792 int i, s, area, face[2];
2796 struct P_line *Line, *Line_i;
2803 G_warning(
_(
"Attempt to access non-existing feature %d"), line);
2808 G_warning(
_(
"Attempt to access dead feature %d"), line);
2816 for (s = 0; s < 2; s++) {
2817 area = s == 0 ? topo->
left : topo->
right;
2829 for (s = 0; s < 2; s++) {
2830 area = s == 0 ? topo->
left : topo->
right;
2835 for (i = 0; i < Area->
n_lines; i++) {
2841 "UPDATE \"%s\".edge_data SET "
2842 "left_face = %d, right_face = %d "
2843 "WHERE edge_id = %d",
2857 snprintf(stmt,
sizeof(stmt),
2858 "UPDATE \"%s\".node SET containing_face = %d "
2859 "WHERE node_id = %d",
2885 int add_line_to_topo_pg(
struct Map_info *Map, off_t offset,
int type,
2892 plus = &(Map->
plus);
2906 for (i = 0; i <
n_nodes; i++) {
2909 if (node > 0 || plus->
Node[abs(node)] ==
NULL)
2912 G_debug(3,
" new node: %d", node);
2919 (
const struct line_pnts **)&Points, 1, -1);
2937 int delete_line_from_topo_pg(
struct Map_info *Map,
int line,
int type,
2940 int N1, N2, node_id;
2958 if (!Node || Node->
n_lines == 0) {
2960 snprintf(stmt,
sizeof(stmt),
2961 "DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
2964 G_warning(
_(
"Unable to delete node %d"), node_id);
2971 if (!Node || Node->
n_lines == 0) {
2973 snprintf(stmt,
sizeof(stmt),
2974 "DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
2977 G_warning(
_(
"Unable to delete node %d"), node_id);
2987 const char *table,
const char *constraint,
2988 const char *column,
const char *ref_table,
2989 const char *ref_column)
2993 snprintf(stmt,
sizeof(stmt),
"ALTER TABLE \"%s\".%s DROP CONSTRAINT %s",
3000 snprintf(stmt,
sizeof(stmt),
3001 "ALTER TABLE \"%s\".%s ADD CONSTRAINT %s "
3002 "FOREIGN KEY (%s) REFERENCES \"%s\".%s (%s) "
3003 "DEFERRABLE INITIALLY DEFERRED",
3040 G_warning(
_(
"Unable to open database <%s> by driver <%s>"),
#define DB_C_TYPE_DATETIME
#define DB_SQL_TYPE_CHARACTER
const char * db_sqltype_name(int)
Get SQL data type description.
int db_test_value_isnull(dbValue *)
Check of value is null.
const char * db_get_value_string(dbValue *)
Get string value.
int db_describe_table(dbDriver *, dbString *, dbTable **)
Describe table.
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
int db_get_column_length(dbColumn *)
Get column's length.
double db_get_value_double(dbValue *)
Get double precision value.
int db_sqltype_to_Ctype(int)
Get C data type based on given SQL data type.
dbDriver * db_start_driver(const char *)
Initialize a new dbDriver for db transaction.
int db_get_column_sqltype(dbColumn *)
Returns column sqltype for column.
int db_open_database(dbDriver *, dbHandle *)
Open database connection.
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
void db_free_string(dbString *)
Free allocated space for dbString.
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
int db_set_handle(dbHandle *, const char *, const char *)
Set handle (database and schema name)
int db_get_value_int(dbValue *)
Get integer value.
void db_init_handle(dbHandle *)
Initialize handle (i.e database/schema)
void db_init_string(dbString *)
Initialize dbString.
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
const char * db_get_column_name(dbColumn *)
Returns column name for given column.
int db_convert_column_value_to_string(dbColumn *, dbString *)
?
char * db_get_string(const dbString *)
Get string.
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
int db_get_table_number_of_columns(dbTable *)
Return the number of columns of the table.
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
void G_free(void *)
Free allocated memory.
const char * G_find_file2(const char *, const char *, const char *)
Searches for a file from the mapset search list or in a specified mapset. (look but don't touch)
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
char * G_str_replace(const char *, const char *, const char *)
Replace all occurrences of old_str in buffer with new_str.
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
void void G_verbose_message(const char *,...) __attribute__((format(printf
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
const char * G_mapset(void)
Get current mapset name.
struct Key_Value * G_fread_key_value(FILE *)
Read key/values pairs from file.
int G_asprintf(char **, const char *,...) __attribute__((format(printf
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
int G_debug(int, const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
int Vect_get_line_nodes(struct Map_info *, int, int *, int *)
Get line nodes.
off_t V2_write_line_sfa(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes feature on level 2 (OGR/PostGIS interface, pseudo-topological level)
int Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
int Vect_get_updated_node(struct Map_info *, int)
Get updated (modified) node by index.
int V2_read_line_pg(struct Map_info *, struct line_pnts *, struct line_cats *, int)
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
plus_t Vect_get_num_primitives(struct Map_info *, int)
Get number of primitives in vector map.
void Vect_reset_updated(struct Map_info *)
Reset list of updated lines/nodes.
int Vect_get_area_box(struct Map_info *, int, struct bound_box *)
Get bounding box of area.
int Vect_get_num_dblinks(struct Map_info *)
Get number of defined dblinks.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
const char * Vect_get_finfo_geometry_type(struct Map_info *)
Get geometry type as string (relevant only for non-native formats)
struct field_info * Vect_get_dblink(struct Map_info *, int)
Get information about link to database.
int Vect_get_num_updated_nodes(struct Map_info *)
Get number of updated nodes.
int Vect_get_isle_box(struct Map_info *, int, struct bound_box *)
Get bounding box of isle.
int Vect_get_node_n_lines(struct Map_info *, int)
Get number of lines for node.
plus_t Vect_get_num_nodes(struct Map_info *)
Get number of nodes in vector map.
void Vect_reset_line(struct line_pnts *)
Reset line.
int V1_read_line_pg(struct Map_info *, struct line_pnts *, struct line_cats *, off_t)
int Vect_is_3d(struct Map_info *)
Check if vector map is 3D.
void Vect_set_updated(struct Map_info *, int)
Enable/disable maintenance of list of updated lines/nodes.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
int V2_delete_line_sfa(struct Map_info *, off_t)
Deletes feature on level 2 (OGR/PostGIS interface)
SF_FeatureType
Simple feature types.
#define GV_POINT
Feature types used in memory on run time (may change)
#define GV_BUILD_BASE
Topology levels - basic level (without areas and isles)
#define GV_BUILD_AREAS
Topology levels - build areas.
#define LEVEL_2
Vector level - with 2D topology.
#define GV_LEFT
Boundary side indicator left/right.
int dig_angle_next_line(struct Plus_head *, plus_t, int, int, float *)
Find line number of next angle to follow a line.
int dig__byte_order_out(void)
Get byte order.
int dig_add_node(struct Plus_head *, double, double, double)
Add new node to plus structure.
const struct driver * driver
#define GV_KEY_COLUMN
Name of default key column.
#define ENDIAN_LITTLE
Endian check.
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
int Vect__execute_get_value_pg(PGconn *conn, const char *stmt)
Execute SQL statement and get value.
int Vect__execute_pg(PGconn *conn, const char *stmt)
Execute SQL statement.
void Vect__reallocate_cache(struct Format_info_cache *cache, int num, int incr)
Reallocate lines cache.
struct dig_head head
Header info.
struct Format_info fInfo
Format info for non-native formats.
struct Plus_head plus
Plus info (topology, version, ...)
plus_t n_lines
Number of boundary lines.
plus_t * lines
List of boundary lines.
plus_t centroid
Number of first centroid within area.
off_t offset
Offset in coor file for line.
void * topo
Topology info.
Topological feature - node.
plus_t n_lines
Number of attached lines (size of lines, angle)
plus_t left
Area number to the left, negative for isle.
plus_t right
Area number to the right, negative for isle.
plus_t area
Area number, negative for duplicate centroid.
Basic topology-related info.
struct P_line ** Line
Array of vector geometries.
plus_t n_lines
Current number of lines.
plus_t n_nodes
Current number of topological features derived from vector geometries.
struct P_area ** Area
Array of areas.
int cidx_up_to_date
Category index to be updated.
int update_cidx
Update category index if vector is modified.
struct P_node ** Node
Array of nodes.
int built
Highest level of topology currently available.
int with_z
2D/3D vector data
Layer (old: field) information.
char * table
Name of DB table.
char * driver
Name of DB driver ('sqlite', 'dbf', ...)
char * key
Name of key column (usually 'cat')
int * field
Array of layers (fields)
int n_cats
Number of categories attached to element.
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
double * z
Array of Z coordinates.
int V2__add_line_to_topo_nat(struct Map_info *Map, off_t offset, int type, const struct line_pnts *points, const struct line_cats *cats, int restore_line, int(*external_routine)(struct Map_info *, int))
Add feature (line) to topology (internal use only)
int V2__delete_line_from_topo_nat(struct Map_info *Map, int line, int type, const struct line_pnts *points, const struct line_cats *cats)
Delete feature from topology (internal use only)
off_t V1_rewrite_line_pg(struct Map_info *Map NOPG_UNUSED, off_t offset, int type, const struct line_pnts *points NOPG_UNUSED, const struct line_cats *cats NOPG_UNUSED)
Rewrites feature at the given offset (level 1) (PostGIS interface, internal use only)
int Vect__define_topo_relation(const struct Format_info_pg *pg_info, int topo_id, int element_id)
off_t V2_rewrite_line_pg(struct Map_info *Map NOPG_UNUSED, off_t line, int type, const struct line_pnts *points NOPG_UNUSED, const struct line_cats *cats UNUSED)
Rewrites feature at topological level (PostGIS interface, internal use only)
int V2_delete_line_pg(struct Map_info *Map NOPG_UNUSED, off_t line NOPG_UNUSED)
Deletes feature on topological level (PostGIS interface)
int V1_delete_line_pg(struct Map_info *Map NOPG_UNUSED, off_t offset NOPG_UNUSED)
Deletes feature at the given offset (level 1)
off_t V1_write_line_pg(struct Map_info *Map NOPG_UNUSED, int type NOPG_UNUSED, const struct line_pnts *points NOPG_UNUSED, const struct line_cats *cats NOPG_UNUSED)
Writes feature on level 1 (PostGIS interface)
off_t V2__write_area_pg(struct Map_info *Map, const struct line_pnts **points, int nparts, const struct line_cats *cats)
Writes area on topological level (PostGIS Simple Features interface, internal use only)
int V2__update_area_pg(struct Map_info *Map, const struct line_pnts **points, int nparts, int cat)
Updates simple features geometry from GRASS-like topo.
off_t V2__write_node_pg(struct Map_info *Map, const struct line_pnts *points)
Writes node on topological level (PostGIS Topology interface, internal use only)
off_t V2_write_line_pg(struct Map_info *Map NOPG_UNUSED, int type NOPG_UNUSED, const struct line_pnts *points NOPG_UNUSED, const struct line_cats *cats NOPG_UNUSED)
Writes feature on topological level (PostGIS interface)
int Vect__insert_face_pg(struct Map_info *Map, int area)
Insert new face to the 'face' table (topo only)