27 #include "local_proto.h" 30 #include "pg_local_proto.h" 32 #define WKBSRIDFLAG 0x20000000 34 #define TOPOGEOM_COLUMN "topo" 39 #define USE_TOPO_STMT 0 44 static int create_pg_layer(
struct Map_info *,
int);
46 static off_t write_line_sf(
struct Map_info *,
int,
49 static off_t write_line_tp(
struct Map_info *,
int,
int,
52 static char *binary_to_hex(
int,
const unsigned char *);
53 static unsigned char *point_to_wkb(
int,
const struct line_pnts *,
int,
int *);
54 static unsigned char *linestring_to_wkb(
int,
const struct line_pnts *,
56 static unsigned char *polygon_to_wkb(
int,
const struct line_pnts **,
int,
60 static int write_feature(
struct Map_info *,
int,
int,
62 static char *build_insert_stmt(
const struct Format_info_pg *,
const char *,
int,
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);
66 static int delete_face(
const struct Map_info *,
int);
67 static int update_topo_edge(
struct Map_info *,
int);
68 static int update_topo_face(
struct Map_info *,
int);
69 static int add_line_to_topo_pg(
struct Map_info *, off_t,
int,
const struct line_pnts *);
70 static int delete_line_from_topo_pg(
struct Map_info *,
int,
int,
const struct line_pnts *);
71 static int set_constraint_to_deferrable(
struct Format_info_pg *,
const char *,
const char *,
72 const char *,
const char *,
const char *);
110 if (create_pg_layer(Map, type) < 0)
118 return write_line_sf(Map, type, &points, 1, cats);
122 return write_line_tp(Map, type,
FALSE, points, cats);
124 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
156 return write_line_tp(Map, type,
FALSE, points, cats);
158 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
188 G_warning(
_(
"Unable to rewrite feature (incompatible feature types)"));
197 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
222 G_debug(3,
"V2_rewrite_line_pg(): line=%d type=%d",
226 char *stmt, *geom_data;
237 G_warning(
_(
"Attempt to access feature with invalid id (%d)"), (
int)line);
243 G_warning(
_(
"Attempt to access dead feature %d"), (
int)line);
256 G_warning(
_(
"Unable to rewrite feature (incompatible feature types)"));
261 if (0 != delete_line_from_topo_pg(Map, line, type, Points))
267 table_name = keycolumn =
"node";
270 table_name =
"edge_data";
280 geom_data = line_to_wkb(pg_info, &points, 1, type, Map->
head.
with_z);
281 G_asprintf(&stmt,
"UPDATE \"%s\".\"%s\" SET geom = '%s'::GEOMETRY WHERE %s_id = %" PRI_OFF_T,
282 schema_name, table_name, geom_data, keycolumn, line);
286 G_warning(
_(
"Unable to rewrite feature %d"), (
int)line);
293 return add_line_to_topo_pg(Map, offset, type, points);
295 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
333 G_debug(3,
"V1_delete_line_pg(): offset = %lu -> fid = %ld",
334 (
unsigned long)offset, fid);
343 sprintf(stmt,
"DELETE FROM %s WHERE %s = %ld",
355 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
382 G_warning(
_(
"Attempt to access feature with invalid id (%d)"), (
int)line);
397 G_warning(
_(
"Attempt to access feature with invalid id (%d)"), (
int)line);
403 G_warning(
_(
"Attempt to access dead feature %d"), (
int)line);
414 table_name = keycolumn =
"node";
417 table_name =
"edge_data";
422 sprintf(stmt,
"UPDATE \"%s\".\"%s\" SET abs_next_left_edge = edge_id, " 423 "next_left_edge = -edge_id WHERE abs_next_left_edge = %d",
431 sprintf(stmt,
"UPDATE \"%s\".\"%s\" SET abs_next_right_edge = edge_id, " 432 "next_right_edge = edge_id WHERE abs_next_right_edge = %d",
450 sprintf(stmt,
"DELETE FROM \"%s\".\"%s\" WHERE %s_id = %d",
453 G_warning(
_(
"Unable to delete feature (%s) %d"), keycolumn,
469 ret = delete_line_from_topo_pg(Map, line, type, Points);
477 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
522 const struct line_pnts **points,
int nparts,
525 return write_line_sf(Map,
GV_BOUNDARY, points, nparts, cats);
540 const struct line_pnts **points,
int nparts,
544 char *stmt, *geom_data;
550 for (part = 0; part < nparts; part++) {
551 npoints = points[part]->
n_points - 1;
552 if (points[part]->
x[0] != points[part]->
x[npoints] ||
553 points[part]->y[0] != points[part]->y[npoints] ||
554 points[part]->z[0] != points[part]->z[npoints]) {
555 G_warning(
_(
"Boundary is not closed. Skipping."));
565 G_asprintf(&stmt,
"UPDATE \"%s\".\"%s\" SET %s = '%s'::GEOMETRY WHERE %s = %d",
595 char *geom_type, *def_file;
601 def_file =
getenv(
"GRASS_VECTOR_PGFILE");
604 spatial_index = primary_key =
TRUE;
622 spatial_index =
FALSE;
635 if (check_schema(pg_info) != 0)
640 sprintf(stmt,
"CREATE TABLE \"%s\".\"%s\" (%s SERIAL%s, %s INTEGER",
648 int col, ncols, sqltype, length;
660 driver = open_db(pg_info);
676 "copying attributes: driver = %s database = %s table = %s cols = %d",
679 for (col = 0; col < ncols; col++) {
685 G_debug(3,
"\tcolumn = %d name = %s type = %d length = %d",
686 col, colname, sqltype, length);
691 G_debug(3,
"\t%s skipped", colname);
697 strcat(stmt, stmt_col);
700 sprintf(stmt_col,
"(%d)", length);
701 strcat(stmt, stmt_col);
726 geom_type =
"LINESTRING";
729 geom_type =
"POLYGON";
732 geom_type =
"POLYGONZ";
735 geom_type =
"GEOMETRY";
744 sprintf(stmt,
"SELECT AddGeometryColumn('%s', '%s', " 745 "'%s', %d, '%s', %d)",
750 result = PQexec(pg_info->
conn, stmt);
752 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
753 G_warning(
"%s", PQresultErrorMessage(result));
764 "CREATE INDEX %s_%s_idx ON \"%s\".\"%s\" (%s)",
777 "CREATE INDEX %s_%s_idx ON \"%s\".\"%s\" USING GIST (%s)",
806 int i, found, nschema;
817 sprintf(stmt,
"SELECT nspname FROM pg_namespace");
819 result = PQexec(pg_info->
conn, stmt);
821 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
828 nschema = PQntuples(result);
829 for (i = 0; i < nschema && !found; i++) {
830 if (strcmp(pg_info->
schema_name, PQgetvalue(result, i, 0)) == 0)
837 sprintf(stmt,
"CREATE SCHEMA %s", pg_info->
schema_name);
842 G_warning(
_(
"Schema <%s> doesn't exist, created"),
863 int create_topo_schema(
struct Format_info_pg *pg_info,
int with_z)
869 def_file =
getenv(
"GRASS_VECTOR_PGFILE");
890 G_debug(1,
"PG: tolerance: %f", tolerance);
923 sprintf(stmt,
"SELECT topology.createtopology('%s', " 924 "find_srid('%s', '%s', '%s'), %f, '%s')",
927 with_z ==
WITH_Z ?
"t" :
"f");
937 sprintf(stmt,
"SELECT topology.AddTopoGeometryColumn('%s', '%s', '%s', " 947 sprintf(stmt,
"CREATE INDEX \"%s_%s_%s_idx\" ON \"%s\".\"%s\" (((%s).id))",
957 if (-1 == set_constraint_to_deferrable(pg_info,
"node",
"face_exists",
958 "containing_face",
"face",
"face_id") ||
959 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
"end_node_exists",
960 "end_node",
"node",
"node_id") ||
961 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
"left_face_exists",
962 "left_face",
"face",
"face_id") ||
963 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
"right_face_exists",
964 "right_face",
"face",
"face_id") ||
965 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
"start_node_exists",
966 "start_node",
"node",
"node_id"))
977 sprintf(stmt,
"CREATE TABLE \"%s\".%s (node_id SERIAL PRIMARY KEY, " 978 "lines integer[], angles float[])", pg_info->
toposchema_name, TOPO_TABLE_NODE);
984 sprintf(stmt,
"ALTER TABLE \"%s\".%s ADD CONSTRAINT node_exists " 985 "FOREIGN KEY (node_id) REFERENCES \"%s\".node (node_id) " 986 "DEFERRABLE INITIALLY DEFERRED",
996 sprintf(stmt,
"CREATE TABLE \"%s\".%s (line_id SERIAL PRIMARY KEY, " 997 "left_area integer, right_area integer)",
1004 sprintf(stmt,
"ALTER TABLE \"%s\".%s ADD CONSTRAINT line_exists " 1005 "FOREIGN KEY (line_id) REFERENCES \"%s\".edge_data (edge_id) " 1006 "DEFERRABLE INITIALLY DEFERRED",
1017 sprintf(stmt,
"CREATE TABLE \"%s\".%s (area_id SERIAL PRIMARY KEY, " 1018 "lines integer[], centroid integer, isles integer[])",
1029 sprintf(stmt,
"CREATE TABLE \"%s\".%s (isle_id SERIAL PRIMARY KEY, " 1030 "lines integer[], area integer)",
1065 int create_pg_layer(
struct Map_info *Map,
int type)
1073 G_warning(
_(
"Connection string not defined"));
1078 G_warning(
_(
"PostGIS feature table not defined"));
1082 G_debug(1,
"Vect__open_new_pg(): conninfo='%s' table='%s' -> type = %d",
1106 G_warning(
_(
"Unsupported geometry type (%d)"), type);
1119 G_warning(
_(
"More layers defined, using driver <%s> and " 1124 G_warning(
_(
"Database connection not defined. " 1125 "Unable to write attributes."));
1130 if (create_table(pg_info) == -1) {
1131 G_warning(
_(
"Unable to create new PostGIS feature table"));
1144 if (create_topo_schema(pg_info,
Vect_is_3d(Map)) == -1) {
1145 G_warning(
_(
"Unable to create new PostGIS topology schema"));
1175 return "COLLECTION";
1177 G_warning(
_(
"Unsupported feature type %d"), sftype);
1194 off_t write_line_sf(
struct Map_info *Map,
int type,
1195 const struct line_pnts **points,
int nparts,
1207 offset_info = &(pg_info->
offset);
1213 if (!pg_info->
conn) {
1218 G_warning(
_(
"PostGIS feature table not defined"));
1224 if (create_pg_layer(Map, type) < 0)
1239 G_warning(
_(
"No category defined for layer %d"), field);
1241 G_warning(
_(
"Feature has more categories, using " 1242 "category %d (from layer %d)"),
1252 G_warning(
_(
"Point skipped (output feature type: %s)"),
1259 G_warning(
_(
"Line skipped (output feature type: %s)"),
1266 G_warning(
_(
"Centroid skipped (output feature type: %s)"),
1273 G_warning(
_(
"Boundary skipped (output feature type: %s)"),
1280 G_warning(
_(
"Face skipped (output feature type: %s)"),
1286 G_warning(
_(
"Unsupported feature type %d"), type);
1290 G_debug(3,
"write_line_sf(): type = %d n_points = %d cat = %d",
1291 type, points[0]->n_points, cat);
1297 for (part = 0; part < nparts; part++) {
1298 npoints = points[part]->
n_points - 1;
1299 if (points[part]->
x[0] != points[part]->
x[npoints] ||
1300 points[part]->y[0] != points[part]->y[npoints] ||
1301 points[part]->z[0] != points[part]->z[npoints]) {
1302 G_warning(
_(
"Boundary is not closed. Skipping."));
1309 if (-1 == write_feature(Map, -1, type, points, nparts, cat)) {
1328 G_debug(3,
"write_line_sf(): -> offset = %lu offset_num = %d cat = %d",
1329 (
unsigned long)offset, offset_info->
array_num, cat);
1347 off_t write_line_tp(
struct Map_info *Map,
int type,
int is_node,
1351 int line, cat, line_id;
1358 plus = &(Map->
plus);
1366 G_warning(
_(
"Invalid feature type (%d) for nodes"), type);
1371 if (!pg_info->
conn) {
1376 G_warning(
_(
"PostGIS feature table not defined"));
1380 G_warning(
_(
"PostGIS topology schema not defined"));
1386 if (create_pg_layer(Map, type) < 0)
1393 G_debug(3,
"write_line_pg(): type = %d n_points = %d",
1399 if (cats && cats->
n_cats > 0) {
1406 G_warning(
_(
"Feature has more categories, using " 1407 "category %d (from layer %d)"),
1408 cat, cats->
field[0]);
1420 line = -1 *
dig_add_node(plus, points->
x[0], points->
y[0], points->
z[0]);
1434 line = add_line_to_topo_pg(Map, offset, type, points);
1442 line_id = write_feature(Map, line, type, &points, 1, cat);
1462 offset = &(pg_info->
offset);
1471 offset->
array[node-1] = (int) line_id;
1476 update_topo_face(Map, line);
1478 return !is_node ? line : 0;
1491 char *binary_to_hex(
int nbytes,
const unsigned char *wkb_data)
1495 static const char ach_hex[] =
"0123456789ABCDEF";
1497 hex_data = (
char *)
G_malloc(nbytes * 2 + 1);
1498 hex_data[nbytes * 2] =
'\0';
1500 for (i = 0; i < nbytes; i++) {
1501 nlow = wkb_data[i] & 0x0f;
1502 nhigh = (wkb_data[i] & 0xf0) >> 4;
1504 hex_data[i * 2] = ach_hex[nhigh];
1505 hex_data[i * 2 + 1] = ach_hex[nlow];
1524 unsigned char *point_to_wkb(
int byte_order,
1525 const struct line_pnts *points,
int with_z,
1528 unsigned char *wkb_data;
1529 unsigned int sf_type;
1535 *nsize = with_z ? 29 : 21;
1537 G_zero(wkb_data, *nsize);
1539 G_debug(5,
"\t->point size=%d (with_z = %d)", *nsize, with_z);
1543 wkb_data[0] =
'\001';
1545 wkb_data[0] =
'\000';
1551 sf_type = LSBWORD32(sf_type);
1553 sf_type = MSBWORD32(sf_type);
1554 memcpy(wkb_data + 1, &sf_type, 4);
1557 memcpy(wkb_data + 5, &(points->
x[0]), 8);
1558 memcpy(wkb_data + 5 + 8, &(points->
y[0]), 8);
1561 memcpy(wkb_data + 5 + 16, &(points->
z[0]), 8);
1566 SWAPDOUBLE(wkb_data + 5);
1567 SWAPDOUBLE(wkb_data + 5 + 8);
1570 SWAPDOUBLE(wkb_data + 5 + 16);
1589 unsigned char *linestring_to_wkb(
int byte_order,
1590 const struct line_pnts *points,
int with_z,
1594 unsigned char *wkb_data;
1595 unsigned int sf_type;
1601 point_size = 8 * (with_z ? 3 : 2);
1602 *nsize = 5 + 4 + points->
n_points * point_size;
1604 G_zero(wkb_data, *nsize);
1606 G_debug(5,
"\t->linestring size=%d (with_z = %d)", *nsize, with_z);
1610 wkb_data[0] =
'\001';
1612 wkb_data[0] =
'\000';
1618 sf_type = LSBWORD32(sf_type);
1620 sf_type = MSBWORD32(sf_type);
1621 memcpy(wkb_data + 1, &sf_type, 4);
1624 memcpy(wkb_data + 5, &(points->
n_points), 4);
1627 for (i = 0; i < points->
n_points; i++) {
1628 memcpy(wkb_data + 9 + point_size * i, &(points->
x[i]), 8);
1629 memcpy(wkb_data + 9 + 8 + point_size * i, &(points->
y[i]), 8);
1632 memcpy(wkb_data + 9 + 16 + point_size * i, &(points->
z[i]), 8);
1638 int npoints, nitems;
1640 npoints = SWAP32(points->
n_points);
1641 memcpy(wkb_data + 5, &npoints, 4);
1643 nitems = (with_z ? 3 : 2) * points->
n_points;
1644 for (i = 0; i < nitems; i++) {
1645 SWAPDOUBLE(wkb_data + 9 + 4 + 8 * i);
1666 unsigned char *polygon_to_wkb(
int byte_order,
1667 const struct line_pnts** points,
int nrings,
1668 int with_z,
int *nsize)
1670 int i, ring, point_size, offset;
1671 unsigned char *wkb_data;
1672 unsigned int sf_type;
1677 for (ring = 0; ring < nrings; ring++) {
1678 if (points[ring]->n_points < 3)
1683 point_size = 8 * (with_z ? 3 : 2);
1685 for (ring = 0; ring < nrings; ring++)
1686 *nsize += 4 + point_size * points[ring]->n_points;
1688 G_zero(wkb_data, *nsize);
1690 G_debug(5,
"\t->polygon size=%d (with_z = %d)", *nsize, with_z);
1694 wkb_data[0] =
'\001';
1696 wkb_data[0] =
'\000';
1702 sf_type = LSBWORD32(sf_type);
1704 sf_type = MSBWORD32(sf_type);
1705 memcpy(wkb_data + 1, &sf_type, 4);
1711 ncount = SWAP32(nrings);
1712 memcpy(wkb_data + 5, &ncount, 4);
1715 memcpy(wkb_data + 5, &nrings, 4);
1720 for (ring = 0; ring < nrings; ring++) {
1721 memcpy(wkb_data + offset, &(points[ring]->n_points), 4);
1722 for (i = 0; i < points[ring]->
n_points; i++) {
1723 memcpy(wkb_data + offset +
1724 4 + point_size * i, &(points[ring]->
x[i]), 8);
1725 memcpy(wkb_data + offset +
1726 4 + 8 + point_size * i, &(points[ring]->y[i]), 8);
1729 memcpy(wkb_data + offset +
1730 4 + 16 + point_size * i, &(points[ring]->z[i]), 8);
1734 offset += 4 + point_size * points[ring]->
n_points;
1738 int npoints, nitems;
1740 npoints = SWAP32(points[ring]->n_points);
1741 memcpy(wkb_data + 5, &npoints, 4);
1743 nitems = (with_z ? 3 : 2) * points[ring]->n_points;
1744 for (i = 0; i < nitems; i++) {
1745 SWAPDOUBLE(wkb_data + offset + 4 + 8 * i);
1768 const struct line_pnts **points,
int nparts,
int type,
int with_z)
1770 int byte_order, nbytes, nsize;
1771 unsigned int sf_type;
1773 unsigned char *wkb_data;
1774 char *text_data, *text_data_p, *hex_data;
1782 wkb_data = point_to_wkb(byte_order, points[0], with_z, &nbytes);
1785 wkb_data = linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
1789 wkb_data = polygon_to_wkb(byte_order, points, nparts,
1794 wkb_data = linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
1798 if (!wkb_data || nbytes < 1) {
1799 G_warning(
_(
"Unsupported feature type %d"), type);
1806 nsize = nbytes * 2 + 8 + 1;
1807 text_data = text_data_p = (
char *)
G_malloc(nsize);
1810 hex_data = binary_to_hex(1, wkb_data);
1811 strcpy(text_data_p, hex_data);
1816 memcpy(&sf_type, wkb_data + 1, 4);
1819 if (pg_info->
srid > 0) {
1820 unsigned int srs_flag;
1825 sf_type = sf_type | srs_flag;
1829 hex_data = binary_to_hex(4, (
unsigned char *)&sf_type);
1830 strcpy(text_data_p, hex_data);
1835 if (pg_info->
srid > 0) {
1836 unsigned int srs_id;
1839 srs_id = LSBWORD32(pg_info->
srid);
1840 hex_data = binary_to_hex(
sizeof(srs_id), (
unsigned char *)&srs_id);
1841 strcpy(text_data_p, hex_data);
1848 hex_data = binary_to_hex(nbytes - 5, wkb_data + 5);
1849 strcpy(text_data_p, hex_data);
1869 int write_feature(
struct Map_info *Map,
int line,
int type,
1870 const struct line_pnts **points,
int nparts,
int cat)
1872 int with_z, topo_id;
1873 char *stmt, *geom_data;
1880 if (with_z && pg_info->
coor_dim != 3) {
1881 G_warning(
_(
"Trying to insert 3D data into feature table " 1882 "which store 2D data only"));
1885 if (!with_z && pg_info->
coor_dim != 2) {
1886 G_warning(
_(
"Trying to insert 2D data into feature table " 1887 "which store 3D data only"));
1892 geom_data = line_to_wkb(pg_info, points, nparts, type, with_z);
1909 topo_id = insert_topo_element(Map, line, type, geom_data);
1911 G_warning(
_(
"Unable to insert topological element into PostGIS Topology schema"));
1926 stmt = build_insert_stmt(pg_info, geom_data, topo_id, cat);
1960 const char *geom_data,
int topo_id,
int cat)
1970 topogeom_type = type_to_topogeom(pg_info);
1971 if (topogeom_type < 0)
1978 if (Fi && cat > -1) {
1980 int col, ncol, more;
1981 int sqltype, ctype, is_fid;
1984 const char *colname;
1996 sprintf(buf,
"SELECT * FROM %s WHERE %s = %d", Fi->
table, Fi->
key,
2002 sprintf(buf,
"INSERT INTO \"%s\".\"%s\" (",
2008 G_warning(
_(
"Unable to select attributes for category %d"), cat);
2012 G_warning(
_(
"Unable to fetch data from table <%s>"),
2017 G_warning(
_(
"No database record for category %d, " 2018 "no attributes will be written"), cat);
2024 for (col = 0; col < ncol; col++) {
2032 G_debug(3,
"col %d : val = %s", col,
2038 is_fid = strcmp(pg_info->
fid_column, colname) == 0;
2041 if (is_fid ==
TRUE &&
2043 G_warning(
_(
"FID column must be integer, column <%s> ignored!"),
2049 sprintf(buf_tmp,
"\"%s\"", colname);
2050 strcat(buf, buf_tmp);
2061 sprintf(buf_tmp,
"%.14f",
2067 sprintf(buf_tmp,
"'%s'", value_tmp);
2077 G_warning(
_(
"Unsupported column type %d"), ctype);
2078 sprintf(buf_tmp,
"NULL");
2084 G_warning(
_(
"Invalid value for FID column: NULL"));
2085 sprintf(buf_tmp,
"NULL");
2087 strcat(buf_val, buf_tmp);
2089 strcat(buf_val,
",");
2094 G_asprintf(&stmt,
"%s,%s) VALUES (%s,'%s'::GEOMETRY)",
2100 if (buf[strlen(buf)-1] ==
',') {
2101 buf[strlen(buf)-1] =
'\0';
2102 buf_val[strlen(buf_val)-1] =
'\0';
2104 G_asprintf(&stmt,
"%s, %s) VALUES (%s, '(%d, 1, %d, %d)'::topology.TopoGeometry)",
2117 G_asprintf(&stmt,
"INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES " 2118 "(%d, '%s'::GEOMETRY)",
2125 G_asprintf(&stmt,
"INSERT INTO \"%s\".\"%s\" (%s) VALUES " 2134 G_asprintf(&stmt,
"INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES " 2135 "(%d, '(%d, 1, %d, %d)'::topology.TopoGeometry)",
2159 int insert_topo_element(
struct Map_info *Map,
int id,
int type,
2160 const char *geom_data)
2169 plus = &(Map->
plus);
2209 G_asprintf(&stmt,
"SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
2214 sprintf(stmt_id,
"SELECT nextval('\"%s\".node_node_id_seq')",
2220 G_asprintf(&stmt,
"INSERT INTO \"%s\".node (node_id, geom) VALUES " 2221 "(%d, '%s'::GEOMETRY)", pg_info->
toposchema_name, topo_id, geom_data);
2229 G_asprintf(&stmt,
"SELECT topology.AddEdge('%s', '%s'::GEOMETRY)",
2232 int n1, n2, nle, nre;
2236 offset = &(pg_info->
offset);
2240 sprintf(stmt_id,
"SELECT nextval('\"%s\".edge_data_edge_id_seq')",
2249 int i, n, next_edge;
2252 topo_id = (
int)Line->
offset;
2258 for (i = 0; i < 2; i++) {
2263 next_edge = update_next_edge(Map, n,
2264 i == 0 ? topo_id : -topo_id);
2265 if (next_edge != 0) {
2272 G_warning(
_(
"Unable to determine next left/right edge for edge %d"), topo_id);
2277 G_warning(
_(
"Unable to insert new edge. Topology not available."));
2281 G_debug(3,
"new edge: id=%d next_left_edge=%d next_right_edge=%d",
2288 G_asprintf(&stmt,
"INSERT INTO \"%s\".edge_data (edge_id, start_node, end_node, " 2289 "next_left_edge, abs_next_left_edge, next_right_edge, abs_next_right_edge, " 2290 "left_face, right_face, geom) VALUES " 2291 "(%d, %d, %d, %d, %d, %d, %d, 0, 0, '%s'::GEOMETRY)",
2293 nle, abs(nle), nre, abs(nre), geom_data);
2300 G_asprintf(&stmt,
"SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
2307 sprintf(stmt_id,
"SELECT nextval('\"%s\".node_node_id_seq')",
2321 G_asprintf(&stmt,
"INSERT INTO \"%s\".node (node_id, containing_face, geom) VALUES " 2323 topo_id, area, geom_data);
2328 G_warning(
_(
"Unsupported feature type %d"), type);
2364 return topogeom_type;
2372 topogeom_type = type_to_topogeom(pg_info);
2373 if (topogeom_type < 0)
2376 sprintf(stmt,
"INSERT into \"%s\".relation VALUES(%d, 1, %d, %d)",
2400 int update_next_edge(
struct Map_info* Map,
int nlines,
int line)
2402 int ret, next_line, edge;
2406 struct P_line *Line_next, *Line;
2408 Line = Line_next =
NULL;
2417 G_debug(3,
"line=%d next_line=%d", line, next_line);
2418 if (next_line == 0) {
2424 Line_next = Map->
plus.
Line[abs(next_line)];
2425 if (!Line || !Line_next) {
2432 ret = next_line > 0 ? Line_next->
offset : -Line_next->
offset;
2436 ret = next_line > 0 ? Line_next->
offset : -Line_next->
offset;
2439 if (next_line < 0) {
2440 sprintf(stmt,
"UPDATE \"%s\".edge_data SET next_left_edge = %d, " 2441 "abs_next_left_edge = %d WHERE edge_id = %d AND abs_next_left_edge = %d",
2443 G_debug(3,
"update edge=%d next_left_edge=%d (?)", (
int)Line_next->
offset, edge);
2446 sprintf(stmt,
"UPDATE \"%s\".edge_data SET next_right_edge = %d, " 2447 "abs_next_right_edge = %d WHERE edge_id = %d AND abs_next_right_edge = %d",
2449 G_debug(3,
"update edge=%d next_right_edge=%d (?)", (
int)Line_next->
offset, edge);
2464 Line_next = Map->
plus.
Line[abs(next_line)];
2466 if (next_line < 0) {
2467 sprintf(stmt,
"UPDATE \"%s\".edge_data SET next_left_edge = %d, " 2468 "abs_next_left_edge = %d WHERE edge_id = %d",
2470 G_debug(3,
"update edge=%d next_left_edge=%d", (
int)Line_next->
offset, edge);
2473 sprintf(stmt,
"UPDATE \"%s\".edge_data SET next_right_edge = %d, " 2474 "abs_next_right_edge = %d WHERE edge_id = %d",
2476 G_debug(3,
"update edge=%d next_right_edge=%d", (
int)Line_next->
offset, edge);
2519 G_asprintf(&stmt,
"INSERT INTO \"%s\".face (face_id, mbr) VALUES " 2520 "(%d, ST_GeomFromText('POLYGON((%.12f %.12f, %.12f %.12f, %.12f %.12f, %.12f %.12f, " 2522 box.
W, box.
S, box.
W, box.
N, box.
E, box.
N,
2523 box.
E, box.
S, box.
W, box.
S, pg_info->
srid);
2524 G_debug(3,
"new face id=%d", area);
2546 int delete_face(
const struct Map_info *Map,
int area)
2555 sprintf(stmt,
"UPDATE \"%s\".node SET containing_face = 0 " 2556 "WHERE containing_face = %d",
2565 sprintf(stmt,
"UPDATE \"%s\".edge_data SET left_face = 0 " 2566 "WHERE left_face = %d",
2575 sprintf(stmt,
"UPDATE \"%s\".edge_data SET right_face = 0 " 2576 "WHERE right_face = %d",
2585 sprintf(stmt,
"DELETE FROM \"%s\".face WHERE face_id = %d",
2587 G_debug(3,
"delete face id=%d", area);
2613 int update_topo_edge(
struct Map_info *Map,
int line)
2616 int nle, nre, next_edge;
2625 G_warning(
_(
"Attempt to access non-existing feature %d"), line);
2630 G_warning(
_(
"Attempt to access dead feature %d"), line);
2639 for (i = 0; i < 2; i++) {
2647 next_edge = update_next_edge(Map, n,
2648 i == 0 ? line : -line);
2649 if (next_edge != 0) {
2656 G_warning(
_(
"Unable to determine next left/right edge"));
2661 if (nle == 0 && nre == 0)
2664 if (nle != 0 && nre != 0) {
2666 sprintf(stmt,
"UPDATE \"%s\".edge_data SET " 2667 "next_left_edge = %d, abs_next_left_edge = %d, " 2668 "next_right_edge = %d, abs_next_right_edge = %d " 2670 nle, abs(nle), nre, abs(nre), (
int)Line->
offset);
2672 else if (nle != 0) {
2674 sprintf(stmt,
"UPDATE \"%s\".edge_data SET " 2675 "next_left_edge = %d, abs_next_left_edge = %d " 2677 nle, abs(nle), (
int)Line->
offset);
2681 sprintf(stmt,
"UPDATE \"%s\".edge_data SET " 2682 "next_right_edge = %d, abs_next_right_edge = %d " 2684 nre, abs(nre), (
int)Line->
offset);
2686 G_debug(3,
"update edge=%d next_left_edge=%d next_right_edge=%d",
2687 (
int)Line->
offset, nle, nre);
2709 int update_topo_face(
struct Map_info *Map,
int line)
2711 int i, s, area, face[2];
2715 struct P_line *Line, *Line_i;
2722 G_warning(
_(
"Attempt to access non-existing feature %d"), line);
2727 G_warning(
_(
"Attempt to access dead feature %d"), line);
2735 for (s = 0; s < 2; s++) {
2736 area = s == 0 ? topo->
left : topo->
right;
2748 for (s = 0; s < 2; s++) {
2749 area = s == 0 ? topo->
left : topo->
right;
2754 for (i = 0; i < Area->
n_lines; i++) {
2758 sprintf(stmt,
"UPDATE \"%s\".edge_data SET " 2759 "left_face = %d, right_face = %d " 2761 topo_i->
left > 0 ? topo_i->
left : 0,
2775 sprintf(stmt,
"UPDATE \"%s\".node SET containing_face = %d " 2777 face[s], (
int)Line_i->
offset);
2802 int add_line_to_topo_pg(
struct Map_info *Map, off_t offset,
int type,
2809 plus = &(Map->
plus);
2824 for (i = 0; i <
n_nodes; i++) {
2827 if (node > 0 || plus->
Node[abs(node)] ==
NULL)
2830 G_debug(3,
" new node: %d", node);
2854 int delete_line_from_topo_pg(
struct Map_info *Map,
int line,
int type,
2857 int N1, N2, node_id;
2875 if (!Node || Node->
n_lines == 0) {
2877 sprintf(stmt,
"DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
2880 G_warning(
_(
"Unable to delete node %d"), node_id);
2887 if (!Node || Node->
n_lines == 0) {
2889 sprintf(stmt,
"DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
2892 G_warning(
_(
"Unable to delete node %d"), node_id);
2902 const char *table,
const char *constraint,
2903 const char *column,
const char *ref_table,
2904 const char *ref_column)
2908 sprintf(stmt,
"ALTER TABLE \"%s\".%s DROP CONSTRAINT %s",
2915 sprintf(stmt,
"ALTER TABLE \"%s\".%s ADD CONSTRAINT %s " 2916 "FOREIGN KEY (%s) REFERENCES \"%s\".%s (%s) " 2917 "DEFERRABLE INITIALLY DEFERRED",
2953 G_warning(
_(
"Unable to open database <%s> by driver <%s>"),
int Vect_get_area_box(const struct Map_info *, int, struct bound_box *)
Get bounding box of area.
#define ENDIAN_LITTLE
Endian check.
#define GV_KEY_COLUMN
Name of default key column.
int db_describe_table(dbDriver *, dbString *, dbTable **)
Describe table.
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
int built
Highest level of topology currently available.
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
plus_t area
Area number, negative for duplicate centroid.
off_t V2_write_line_pg(struct Map_info *Map, int type, const struct line_pnts *points, const struct line_cats *cats)
Writes feature on topological level (PostGIS interface)
#define GV_LEFT
Boundary side indicator left/right.
plus_t Vect_get_num_nodes(const struct Map_info *)
Get number of nodes in vector map.
dbDriver * db_start_driver(const char *)
Initialize a new dbDriver for db transaction.
off_t offset
Offset in coor file for line.
off_t V2_rewrite_line_pg(struct Map_info *Map, off_t line, int type, const struct line_pnts *points, const struct line_cats *cats)
Rewrites feature at topological level (PostGIS interface, internal use only)
struct P_line ** Line
Array of vector geometries.
int db_get_column_length(dbColumn *)
Get column's length.
const char * db_get_column_name(dbColumn *)
Returns column name for given column.
void db_init_string(dbString *)
Initialize dbString.
plus_t right
Area number to the right, negative for isle.
#define GV_BUILD_BASE
Topology levels - basic level (without areas and isles)
struct P_area ** Area
Array of areas.
struct P_node ** Node
Array of nodes.
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
struct Key_Value * G_fread_key_value(FILE *)
Read key/values pairs from file.
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
int n_points
Number of points.
char * db_get_string(const dbString *)
Get string.
char * table
Name of DB table.
#define DB_C_TYPE_DATETIME
plus_t n_lines
Number of attached lines (size of lines, angle)
void G_free(void *)
Free allocated memory.
int db_get_value_int(dbValue *)
Get integer value.
plus_t left
Area number to the left, negative for isle.
struct Format_info fInfo
Format info for non-native formats.
int db_set_handle(dbHandle *, const char *, const char *)
Set handle (database and schema name)
plus_t centroid
Number of first centroid within area.
#define DB_SQL_TYPE_CHARACTER
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
#define GV_POINT
Feature types used in memory on run time (may change)
int Vect_get_node_n_lines(const struct Map_info *, int)
Get number of lines for node.
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
int V1_delete_line_pg(struct Map_info *Map, off_t offset)
Deletes feature at the given offset (level 1)
int Vect_get_num_dblinks(const struct Map_info *)
Get number of defined dblinks.
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 db_convert_column_value_to_string(dbColumn *, dbString *)
?
plus_t n_lines
Current number of lines.
plus_t Vect_get_num_primitives(const struct Map_info *, int)
Get number of primitives in vector map.
void Vect__reallocate_cache(struct Format_info_cache *cache, int num, int incr)
Reallocate lines cache.
int Vect_get_node_coor(const struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Layer (old: field) information.
double * x
Array of X coordinates.
int dig_angle_next_line(struct Plus_head *, plus_t, int, int, float *)
Find line number of next angle to follow a line.
int cidx_up_to_date
Category index to be updated.
int Vect__execute_get_value_pg(PGconn *conn, const char *stmt)
Execute SQL statement and get value.
Feature geometry info - coordinates.
int with_z
2D/3D vector data
int db_get_column_sqltype(dbColumn *)
Returns column sqltype for column.
plus_t * lines
List of boundary lines.
int db_test_value_isnull(dbValue *)
Check of value is null.
const char * db_sqltype_name(int)
Get SQL data type description.
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Basic topology-related info.
char * G_str_replace(const char *, const char *, const char *)
Replace all occurrences of old_str in buffer with new_str.
#define GV_BUILD_AREAS
Topology levels - build areas.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
void * topo
Topology info.
struct field_info * Vect_get_dblink(const struct Map_info *, int)
Get information about link to database.
int n_cats
Number of categories attached to element.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
const struct driver * driver
struct Plus_head plus
Plus info (topology, version, ...)
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)
int db_sqltype_to_Ctype(int)
Get C data type based on given SQL data type.
int V2_read_line_pg(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read feature from PostGIS layer on topological level.
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
off_t V1_rewrite_line_pg(struct Map_info *Map, off_t offset, int type, const struct line_pnts *points, const struct line_cats *cats)
Rewrites feature at the given offset (level 1) (PostGIS interface, internal use only) ...
Topological feature - node.
int Vect_get_num_updated_nodes(const struct Map_info *)
Get number of updated nodes.
int V1_read_line_pg(struct Map_info *, struct line_pnts *, struct line_cats *, off_t)
Read feature from PostGIS layer at given offset (level 1 without topology)
off_t V1_write_line_pg(struct Map_info *Map, int type, const struct line_pnts *points, const struct line_cats *cats)
Writes feature on level 1 (PostGIS interface)
int Vect_get_isle_box(const struct Map_info *, int, struct bound_box *)
Get bounding box of isle.
void db_init_handle(dbHandle *)
Initialize handle (i.e database/schema)
struct dig_head head
Header info.
int Vect_get_line_nodes(const struct Map_info *, int, int *, int *)
Get line nodes.
const char * db_get_value_string(dbValue *)
Get string value.
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)(const struct Map_info *, int))
Add feature (line) to topology (internal use only)
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)
double * y
Array of Y coordinates.
char * driver
Name of DB driver ('sqlite', 'dbf', ...)
int db_open_database(dbDriver *, dbHandle *)
Open database connection.
int dig_add_node(struct Plus_head *, double, double, double)
Add new node to plus structure.
int Vect__execute_pg(PGconn *conn, const char *stmt)
Execute SQL statement.
double db_get_value_double(dbValue *)
Get double precision value.
int Vect__insert_face_pg(struct Map_info *Map, int area)
Insert new face to the 'face' table (topo only)
int Vect_is_3d(const struct Map_info *)
Check if vector map is 3D.
int dig__byte_order_out()
Get byte order.
const char * G_mapset(void)
Get current mapset name.
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
#define LEVEL_2
Vector level - with 2D topology.
void G_warning(const char *,...) __attribute__((format(printf
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)
const char * Vect_get_finfo_geometry_type(const struct Map_info *)
Get geometry type as string (relevant only for non-native formats)
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
double * z
Array of Z coordinates.
char * G_store(const char *)
Copy string to allocated memory.
int * field
Array of layers (fields)
int G_asprintf(char **, const char *,...) __attribute__((format(printf
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
void Vect_reset_updated(struct Map_info *)
Reset list of updated lines/nodes.
int Vect__define_topo_relation(const struct Format_info_pg *pg_info, int topo_id, int element_id)
int db_get_table_number_of_columns(dbTable *)
Return the number of columns of the table.
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
int Vect_get_updated_node(const struct Map_info *, int)
Get updated (modified) node by index.
int update_cidx
Update category index if vector is modified.
void void G_verbose_message(const char *,...) __attribute__((format(printf
plus_t n_lines
Number of boundary lines.
void Vect_set_updated(struct Map_info *, int)
Enable/disable maintanance of list of updated lines/nodes.
int V2_delete_line_pg(struct Map_info *Map, off_t line)
Deletes feature on topological level (PostGIS interface)
int G_debug(int, const char *,...) __attribute__((format(printf
void db_free_string(dbString *)
Free allocated space for dbString.
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
void Vect_reset_line(struct line_pnts *)
Reset line.
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
plus_t n_nodes
Current number of topological features derived from vector geometries.
SF_FeatureType
Simple feature types.
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.
char * key
Name of key column (usually 'cat')
int V2_delete_line_sfa(struct Map_info *, off_t)
Deletes feature on level 2 (OGR/PostGIS interface)