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 sprintf(stmt,
"DELETE FROM %s WHERE %s = %ld", pg_info->
table_name,
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";
440 "UPDATE \"%s\".\"%s\" SET abs_next_left_edge = edge_id, "
441 "next_left_edge = -edge_id WHERE abs_next_left_edge = %d",
450 "UPDATE \"%s\".\"%s\" SET abs_next_right_edge = edge_id, "
451 "next_right_edge = edge_id WHERE abs_next_right_edge = %d",
468 sprintf(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 sprintf(stmt,
"CREATE TABLE \"%s\".\"%s\" (%s SERIAL%s, %s INTEGER",
665 int col, ncols, sqltype, length;
677 driver = open_db(pg_info);
692 "copying attributes: driver = %s database = %s table = %s cols "
696 for (col = 0; col < ncols; col++) {
702 G_debug(3,
"\tcolumn = %d name = %s type = %d length = %d", col,
703 colname, sqltype, length);
708 G_debug(3,
"\t%s skipped", colname);
714 strcat(stmt, stmt_col);
717 sprintf(stmt_col,
"(%d)", length);
718 strcat(stmt, stmt_col);
743 geom_type =
"LINESTRING";
746 geom_type =
"POLYGON";
749 geom_type =
"POLYGONZ";
752 geom_type =
"GEOMETRY";
762 "SELECT AddGeometryColumn('%s', '%s', "
763 "'%s', %d, '%s', %d)",
767 result = PQexec(pg_info->
conn, stmt);
769 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
770 G_warning(
"%s", PQresultErrorMessage(result));
780 sprintf(stmt,
"CREATE INDEX %s_%s_idx ON \"%s\".\"%s\" (%s)",
791 sprintf(stmt,
"CREATE INDEX %s_%s_idx ON \"%s\".\"%s\" USING GIST (%s)",
819 int i, found, nschema;
830 sprintf(stmt,
"SELECT nspname FROM pg_namespace");
832 result = PQexec(pg_info->
conn, stmt);
834 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
841 nschema = PQntuples(result);
842 for (i = 0; i < nschema && !found; i++) {
843 if (strcmp(pg_info->
schema_name, PQgetvalue(result, i, 0)) == 0)
850 sprintf(stmt,
"CREATE SCHEMA %s", pg_info->
schema_name);
855 G_warning(
_(
"Schema <%s> doesn't exist, created"),
876 int create_topo_schema(
struct Format_info_pg *pg_info,
int with_z)
882 def_file = getenv(
"GRASS_VECTOR_PGFILE");
903 G_debug(1,
"PG: tolerance: %f", tolerance);
937 "SELECT topology.createtopology('%s', "
938 "find_srid('%s', '%s', '%s'), %f, '%s')",
951 "SELECT topology.AddTopoGeometryColumn('%s', '%s', '%s', "
961 sprintf(stmt,
"CREATE INDEX \"%s_%s_%s_idx\" ON \"%s\".\"%s\" (((%s).id))",
972 if (-1 == set_constraint_to_deferrable(pg_info,
"node",
"face_exists",
973 "containing_face",
"face",
975 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
976 "end_node_exists",
"end_node",
977 "node",
"node_id") ||
978 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
979 "left_face_exists",
"left_face",
980 "face",
"face_id") ||
981 -1 == set_constraint_to_deferrable(
982 pg_info,
"edge_data",
"right_face_exists",
"right_face",
983 "face",
"face_id") ||
984 -1 == set_constraint_to_deferrable(pg_info,
"edge_data",
986 "start_node",
"node",
"node_id"))
998 "CREATE TABLE \"%s\".%s (node_id SERIAL PRIMARY KEY, "
999 "lines integer[], angles float[])",
1007 "ALTER TABLE \"%s\".%s ADD CONSTRAINT node_exists "
1008 "FOREIGN KEY (node_id) REFERENCES \"%s\".node (node_id) "
1009 "DEFERRABLE INITIALLY DEFERRED",
1021 "CREATE TABLE \"%s\".%s (line_id SERIAL PRIMARY KEY, "
1022 "left_area integer, right_area integer)",
1030 "ALTER TABLE \"%s\".%s ADD CONSTRAINT line_exists "
1031 "FOREIGN KEY (line_id) REFERENCES \"%s\".edge_data (edge_id) "
1032 "DEFERRABLE INITIALLY DEFERRED",
1045 "CREATE TABLE \"%s\".%s (area_id SERIAL PRIMARY KEY, "
1046 "lines integer[], centroid integer, isles integer[])",
1058 "CREATE TABLE \"%s\".%s (isle_id SERIAL PRIMARY KEY, "
1059 "lines integer[], area integer)",
1094 int create_pg_layer(
struct Map_info *Map,
int type)
1102 G_warning(
_(
"Connection string not defined"));
1107 G_warning(
_(
"PostGIS feature table not defined"));
1111 G_debug(1,
"Vect__open_new_pg(): conninfo='%s' table='%s' -> type = %d",
1135 G_warning(
_(
"Unsupported geometry type (%d)"), type);
1148 G_warning(
_(
"More layers defined, using driver <%s> and "
1153 G_warning(
_(
"Database connection not defined. "
1154 "Unable to write attributes."));
1159 if (create_table(pg_info) == -1) {
1160 G_warning(
_(
"Unable to create new PostGIS feature table"));
1173 if (create_topo_schema(pg_info,
Vect_is_3d(Map)) == -1) {
1174 G_warning(
_(
"Unable to create new PostGIS topology schema"));
1204 return "COLLECTION";
1206 G_warning(
_(
"Unsupported feature type %d"), sftype);
1223 off_t write_line_sf(
struct Map_info *Map,
int type,
1224 const struct line_pnts **points,
int nparts,
1236 offset_info = &(pg_info->
offset);
1242 if (!pg_info->
conn) {
1247 G_warning(
_(
"PostGIS feature table not defined"));
1253 if (create_pg_layer(Map, type) < 0)
1268 G_warning(
_(
"No category defined for layer %d"), field);
1270 G_warning(
_(
"Feature has more categories, using "
1271 "category %d (from layer %d)"),
1281 G_warning(
_(
"Point skipped (output feature type: %s)"),
1288 G_warning(
_(
"Line skipped (output feature type: %s)"),
1295 G_warning(
_(
"Centroid skipped (output feature type: %s)"),
1302 G_warning(
_(
"Boundary skipped (output feature type: %s)"),
1309 G_warning(
_(
"Face skipped (output feature type: %s)"),
1315 G_warning(
_(
"Unsupported feature type %d"), type);
1319 G_debug(3,
"write_line_sf(): type = %d n_points = %d cat = %d", type,
1320 points[0]->n_points, cat);
1326 for (part = 0; part < nparts; part++) {
1327 npoints = points[part]->
n_points - 1;
1328 if (points[part]->
x[0] != points[part]->
x[npoints] ||
1329 points[part]->y[0] != points[part]->y[npoints] ||
1330 points[part]->z[0] != points[part]->z[npoints]) {
1331 G_warning(
_(
"Boundary is not closed. Skipping."));
1338 if (-1 == write_feature(Map, -1, type, points, nparts, cat)) {
1356 G_debug(3,
"write_line_sf(): -> offset = %lu offset_num = %d cat = %d",
1357 (
unsigned long)offset, offset_info->
array_num, cat);
1375 off_t write_line_tp(
struct Map_info *Map,
int type,
int is_node,
1379 int line, cat, line_id;
1386 plus = &(Map->
plus);
1394 G_warning(
_(
"Invalid feature type (%d) for nodes"), type);
1399 if (!pg_info->
conn) {
1404 G_warning(
_(
"PostGIS feature table not defined"));
1408 G_warning(
_(
"PostGIS topology schema not defined"));
1414 if (create_pg_layer(Map, type) < 0)
1421 G_debug(3,
"write_line_pg(): type = %d n_points = %d", type,
1427 if (cats && cats->
n_cats > 0) {
1434 G_warning(
_(
"Feature has more categories, using "
1435 "category %d (from layer %d)"),
1436 cat, cats->
field[0]);
1464 line = add_line_to_topo_pg(Map, offset, type, points);
1472 line_id = write_feature(Map, line, type, &points, 1, cat);
1492 offset = &(pg_info->
offset);
1502 offset->
array[node - 1] = (int)line_id;
1507 update_topo_face(Map, line);
1509 return !is_node ? line : 0;
1522 char *binary_to_hex(
int nbytes,
const unsigned char *wkb_data)
1526 static const char ach_hex[] =
"0123456789ABCDEF";
1528 hex_data = (
char *)
G_malloc(nbytes * 2 + 1);
1529 hex_data[nbytes * 2] =
'\0';
1531 for (i = 0; i < nbytes; i++) {
1532 nlow = wkb_data[i] & 0x0f;
1533 nhigh = (wkb_data[i] & 0xf0) >> 4;
1535 hex_data[i * 2] = ach_hex[nhigh];
1536 hex_data[i * 2 + 1] = ach_hex[nlow];
1555 unsigned char *point_to_wkb(
int byte_order,
const struct line_pnts *points,
1556 int with_z,
int *nsize)
1558 unsigned char *wkb_data;
1559 unsigned int sf_type;
1565 *nsize = with_z ? 29 : 21;
1567 G_zero(wkb_data, *nsize);
1569 G_debug(5,
"\t->point size=%d (with_z = %d)", *nsize, with_z);
1573 wkb_data[0] =
'\001';
1575 wkb_data[0] =
'\000';
1581 sf_type = LSBWORD32(sf_type);
1583 sf_type = MSBWORD32(sf_type);
1584 memcpy(wkb_data + 1, &sf_type, 4);
1587 memcpy(wkb_data + 5, &(points->
x[0]), 8);
1588 memcpy(wkb_data + 5 + 8, &(points->
y[0]), 8);
1591 memcpy(wkb_data + 5 + 16, &(points->
z[0]), 8);
1596 SWAPDOUBLE(wkb_data + 5);
1597 SWAPDOUBLE(wkb_data + 5 + 8);
1600 SWAPDOUBLE(wkb_data + 5 + 16);
1619 unsigned char *linestring_to_wkb(
int byte_order,
const struct line_pnts *points,
1620 int with_z,
int *nsize)
1623 unsigned char *wkb_data;
1624 unsigned int sf_type;
1630 point_size = 8 * (with_z ? 3 : 2);
1631 *nsize = 5 + 4 + points->
n_points * point_size;
1633 G_zero(wkb_data, *nsize);
1635 G_debug(5,
"\t->linestring size=%d (with_z = %d)", *nsize, with_z);
1639 wkb_data[0] =
'\001';
1641 wkb_data[0] =
'\000';
1647 sf_type = LSBWORD32(sf_type);
1649 sf_type = MSBWORD32(sf_type);
1650 memcpy(wkb_data + 1, &sf_type, 4);
1653 memcpy(wkb_data + 5, &(points->
n_points), 4);
1656 for (i = 0; i < points->
n_points; i++) {
1657 memcpy(wkb_data + 9 + point_size * i, &(points->
x[i]), 8);
1658 memcpy(wkb_data + 9 + 8 + point_size * i, &(points->
y[i]), 8);
1661 memcpy(wkb_data + 9 + 16 + point_size * i, &(points->
z[i]), 8);
1667 int npoints, nitems;
1669 npoints = SWAP32(points->
n_points);
1670 memcpy(wkb_data + 5, &npoints, 4);
1672 nitems = (with_z ? 3 : 2) * points->
n_points;
1673 for (i = 0; i < nitems; i++) {
1674 SWAPDOUBLE(wkb_data + 9 + 4 + 8 * i);
1695 unsigned char *polygon_to_wkb(
int byte_order,
const struct line_pnts **points,
1696 int nrings,
int with_z,
int *nsize)
1698 int i, ring, point_size, offset;
1699 unsigned char *wkb_data;
1700 unsigned int sf_type;
1705 for (ring = 0; ring < nrings; ring++) {
1706 if (points[ring]->n_points < 3)
1711 point_size = 8 * (with_z ? 3 : 2);
1713 for (ring = 0; ring < nrings; ring++)
1714 *nsize += 4 + point_size * points[ring]->n_points;
1716 G_zero(wkb_data, *nsize);
1718 G_debug(5,
"\t->polygon size=%d (with_z = %d)", *nsize, with_z);
1722 wkb_data[0] =
'\001';
1724 wkb_data[0] =
'\000';
1730 sf_type = LSBWORD32(sf_type);
1732 sf_type = MSBWORD32(sf_type);
1733 memcpy(wkb_data + 1, &sf_type, 4);
1739 ncount = SWAP32(nrings);
1740 memcpy(wkb_data + 5, &ncount, 4);
1743 memcpy(wkb_data + 5, &nrings, 4);
1748 for (ring = 0; ring < nrings; ring++) {
1749 memcpy(wkb_data + offset, &(points[ring]->n_points), 4);
1750 for (i = 0; i < points[ring]->
n_points; i++) {
1751 memcpy(wkb_data + offset + 4 + point_size * i,
1752 &(points[ring]->
x[i]), 8);
1753 memcpy(wkb_data + offset + 4 + 8 + point_size * i,
1754 &(points[ring]->y[i]), 8);
1757 memcpy(wkb_data + offset + 4 + 16 + point_size * i,
1758 &(points[ring]->z[i]), 8);
1762 offset += 4 + point_size * points[ring]->
n_points;
1766 int npoints, nitems;
1768 npoints = SWAP32(points[ring]->n_points);
1769 memcpy(wkb_data + 5, &npoints, 4);
1771 nitems = (with_z ? 3 : 2) * points[ring]->n_points;
1772 for (i = 0; i < nitems; i++) {
1773 SWAPDOUBLE(wkb_data + offset + 4 + 8 * i);
1796 const struct line_pnts **points,
int nparts,
int type,
1799 int byte_order, nbytes, nsize;
1800 unsigned int sf_type;
1802 unsigned char *wkb_data;
1803 char *text_data, *text_data_p, *hex_data;
1811 wkb_data = point_to_wkb(byte_order, points[0], with_z, &nbytes);
1814 wkb_data = linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
1819 polygon_to_wkb(byte_order, points, nparts, with_z, &nbytes);
1824 linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
1828 if (!wkb_data || nbytes < 1) {
1829 G_warning(
_(
"Unsupported feature type %d"), type);
1836 nsize = nbytes * 2 + 8 + 1;
1837 text_data = text_data_p = (
char *)
G_malloc(nsize);
1840 hex_data = binary_to_hex(1, wkb_data);
1841 strcpy(text_data_p, hex_data);
1846 memcpy(&sf_type, wkb_data + 1, 4);
1849 if (pg_info->
srid > 0) {
1850 unsigned int srs_flag;
1855 sf_type = sf_type | srs_flag;
1859 hex_data = binary_to_hex(4, (
unsigned char *)&sf_type);
1860 strcpy(text_data_p, hex_data);
1865 if (pg_info->
srid > 0) {
1866 unsigned int srs_id;
1869 srs_id = LSBWORD32(pg_info->
srid);
1870 hex_data = binary_to_hex(
sizeof(srs_id), (
unsigned char *)&srs_id);
1871 strcpy(text_data_p, hex_data);
1878 hex_data = binary_to_hex(nbytes - 5, wkb_data + 5);
1879 strcpy(text_data_p, hex_data);
1899 int write_feature(
struct Map_info *Map,
int line,
int type,
1900 const struct line_pnts **points,
int nparts,
int cat)
1902 int with_z, topo_id;
1903 char *stmt, *geom_data;
1910 if (with_z && pg_info->
coor_dim != 3) {
1911 G_warning(
_(
"Trying to insert 3D data into feature table "
1912 "which store 2D data only"));
1915 if (!with_z && pg_info->
coor_dim != 2) {
1916 G_warning(
_(
"Trying to insert 2D data into feature table "
1917 "which store 3D data only"));
1922 geom_data = line_to_wkb(pg_info, points, nparts, type, with_z);
1939 topo_id = insert_topo_element(Map, line, type, geom_data);
1941 G_warning(
_(
"Unable to insert topological element into PostGIS "
1942 "Topology schema"));
1957 stmt = build_insert_stmt(pg_info, geom_data, topo_id, cat);
1991 const char *geom_data,
int topo_id,
int cat)
2001 topogeom_type = type_to_topogeom(pg_info);
2002 if (topogeom_type < 0)
2009 if (Fi && cat > -1) {
2011 int col, ncol, more;
2012 int sqltype, ctype, is_fid;
2015 const char *colname;
2027 sprintf(buf,
"SELECT * FROM %s WHERE %s = %d", Fi->
table, Fi->
key, cat);
2032 sprintf(buf,
"INSERT INTO \"%s\".\"%s\" (", pg_info->
schema_name,
2038 G_warning(
_(
"Unable to select attributes for category %d"), cat);
2046 G_warning(
_(
"No database record for category %d, "
2047 "no attributes will be written"),
2054 for (col = 0; col < ncol; col++) {
2062 G_debug(3,
"col %d : val = %s", col,
2068 is_fid = strcmp(pg_info->
fid_column, colname) == 0;
2072 G_warning(
_(
"FID column must be integer, column <%s> "
2079 sprintf(buf_tmp,
"\"%s\"", colname);
2080 strcat(buf, buf_tmp);
2091 sprintf(buf_tmp,
"%.14f",
2099 sprintf(buf_tmp,
"'%s'", value_tmp);
2108 G_warning(
_(
"Unsupported column type %d"), ctype);
2109 sprintf(buf_tmp,
"NULL");
2115 G_warning(
_(
"Invalid value for FID column: NULL"));
2116 sprintf(buf_tmp,
"NULL");
2118 strcat(buf_val, buf_tmp);
2120 strcat(buf_val,
",");
2125 G_asprintf(&stmt,
"%s,%s) VALUES (%s,'%s'::GEOMETRY)", buf,
2131 if (buf[strlen(buf) - 1] ==
',') {
2132 buf[strlen(buf) - 1] =
'\0';
2133 buf_val[strlen(buf_val) - 1] =
'\0';
2136 "%s, %s) VALUES (%s, '(%d, 1, %d, "
2137 "%d)'::topology.TopoGeometry)",
2151 "INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES "
2152 "(%d, '%s'::GEOMETRY)",
2159 "INSERT INTO \"%s\".\"%s\" (%s) VALUES "
2169 "INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES "
2170 "(%d, '(%d, 1, %d, %d)'::topology.TopoGeometry)",
2194 int insert_topo_element(
struct Map_info *Map,
int id,
int type,
2195 const char *geom_data)
2204 plus = &(Map->
plus);
2211 G_warning(
_(
"Invalid feature %d (max: %d)"), topo_id,
2230 G_warning(
_(
"Invalid node %d (%d)"), topo_id,
2246 G_asprintf(&stmt,
"SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
2251 sprintf(stmt_id,
"SELECT nextval('\"%s\".node_node_id_seq')",
2258 "INSERT INTO \"%s\".node (node_id, geom) VALUES "
2259 "(%d, '%s'::GEOMETRY)",
2268 G_asprintf(&stmt,
"SELECT topology.AddEdge('%s', '%s'::GEOMETRY)",
2271 int n1, n2, nle, nre;
2275 offset = &(pg_info->
offset);
2279 sprintf(stmt_id,
"SELECT nextval('\"%s\".edge_data_edge_id_seq')",
2288 int i, n, next_edge;
2291 topo_id = (
int)Line->
offset;
2297 for (i = 0; i < 2; i++) {
2303 update_next_edge(Map, n, i == 0 ? topo_id : -topo_id);
2304 if (next_edge != 0) {
2313 G_warning(
_(
"Unable to determine next left/right edge for "
2320 G_warning(
_(
"Unable to insert new edge. Topology not available."));
2324 G_debug(3,
"new edge: id=%d next_left_edge=%d next_right_edge=%d",
2334 "INSERT INTO \"%s\".edge_data (edge_id, start_node, end_node, "
2335 "next_left_edge, abs_next_left_edge, next_right_edge, "
2336 "abs_next_right_edge, "
2337 "left_face, right_face, geom) VALUES "
2338 "(%d, %d, %d, %d, %d, %d, %d, 0, 0, '%s'::GEOMETRY)",
2340 offset->
array[n2 - 1], nle, abs(nle), nre, abs(nre), geom_data);
2347 G_asprintf(&stmt,
"SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
2354 sprintf(stmt_id,
"SELECT nextval('\"%s\".node_node_id_seq')",
2370 "INSERT INTO \"%s\".node (node_id, containing_face, geom) VALUES "
2371 "(%d, %d, '%s'::GEOMETRY)",
2377 G_warning(
_(
"Unsupported feature type %d"), type);
2413 return topogeom_type;
2417 int topo_id,
int element_id)
2422 topogeom_type = type_to_topogeom(pg_info);
2423 if (topogeom_type < 0)
2426 sprintf(stmt,
"INSERT into \"%s\".relation VALUES(%d, 1, %d, %d)",
2450 int update_next_edge(
struct Map_info *Map,
int nlines,
int line)
2452 int ret, next_line, edge;
2456 struct P_line *Line_next, *Line;
2458 Line = Line_next =
NULL;
2468 G_debug(3,
"line=%d next_line=%d", line, next_line);
2469 if (next_line == 0) {
2475 Line_next = Map->
plus.
Line[abs(next_line)];
2476 if (!Line || !Line_next) {
2483 ret = next_line > 0 ? Line_next->
offset : -Line_next->
offset;
2487 ret = next_line > 0 ? Line_next->
offset : -Line_next->
offset;
2490 if (next_line < 0) {
2492 "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
2493 "abs_next_left_edge = %d WHERE edge_id = %d AND "
2494 "abs_next_left_edge = %d",
2497 G_debug(3,
"update edge=%d next_left_edge=%d (?)",
2498 (
int)Line_next->
offset, edge);
2502 "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
2503 "abs_next_right_edge = %d WHERE edge_id = %d AND "
2504 "abs_next_right_edge = %d",
2507 G_debug(3,
"update edge=%d next_right_edge=%d (?)",
2508 (
int)Line_next->
offset, edge);
2524 Line_next = Map->
plus.
Line[abs(next_line)];
2526 if (next_line < 0) {
2528 "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
2529 "abs_next_left_edge = %d WHERE edge_id = %d",
2532 G_debug(3,
"update edge=%d next_left_edge=%d",
2533 (
int)Line_next->
offset, edge);
2537 "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
2538 "abs_next_right_edge = %d WHERE edge_id = %d",
2541 G_debug(3,
"update edge=%d next_right_edge=%d",
2542 (
int)Line_next->
offset, edge);
2586 "INSERT INTO \"%s\".face (face_id, mbr) VALUES "
2587 "(%d, ST_GeomFromText('POLYGON((%.12f %.12f, %.12f %.12f, %.12f "
2588 "%.12f, %.12f %.12f, "
2589 "%.12f %.12f))', %d))",
2591 box.
E, box.
N, box.
E, box.
S, box.
W, box.
S, pg_info->
srid);
2592 G_debug(3,
"new face id=%d", area);
2615 int delete_face(
struct Map_info *Map,
int area)
2624 sprintf(stmt,
"UPDATE \"%s\".node SET containing_face = 0 "
2633 sprintf(stmt,
"UPDATE \"%s\".edge_data SET left_face = 0 "
2642 sprintf(stmt,
"UPDATE \"%s\".edge_data SET right_face = 0 "
2651 sprintf(stmt,
"DELETE FROM \"%s\".face WHERE face_id = %d",
2653 G_debug(3,
"delete face id=%d", area);
2679 int update_topo_edge(
struct Map_info *Map,
int line)
2682 int nle, nre, next_edge;
2691 G_warning(
_(
"Attempt to access non-existing feature %d"), line);
2696 G_warning(
_(
"Attempt to access dead feature %d"), line);
2705 for (i = 0; i < 2; i++) {
2713 next_edge = update_next_edge(Map, n, i == 0 ? line : -line);
2714 if (next_edge != 0) {
2721 G_warning(
_(
"Unable to determine next left/right edge"));
2726 if (nle == 0 && nre == 0)
2729 if (nle != 0 && nre != 0) {
2731 sprintf(stmt,
"UPDATE \"%s\".edge_data SET "
2732 "next_left_edge = %d, abs_next_left_edge = %d, "
2733 "next_right_edge = %d, abs_next_right_edge = %d "
2735 nle, abs(nle), nre, abs(nre), (
int)Line->
offset);
2737 else if (nle != 0) {
2739 sprintf(stmt,
"UPDATE \"%s\".edge_data SET "
2740 "next_left_edge = %d, abs_next_left_edge = %d "
2742 nle, abs(nle), (
int)Line->
offset);
2746 sprintf(stmt,
"UPDATE \"%s\".edge_data SET "
2747 "next_right_edge = %d, abs_next_right_edge = %d "
2749 nre, abs(nre), (
int)Line->
offset);
2751 G_debug(3,
"update edge=%d next_left_edge=%d next_right_edge=%d",
2752 (
int)Line->
offset, nle, nre);
2775 int update_topo_face(
struct Map_info *Map,
int line)
2777 int i, s, area, face[2];
2781 struct P_line *Line, *Line_i;
2788 G_warning(
_(
"Attempt to access non-existing feature %d"), line);
2793 G_warning(
_(
"Attempt to access dead feature %d"), line);
2801 for (s = 0; s < 2; s++) {
2802 area = s == 0 ? topo->
left : topo->
right;
2814 for (s = 0; s < 2; s++) {
2815 area = s == 0 ? topo->
left : topo->
right;
2820 for (i = 0; i < Area->
n_lines; i++) {
2825 "UPDATE \"%s\".edge_data SET "
2826 "left_face = %d, right_face = %d "
2827 "WHERE edge_id = %d",
2829 topo_i->
left > 0 ? topo_i->
left : 0,
2843 "UPDATE \"%s\".node SET containing_face = %d "
2844 "WHERE node_id = %d",
2870 int add_line_to_topo_pg(
struct Map_info *Map, off_t offset,
int type,
2877 plus = &(Map->
plus);
2891 for (i = 0; i <
n_nodes; i++) {
2894 if (node > 0 || plus->
Node[abs(node)] ==
NULL)
2897 G_debug(3,
" new node: %d", node);
2904 (
const struct line_pnts **)&Points, 1, -1);
2922 int delete_line_from_topo_pg(
struct Map_info *Map,
int line,
int type,
2925 int N1, N2, node_id;
2943 if (!Node || Node->
n_lines == 0) {
2945 sprintf(stmt,
"DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
2948 G_warning(
_(
"Unable to delete node %d"), node_id);
2955 if (!Node || Node->
n_lines == 0) {
2957 sprintf(stmt,
"DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
2960 G_warning(
_(
"Unable to delete node %d"), node_id);
2970 const char *table,
const char *constraint,
2971 const char *column,
const char *ref_table,
2972 const char *ref_column)
2976 sprintf(stmt,
"ALTER TABLE \"%s\".%s DROP CONSTRAINT %s",
2984 "ALTER TABLE \"%s\".%s ADD CONSTRAINT %s "
2985 "FOREIGN KEY (%s) REFERENCES \"%s\".%s (%s) "
2986 "DEFERRABLE INITIALLY DEFERRED",
3023 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)