PostGIS  2.5.7dev-r@@SVN_REVISION@@

◆ getTableInfo()

static int getTableInfo ( SHPDUMPERSTATE state)
static

Definition at line 874 of file pgsql2shp-core.c.

875 {
876 
877  /* Get some more information from the table:
878  - count = total number of geometries/geographies in the table
879 
880  and if we have found a suitable geometry column:
881 
882  - max = maximum number of dimensions within the geometry/geography column
883  - geometrytype = string representing the geometry/geography type, e.g. POINT
884 
885  Since max/geometrytype already require a sequential scan of the table, we may as
886  well get the row count too.
887  */
888 
889  PGresult *res;
890  char *query;
891  int tmpint;
892 
893 
894  if (state->geo_col_name)
895  {
896  /* Include geometry information */
897  if (state->schema)
898  {
899  query = malloc(150 + 4 * strlen(state->geo_col_name) + strlen(state->schema) + strlen(state->table));
900 
901  sprintf(query, "SELECT count(1), max(ST_zmflag(\"%s\"::geometry)), geometrytype(\"%s\"::geometry) FROM \"%s\".\"%s\" GROUP BY 3",
902  state->geo_col_name, state->geo_col_name, state->schema, state->table);
903  }
904  else
905  {
906  query = malloc(150 + 4 * strlen(state->geo_col_name) + strlen(state->table));
907 
908  sprintf(query, "SELECT count(1), max(ST_zmflag(\"%s\"::geometry)), geometrytype(\"%s\"::geometry) FROM \"%s\" GROUP BY 3",
909  state->geo_col_name, state->geo_col_name, state->table);
910  }
911  }
912  else
913  {
914  /* Otherwise... just a row count will do */
915  if (state->schema)
916  {
917  query = malloc(40 + strlen(state->schema) + strlen(state->table));
918 
919  sprintf(query, "SELECT count(1) FROM \"%s\".\"%s\"", state->schema, state->table);
920  }
921  else
922  {
923  query = malloc(40 + strlen(state->table));
924 
925  sprintf(query, "SELECT count(1) FROM \"%s\"", state->table);
926  }
927  }
928 
929  LWDEBUGF(3, "Table metadata query: %s\n", query);
930 
931  res = PQexec(state->conn, query);
932  free(query);
933 
934  if (PQresultStatus(res) != PGRES_TUPLES_OK)
935  {
936  snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Could not execute table metadata query: %s"), PQresultErrorMessage(res));
937  PQclear(res);
938  return SHPDUMPERERR;
939  }
940 
941  /* Make sure we error if the table is empty */
942  if (PQntuples(res) == 0)
943  {
944  snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Could not determine table metadata (empty table)"));
945  PQclear(res);
946  return SHPDUMPERERR;
947  }
948 
949  /* If we have a geo* column, get the dimension, type and count information */
950  if (state->geo_col_name)
951  {
952  /* If a table has a geometry column containing mixed types then
953  the metadata query will return multiple rows. We need to cycle
954  through all rows to determine if the type combinations are valid.
955 
956  Note that if we find a combination of a MULTI and non-MULTI geometry
957  of the same type, we always choose MULTI to ensure that everything
958  gets output correctly. The create_* conversion functions are clever
959  enough to up-convert the non-MULTI geometry to a MULTI in this case. */
960 
961  int dummy, i;
962  uint8_t type = 0;
963  int typefound = 0, typemismatch = 0;
964 
965  state->rowcount = 0;
966 
967  for (i = 0; i < PQntuples(res); i++)
968  {
969  /* skip null geometries */
970  if (PQgetisnull(res, i, 2))
971  {
972  state->rowcount += atoi(PQgetvalue(res, i, 0));
973  continue;
974  }
975 
976  geometry_type_from_string(PQgetvalue(res, i, 2), &type, &dummy, &dummy);
977 
978  /* We can always set typefound to that of the first column found */
979  if (!typefound)
980  typefound = type;
981 
982  switch (type)
983  {
984  case MULTIPOINTTYPE:
985  if (typefound != MULTIPOINTTYPE && typefound != POINTTYPE)
986  typemismatch = 1;
987  else
988  typefound = MULTIPOINTTYPE;
989  break;
990 
991  case MULTILINETYPE:
992  if (typefound != MULTILINETYPE && typefound != LINETYPE)
993  typemismatch = 1;
994  else
995  typefound = MULTILINETYPE;
996  break;
997 
998  case MULTIPOLYGONTYPE:
999  if (typefound != MULTIPOLYGONTYPE && typefound != POLYGONTYPE)
1000  typemismatch = 1;
1001  else
1002  typefound = MULTIPOLYGONTYPE;
1003  break;
1004 
1005  case POINTTYPE:
1006  if (typefound != POINTTYPE && typefound != MULTIPOINTTYPE)
1007  typemismatch = 1;
1008  else if (!lwtype_is_collection(type))
1009  typefound = POINTTYPE;
1010  break;
1011 
1012  case LINETYPE:
1013  if (typefound != LINETYPE && typefound != MULTILINETYPE)
1014  typemismatch = 1;
1015  else if (!lwtype_is_collection(type))
1016  typefound = LINETYPE;
1017  break;
1018 
1019  case POLYGONTYPE:
1020  if (typefound != POLYGONTYPE && typefound != MULTIPOLYGONTYPE)
1021  typemismatch = 1;
1022  else if (!lwtype_is_collection(type))
1023  typefound = POLYGONTYPE;
1024  break;
1025  }
1026 
1027  /* Update the rowcount for each type */
1028  state->rowcount += atoi(PQgetvalue(res, i, 0));
1029 
1030  /* Set up the dimension output type (note: regardless of how many rows
1031  the table metadata query returns, this value will be the same. But
1032  we'll choose to use the first value anyway) */
1033  tmpint = atoi(PQgetvalue(res, i, 1));
1034  switch (tmpint)
1035  {
1036  case 0:
1037  state->outtype = 's';
1038  break;
1039  case 1:
1040  state->outtype = 'm';
1041  break;
1042  default:
1043  state->outtype = 'z';
1044  break;
1045  }
1046 
1047  }
1048 
1049  /* Flag an error if the table contains incompatible geometry combinations */
1050  if (typemismatch)
1051  {
1052  snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Incompatible mixed geometry types in table"));
1053  PQclear(res);
1054  return SHPDUMPERERR;
1055  }
1056 
1057  /* Set up the shapefile output type based upon the dimension information */
1058  switch (typefound)
1059  {
1060  case POINTTYPE:
1061  switch(state->outtype)
1062  {
1063  case 'z':
1064  state->outshptype = SHPT_POINTZ;
1065  break;
1066 
1067  case 'm':
1068  state->outshptype = SHPT_POINTM;
1069  break;
1070 
1071  default:
1072  state->outshptype = SHPT_POINT;
1073  }
1074  break;
1075 
1076  case MULTIPOINTTYPE:
1077  switch(state->outtype)
1078  {
1079  case 'z':
1080  state->outshptype = SHPT_MULTIPOINTZ;
1081  break;
1082 
1083  case 'm':
1084  state->outshptype = SHPT_MULTIPOINTM;
1085  break;
1086 
1087  default:
1088  state->outshptype = SHPT_MULTIPOINT;
1089  }
1090  break;
1091 
1092  case LINETYPE:
1093  case MULTILINETYPE:
1094  switch(state->outtype)
1095  {
1096  case 'z':
1097  state->outshptype = SHPT_ARCZ;
1098  break;
1099 
1100  case 'm':
1101  state->outshptype = SHPT_ARCM;
1102  break;
1103 
1104  default:
1105  state->outshptype = SHPT_ARC;
1106  }
1107  break;
1108 
1109  case POLYGONTYPE:
1110  case MULTIPOLYGONTYPE:
1111  switch(state->outtype)
1112  {
1113  case 'z':
1114  state->outshptype = SHPT_POLYGONZ;
1115  break;
1116 
1117  case 'm':
1118  state->outshptype = SHPT_POLYGONM;
1119  break;
1120 
1121  default:
1122  state->outshptype = SHPT_POLYGON;
1123  }
1124  break;
1125  }
1126  }
1127  else
1128  {
1129  /* Without a geo* column the total is simply the first (COUNT) column */
1130  state->rowcount = atoi(PQgetvalue(res, 0, 0));
1131  }
1132 
1133  /* Dispose of the result set */
1134  PQclear(res);
1135 
1136  return SHPDUMPEROK;
1137 }
int geometry_type_from_string(const char *str, uint8_t *type, int *z, int *m)
Calculate type integer and dimensional flags from string input.
Definition: g_util.c:163
#define MULTILINETYPE
Definition: liblwgeom.h:89
#define LINETYPE
Definition: liblwgeom.h:86
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition: lwgeom.c:1093
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
#define POLYGONTYPE
Definition: liblwgeom.h:87
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void * malloc(YYSIZE_T)
void free(void *)
type
Definition: ovdump.py:41
tuple res
Definition: window.py:78
#define SHPDUMPERMSGLEN
#define SHPDUMPEROK
#define SHPDUMPERERR
#define SHPT_ARCZ
Definition: shapefil.h:312
#define SHPT_ARCM
Definition: shapefil.h:316
#define SHPT_POLYGONM
Definition: shapefil.h:317
#define SHPT_ARC
Definition: shapefil.h:308
#define SHPT_POLYGON
Definition: shapefil.h:309
#define SHPT_MULTIPOINT
Definition: shapefil.h:310
#define SHPT_POINTZ
Definition: shapefil.h:311
#define SHPT_MULTIPOINTZ
Definition: shapefil.h:314
#define SHPT_MULTIPOINTM
Definition: shapefil.h:318
#define SHPT_POINTM
Definition: shapefil.h:315
#define SHPT_POINT
Definition: shapefil.h:307
#define SHPT_POLYGONZ
Definition: shapefil.h:313
#define _(String)
Definition: shpcommon.h:24
char message[SHPDUMPERMSGLEN]
unsigned char uint8_t
Definition: uthash.h:79

References _, shp_dumper_state::conn, free(), shp_dumper_state::geo_col_name, geometry_type_from_string(), LINETYPE, LWDEBUGF, lwtype_is_collection(), malloc(), shp_dumper_state::message, MULTILINETYPE, MULTIPOINTTYPE, MULTIPOLYGONTYPE, shp_dumper_state::outshptype, shp_dumper_state::outtype, POINTTYPE, POLYGONTYPE, window::res, shp_dumper_state::rowcount, shp_dumper_state::schema, SHPDUMPERERR, SHPDUMPERMSGLEN, SHPDUMPEROK, SHPT_ARC, SHPT_ARCM, SHPT_ARCZ, SHPT_MULTIPOINT, SHPT_MULTIPOINTM, SHPT_MULTIPOINTZ, SHPT_POINT, SHPT_POINTM, SHPT_POINTZ, SHPT_POLYGON, SHPT_POLYGONM, SHPT_POLYGONZ, shp_dumper_state::table, and ovdump::type.

Referenced by ShpDumperOpenTable().

Here is the call graph for this function:
Here is the caller graph for this function: