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

Definition at line 862 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().

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

Here is the call graph for this function:

Here is the caller graph for this function: