PostGIS  3.1.6dev-r@@SVN_REVISION@@

◆ ShpLoaderOpenShape()

int ShpLoaderOpenShape ( SHPLOADERSTATE state)

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

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