PostGIS  2.5.0dev-r@@SVN_REVISION@@
static int getTableInfo ( SHPDUMPERSTATE state)
static

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

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, and shp_dumper_state::table.

Referenced by ShpDumperOpenTable().

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

Here is the call graph for this function:

Here is the caller graph for this function: