PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ ShpLoaderOpenShape()

int ShpLoaderOpenShape ( SHPLOADERSTATE state)

Definition at line 846 of file shp2pgsql-core.c.

847 {
848  SHPObject *obj = NULL;
849  int ret = SHPLOADEROK;
850  char name[MAXFIELDNAMELEN];
852  char *utf8str;
853 
854  /* If we are reading the entire shapefile, open it */
855  if (state->config->readshape == 1)
856  {
857  state->hSHPHandle = SHPOpen(state->config->shp_file, "rb");
858 
859  if (state->hSHPHandle == NULL)
860  {
861  snprintf(state->message, SHPLOADERMSGLEN, _("%s: shape (.shp) or index files (.shx) can not be opened, will just import attribute data."), state->config->shp_file);
862  state->config->readshape = 0;
863 
864  ret = SHPLOADERWARN;
865  }
866  }
867 
868  /* Open the DBF (attributes) file */
869  state->hDBFHandle = DBFOpen(state->config->shp_file, "rb");
870  if ((state->hSHPHandle == NULL && state->config->readshape == 1) || state->hDBFHandle == NULL)
871  {
872  snprintf(state->message, SHPLOADERMSGLEN, _("%s: dbf file (.dbf) can not be opened."), state->config->shp_file);
873 
874  return SHPLOADERERR;
875  }
876 
877 
878  /* Open the column map if one was specified */
879  if (state->config->column_map_filename)
880  {
881  ret = colmap_read(state->config->column_map_filename,
882  &state->column_map, state->message, SHPLOADERMSGLEN);
883  if (!ret) return SHPLOADERERR;
884  }
885 
886  /* User hasn't altered the default encoding preference... */
887  if ( strcmp(state->config->encoding, ENCODING_DEFAULT) == 0 )
888  {
889  /* But the file has a code page entry... */
890  if ( state->hDBFHandle->pszCodePage )
891  {
892  /* And we figured out what iconv encoding it maps to, so use it! */
893  char *newencoding = NULL;
894  if ( (newencoding = codepage2encoding(state->hDBFHandle->pszCodePage)) )
895  {
896  lwfree(state->config->encoding);
897  state->config->encoding = newencoding;
898  }
899  }
900  }
901 
902  /* If reading the whole shapefile (not just attributes)... */
903  if (state->config->readshape == 1)
904  {
905  SHPGetInfo(state->hSHPHandle, &state->num_entities, &state->shpfiletype, NULL, NULL);
906 
907  /* If null_policy is set to abort, check for NULLs */
908  if (state->config->null_policy == POLICY_NULL_ABORT)
909  {
910  /* If we abort on null items, scan the entire file for NULLs */
911  for (int j = 0; j < state->num_entities; j++)
912  {
913  obj = SHPReadObject(state->hSHPHandle, j);
914 
915  if (!obj)
916  {
917  snprintf(state->message, SHPLOADERMSGLEN, _("Error reading shape object %d"), j);
918  return SHPLOADERERR;
919  }
920 
921  if (obj->nVertices == 0)
922  {
923  snprintf(state->message, SHPLOADERMSGLEN, _("Empty geometries found, aborted.)"));
924  return SHPLOADERERR;
925  }
926 
927  SHPDestroyObject(obj);
928  }
929  }
930 
931  /* Check the shapefile type */
932  int geomtype = 0;
933  switch (state->shpfiletype)
934  {
935  case SHPT_POINT:
936  /* Point */
937  state->pgtype = "POINT";
938  geomtype = POINTTYPE;
939  state->pgdims = 2;
940  break;
941 
942  case SHPT_ARC:
943  /* PolyLine */
944  state->pgtype = "MULTILINESTRING";
945  geomtype = MULTILINETYPE ;
946  state->pgdims = 2;
947  break;
948 
949  case SHPT_POLYGON:
950  /* Polygon */
951  state->pgtype = "MULTIPOLYGON";
952  geomtype = MULTIPOLYGONTYPE;
953  state->pgdims = 2;
954  break;
955 
956  case SHPT_MULTIPOINT:
957  /* MultiPoint */
958  state->pgtype = "MULTIPOINT";
959  geomtype = MULTIPOINTTYPE;
960  state->pgdims = 2;
961  break;
962 
963  case SHPT_POINTM:
964  /* PointM */
965  geomtype = POINTTYPE;
966  state->has_m = 1;
967  state->pgtype = "POINTM";
968  state->pgdims = 3;
969  break;
970 
971  case SHPT_ARCM:
972  /* PolyLineM */
973  geomtype = MULTILINETYPE;
974  state->has_m = 1;
975  state->pgtype = "MULTILINESTRINGM";
976  state->pgdims = 3;
977  break;
978 
979  case SHPT_POLYGONM:
980  /* PolygonM */
981  geomtype = MULTIPOLYGONTYPE;
982  state->has_m = 1;
983  state->pgtype = "MULTIPOLYGONM";
984  state->pgdims = 3;
985  break;
986 
987  case SHPT_MULTIPOINTM:
988  /* MultiPointM */
989  geomtype = MULTIPOINTTYPE;
990  state->has_m = 1;
991  state->pgtype = "MULTIPOINTM";
992  state->pgdims = 3;
993  break;
994 
995  case SHPT_POINTZ:
996  /* PointZ */
997  geomtype = POINTTYPE;
998  state->has_m = 1;
999  state->has_z = 1;
1000  state->pgtype = "POINT";
1001  state->pgdims = 4;
1002  break;
1003 
1004  case SHPT_ARCZ:
1005  /* PolyLineZ */
1006  state->pgtype = "MULTILINESTRING";
1007  geomtype = MULTILINETYPE;
1008  state->has_z = 1;
1009  state->has_m = 1;
1010  state->pgdims = 4;
1011  break;
1012 
1013  case SHPT_POLYGONZ:
1014  /* MultiPolygonZ */
1015  state->pgtype = "MULTIPOLYGON";
1016  geomtype = MULTIPOLYGONTYPE;
1017  state->has_z = 1;
1018  state->has_m = 1;
1019  state->pgdims = 4;
1020  break;
1021 
1022  case SHPT_MULTIPOINTZ:
1023  /* MultiPointZ */
1024  state->pgtype = "MULTIPOINT";
1025  geomtype = MULTIPOINTTYPE;
1026  state->has_z = 1;
1027  state->has_m = 1;
1028  state->pgdims = 4;
1029  break;
1030 
1031  default:
1032  state->pgtype = "GEOMETRY";
1033  geomtype = COLLECTIONTYPE;
1034  state->has_z = 1;
1035  state->has_m = 1;
1036  state->pgdims = 4;
1037 
1038  snprintf(state->message, SHPLOADERMSGLEN, _("Unknown geometry type: %d\n"), state->shpfiletype);
1039  return SHPLOADERERR;
1040 
1041  break;
1042  }
1043 
1044  /* Force Z/M-handling if configured to do so */
1045  switch(state->config->force_output)
1046  {
1047  case FORCE_OUTPUT_2D:
1048  state->has_z = 0;
1049  state->has_m = 0;
1050  state->pgdims = 2;
1051  break;
1052 
1053  case FORCE_OUTPUT_3DZ:
1054  state->has_z = 1;
1055  state->has_m = 0;
1056  state->pgdims = 3;
1057  break;
1058 
1059  case FORCE_OUTPUT_3DM:
1060  state->has_z = 0;
1061  state->has_m = 1;
1062  state->pgdims = 3;
1063  break;
1064 
1065  case FORCE_OUTPUT_4D:
1066  state->has_z = 1;
1067  state->has_m = 1;
1068  state->pgdims = 4;
1069  break;
1070  default:
1071  /* Simply use the auto-detected values above */
1072  break;
1073  }
1074 
1075  /* If in simple geometry mode, alter names for CREATE TABLE by skipping MULTI */
1076  if (state->config->simple_geometries)
1077  {
1078  if ((geomtype == MULTIPOLYGONTYPE) || (geomtype == MULTILINETYPE) || (geomtype == MULTIPOINTTYPE))
1079  {
1080  /* Chop off the "MULTI" from the string. */
1081  state->pgtype += 5;
1082  }
1083  }
1084 
1085  }
1086  else
1087  {
1088  /* Otherwise just count the number of records in the DBF */
1089  state->num_entities = DBFGetRecordCount(state->hDBFHandle);
1090  }
1091 
1092 
1093  /* Get the field information from the DBF */
1094  state->num_fields = DBFGetFieldCount(state->hDBFHandle);
1095 
1096  state->num_records = DBFGetRecordCount(state->hDBFHandle);
1097 
1098  /* Allocate storage for field information */
1099  state->field_names = malloc(state->num_fields * sizeof(char*));
1100  state->types = (DBFFieldType *)malloc(state->num_fields * sizeof(int));
1101  state->widths = malloc(state->num_fields * sizeof(int));
1102  state->precisions = malloc(state->num_fields * sizeof(int));
1103  state->pgfieldtypes = malloc(state->num_fields * sizeof(char *));
1104  state->col_names = malloc((state->num_fields + 2) * sizeof(char) * MAXFIELDNAMELEN);
1105 
1106  strcpy(state->col_names, "" );
1107  /* Generate a string of comma separated column names of the form "col1, col2 ... colN" for the SQL
1108  insertion string */
1109 
1110  for (int j = 0; j < state->num_fields; j++)
1111  {
1112  int field_precision = 0, field_width = 0;
1113  type = DBFGetFieldInfo(state->hDBFHandle, j, name, &field_width, &field_precision);
1114 
1115  state->types[j] = type;
1116  state->widths[j] = field_width;
1117  state->precisions[j] = field_precision;
1118 /* fprintf(stderr, "XXX %s width:%d prec:%d\n", name, field_width, field_precision); */
1119 
1120  if (state->config->encoding)
1121  {
1122  char *encoding_msg = _("Try \"LATIN1\" (Western European), or one of the values described at http://www.gnu.org/software/libiconv/.");
1123 
1124  int rv = utf8(state->config->encoding, name, &utf8str);
1125 
1126  if (rv != UTF8_GOOD_RESULT)
1127  {
1128  if ( rv == UTF8_BAD_RESULT )
1129  snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert field name \"%s\" to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), utf8str, strerror(errno), state->config->encoding, encoding_msg);
1130  else if ( rv == UTF8_NO_RESULT )
1131  snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert field name to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), strerror(errno), state->config->encoding, encoding_msg);
1132  else
1133  snprintf(state->message, SHPLOADERMSGLEN, _("Unexpected return value from utf8()"));
1134 
1135  if ( rv == UTF8_BAD_RESULT )
1136  free(utf8str);
1137 
1138  return SHPLOADERERR;
1139  }
1140 
1141  strncpy(name, utf8str, MAXFIELDNAMELEN);
1142  name[MAXFIELDNAMELEN-1] = '\0';
1143  free(utf8str);
1144  }
1145 
1146  /* If a column map file has been passed in, use this to create the postgresql field name from
1147  the dbf column name */
1148  {
1149  const char *mapped = colmap_pg_by_dbf(&state->column_map, name);
1150  if (mapped)
1151  {
1152  strncpy(name, mapped, MAXFIELDNAMELEN);
1153  name[MAXFIELDNAMELEN-1] = '\0';
1154  }
1155  }
1156 
1157  /*
1158  * Make field names lowercase unless asked to
1159  * keep identifiers case.
1160  */
1161  if (!state->config->quoteidentifiers)
1162  strtolower(name);
1163 
1164  /*
1165  * Escape names starting with the
1166  * escape char (_), those named 'gid'
1167  * or after pgsql reserved attribute names
1168  */
1169  if (name[0] == '_' ||
1170  ! strcmp(name, "gid") ||
1171  ! strcmp(name, "tableoid") ||
1172  ! strcmp(name, "cmin") ||
1173  ! strcmp(name, "cmax") ||
1174  ! strcmp(name, "xmin") ||
1175  ! strcmp(name, "xmax") ||
1176  ! strcmp(name, "primary") ||
1177  ! strcmp(name, "oid") ||
1178  ! strcmp(name, "ctid"))
1179  {
1180  char tmp[MAXFIELDNAMELEN] = "__";
1181  memcpy(tmp+2, name, MAXFIELDNAMELEN-2);
1182  tmp[MAXFIELDNAMELEN-1] = '\0';
1183  strncpy(name, tmp, MAXFIELDNAMELEN);
1184  }
1185 
1186  /* Avoid duplicating field names */
1187  for (int z = 0; z < j; z++)
1188  {
1189  if (strcmp(state->field_names[z], name) == 0)
1190  {
1191  strncat(name, "__", MAXFIELDNAMELEN - 1);
1192  snprintf(name + strlen(name),
1193  MAXFIELDNAMELEN - 1 - strlen(name),
1194  "%i",
1195  j);
1196  break;
1197  }
1198  }
1199 
1200  state->field_names[j] = strdup(name);
1201 
1202  /* Now generate the PostgreSQL type name string and width based upon the shapefile type */
1203  switch (state->types[j])
1204  {
1205  case FTString:
1206  state->pgfieldtypes[j] = strdup("varchar");
1207  break;
1208 
1209  case FTDate:
1210  state->pgfieldtypes[j] = strdup("date");
1211  break;
1212 
1213  case FTInteger:
1214  /* Determine exact type based upon field width */
1215  if (state->config->forceint4 || (state->widths[j] >=5 && state->widths[j] < 10))
1216  {
1217  state->pgfieldtypes[j] = strdup("int4");
1218  }
1219  else if (state->widths[j] >=10 && state->widths[j] < 19)
1220  {
1221  state->pgfieldtypes[j] = strdup("int8");
1222  }
1223  else if (state->widths[j] < 5)
1224  {
1225  state->pgfieldtypes[j] = strdup("int2");
1226  }
1227  else
1228  {
1229  state->pgfieldtypes[j] = strdup("numeric");
1230  }
1231  break;
1232 
1233  case FTDouble:
1234  /* Determine exact type based upon field width */
1235  fprintf(stderr, "Field %s is an FTDouble with width %d and precision %d\n",
1236  state->field_names[j], state->widths[j], state->precisions[j]);
1237  if (state->widths[j] > 18)
1238  {
1239  state->pgfieldtypes[j] = strdup("numeric");
1240  }
1241  else
1242  {
1243  state->pgfieldtypes[j] = strdup("float8");
1244  }
1245  break;
1246 
1247  case FTLogical:
1248  state->pgfieldtypes[j] = strdup("boolean");
1249  break;
1250 
1251  default:
1252  snprintf(state->message, SHPLOADERMSGLEN, _("Invalid type %x in DBF file"), state->types[j]);
1253  return SHPLOADERERR;
1254  }
1255 
1256  strcat(state->col_names, "\"");
1257  strcat(state->col_names, name);
1258 
1259  if (state->config->readshape == 1 || j < (state->num_fields - 1))
1260  {
1261  /* Don't include last comma if its the last field and no geometry field will follow */
1262  strcat(state->col_names, "\",");
1263  }
1264  else
1265  {
1266  strcat(state->col_names, "\"");
1267  }
1268  }
1269 
1270  /* Append the geometry column if required */
1271  if (state->config->readshape == 1)
1272  strcat(state->col_names, state->geo_col);
1273 
1274  /* Return status */
1275  return ret;
1276 }
int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF)
Definition: dbfopen.c:1246
DBFHandle SHPAPI_CALL DBFOpen(const char *pszFilename, const char *pszAccess)
Definition: dbfopen.c:351
int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF)
Definition: dbfopen.c:1259
DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
Definition: dbfopen.c:1274
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
#define MULTILINETYPE
Definition: liblwgeom.h:106
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
void lwfree(void *mem)
Definition: lwutil.c:248
void * malloc(YYSIZE_T)
void free(void *)
type
Definition: ovdump.py:42
#define SHPT_ARCZ
Definition: shapefil.h:354
DBFFieldType
Definition: shapefil.h:638
@ FTDouble
Definition: shapefil.h:641
@ FTString
Definition: shapefil.h:639
@ FTInvalid
Definition: shapefil.h:644
@ FTLogical
Definition: shapefil.h:642
@ FTDate
Definition: shapefil.h:643
@ FTInteger
Definition: shapefil.h:640
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle hSHP, int iShape);int SHPAPI_CALL SHPWriteObject(SHPHandle hSHP, int iShape, SHPObject *psObject
Definition: shpopen.c:1842
#define SHPT_ARCM
Definition: shapefil.h:358
#define SHPT_POLYGONM
Definition: shapefil.h:359
#define SHPT_ARC
Definition: shapefil.h:350
#define SHPT_POLYGON
Definition: shapefil.h:351
void SHPAPI_CALL SHPDestroyObject(SHPObject *psObject)
Definition: shpopen.c:2652
SHPHandle SHPAPI_CALL SHPOpen(const char *pszShapeFile, const char *pszAccess)
Definition: shpopen.c:291
#define SHPT_MULTIPOINT
Definition: shapefil.h:352
void SHPAPI_CALL SHPGetInfo(SHPHandle hSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
Definition: shpopen.c:956
#define SHPT_POINTZ
Definition: shapefil.h:353
#define SHPT_MULTIPOINTZ
Definition: shapefil.h:356
#define SHPT_MULTIPOINTM
Definition: shapefil.h:360
#define SHPT_POINTM
Definition: shapefil.h:357
#define SHPT_POINT
Definition: shapefil.h:349
#define SHPT_POLYGONZ
Definition: shapefil.h:355
static int utf8(const char *fromcode, char *inputbuf, char **outputbuf)
#define UTF8_GOOD_RESULT
#define UTF8_BAD_RESULT
void strtolower(char *s)
#define UTF8_NO_RESULT
#define FORCE_OUTPUT_4D
#define POLICY_NULL_ABORT
#define FORCE_OUTPUT_2D
#define SHPLOADERWARN
#define FORCE_OUTPUT_3DM
#define ENCODING_DEFAULT
#define SHPLOADERMSGLEN
#define SHPLOADERERR
#define MAXFIELDNAMELEN
#define SHPLOADEROK
#define FORCE_OUTPUT_3DZ
int colmap_read(const char *filename, colmap *map, char *errbuf, size_t errbuflen)
Read the content of filename into a symbol map.
Definition: shpcommon.c:217
const char * colmap_pg_by_dbf(colmap *map, const char *dbfname)
Definition: shpcommon.c:203
char * codepage2encoding(const char *cpg)
Definition: shpcommon.c:302
#define _(String)
Definition: shpcommon.h:24
char * pszCodePage
Definition: shapefil.h:625
char message[SHPLOADERMSGLEN]
DBFFieldType * types
SHPHandle hSHPHandle
DBFHandle hDBFHandle
SHPLOADERCONFIG * config
int nVertices
Definition: shapefil.h:389

References _, codepage2encoding(), shp_loader_state::col_names, COLLECTIONTYPE, colmap_pg_by_dbf(), colmap_read(), shp_loader_state::column_map, shp_loader_config::column_map_filename, shp_loader_state::config, DBFGetFieldCount(), DBFGetFieldInfo(), DBFGetRecordCount(), DBFOpen(), shp_loader_config::encoding, ENCODING_DEFAULT, shp_loader_state::field_names, shp_loader_config::force_output, FORCE_OUTPUT_2D, FORCE_OUTPUT_3DM, FORCE_OUTPUT_3DZ, FORCE_OUTPUT_4D, shp_loader_config::forceint4, free(), FTDate, FTDouble, FTInteger, FTInvalid, FTLogical, FTString, shp_loader_state::geo_col, shp_loader_state::has_m, shp_loader_state::has_z, shp_loader_state::hDBFHandle, shp_loader_state::hSHPHandle, lwfree(), malloc(), MAXFIELDNAMELEN, shp_loader_state::message, MULTILINETYPE, MULTIPOINTTYPE, MULTIPOLYGONTYPE, shp_loader_config::null_policy, shp_loader_state::num_entities, shp_loader_state::num_fields, shp_loader_state::num_records, tagSHPObject::nVertices, shp_loader_state::pgdims, shp_loader_state::pgfieldtypes, shp_loader_state::pgtype, POINTTYPE, POLICY_NULL_ABORT, shp_loader_state::precisions, DBFInfo::pszCodePage, shp_loader_config::quoteidentifiers, shp_loader_config::readshape, shp_loader_config::shp_file, SHPDestroyObject(), shp_loader_state::shpfiletype, SHPGetInfo(), SHPLOADERERR, SHPLOADERMSGLEN, SHPLOADEROK, SHPLOADERWARN, SHPOpen(), SHPReadObject(), 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_loader_config::simple_geometries, strtolower(), ovdump::type, shp_loader_state::types, utf8(), UTF8_BAD_RESULT, UTF8_GOOD_RESULT, UTF8_NO_RESULT, and shp_loader_state::widths.

Referenced by pgui_action_import(), and validate_remote_loader_columns().

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