[Git][debian-gis-team/pgsql-ogr-fdw][master] 5 commits: New upstream version 1.0.8
Bas Couwenberg
gitlab at salsa.debian.org
Thu May 2 06:27:56 BST 2019
Bas Couwenberg pushed to branch master at Debian GIS Project / pgsql-ogr-fdw
Commits:
6f4a8c53 by Bas Couwenberg at 2019-05-02T05:03:22Z
New upstream version 1.0.8
- - - - -
5723387f by Bas Couwenberg at 2019-05-02T05:03:23Z
Merge tag 'upstream/1.0.8'
Upstream version 1.0.8
- - - - -
01f86db7 by Bas Couwenberg at 2019-05-02T05:03:46Z
New upstream release.
- - - - -
7a72bcbe by Bas Couwenberg at 2019-05-02T05:17:04Z
Add lintian overrides for file-references-package-build-path.
- - - - -
22e03fce by Bas Couwenberg at 2019-05-02T05:17:05Z
Set distribution to experimental.
- - - - -
17 changed files:
- + .astylerc
- .editorconfig
- .travis.yml
- README.md
- + data/poly.dbf
- + data/poly.shp
- + data/poly.shx
- debian/changelog
- + debian/lintian-overrides
- input/file.source
- ogr_fdw.c
- ogr_fdw.h
- ogr_fdw_common.c
- ogr_fdw_deparse.c
- ogr_fdw_gdal.h
- output/file.source
- output/import.source
Changes:
=====================================
.astylerc
=====================================
@@ -0,0 +1,14 @@
+--style=allman
+--indent=tab=4
+--max-code-length=120
+--lineend=linux
+--unpad-paren
+--pad-oper
+--pad-header
+--align-pointer=type
+--align-reference=type
+--break-closing-braces
+--add-braces
+--break-return-type
+--break-after-logical
+
=====================================
.editorconfig
=====================================
@@ -7,10 +7,19 @@ root = true
[*]
charset = utf-8
end_of_line = lf
-trim_trailing_whitespace = true
insert_final_newline = true
+trim_trailing_whitespace = true
+
+# Test files need kid gloves
+[*.source]
+insert_final_newline = false
+trim_trailing_whitespace = false
# C files want tab indentation
-[*.{c,h}]
+[*.{c,h,md}]
indent_style = tab
+indent_size = 4
+# Makefiles want tab indentation
+[Makefile]
+indent_style = tab
=====================================
.travis.yml
=====================================
@@ -9,15 +9,16 @@ addons:
- curl
- libcurl4-gnutls-dev
- ca-certificates
- - software-properties-common
+ - software-properties-common
- python-software-properties
- gnupg-curl
env:
- - PG_VERSION=9.6 GDAL_VERSION=1.1
+ - PG_VERSION=9.6 GDAL_VERSION=1.11
- PG_VERSION=9.6 GDAL_VERSION=2.2.4
- - PG_VERSION=9.6 GDAL_VERSION=2.3.1
- - PG_VERSION=10 GDAL_VERSION=2.3.1
+ - PG_VERSION=10 GDAL_VERSION=2.3.3
+ - PG_VERSION=10 GDAL_VERSION=2.4.1
+ - PG_VERSION=11 GDAL_VERSION=2.4.1
before_script:
- sudo /etc/init.d/postgresql stop
@@ -27,21 +28,22 @@ before_script:
- sudo apt-get -y --purge remove postgresql-9.4
- sudo apt-get -y --purge remove postgresql-9.5
- sudo apt-get -y --purge remove postgresql-9.6
+ - sudo apt-get -y --purge remove postgresql-10
+ - sudo apt-get -y --purge remove postgresql-11
+ - sudo apt-get -y --purge remove postgresql-common
- sudo apt-get -y autoremove
- sudo rm -rf /var/lib/postgresql
- apt-key adv --fetch-keys https://www.postgresql.org/media/keys/ACCC4CF8.asc
- - sudo add-apt-repository "deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main $PG_VERSION"
+ - sudo add-apt-repository "deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main $PG_VERSION"
- sudo apt-get update -qq
- sudo apt-get -y install postgresql-$PG_VERSION postgresql-server-dev-$PG_VERSION
- sudo cp ci/pg_hba.conf /etc/postgresql/$PG_VERSION/main/pg_hba.conf
- sudo /etc/init.d/postgresql reload
-
+
- if [[ $GDAL_VERSION == 1* ]]; then sudo apt-get install libgdal1h libgdal-dev; fi
- if [[ $GDAL_VERSION == 2* ]]; then wget http://download.osgeo.org/gdal/$GDAL_VERSION/gdal-$GDAL_VERSION.tar.xz; tar xJf gdal-$GDAL_VERSION.tar.xz; cd gdal-$GDAL_VERSION; ./configure --prefix=/usr --enable-debug --without-libtool; make -j4 >/dev/null; sudo make install >/dev/null; cd ..; gdalinfo --version; fi
-
+
script:
- - make
- - sudo make install
- - sudo chmod 755 $HOME
- - PGUSER=postgres make installcheck || (cat regression.diffs && /bin/false)
+ - make && sudo make install && sudo chmod 755 $HOME && (PGUSER=postgres make installcheck || (cat regression.diffs && /bin/false))
+
=====================================
README.md
=====================================
@@ -100,40 +100,41 @@ Since we can access any OGR data source as a table, how about a public WFS serve
CREATE EXTENSION postgis;
CREATE EXTENSION ogr_fdw;
- CREATE SERVER opengeo
+ CREATE SERVER geoserver
FOREIGN DATA WRAPPER ogr_fdw
OPTIONS (
- datasource 'WFS:http://demo.opengeo.org/geoserver/wfs',
- format 'WFS' );
+ datasource 'WFS:https://demo.geo-solutions.it/geoserver/wfs',
+ format 'WFS' );
CREATE FOREIGN TABLE topp_states (
- fid integer,
- geom geometry,
+ fid bigint,
+ the_geom Geometry(MultiSurface,4326),
gml_id varchar,
state_name varchar,
state_fips varchar,
sub_region varchar,
state_abbr varchar,
- land_km real,
- water_km real,
- persons real,
- families real,
- houshold real,
- male real,
- female real,
- workers real,
- drvalone real,
- carpool real,
- pubtrans real,
- employed real,
- unemploy real,
- service real,
- manual real,
- p_male real,
- p_female real,
- samp_pop real )
- SERVER opengeo
- OPTIONS (layer 'topp:states');
+ land_km double precision,
+ water_km double precision,
+ persons double precision,
+ families double precision,
+ houshold double precision,
+ male double precision,
+ female double precision,
+ workers double precision,
+ drvalone double precision,
+ carpool double precision,
+ pubtrans double precision,
+ employed double precision,
+ unemploy double precision,
+ service double precision,
+ manual double precision,
+ p_male double precision,
+ p_female double precision,
+ samp_pop double precision
+ ) SERVER "geoserver"
+ OPTIONS (layer 'topp:states');
+
### FGDB FDW
=====================================
data/poly.dbf
=====================================
Binary files /dev/null and b/data/poly.dbf differ
=====================================
data/poly.shp
=====================================
Binary files /dev/null and b/data/poly.shp differ
=====================================
data/poly.shx
=====================================
Binary files /dev/null and b/data/poly.shx differ
=====================================
debian/changelog
=====================================
@@ -1,8 +1,11 @@
-pgsql-ogr-fdw (1.0.7-3) UNRELEASED; urgency=medium
+pgsql-ogr-fdw (1.0.8-1~exp1) experimental; urgency=medium
+ * Team upload.
+ * New upstream release.
* Bump Standards-Version to 4.3.0, no changes.
+ * Add lintian overrides for file-references-package-build-path.
- -- Bas Couwenberg <sebastic at debian.org> Tue, 25 Dec 2018 22:56:13 +0100
+ -- Bas Couwenberg <sebastic at debian.org> Thu, 02 May 2019 07:04:51 +0200
pgsql-ogr-fdw (1.0.7-2) unstable; urgency=medium
=====================================
debian/lintian-overrides
=====================================
@@ -0,0 +1,3 @@
+# Cannot easily be fixed
+file-references-package-build-path *
+
=====================================
input/file.source
=====================================
@@ -14,7 +14,7 @@ CREATE FOREIGN TABLE pt_1 (
geom bytea,
name varchar,
age integer,
- height real,
+ height double precision,
birthdate date )
SERVER myserver
OPTIONS ( layer 'pt_two' );
@@ -41,6 +41,19 @@ CREATE FOREIGN TABLE pt_3 (
SELECT * FROM pt_3 ORDER BY name;
+
+------------------------------------------------
+
+CREATE FOREIGN TABLE poly_1 (
+ fid bigint,
+ geom bytea,
+ id double precision,
+ name varchar(5)
+) SERVER myserver
+OPTIONS (layer 'poly');
+
+SELECT length(geom) FROM poly_1 WHERE name = 'Three';
+
------------------------------------------------
-- Laundering and explicit column naming test
@@ -77,9 +90,9 @@ CREATE FOREIGN TABLE e_1 (
SERVER myserver_latin1
OPTIONS ( layer 'enc' );
-SET client_min_messages = debug1;
+SET client_min_messages = debug1;
SELECT * FROM e_1 WHERE fid = 1;
-SET client_min_messages = notice;
+SET client_min_messages = notice;
------------------------------------------------
-- Geometryless test
@@ -98,9 +111,9 @@ CREATE FOREIGN TABLE no_geom (
) SERVER csvserver
OPTIONS (layer 'no_geom');
-SELECT c.*
- FROM generate_series(1,4) g
- JOIN no_geom c
+SELECT c.*
+ FROM generate_series(1,4) g
+ JOIN no_geom c
ON (c.fid = g.g);
------------------------------------------------
=====================================
ogr_fdw.c
=====================================
@@ -43,7 +43,7 @@ PG_MODULE_MAGIC;
*/
struct OgrFdwOption
{
- const char *optname;
+ const char* optname;
Oid optcontext; /* Oid of catalog in which option may appear */
bool optrequired; /* Flag mandatory options */
bool optfound; /* Flag whether options was specified by user */
@@ -67,7 +67,8 @@ struct OgrFdwOption
* UserMappingRelationId (CREATE USER MAPPING options)
* ForeignTableRelationId (CREATE FOREIGN TABLE options)
*/
-static struct OgrFdwOption valid_options[] = {
+static struct OgrFdwOption valid_options[] =
+{
/* OGR column mapping */
{OPT_COLUMN, AttributeRelationId, false, false},
@@ -101,98 +102,134 @@ void _PG_init(void);
/*
* FDW query callback routines
*/
-static void ogrGetForeignRelSize(PlannerInfo *root,
- RelOptInfo *baserel,
- Oid foreigntableid);
-static void ogrGetForeignPaths(PlannerInfo *root,
- RelOptInfo *baserel,
- Oid foreigntableid);
-static ForeignScan *ogrGetForeignPlan(PlannerInfo *root,
- RelOptInfo *baserel,
- Oid foreigntableid,
- ForeignPath *best_path,
- List *tlist,
- List *scan_clauses
+static void ogrGetForeignRelSize(PlannerInfo* root,
+ RelOptInfo* baserel,
+ Oid foreigntableid);
+static void ogrGetForeignPaths(PlannerInfo* root,
+ RelOptInfo* baserel,
+ Oid foreigntableid);
+static ForeignScan* ogrGetForeignPlan(PlannerInfo* root,
+ RelOptInfo* baserel,
+ Oid foreigntableid,
+ ForeignPath* best_path,
+ List* tlist,
+ List* scan_clauses
#if PG_VERSION_NUM >= 90500
- ,Plan *outer_plan
+ , Plan* outer_plan
#endif
-);
-static void ogrBeginForeignScan(ForeignScanState *node, int eflags);
-static TupleTableSlot *ogrIterateForeignScan(ForeignScanState *node);
-static void ogrReScanForeignScan(ForeignScanState *node);
-static void ogrEndForeignScan(ForeignScanState *node);
+ );
+static void ogrBeginForeignScan(ForeignScanState* node, int eflags);
+static TupleTableSlot* ogrIterateForeignScan(ForeignScanState* node);
+static void ogrReScanForeignScan(ForeignScanState* node);
+static void ogrEndForeignScan(ForeignScanState* node);
/*
* FDW modify callback routines
*/
-static void ogrAddForeignUpdateTargets (Query *parsetree,
- RangeTblEntry *target_rte,
- Relation target_relation);
-static void ogrBeginForeignModify (ModifyTableState *mtstate,
- ResultRelInfo *rinfo,
- List *fdw_private,
- int subplan_index,
- int eflags);
-static TupleTableSlot *ogrExecForeignInsert (EState *estate,
- ResultRelInfo *rinfo,
- TupleTableSlot *slot,
- TupleTableSlot *planSlot);
-static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
- ResultRelInfo *rinfo,
- TupleTableSlot *slot,
- TupleTableSlot *planSlot);
-static TupleTableSlot *ogrExecForeignDelete (EState *estate,
- ResultRelInfo *rinfo,
- TupleTableSlot *slot,
- TupleTableSlot *planSlot);
-static void ogrEndForeignModify (EState *estate,
- ResultRelInfo *rinfo);
-static int ogrIsForeignRelUpdatable (Relation rel);
+static void ogrAddForeignUpdateTargets(Query* parsetree,
+ RangeTblEntry* target_rte,
+ Relation target_relation);
+static void ogrBeginForeignModify(ModifyTableState* mtstate,
+ ResultRelInfo* rinfo,
+ List* fdw_private,
+ int subplan_index,
+ int eflags);
+static TupleTableSlot* ogrExecForeignInsert(EState* estate,
+ ResultRelInfo* rinfo,
+ TupleTableSlot* slot,
+ TupleTableSlot* planSlot);
+static TupleTableSlot* ogrExecForeignUpdate(EState* estate,
+ ResultRelInfo* rinfo,
+ TupleTableSlot* slot,
+ TupleTableSlot* planSlot);
+static TupleTableSlot* ogrExecForeignDelete(EState* estate,
+ ResultRelInfo* rinfo,
+ TupleTableSlot* slot,
+ TupleTableSlot* planSlot);
+static void ogrEndForeignModify(EState* estate,
+ ResultRelInfo* rinfo);
+static int ogrIsForeignRelUpdatable(Relation rel);
#if PG_VERSION_NUM >= 90500
-static List *ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid);
+static List* ogrImportForeignSchema(ImportForeignSchemaStmt* stmt, Oid serverOid);
#endif
/*
* Helper functions
*/
-static OgrConnection ogrGetConnectionFromTable(Oid foreigntableid, bool updateable);
+static OgrConnection ogrGetConnectionFromTable(Oid foreigntableid, OgrUpdateable updateable);
static void ogr_fdw_exit(int code, Datum arg);
-static void ogrReadColumnData(OgrFdwState *state);
+static void ogrReadColumnData(OgrFdwState* state);
/* Global to hold GEOMETRYOID */
Oid GEOMETRYOID = InvalidOid;
+
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,1,0)
+
+const char* const gdalErrorTypes[] =
+{
+ "None",
+ "AppDefined",
+ "OutOfMemory",
+ "FileIO",
+ "OpenFailed",
+ "IllegalArg",
+ "NotSupported",
+ "AssertionFailed",
+ "NoWriteAccess",
+ "UserInterrupt",
+ "ObjectNull",
+ "HttpResponse",
+ "AWSBucketNotFound",
+ "AWSObjectNotFound",
+ "AWSAccessDenied",
+ "AWSInvalidCredentials",
+ "AWSSignatureDoesNotMatch"
+};
+
+/* In theory this function should be declared "static void CPL_STDCALL" */
+/* since this is the official signature of error handler callbacks. */
+/* That would be needed if both GDAL and ogr_fdw were compiled with Visual */
+/* Studio, but with non-Visual Studio compilers, the macro expands to empty, */
+/* so if both GDAL and ogr_fdw are compiled with gcc things are fine. In case */
+/* of mixes, crashes may occur but there is no clean fix... So let this as a note */
+/* in case of future issue... */
static void
-ogrErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
+ogrErrorHandler(CPLErr eErrClass, int err_no, const char* msg)
{
+ const char* gdalErrType = "unknown type";
+ if (err_no >= 0 && err_no <
+ (int)sizeof(gdalErrorTypes)/sizeof(gdalErrorTypes[0]))
+ {
+ gdalErrType = gdalErrorTypes[err_no];
+ }
switch (eErrClass)
{
- case CE_None:
- elog(NOTICE, "[%d] %s", err_no, msg);
- break;
- case CE_Debug:
- elog(DEBUG2, "[%d] %s", err_no, msg);
- break;
- case CE_Warning:
- elog(WARNING, "[%d] %s", err_no, msg);
- break;
- case CE_Failure:
- case CE_Fatal:
- default:
- elog(ERROR, "[%d] %s", err_no, msg);
- break;
+ case CE_None:
+ elog(NOTICE, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ break;
+ case CE_Debug:
+ elog(DEBUG2, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ break;
+ case CE_Warning:
+ elog(WARNING, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ break;
+ case CE_Failure:
+ case CE_Fatal:
+ default:
+ elog(ERROR, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ break;
}
return;
}
-#endif
+
+#endif /* GDAL 2.1.0+ */
void
_PG_init(void)
{
-
on_proc_exit(&ogr_fdw_exit, PointerGetDatum(NULL));
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,1,0)
@@ -214,9 +251,11 @@ ogr_fdw_exit(int code, Datum arg)
/*
* Function to get the geometry OID if required
*/
-Oid ogrGetGeometryOid(void)
+Oid
+ogrGetGeometryOid(void)
{
- if (GEOMETRYOID == InvalidOid) {
+ if (GEOMETRYOID == InvalidOid)
+ {
Oid typoid = TypenameGetTypid("geometry");
if (OidIsValid(typoid) && get_typisdefined(typoid))
{
@@ -238,7 +277,7 @@ Oid ogrGetGeometryOid(void)
Datum
ogr_fdw_handler(PG_FUNCTION_ARGS)
{
- FdwRoutine *fdwroutine = makeNode(FdwRoutine);
+ FdwRoutine* fdwroutine = makeNode(FdwRoutine);
/* Read support */
fdwroutine->GetForeignRelSize = ogrGetForeignRelSize;
@@ -267,125 +306,163 @@ ogr_fdw_handler(PG_FUNCTION_ARGS)
}
/*
- * Given a connection string and (optional) driver string, try to connect
- * with appropriate error handling and reporting. Used in query startup,
- * and in FDW options validation.
- */
-static GDALDatasetH
-ogrGetDataSource(const char *source, const char *driver, bool updateable,
- const char *config_options, const char *open_options)
+* When attempting a soft open (allowing for failure and retry),
+* we might need to call the opening
+* routines twice, so all the opening machinery is placed here
+* for convenient re-calling.
+*/
+static OGRErr
+ogrGetDataSourceAttempt(OgrConnection* ogr, bool bUpdateable, char** open_option_list)
{
- GDALDatasetH ogr_ds = NULL;
GDALDriverH ogr_dr = NULL;
- char **open_option_list = NULL;
#if GDAL_VERSION_MAJOR >= 2
unsigned int open_flags = GDAL_OF_VECTOR;
- if ( updateable )
+ if (bUpdateable)
+ {
open_flags |= GDAL_OF_UPDATE;
+ }
else
+ {
open_flags |= GDAL_OF_READONLY;
+ }
+#endif
+
+ if (ogr->dr_str)
+ {
+ ogr_dr = GDALGetDriverByName(ogr->dr_str);
+ if (!ogr_dr)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION),
+ errmsg("unable to find format \"%s\"", ogr->dr_str),
+ errhint("See the formats list at http://www.gdal.org/ogr_formats.html")));
+ }
+#if GDAL_VERSION_MAJOR < 2
+ ogr->ds = OGR_Dr_Open(ogr_dr, ogr->ds_str, bUpdateable);
+#else
+ {
+ char** driver_list = CSLAddString(NULL, ogr->dr_str);
+ ogr->ds = GDALOpenEx(ogr->ds_str, /* file/data source */
+ open_flags, /* open flags */
+ (const char* const*)driver_list, /* driver */
+ (const char* const*)open_option_list, /* open options */
+ NULL); /* sibling files */
+ CSLDestroy(driver_list);
+ }
+#endif
+ }
+ /* No driver, try a blind open... */
+ else
+ {
+#if GDAL_VERSION_MAJOR < 2
+ ogr->ds = OGROpen(ogr->ds_str, bUpdateable, &ogr_dr);
+#else
+ ogr->ds = GDALOpenEx(ogr->ds_str,
+ open_flags,
+ NULL,
+ (const char* const*)open_option_list,
+ NULL);
#endif
+ }
+ return ogr->ds ? OGRERR_NONE : OGRERR_FAILURE;
+}
- if ( config_options )
+/*
+ * Given a connection string and (optional) driver string, try to connect
+ * with appropriate error handling and reporting. Used in query startup,
+ * and in FDW options validation.
+ */
+static OGRErr
+ogrGetDataSource(OgrConnection* ogr, OgrUpdateable updateable)
+{
+ char** open_option_list = NULL;
+ bool bUpdateable = (updateable == OGR_UPDATEABLE_TRUE || updateable == OGR_UPDATEABLE_TRY);
+ OGRErr err;
+
+ /* Set the GDAL config options into the environment */
+ if (ogr->config_options)
{
- char **option_iter;
- char **option_list = CSLTokenizeString(config_options);
+ char** option_iter;
+ char** option_list = CSLTokenizeString(ogr->config_options);
- for ( option_iter = option_list; option_iter && *option_iter; option_iter++ )
+ for (option_iter = option_list; option_iter && *option_iter; option_iter++)
{
- char *key;
- const char *value;
+ char* key;
+ const char* value;
value = CPLParseNameValue(*option_iter, &key);
- if ( ! (key && value) )
- elog(ERROR, "bad config option string '%s'", config_options);
+ if (!(key && value))
+ {
+ elog(ERROR, "bad config option string '%s'", ogr->config_options);
+ }
elog(DEBUG1, "GDAL config option '%s' set to '%s'", key, value);
CPLSetConfigOption(key, value);
CPLFree(key);
}
- CSLDestroy( option_list );
+ CSLDestroy(option_list);
}
- if ( open_options )
- open_option_list = CSLTokenizeString(open_options);
+ /* Parse the GDAL layer open options */
+ if (ogr->open_options)
+ {
+ open_option_list = CSLTokenizeString(ogr->open_options);
+ }
- /* Cannot search for drivers if they aren't registered */
- /* But don't call for registration if we already have drivers */
- if ( GDALGetDriverCount() <= 0 )
+ /* Cannot search for drivers if they aren't registered, */
+ /* but don't do registration if we already have drivers loaded */
+ if (GDALGetDriverCount() <= 0)
+ {
GDALAllRegister();
+ }
- if ( driver )
+ /* First attempt at connection */
+ err = ogrGetDataSourceAttempt(ogr, bUpdateable, open_option_list);
+
+ /* Failed on soft updateable attempt, try and fall back to readonly */
+ if ((!ogr->ds) && updateable == OGR_UPDATEABLE_TRY)
{
- ogr_dr = GDALGetDriverByName(driver);
- if ( ! ogr_dr )
+ err = ogrGetDataSourceAttempt(ogr, false, open_option_list);
+ /* Succeeded with readonly connection */
+ if (ogr->ds)
{
- ereport(ERROR,
- (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
- errmsg("unable to find format \"%s\"", driver),
- errhint("See the formats list at http://www.gdal.org/ogr_formats.html")));
+ ogr->ds_updateable = ogr->lyr_updateable = OGR_UPDATEABLE_FALSE;
}
-#if GDAL_VERSION_MAJOR < 2
- ogr_ds = OGR_Dr_Open(ogr_dr, source, updateable);
-#else
- {
- char** driver_list = CSLAddString(NULL, driver);
- ogr_ds = GDALOpenEx(source, /* file/data source */
- open_flags, /* open flags */
- (const char* const*)driver_list, /* driver */
- (const char *const *)open_option_list, /* open options */
- NULL); /* sibling files */
- CSLDestroy( driver_list );
- }
-#endif
- }
- /* No driver, try a blind open... */
- else
- {
-#if GDAL_VERSION_MAJOR < 2
- ogr_ds = OGROpen(source, updateable, &ogr_dr);
-#else
- ogr_ds = GDALOpenEx(source,
- open_flags,
- NULL,
- (const char *const *)open_option_list,
- NULL);
-#endif
}
/* Open failed, provide error hint if OGR gives us one. */
- if ( ! ogr_ds )
+ if (!ogr->ds)
{
- const char *ogrerr = CPLGetLastErrorMsg();
- if ( ogrerr && ! streq(ogrerr, "") )
+ const char* ogrerrmsg = CPLGetLastErrorMsg();
+ if (ogrerrmsg && !streq(ogrerrmsg, ""))
{
ereport(ERROR,
- (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
- errmsg("unable to connect to data source \"%s\"", source),
- errhint("%s", ogrerr)));
+ (errcode(ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION),
+ errmsg("unable to connect to data source \"%s\"", ogr->ds_str),
+ errhint("%s", ogrerrmsg)));
}
else
{
- ereport(ERROR,
- (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
- errmsg("unable to connect to data source \"%s\"", source)));
+ ereport(ERROR,
+ (errcode(ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION),
+ errmsg("unable to connect to data source \"%s\"", ogr->ds_str)));
}
}
- CSLDestroy( open_option_list );
+ CSLDestroy(open_option_list);
- return ogr_ds;
+ return err;
}
static bool
-ogrCanReallyCountFast(const OgrConnection *con)
+ogrCanReallyCountFast(const OgrConnection* con)
{
GDALDriverH dr = GDALGetDatasetDriver(con->ds);
- const char *dr_str = GDALGetDriverShortName(dr);
+ const char* dr_str = GDALGetDriverShortName(dr);
- if ( streq(dr_str, "ESRI Shapefile" ) ||
- streq(dr_str, "FileGDB" ) ||
- streq(dr_str, "OpenFileGDB" ) )
+ if (streq(dr_str, "ESRI Shapefile") ||
+ streq(dr_str, "FileGDB") ||
+ streq(dr_str, "OpenFileGDB"))
{
return true;
}
@@ -393,21 +470,21 @@ ogrCanReallyCountFast(const OgrConnection *con)
}
static void
-ogrEreportError(const char *errstr)
+ogrEreportError(const char* errstr)
{
- const char *ogrerr = CPLGetLastErrorMsg();
- if ( ogrerr && ! streq(ogrerr,"") )
+ const char* ogrerrmsg = CPLGetLastErrorMsg();
+ if (ogrerrmsg && !streq(ogrerrmsg, ""))
{
ereport(ERROR,
- (errcode(ERRCODE_FDW_ERROR),
- errmsg("%s", errstr),
- errhint("%s", ogrerr)));
+ (errcode(ERRCODE_FDW_ERROR),
+ errmsg("%s", errstr),
+ errhint("%s", ogrerrmsg)));
}
else
{
ereport(ERROR,
- (errcode(ERRCODE_FDW_ERROR),
- errmsg("%s", errstr)));
+ (errcode(ERRCODE_FDW_ERROR),
+ errmsg("%s", errstr)));
}
}
@@ -416,23 +493,28 @@ ogrEreportError(const char *errstr)
* with a connection.
*/
static void
-ogrFinishConnection(OgrConnection *ogr)
+ogrFinishConnection(OgrConnection* ogr)
{
- if ( ogr->lyr && OGR_L_SyncToDisk(ogr->lyr) != OGRERR_NONE )
+ if (ogr->lyr && OGR_L_SyncToDisk(ogr->lyr) != OGRERR_NONE)
+ {
elog(NOTICE, "failed to flush writes to OGR data source");
+ }
- if ( ogr->ds )
+ if (ogr->ds)
+ {
GDALClose(ogr->ds);
+ }
ogr->ds = NULL;
}
static OgrConnection
-ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
+ogrGetConnectionFromServer(Oid foreignserverid, OgrUpdateable updateable)
{
- ForeignServer *server;
+ ForeignServer* server;
OgrConnection ogr;
- ListCell *cell;
+ ListCell* cell;
+ OGRErr err;
/* Null all values */
memset(&ogr, 0, sizeof(OgrConnection));
@@ -441,34 +523,44 @@ ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
server = GetForeignServer(foreignserverid);
- foreach(cell, server->options)
+ foreach (cell, server->options)
{
- DefElem *def = (DefElem *) lfirst(cell);
+ DefElem* def = (DefElem*) lfirst(cell);
if (streq(def->defname, OPT_SOURCE))
+ {
ogr.ds_str = defGetString(def);
+ }
if (streq(def->defname, OPT_DRIVER))
+ {
ogr.dr_str = defGetString(def);
+ }
if (streq(def->defname, OPT_CONFIG_OPTIONS))
+ {
ogr.config_options = defGetString(def);
+ }
if (streq(def->defname, OPT_OPEN_OPTIONS))
+ {
ogr.open_options = defGetString(def);
+ }
if (streq(def->defname, OPT_UPDATEABLE))
{
- if ( defGetBoolean(def) )
+ if (defGetBoolean(def))
+ {
ogr.ds_updateable = OGR_UPDATEABLE_TRUE;
+ }
else
+ {
ogr.ds_updateable = OGR_UPDATEABLE_FALSE;
+ /* Over-ride the open mode to favour user-defined mode */
+ updateable = OGR_UPDATEABLE_FALSE;
+ }
}
}
- if ( ! ogr.ds_str )
+ if (!ogr.ds_str)
+ {
elog(ERROR, "FDW table '%s' option is missing", OPT_SOURCE);
-
- if ( updateable && ogr.ds_updateable == OGR_UPDATEABLE_FALSE )
- ereport(ERROR,
- (errcode(ERRCODE_FDW_ERROR),
- errmsg("updates are not allowed on foreign server '%s'", server->servername),
- errhint("ALTER FOREIGN SERVER %s OPTIONS (SET updatable 'true')", server->servername)));
+ }
/*
* TODO: Connections happen twice for each query, having a
@@ -476,8 +568,7 @@ ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
*/
/* Connect! */
- ogr.ds = ogrGetDataSource(ogr.ds_str, ogr.dr_str, updateable, ogr.config_options, ogr.open_options);
-
+ err = ogrGetDataSource(&ogr, updateable);
return ogr;
}
@@ -489,12 +580,12 @@ ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
* has handles for both the datasource and layer.
*/
static OgrConnection
-ogrGetConnectionFromTable(Oid foreigntableid, bool updateable)
+ogrGetConnectionFromTable(Oid foreigntableid, OgrUpdateable updateable)
{
- ForeignTable *table;
+ ForeignTable* table;
/* UserMapping *mapping; */
/* ForeignDataWrapper *wrapper; */
- ListCell *cell;
+ ListCell* cell;
OgrConnection ogr;
/* Gather all data for the foreign table. */
@@ -503,41 +594,51 @@ ogrGetConnectionFromTable(Oid foreigntableid, bool updateable)
ogr = ogrGetConnectionFromServer(table->serverid, updateable);
- foreach(cell, table->options)
+ foreach (cell, table->options)
{
- DefElem *def = (DefElem *) lfirst(cell);
+ DefElem* def = (DefElem*) lfirst(cell);
if (streq(def->defname, OPT_LAYER))
+ {
ogr.lyr_str = defGetString(def);
+ }
if (streq(def->defname, OPT_UPDATEABLE))
{
- if ( defGetBoolean(def) )
+ if (defGetBoolean(def))
+ {
+ if (ogr.ds_updateable == OGR_UPDATEABLE_FALSE)
+ {
+ ereport(ERROR, (
+ errcode(ERRCODE_FDW_ERROR),
+ errmsg("data source \"%s\" is not updateable", ogr.ds_str),
+ errhint("cannot set table '%s' option to true", OPT_UPDATEABLE)
+ ));
+ }
ogr.lyr_updateable = OGR_UPDATEABLE_TRUE;
+ }
else
+ {
ogr.lyr_updateable = OGR_UPDATEABLE_FALSE;
+ }
}
}
- if ( ! ogr.lyr_str )
+ if (!ogr.lyr_str)
+ {
elog(ERROR, "FDW table '%s' option is missing", OPT_LAYER);
-
- if ( updateable && ogr.lyr_updateable == OGR_UPDATEABLE_FALSE )
- ereport(ERROR,
- (errcode(ERRCODE_FDW_ERROR),
- errmsg("updates are not allowed on foreign table '%s'", get_rel_name(table->relid)),
- errhint("ALTER FOREIGN TABLE %s OPTIONS (SET updatable 'true')", get_rel_name(table->relid))));
+ }
/* Does the layer exist in the data source? */
ogr.lyr = GDALDatasetGetLayerByName(ogr.ds, ogr.lyr_str);
- if ( ! ogr.lyr )
+ if (!ogr.lyr)
{
- const char *ogrerr = CPLGetLastErrorMsg();
+ const char* ogrerr = CPLGetLastErrorMsg();
ereport(ERROR, (
- errcode(ERRCODE_FDW_OPTION_NAME_NOT_FOUND),
- errmsg("unable to connect to %s to \"%s\"", OPT_LAYER, ogr.lyr_str),
- (ogrerr && ! streq(ogrerr, ""))
- ? errhint("%s", ogrerr)
- : errhint("Does the layer exist?")
- ));
+ errcode(ERRCODE_FDW_TABLE_NOT_FOUND),
+ errmsg("unable to connect to %s to \"%s\"", OPT_LAYER, ogr.lyr_str),
+ (ogrerr && ! streq(ogrerr, ""))
+ ? errhint("%s", ogrerr)
+ : errhint("Does the layer exist?")
+ ));
}
ogr.lyr_utf8 = OGR_L_TestCapability(ogr.lyr, OLCStringsAsUTF8);
@@ -553,23 +654,23 @@ ogrGetConnectionFromTable(Oid foreigntableid, bool updateable)
Datum
ogr_fdw_validator(PG_FUNCTION_ARGS)
{
- List *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
+ List* options_list = untransformRelOptions(PG_GETARG_DATUM(0));
Oid catalog = PG_GETARG_OID(1);
- ListCell *cell;
- struct OgrFdwOption *opt;
- const char *source = NULL, *driver = NULL;
- const char *config_options = NULL, *open_options = NULL;
- bool updateable = false;
+ ListCell* cell;
+ struct OgrFdwOption* opt;
+ const char* source = NULL, *driver = NULL;
+ const char* config_options = NULL, *open_options = NULL;
+ OgrUpdateable updateable = OGR_UPDATEABLE_FALSE;
/* Check that the database encoding is UTF8, to match OGR internals */
- if ( GetDatabaseEncoding() != PG_UTF8 )
+ if (GetDatabaseEncoding() != PG_UTF8)
{
elog(ERROR, "OGR FDW only works with UTF-8 databases");
PG_RETURN_VOID();
}
/* Initialize found state to not found */
- for ( opt = valid_options; opt->optname; opt++ )
+ for (opt = valid_options; opt->optname; opt++)
{
opt->optfound = false;
}
@@ -578,41 +679,54 @@ ogr_fdw_validator(PG_FUNCTION_ARGS)
* Check that only options supported by ogr_fdw, and allowed for the
* current object type, are given.
*/
- foreach(cell, options_list)
+ foreach (cell, options_list)
{
- DefElem *def = (DefElem *) lfirst(cell);
+ DefElem* def = (DefElem*) lfirst(cell);
bool optfound = false;
- for ( opt = valid_options; opt->optname; opt++ )
+ for (opt = valid_options; opt->optname; opt++)
{
- if ( catalog == opt->optcontext && streq(opt->optname, def->defname) )
+ if (catalog == opt->optcontext && streq(opt->optname, def->defname))
{
/* Mark that this user option was found */
opt->optfound = optfound = true;
/* Store some options for testing later */
- if ( streq(opt->optname, OPT_SOURCE) )
+ if (streq(opt->optname, OPT_SOURCE))
+ {
source = defGetString(def);
- if ( streq(opt->optname, OPT_DRIVER) )
+ }
+ if (streq(opt->optname, OPT_DRIVER))
+ {
driver = defGetString(def);
- if ( streq(opt->optname, OPT_CONFIG_OPTIONS) )
+ }
+ if (streq(opt->optname, OPT_CONFIG_OPTIONS))
+ {
config_options = defGetString(def);
- if ( streq(opt->optname, OPT_OPEN_OPTIONS) )
+ }
+ if (streq(opt->optname, OPT_OPEN_OPTIONS))
+ {
open_options = defGetString(def);
- if ( streq(opt->optname, OPT_UPDATEABLE) )
- updateable = defGetBoolean(def);
+ }
+ if (streq(opt->optname, OPT_UPDATEABLE))
+ {
+ if (defGetBoolean(def))
+ {
+ updateable = OGR_UPDATEABLE_TRY;
+ }
+ }
break;
}
}
- if ( ! optfound )
+ if (!optfound)
{
/*
* Unknown option specified, complain about it. Provide a hint
* with list of valid options for the object.
*/
- const struct OgrFdwOption *opt;
+ const struct OgrFdwOption* opt;
StringInfoData buf;
initStringInfo(&buf);
@@ -620,38 +734,45 @@ ogr_fdw_validator(PG_FUNCTION_ARGS)
{
if (catalog == opt->optcontext)
appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
- opt->optname);
+ opt->optname);
}
ereport(ERROR, (
- errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
- errmsg("invalid option \"%s\"", def->defname),
- buf.len > 0
- ? errhint("Valid options in this context are: %s", buf.data)
- : errhint("There are no valid options in this context.")));
+ errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
+ errmsg("invalid option \"%s\"", def->defname),
+ buf.len > 0
+ ? errhint("Valid options in this context are: %s", buf.data)
+ : errhint("There are no valid options in this context.")));
}
}
/* Check that all the mandatory options were found */
- for ( opt = valid_options; opt->optname; opt++ )
+ for (opt = valid_options; opt->optname; opt++)
{
/* Required option for this catalog type is missing? */
- if ( catalog == opt->optcontext && opt->optrequired && ! opt->optfound )
+ if (catalog == opt->optcontext && opt->optrequired && ! opt->optfound)
{
ereport(ERROR, (
- errcode(ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED),
- errmsg("required option \"%s\" is missing", opt->optname)));
+ errcode(ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED),
+ errmsg("required option \"%s\" is missing", opt->optname)));
}
}
/* Make sure server connection can actually be established */
- if ( catalog == ForeignServerRelationId && source )
+ if (catalog == ForeignServerRelationId && source)
{
- OGRDataSourceH ogr_ds;
- ogr_ds = ogrGetDataSource(source, driver, updateable, config_options, open_options);
- if ( ogr_ds )
+ OgrConnection ogr;
+ OGRErr err;
+
+ ogr.ds_str = source;
+ ogr.dr_str = driver;
+ ogr.config_options = config_options;
+ ogr.open_options = open_options;
+
+ err = ogrGetDataSource(&ogr, updateable);
+ if (ogr.ds)
{
- GDALClose(ogr_ds);
+ GDALClose(ogr.ds);
}
}
@@ -664,26 +785,26 @@ ogr_fdw_validator(PG_FUNCTION_ARGS)
static OgrFdwState*
getOgrFdwState(Oid foreigntableid, OgrFdwStateType state_type)
{
- OgrFdwState *state;
+ OgrFdwState* state;
size_t size;
- bool updateable = false;
+ OgrUpdateable updateable = OGR_UPDATEABLE_FALSE;
switch (state_type)
{
- case OGR_PLAN_STATE:
- size = sizeof(OgrFdwPlanState);
- updateable = false;
- break;
- case OGR_EXEC_STATE:
- size = sizeof(OgrFdwExecState);
- updateable = false;
- break;
- case OGR_MODIFY_STATE:
- updateable = true;
- size = sizeof(OgrFdwModifyState);
- break;
- default:
- elog(ERROR, "invalid state type");
+ case OGR_PLAN_STATE:
+ size = sizeof(OgrFdwPlanState);
+ updateable = OGR_UPDATEABLE_FALSE;
+ break;
+ case OGR_EXEC_STATE:
+ size = sizeof(OgrFdwExecState);
+ updateable = OGR_UPDATEABLE_FALSE;
+ break;
+ case OGR_MODIFY_STATE:
+ updateable = OGR_UPDATEABLE_TRUE;
+ size = sizeof(OgrFdwModifyState);
+ break;
+ default:
+ elog(ERROR, "invalid state type");
}
state = palloc0(size);
@@ -703,14 +824,14 @@ getOgrFdwState(Oid foreigntableid, OgrFdwStateType state_type)
* Obtain relation size estimates for a foreign table
*/
static void
-ogrGetForeignRelSize(PlannerInfo *root,
- RelOptInfo *baserel,
+ogrGetForeignRelSize(PlannerInfo* root,
+ RelOptInfo* baserel,
Oid foreigntableid)
{
/* Initialize the OGR connection */
- OgrFdwState *state = (OgrFdwState *)getOgrFdwState(foreigntableid, OGR_PLAN_STATE);
- OgrFdwPlanState *planstate = (OgrFdwPlanState *)state;
- List *scan_clauses = baserel->baserestrictinfo;
+ OgrFdwState* state = (OgrFdwState*)getOgrFdwState(foreigntableid, OGR_PLAN_STATE);
+ OgrFdwPlanState* planstate = (OgrFdwPlanState*)state;
+ List* scan_clauses = baserel->baserestrictinfo;
/* Set to NULL to clear the restriction clauses in OGR */
OGR_L_SetIgnoredFields(planstate->ogr.lyr, NULL);
@@ -733,14 +854,14 @@ ogrGetForeignRelSize(PlannerInfo *root,
*/
/* If we can quickly figure how many rows this layer has, then do so */
- if ( scan_clauses == NIL &&
- OGR_L_TestCapability(planstate->ogr.lyr, OLCFastFeatureCount) == TRUE &&
- ogrCanReallyCountFast(&(planstate->ogr)) )
+ if (scan_clauses == NIL &&
+ OGR_L_TestCapability(planstate->ogr.lyr, OLCFastFeatureCount) == TRUE &&
+ ogrCanReallyCountFast(&(planstate->ogr)))
{
/* Count rows, but don't force a slow count */
int rows = OGR_L_GetFeatureCount(planstate->ogr.lyr, false);
/* Only use row count if return is valid (>0) */
- if ( rows >= 0 )
+ if (rows >= 0)
{
planstate->nrows = rows;
baserel->rows = rows;
@@ -748,7 +869,7 @@ ogrGetForeignRelSize(PlannerInfo *root,
}
/* Save connection state for next calls */
- baserel->fdw_private = (void *) planstate;
+ baserel->fdw_private = (void*) planstate;
return;
}
@@ -764,11 +885,11 @@ ogrGetForeignRelSize(PlannerInfo *root,
* the data file.
*/
static void
-ogrGetForeignPaths(PlannerInfo *root,
- RelOptInfo *baserel,
+ogrGetForeignPaths(PlannerInfo* root,
+ RelOptInfo* baserel,
Oid foreigntableid)
{
- OgrFdwPlanState *planstate = (OgrFdwPlanState *)(baserel->fdw_private);
+ OgrFdwPlanState* planstate = (OgrFdwPlanState*)(baserel->fdw_private);
/* TODO: replace this with something that looks at the OGRDriver and */
/* makes a determination based on that? Better: add connection caching */
@@ -784,21 +905,21 @@ ogrGetForeignPaths(PlannerInfo *root,
/* explain info on how they complete the query, not for something as */
/* obtuse as OGR. (So far, have only seen it w/ the postgres_fdw */
add_path(baserel,
- (Path *) create_foreignscan_path(root, baserel,
+ (Path*) create_foreignscan_path(root, baserel,
#if PG_VERSION_NUM >= 90600
- NULL, /* PathTarget */
+ NULL, /* PathTarget */
#endif
- baserel->rows,
- planstate->startup_cost,
- planstate->total_cost,
- NIL, /* no pathkeys */
- NULL, /* no outer rel either */
- NULL /* no extra plan */
+ baserel->rows,
+ planstate->startup_cost,
+ planstate->total_cost,
+ NIL, /* no pathkeys */
+ NULL, /* no outer rel either */
+ NULL /* no extra plan */
#if PG_VERSION_NUM >= 90500
- ,NIL /* no fdw_private list */
+ , NIL /* no fdw_private list */
#endif
- )
- ); /* no fdw_private data */
+ )
+ ); /* no fdw_private data */
}
@@ -808,25 +929,25 @@ ogrGetForeignPaths(PlannerInfo *root,
* fileGetForeignPlan
* Create a ForeignScan plan node for scanning the foreign table
*/
-static ForeignScan *
-ogrGetForeignPlan(PlannerInfo *root,
- RelOptInfo *baserel,
+static ForeignScan*
+ogrGetForeignPlan(PlannerInfo* root,
+ RelOptInfo* baserel,
Oid foreigntableid,
- ForeignPath *best_path,
- List *tlist,
- List *scan_clauses
+ ForeignPath* best_path,
+ List* tlist,
+ List* scan_clauses
#if PG_VERSION_NUM >= 90500
- ,Plan *outer_plan
+ , Plan* outer_plan
#endif
- )
+ )
{
Index scan_relid = baserel->relid;
bool sql_generated;
StringInfoData sql;
- List *params_list = NULL;
- List *fdw_private;
- OgrFdwPlanState *planstate = (OgrFdwPlanState *)(baserel->fdw_private);
- OgrFdwState *state = (OgrFdwState *)(baserel->fdw_private);
+ List* params_list = NULL;
+ List* fdw_private;
+ OgrFdwPlanState* planstate = (OgrFdwPlanState*)(baserel->fdw_private);
+ OgrFdwState* state = (OgrFdwState*)(baserel->fdw_private);
/* Add in column mapping data to build SQL with the right OGR column names */
ogrReadColumnData(state);
@@ -838,7 +959,7 @@ ogrGetForeignPlan(PlannerInfo *root,
*/
initStringInfo(&sql);
sql_generated = ogrDeparse(&sql, root, baserel, scan_clauses, state, ¶ms_list);
- elog(DEBUG1,"OGR SQL: %s", sql.data);
+ elog(DEBUG1, "OGR SQL: %s", sql.data);
/*
* Here we strip RestrictInfo
@@ -860,10 +981,14 @@ ogrGetForeignPlan(PlannerInfo *root,
*
* TODO: Pass a spatial filter down also.
*/
- if ( sql_generated )
+ if (sql_generated)
+ {
fdw_private = list_make2(makeString(sql.data), params_list);
+ }
else
+ {
fdw_private = list_make2(NULL, params_list);
+ }
/*
* Clean up our connection
@@ -872,165 +997,219 @@ ogrGetForeignPlan(PlannerInfo *root,
/* Create the ForeignScan node */
return make_foreignscan(tlist,
- scan_clauses,
- scan_relid,
- NIL, /* no expressions to evaluate */
- fdw_private
+ scan_clauses,
+ scan_relid,
+ NIL, /* no expressions to evaluate */
+ fdw_private
#if PG_VERSION_NUM >= 90500
- ,NIL /* no scan_tlist */
- ,NIL /* no remote quals */
- ,outer_plan
+ , NIL /* no scan_tlist */
+ , NIL /* no remote quals */
+ , outer_plan
#endif
-);
+ );
}
static void
-pgCanConvertToOgr(Oid pg_type, OGRFieldType ogr_type, const char *colname, const char *tblname)
+pgCanConvertToOgr(Oid pg_type, OGRFieldType ogr_type, const char* colname, const char* tblname)
{
- if ( pg_type == BOOLOID && ogr_type == OFTInteger )
+ if (pg_type == BOOLOID && ogr_type == OFTInteger)
+ {
return;
- else if ( pg_type == INT2OID && ogr_type == OFTInteger )
+ }
+ else if (pg_type == INT2OID && ogr_type == OFTInteger)
+ {
return;
- else if ( pg_type == INT4OID && ogr_type == OFTInteger )
+ }
+ else if (pg_type == INT4OID && ogr_type == OFTInteger)
+ {
return;
- else if ( pg_type == INT8OID )
+ }
+ else if (pg_type == INT8OID)
{
#if GDAL_VERSION_MAJOR >= 2
- if ( ogr_type == OFTInteger64 )
+ if (ogr_type == OFTInteger64)
+ {
return;
+ }
#else
- if ( ogr_type == OFTInteger )
+ if (ogr_type == OFTInteger)
+ {
return;
+ }
#endif
}
- else if ( pg_type == NUMERICOID && ogr_type == OFTReal )
+ else if (pg_type == NUMERICOID && ogr_type == OFTReal)
+ {
return;
- else if ( pg_type == FLOAT4OID && ogr_type == OFTReal )
+ }
+ else if (pg_type == FLOAT4OID && ogr_type == OFTReal)
+ {
return;
- else if ( pg_type == FLOAT8OID && ogr_type == OFTReal )
+ }
+ else if (pg_type == FLOAT8OID && ogr_type == OFTReal)
+ {
return;
- else if ( pg_type == TEXTOID && ogr_type == OFTString )
+ }
+ else if (pg_type == TEXTOID && ogr_type == OFTString)
+ {
return;
- else if ( pg_type == VARCHAROID && ogr_type == OFTString )
+ }
+ else if (pg_type == VARCHAROID && ogr_type == OFTString)
+ {
return;
- else if ( pg_type == CHAROID && ogr_type == OFTString )
+ }
+ else if (pg_type == CHAROID && ogr_type == OFTString)
+ {
return;
- else if ( pg_type == BPCHAROID && ogr_type == OFTString )
+ }
+ else if (pg_type == BPCHAROID && ogr_type == OFTString)
+ {
return;
- else if ( pg_type == NAMEOID && ogr_type == OFTString )
+ }
+ else if (pg_type == NAMEOID && ogr_type == OFTString)
+ {
return;
- else if ( pg_type == BYTEAOID && ogr_type == OFTBinary )
+ }
+ else if (pg_type == BYTEAOID && ogr_type == OFTBinary)
+ {
return;
- else if ( pg_type == DATEOID && ogr_type == OFTDate )
+ }
+ else if (pg_type == DATEOID && ogr_type == OFTDate)
+ {
return;
- else if ( pg_type == TIMEOID && ogr_type == OFTTime )
+ }
+ else if (pg_type == TIMEOID && ogr_type == OFTTime)
+ {
return;
- else if ( pg_type == TIMESTAMPOID && ogr_type == OFTDateTime )
+ }
+ else if (pg_type == TIMESTAMPOID && ogr_type == OFTDateTime)
+ {
return;
+ }
ereport(ERROR, (
- errcode(ERRCODE_FDW_INVALID_DATA_TYPE),
- errmsg("column \"%s\" of foreign table \"%s\" converts \"%s\" to OGR \"%s\"",
- colname, tblname,
- format_type_be(pg_type), OGR_GetFieldTypeName(ogr_type))
- ));
+ errcode(ERRCODE_FDW_INVALID_DATA_TYPE),
+ errmsg("column \"%s\" of foreign table \"%s\" converts \"%s\" to OGR \"%s\"",
+ colname, tblname,
+ format_type_be(pg_type), OGR_GetFieldTypeName(ogr_type))
+ ));
}
static void
-ogrCanConvertToPg(OGRFieldType ogr_type, Oid pg_type, const char *colname, const char *tblname)
+ogrCanConvertToPg(OGRFieldType ogr_type, Oid pg_type, const char* colname, const char* tblname)
{
switch (ogr_type)
{
- case OFTInteger:
- if ( pg_type == BOOLOID || pg_type == INT4OID || pg_type == INT8OID || pg_type == NUMERICOID || pg_type == FLOAT4OID || pg_type == FLOAT8OID || pg_type == TEXTOID || pg_type == VARCHAROID )
- return;
- break;
-
- case OFTReal:
- if ( pg_type == NUMERICOID || pg_type == FLOAT4OID || pg_type == FLOAT8OID || pg_type == TEXTOID || pg_type == VARCHAROID )
- return;
- break;
-
- case OFTBinary:
- if ( pg_type == BYTEAOID )
- return;
- break;
-
- case OFTString:
- if ( pg_type == TEXTOID || pg_type == VARCHAROID || pg_type == CHAROID || pg_type == BPCHAROID )
- return;
- break;
-
- case OFTDate:
- if ( pg_type == DATEOID || pg_type == TIMESTAMPOID || pg_type == TEXTOID || pg_type == VARCHAROID )
- return;
- break;
-
- case OFTTime:
- if ( pg_type == TIMEOID || pg_type == TEXTOID || pg_type == VARCHAROID )
- return;
- break;
-
- case OFTDateTime:
- if ( pg_type == TIMESTAMPOID || pg_type == TEXTOID || pg_type == VARCHAROID )
- return;
- break;
+ case OFTInteger:
+ if (pg_type == BOOLOID || pg_type == INT4OID || pg_type == INT8OID ||
+ pg_type == NUMERICOID || pg_type == FLOAT4OID ||
+ pg_type == FLOAT8OID || pg_type == TEXTOID || pg_type == VARCHAROID)
+ {
+ return;
+ }
+ break;
+
+ case OFTReal:
+ if (pg_type == NUMERICOID || pg_type == FLOAT4OID || pg_type == FLOAT8OID ||
+ pg_type == TEXTOID || pg_type == VARCHAROID)
+ {
+ return;
+ }
+ break;
+
+ case OFTBinary:
+ if (pg_type == BYTEAOID)
+ {
+ return;
+ }
+ break;
+
+ case OFTString:
+ if (pg_type == TEXTOID || pg_type == VARCHAROID || pg_type == CHAROID || pg_type == BPCHAROID)
+ {
+ return;
+ }
+ break;
+
+ case OFTDate:
+ if (pg_type == DATEOID || pg_type == TIMESTAMPOID || pg_type == TEXTOID || pg_type == VARCHAROID)
+ {
+ return;
+ }
+ break;
+
+ case OFTTime:
+ if (pg_type == TIMEOID || pg_type == TEXTOID || pg_type == VARCHAROID)
+ {
+ return;
+ }
+ break;
+
+ case OFTDateTime:
+ if (pg_type == TIMESTAMPOID || pg_type == TEXTOID || pg_type == VARCHAROID)
+ {
+ return;
+ }
+ break;
#if GDAL_VERSION_MAJOR >= 2
- case OFTInteger64:
- if ( pg_type == INT8OID || pg_type == NUMERICOID || pg_type == FLOAT8OID || pg_type == TEXTOID || pg_type == VARCHAROID )
- return;
- break;
+ case OFTInteger64:
+ if (pg_type == INT8OID || pg_type == NUMERICOID || pg_type == FLOAT8OID ||
+ pg_type == TEXTOID || pg_type == VARCHAROID)
+ {
+ return;
+ }
+ break;
#endif
- case OFTWideString:
- case OFTIntegerList:
+ case OFTWideString:
+ case OFTIntegerList:
#if GDAL_VERSION_MAJOR >= 2
- case OFTInteger64List:
+ case OFTInteger64List:
#endif
- case OFTRealList:
- case OFTStringList:
- case OFTWideStringList:
- {
- ereport(ERROR, (
- errcode(ERRCODE_FDW_INVALID_DATA_TYPE),
- errmsg("column \"%s\" of foreign table \"%s\" uses an OGR array, currently unsupported", colname, tblname)
- ));
- break;
- }
+ case OFTRealList:
+ case OFTStringList:
+ case OFTWideStringList:
+ {
+ ereport(ERROR, (
+ errcode(ERRCODE_FDW_INVALID_DATA_TYPE),
+ errmsg("column \"%s\" of foreign table \"%s\" uses an OGR array, currently unsupported", colname, tblname)
+ ));
+ break;
+ }
}
ereport(ERROR, (
- errcode(ERRCODE_FDW_INVALID_DATA_TYPE),
- errmsg("column \"%s\" of foreign table \"%s\" converts OGR \"%s\" to \"%s\"",
- colname, tblname,
- OGR_GetFieldTypeName(ogr_type), format_type_be(pg_type))
- ));
+ errcode(ERRCODE_FDW_INVALID_DATA_TYPE),
+ errmsg("column \"%s\" of foreign table \"%s\" converts OGR \"%s\" to \"%s\"",
+ colname, tblname,
+ OGR_GetFieldTypeName(ogr_type), format_type_be(pg_type))
+ ));
}
#ifdef OGR_FDW_HEXWKB
-static char *hexchr = "0123456789ABCDEF";
+static char* hexchr = "0123456789ABCDEF";
-static char *
-ogrBytesToHex(unsigned char *bytes, size_t size)
+static char*
+ogrBytesToHex(unsigned char* bytes, size_t size)
{
- char *hex;
+ char* hex;
int i;
- if ( ! bytes || ! size )
+ if (! bytes || ! size)
{
elog(ERROR, "hexbytes_from_bytes: invalid input");
return NULL;
}
hex = palloc(size * 2 + 1);
- hex[2*size] = '\0';
- for( i = 0; i < size; i++ )
+ hex[2 * size] = '\0';
+ for (i = 0; i < size; i++)
{
/* Top four bits to 0-F */
- hex[2*i] = hexchr[bytes[i] >> 4];
+ hex[2 * i] = hexchr[bytes[i] >> 4];
/* Bottom four bits to 0-F */
- hex[2*i+1] = hexchr[bytes[i] & 0x0F];
+ hex[2 * i + 1] = hexchr[bytes[i] & 0x0F];
}
return hex;
}
@@ -1038,26 +1217,33 @@ ogrBytesToHex(unsigned char *bytes, size_t size)
#endif
static void
-freeOgrFdwTable(OgrFdwTable *table)
+freeOgrFdwTable(OgrFdwTable* table)
{
- if ( table )
+ if (table)
{
- if ( table->tblname ) pfree(table->tblname);
- if ( table->cols ) pfree(table->cols);
+ if (table->tblname)
+ {
+ pfree(table->tblname);
+ }
+ if (table->cols)
+ {
+ pfree(table->cols);
+ }
pfree(table);
}
}
typedef struct
{
- char *fldname;
+ char* fldname;
int fldnum;
} OgrFieldEntry;
-static int ogrFieldEntryCmpFunc(const void * a, const void * b)
+static int
+ogrFieldEntryCmpFunc(const void* a, const void* b)
{
- const char *a_name = ((OgrFieldEntry*)a)->fldname;
- const char *b_name = ((OgrFieldEntry*)b)->fldname;
+ const char* a_name = ((OgrFieldEntry*)a)->fldname;
+ const char* b_name = ((OgrFieldEntry*)b)->fldname;
return strcasecmp(a_name, b_name);
}
@@ -1072,24 +1258,24 @@ static int ogrFieldEntryCmpFunc(const void * a, const void * b)
* returns.
*/
static void
-ogrReadColumnData(OgrFdwState *state)
+ogrReadColumnData(OgrFdwState* state)
{
Relation rel;
TupleDesc tupdesc;
int i;
- OgrFdwTable *tbl;
+ OgrFdwTable* tbl;
OGRFeatureDefnH dfn;
int ogr_ncols;
int fid_count = 0;
int geom_count = 0;
int ogr_geom_count = 0;
int field_count = 0;
- OgrFieldEntry *ogr_fields;
+ OgrFieldEntry* ogr_fields;
int ogr_fields_count = 0;
- char *tblname = get_rel_name(state->foreigntableid);
+ char* tblname = get_rel_name(state->foreigntableid);
/* Blow away any existing table in the state */
- if ( state->table )
+ if (state->table)
{
freeOgrFdwTable(state->table);
state->table = NULL;
@@ -1112,7 +1298,7 @@ ogrReadColumnData(OgrFdwState *state)
#if (GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0))
ogr_geom_count = OGR_FD_GetGeomFieldCount(dfn);
#else
- ogr_geom_count = ( OGR_FD_GetGeomType(dfn) != wkbNone ) ? 1 : 0;
+ ogr_geom_count = (OGR_FD_GetGeomType(dfn) != wkbNone) ? 1 : 0;
#endif
@@ -1121,26 +1307,26 @@ ogrReadColumnData(OgrFdwState *state)
/* We will search both the original and laundered OGR field names for matches */
ogr_fields_count = 2 * ogr_ncols;
ogr_fields = palloc0(ogr_fields_count * sizeof(OgrFieldEntry));
- for ( i = 0; i < ogr_ncols; i++ )
+ for (i = 0; i < ogr_ncols; i++)
{
- char *fldname = pstrdup(OGR_Fld_GetNameRef(OGR_FD_GetFieldDefn(dfn, i)));
- char *fldname_laundered = palloc(STR_MAX_LEN);
+ char* fldname = pstrdup(OGR_Fld_GetNameRef(OGR_FD_GetFieldDefn(dfn, i)));
+ char* fldname_laundered = palloc(STR_MAX_LEN);
strncpy(fldname_laundered, fldname, STR_MAX_LEN);
ogrStringLaunder(fldname_laundered);
- ogr_fields[2*i].fldname = fldname;
- ogr_fields[2*i].fldnum = i;
- ogr_fields[2*i+1].fldname = fldname_laundered;
- ogr_fields[2*i+1].fldnum = i;
+ ogr_fields[2 * i].fldname = fldname;
+ ogr_fields[2 * i].fldnum = i;
+ ogr_fields[2 * i + 1].fldname = fldname_laundered;
+ ogr_fields[2 * i + 1].fldnum = i;
}
qsort(ogr_fields, ogr_fields_count, sizeof(OgrFieldEntry), ogrFieldEntryCmpFunc);
/* loop through foreign table columns */
- for ( i = 0; i < tbl->ncols; i++ )
+ for (i = 0; i < tbl->ncols; i++)
{
- List *options;
- ListCell *lc;
- OgrFieldEntry *found_entry;
+ List* options;
+ ListCell* lc;
+ OgrFieldEntry* found_entry;
OgrFieldEntry entry;
#if PG_VERSION_NUM >= 110000
@@ -1155,8 +1341,10 @@ ogrReadColumnData(OgrFdwState *state)
col.pgattisdropped = att_tuple->attisdropped;
/* Skip filling in any further metadata about dropped columns */
- if ( col.pgattisdropped )
+ if (col.pgattisdropped)
+ {
continue;
+ }
/* Find the appropriate conversion functions */
getTypeInputInfo(col.pgtype, &col.pginputfunc, &col.pginputioparam);
@@ -1172,10 +1360,13 @@ ogrReadColumnData(OgrFdwState *state)
#endif
/* Handle FID first */
- if ( strcaseeq(col.pgname, "fid") && (col.pgtype == INT4OID || col.pgtype == INT8OID) )
+ if (strcaseeq(col.pgname, "fid") &&
+ (col.pgtype == INT4OID || col.pgtype == INT8OID))
{
- if ( fid_count >= 1 )
+ if (fid_count >= 1)
+ {
elog(ERROR, "FDW table '%s' includes more than one FID column", tblname);
+ }
col.ogrvariant = OGR_FID;
col.ogrfldnum = fid_count++;
@@ -1185,7 +1376,7 @@ ogrReadColumnData(OgrFdwState *state)
/* If the OGR source has geometries, can we match them to Pg columns? */
/* We'll match to the first ones we find, irrespective of name */
- if ( geom_count < ogr_geom_count && col.pgtype == ogrGetGeometryOid() )
+ if (geom_count < ogr_geom_count && col.pgtype == ogrGetGeometryOid())
{
col.ogrvariant = OGR_GEOMETRY;
col.ogrfldtype = OFTBinary;
@@ -1205,11 +1396,11 @@ ogrReadColumnData(OgrFdwState *state)
* want to search for *that* in the OGR layer.
*/
options = GetForeignColumnOptions(state->foreigntableid, i + 1);
- foreach(lc, options)
+ foreach (lc, options)
{
- DefElem *def = (DefElem *) lfirst(lc);
+ DefElem* def = (DefElem*) lfirst(lc);
- if ( streq(def->defname, OPT_COLUMN) )
+ if (streq(def->defname, OPT_COLUMN))
{
entry.fldname = defGetString(def);
break;
@@ -1220,7 +1411,7 @@ ogrReadColumnData(OgrFdwState *state)
found_entry = bsearch(&entry, ogr_fields, ogr_fields_count, sizeof(OgrFieldEntry), ogrFieldEntryCmpFunc);
/* Column name matched, so save this entry, if the types are consistent */
- if ( found_entry )
+ if (found_entry)
{
OGRFieldDefnH fld = OGR_FD_GetFieldDefn(dfn, found_entry->fldnum);
OGRFieldType fldtype = OGR_Fld_GetType(fld);
@@ -1240,13 +1431,19 @@ ogrReadColumnData(OgrFdwState *state)
tbl->cols[i] = col;
}
- elog(DEBUG2, "ogrReadColumnData matched %d FID, %d GEOM, %d FIELDS out of %d PGSQL COLUMNS", fid_count, geom_count, field_count, tbl->ncols);
+ elog(DEBUG2, "ogrReadColumnData matched %d FID, %d GEOM, %d FIELDS out of %d PGSQL COLUMNS", fid_count, geom_count,
+ field_count, tbl->ncols);
/* Clean up */
state->table = tbl;
- for( i = 0; i < 2*ogr_ncols; i++ )
- if ( ogr_fields[i].fldname ) pfree(ogr_fields[i].fldname);
+ for (i = 0; i < 2 * ogr_ncols; i++)
+ {
+ if (ogr_fields[i].fldname)
+ {
+ pfree(ogr_fields[i].fldname);
+ }
+ }
pfree(ogr_fields);
heap_close(rel, NoLock);
@@ -1260,14 +1457,16 @@ ogrReadColumnData(OgrFdwState *state)
* them later.
*/
static Oid
-ogrLookupGeometryFunctionOid(const char *proname)
+ogrLookupGeometryFunctionOid(const char* proname)
{
- List *names;
+ List* names;
FuncCandidateList clist;
/* This only works if PostGIS is installed */
- if ( ogrGetGeometryOid() == InvalidOid || ogrGetGeometryOid() == BYTEAOID )
+ if (ogrGetGeometryOid() == InvalidOid || ogrGetGeometryOid() == BYTEAOID)
+ {
return InvalidOid;
+ }
names = stringToQualifiedNameList(proname);
#if PG_VERSION_NUM < 90400
@@ -1275,20 +1474,22 @@ ogrLookupGeometryFunctionOid(const char *proname)
#else
clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
#endif
- if ( streq(proname, "st_setsrid") )
+ if (streq(proname, "st_setsrid"))
{
do
{
int i;
- for ( i = 0; i < clist->nargs; i++ )
+ for (i = 0; i < clist->nargs; i++)
{
- if ( clist->args[i] == ogrGetGeometryOid() )
+ if (clist->args[i] == ogrGetGeometryOid())
+ {
return clist->oid;
+ }
}
}
- while( (clist = clist->next) );
+ while ((clist = clist->next));
}
- else if ( streq(proname, "postgis_typmod_srid") )
+ else if (streq(proname, "postgis_typmod_srid"))
{
return clist->oid;
}
@@ -1300,14 +1501,14 @@ ogrLookupGeometryFunctionOid(const char *proname)
* ogrBeginForeignScan
*/
static void
-ogrBeginForeignScan(ForeignScanState *node, int eflags)
+ogrBeginForeignScan(ForeignScanState* node, int eflags)
{
Oid foreigntableid = RelationGetRelid(node->ss.ss_currentRelation);
- ForeignScan *fsplan = (ForeignScan *)node->ss.ps.plan;
+ ForeignScan* fsplan = (ForeignScan*)node->ss.ps.plan;
/* Initialize OGR connection */
- OgrFdwState *state = getOgrFdwState(foreigntableid, OGR_EXEC_STATE);
- OgrFdwExecState *execstate = (OgrFdwExecState *)state;
+ OgrFdwState* state = getOgrFdwState(foreigntableid, OGR_EXEC_STATE);
+ OgrFdwExecState* execstate = (OgrFdwExecState*)state;
/* Read the OGR layer definition and PgSQL foreign table definitions */
ogrReadColumnData(state);
@@ -1320,25 +1521,25 @@ ogrBeginForeignScan(ForeignScanState *node, int eflags)
execstate->sql = strVal(list_nth(fsplan->fdw_private, 0));
// execstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private, 1);
- if ( execstate->sql && strlen(execstate->sql) > 0 )
+ if (execstate->sql && strlen(execstate->sql) > 0)
{
OGRErr err = OGR_L_SetAttributeFilter(execstate->ogr.lyr, execstate->sql);
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
{
- const char *ogrerr = CPLGetLastErrorMsg();
+ const char* ogrerr = CPLGetLastErrorMsg();
- if ( ogrerr && ! streq(ogrerr,"") )
+ if (ogrerr && ! streq(ogrerr, ""))
{
ereport(NOTICE,
- (errcode(ERRCODE_FDW_ERROR),
- errmsg("unable to set OGR SQL '%s' on layer", execstate->sql),
- errhint("%s", ogrerr)));
+ (errcode(ERRCODE_FDW_ERROR),
+ errmsg("unable to set OGR SQL '%s' on layer", execstate->sql),
+ errhint("%s", ogrerr)));
}
else
{
ereport(NOTICE,
- (errcode(ERRCODE_FDW_ERROR),
- errmsg("unable to set OGR SQL '%s' on layer", execstate->sql)));
+ (errcode(ERRCODE_FDW_ERROR),
+ errmsg("unable to set OGR SQL '%s' on layer", execstate->sql)));
}
}
}
@@ -1348,7 +1549,7 @@ ogrBeginForeignScan(ForeignScanState *node, int eflags)
}
/* Save the state for the next call */
- node->fdw_state = (void *) execstate;
+ node->fdw_state = (void*) execstate;
return;
}
@@ -1360,20 +1561,20 @@ ogrBeginForeignScan(ForeignScanState *node, int eflags)
* each column in the foreign table.
*/
static Datum
-pgDatumFromCString(const char *cstr, Oid pgtype, int pgtypmod, Oid pginputfunc)
+pgDatumFromCString(const char* cstr, Oid pgtype, int pgtypmod, Oid pginputfunc)
{
Datum value;
Datum cdata = CStringGetDatum(cstr);
value = OidFunctionCall3(pginputfunc, cdata,
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(pgtypmod));
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(pgtypmod));
return value;
}
static inline void
-ogrNullSlot(Datum *values, bool *nulls, int i)
+ogrNullSlot(Datum* values, bool* nulls, int i)
{
values[i] = PointerGetDatum(NULL);
nulls[i] = true;
@@ -1394,27 +1595,27 @@ ogrNullSlot(Datum *values, bool *nulls, int i)
* the type, then everything else.
*/
static OGRErr
-ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecState *execstate)
+ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot* slot, const OgrFdwExecState* execstate)
{
- const OgrFdwTable *tbl = execstate->table;
+ const OgrFdwTable* tbl = execstate->table;
int i;
- Datum *values = slot->tts_values;
- bool *nulls = slot->tts_isnull;
+ Datum* values = slot->tts_values;
+ bool* nulls = slot->tts_isnull;
TupleDesc tupdesc = slot->tts_tupleDescriptor;
int have_typmod_funcs = (execstate->setsridfunc && execstate->typmodsridfunc);
/* Check our assumption that slot and setup data match */
- if ( tbl->ncols != tupdesc->natts )
+ if (tbl->ncols != tupdesc->natts)
{
elog(ERROR, "FDW metadata table and exec table have mismatching number of columns");
return OGRERR_FAILURE;
}
/* For each pgtable column, get a value from OGR */
- for ( i = 0; i < tbl->ncols; i++ )
+ for (i = 0; i < tbl->ncols; i++)
{
OgrFdwColumn col = tbl->cols[i];
- const char *pgname = col.pgname;
+ const char* pgname = col.pgname;
Oid pgtype = col.pgtype;
int pgtypmod = col.pgtypmod;
Oid pginputfunc = col.pginputfunc;
@@ -1425,17 +1626,17 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
/*
* Fill in dropped attributes with NULL
*/
- if ( col.pgattisdropped )
+ if (col.pgattisdropped)
{
ogrNullSlot(values, nulls, i);
continue;
}
- if ( ogrvariant == OGR_FID )
+ if (ogrvariant == OGR_FID)
{
GIntBig fid = OGR_F_GetFID(feat);
- if ( fid == OGRNullFID )
+ if (fid == OGRNullFID)
{
ogrNullSlot(values, nulls, i);
}
@@ -1448,12 +1649,12 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
values[i] = pgDatumFromCString(fidstr, pgtype, pgtypmod, pginputfunc);
}
}
- else if ( ogrvariant == OGR_GEOMETRY )
+ else if (ogrvariant == OGR_GEOMETRY)
{
int wkbsize;
int varsize;
- bytea *varlena;
- unsigned char *wkb;
+ bytea* varlena;
+ unsigned char* wkb;
OGRErr err;
#if (GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0))
@@ -1463,7 +1664,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
#endif
/* No geometry ? NULL */
- if ( ! geom )
+ if (! geom)
{
/* No geometry column, so make the output null */
ogrNullSlot(values, nulls, i);
@@ -1477,17 +1678,17 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
wkbsize = OGR_G_WkbSize(geom);
varsize = wkbsize + VARHDRSZ;
varlena = palloc(varsize);
- wkb = (unsigned char *)VARDATA(varlena);
+ wkb = (unsigned char*)VARDATA(varlena);
err = OGR_G_ExportToWkb(geom, wkbNDR, wkb);
SET_VARSIZE(varlena, varsize);
/* Couldn't create WKB from OGR geometry? error */
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
{
return err;
}
- if ( pgtype == BYTEAOID )
+ if (pgtype == BYTEAOID)
{
/*
* Nothing special to do for bytea, just send the varlena data through!
@@ -1495,7 +1696,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
nulls[i] = false;
values[i] = PointerGetDatum(varlena);
}
- else if ( pgtype == ogrGetGeometryOid() )
+ else if (pgtype == ogrGetGeometryOid())
{
/*
* For geometry we need to convert the varlena WKB data into a serialized
@@ -1505,7 +1706,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
* structure errors (unclosed polys, etc).
*/
#ifdef OGR_FDW_HEXWKB
- char *hexwkb = ogrBytesToHex(wkb, wkbsize);
+ char* hexwkb = ogrBytesToHex(wkb, wkbsize);
/*
* Use the input function to convert the WKB from OGR into
* a PostGIS internal format.
@@ -1524,7 +1725,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
* things like polygon closure, etc. So don't feed it junk.
*/
StringInfoData strinfo;
- strinfo.data = (char *)wkb;
+ strinfo.data = (char*)wkb;
strinfo.len = wkbsize;
strinfo.maxlen = strinfo.len;
strinfo.cursor = 0;
@@ -1545,7 +1746,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
* it is, we should actually apply *that* and let the restriction run
* its usual course.
*/
- if ( have_typmod_funcs && col.pgtypmod >= 0 )
+ if (have_typmod_funcs && col.pgtypmod >= 0)
{
Datum srid = OidFunctionCall1(execstate->typmodsridfunc, Int32GetDatum(col.pgtypmod));
values[i] = OidFunctionCall2(execstate->setsridfunc, values[i], srid);
@@ -1558,7 +1759,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
}
}
- else if ( ogrvariant == OGR_FIELD )
+ else if (ogrvariant == OGR_FIELD)
{
#if (GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0))
int field_not_null = OGR_F_IsFieldSet(feat, ogrfldnum) && ! OGR_F_IsFieldNull(feat, ogrfldnum);
@@ -1570,101 +1771,105 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
ogrCanConvertToPg(ogrfldtype, pgtype, pgname, tbl->tblname);
/* Only convert non-null fields */
- if ( field_not_null )
+ if (field_not_null)
{
- switch(ogrfldtype)
+ switch (ogrfldtype)
{
- case OFTBinary:
- {
- /*
- * Convert binary fields to bytea directly
- */
- int bufsize;
- GByte *buf = OGR_F_GetFieldAsBinary(feat, ogrfldnum, &bufsize);
- int varsize = bufsize + VARHDRSZ;
- bytea *varlena = palloc(varsize);
- memcpy(VARDATA(varlena), buf, bufsize);
- SET_VARSIZE(varlena, varsize);
- nulls[i] = false;
- values[i] = PointerGetDatum(varlena);
- break;
- }
- case OFTInteger:
- case OFTReal:
- case OFTString:
+ case OFTBinary:
+ {
+ /*
+ * Convert binary fields to bytea directly
+ */
+ int bufsize;
+ GByte* buf = OGR_F_GetFieldAsBinary(feat, ogrfldnum, &bufsize);
+ int varsize = bufsize + VARHDRSZ;
+ bytea* varlena = palloc(varsize);
+ memcpy(VARDATA(varlena), buf, bufsize);
+ SET_VARSIZE(varlena, varsize);
+ nulls[i] = false;
+ values[i] = PointerGetDatum(varlena);
+ break;
+ }
+ case OFTInteger:
+ case OFTReal:
+ case OFTString:
#if GDAL_VERSION_MAJOR >= 2
- case OFTInteger64:
+ case OFTInteger64:
#endif
+ {
+ /*
+ * Convert numbers and strings via a string representation.
+ * Handling numbers directly would be faster, but require a lot of extra code.
+ * For now, we go via text.
+ */
+ const char* cstr_in = OGR_F_GetFieldAsString(feat, ogrfldnum);
+ size_t cstr_len = cstr_in ? strlen(cstr_in) : 0;
+ if (cstr_in && cstr_len > 0)
{
- /*
- * Convert numbers and strings via a string representation.
- * Handling numbers directly would be faster, but require a lot of extra code.
- * For now, we go via text.
- */
- const char *cstr_in = OGR_F_GetFieldAsString(feat, ogrfldnum);
- size_t cstr_len = cstr_in ? strlen(cstr_in) : 0;
- if ( cstr_in && cstr_len > 0 )
+ char* cstr_decoded;
+ if (execstate->ogr.lyr_utf8)
{
- char *cstr_decoded;
- if(execstate->ogr.lyr_utf8)
- cstr_decoded = pg_any_to_server(cstr_in, cstr_len, PG_UTF8);
- else
- cstr_decoded = pstrdup(cstr_in);
- nulls[i] = false;
- values[i] = pgDatumFromCString(cstr_decoded, pgtype, pgtypmod, pginputfunc);
+ cstr_decoded = pg_any_to_server(cstr_in, cstr_len, PG_UTF8);
}
else
{
- ogrNullSlot(values, nulls, i);
+ cstr_decoded = pstrdup(cstr_in);
}
- break;
+ nulls[i] = false;
+ values[i] = pgDatumFromCString(cstr_decoded, pgtype, pgtypmod, pginputfunc);
}
- case OFTDate:
- case OFTTime:
- case OFTDateTime:
+ else
{
- /*
- * OGR date/times have a weird access method, so we use that to pull
- * out the raw data and turn it into a string for PgSQL's (very
- * sophisticated) date/time parsing routines to handle.
- */
- int year, month, day, hour, minute, second, tz;
- char cstr[256];
-
- OGR_F_GetFieldAsDateTime(feat, ogrfldnum,
- &year, &month, &day,
- &hour, &minute, &second, &tz);
-
- if ( ogrfldtype == OFTDate )
- {
- snprintf(cstr, 256, "%d-%02d-%02d", year, month, day);
- }
- else if ( ogrfldtype == OFTTime )
- {
- snprintf(cstr, 256, "%02d:%02d:%02d", hour, minute, second);
- }
- else
- {
- snprintf(cstr, 256, "%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
- }
- nulls[i] = false;
- values[i] = pgDatumFromCString(cstr, pgtype, pgtypmod, pginputfunc);
- break;
-
+ ogrNullSlot(values, nulls, i);
+ }
+ break;
+ }
+ case OFTDate:
+ case OFTTime:
+ case OFTDateTime:
+ {
+ /*
+ * OGR date/times have a weird access method, so we use that to pull
+ * out the raw data and turn it into a string for PgSQL's (very
+ * sophisticated) date/time parsing routines to handle.
+ */
+ int year, month, day, hour, minute, second, tz;
+ char cstr[256];
+
+ OGR_F_GetFieldAsDateTime(feat, ogrfldnum,
+ &year, &month, &day,
+ &hour, &minute, &second, &tz);
+
+ if (ogrfldtype == OFTDate)
+ {
+ snprintf(cstr, 256, "%d-%02d-%02d", year, month, day);
}
- case OFTIntegerList:
- case OFTRealList:
- case OFTStringList:
+ else if (ogrfldtype == OFTTime)
{
- /* TODO, map these OGR array types into PgSQL arrays (fun!) */
- elog(ERROR, "unsupported OGR array type \"%s\"", OGR_GetFieldTypeName(ogrfldtype));
- break;
+ snprintf(cstr, 256, "%02d:%02d:%02d", hour, minute, second);
}
- default:
+ else
{
- elog(ERROR, "unsupported OGR type \"%s\"", OGR_GetFieldTypeName(ogrfldtype));
- break;
+ snprintf(cstr, 256, "%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
}
+ nulls[i] = false;
+ values[i] = pgDatumFromCString(cstr, pgtype, pgtypmod, pginputfunc);
+ break;
+
+ }
+ case OFTIntegerList:
+ case OFTRealList:
+ case OFTStringList:
+ {
+ /* TODO, map these OGR array types into PgSQL arrays (fun!) */
+ elog(ERROR, "unsupported OGR array type \"%s\"", OGR_GetFieldTypeName(ogrfldtype));
+ break;
+ }
+ default:
+ {
+ elog(ERROR, "unsupported OGR type \"%s\"", OGR_GetFieldTypeName(ogrfldtype));
+ break;
+ }
}
}
@@ -1674,7 +1879,7 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
}
}
/* Fill in unmatched columns with NULL */
- else if ( ogrvariant == OGR_UNMATCHED )
+ else if (ogrvariant == OGR_UNMATCHED)
{
ogrNullSlot(values, nulls, i);
}
@@ -1690,7 +1895,8 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
return OGRERR_NONE;
}
-static void ogrStaticText(char *text, const char *str)
+static void
+ogrStaticText(char* text, const char* str)
{
size_t len = strlen(str);
memcpy(VARDATA(text), str, len);
@@ -1706,36 +1912,36 @@ static void ogrStaticText(char *text, const char *str)
* generate more "standard" WKB for OGR to consume.
*/
static size_t
-ogrEwkbStripSrid(unsigned char *wkb, size_t wkbsize)
+ogrEwkbStripSrid(unsigned char* wkb, size_t wkbsize)
{
unsigned int type = 0;
int has_srid = 0;
size_t newwkbsize = wkbsize;
- memcpy(&type, wkb+1, 4);
+ memcpy(&type, wkb + 1, 4);
/* has_z = type & 0x80000000; */
/* has_m = type & 0x40000000; */
has_srid = type & 0x20000000;
/* Flatten SRID flag away */
type &= 0xDFFFFFFF;
- memcpy(wkb+1, &type, 4);
+ memcpy(wkb + 1, &type, 4);
/* If there was an SRID number embedded, overwrite it */
- if ( has_srid )
+ if (has_srid)
{
newwkbsize -= 4; /* no space for SRID number needed */
- memmove(wkb+5, wkb+9, newwkbsize - 5);
+ memmove(wkb + 5, wkb + 9, newwkbsize - 5);
}
return newwkbsize;
}
static OGRErr
-ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable *tbl)
+ogrSlotToFeature(const TupleTableSlot* slot, OGRFeatureH feat, const OgrFdwTable* tbl)
{
int i;
- Datum *values = slot->tts_values;
- bool *nulls = slot->tts_isnull;
+ Datum* values = slot->tts_values;
+ bool* nulls = slot->tts_isnull;
TupleDesc tupdesc = slot->tts_tupleDescriptor;
int year, month, day, hour, minute, second;
@@ -1756,17 +1962,17 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
ogrStaticText(txtsecond, "second");
/* Check our assumption that slot and setup data match */
- if ( tbl->ncols != tupdesc->natts )
+ if (tbl->ncols != tupdesc->natts)
{
elog(ERROR, "FDW metadata table and slot table have mismatching number of columns");
return OGRERR_FAILURE;
}
/* For each pgtable column, set a value on the feature OGR */
- for ( i = 0; i < tbl->ncols; i++ )
+ for (i = 0; i < tbl->ncols; i++)
{
OgrFdwColumn col = tbl->cols[i];
- const char *pgname = col.pgname;
+ const char* pgname = col.pgname;
Oid pgtype = col.pgtype;
Oid pgoutputfunc = col.pgoutputfunc;
int ogrfldnum = col.ogrfldnum;
@@ -1774,24 +1980,26 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
OgrColumnVariant ogrvariant = col.ogrvariant;
/* Skip dropped attributes */
- if ( col.pgattisdropped )
+ if (col.pgattisdropped)
+ {
continue;
+ }
/* Skip the FID, we have to treat it as immutable anyways */
- if ( ogrvariant == OGR_FID )
+ if (ogrvariant == OGR_FID)
{
- if ( nulls[i] )
+ if (nulls[i])
{
OGR_F_SetFID(feat, OGRNullFID);
}
else
{
- if ( pgtype == INT4OID )
+ if (pgtype == INT4OID)
{
int32 val = DatumGetInt32(values[i]);
OGR_F_SetFID(feat, val);
}
- else if ( pgtype == INT8OID )
+ else if (pgtype == INT8OID)
{
int64 val = DatumGetInt64(values[i]);
OGR_F_SetFID(feat, val);
@@ -1806,10 +2014,10 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
/* TODO: For updates, we should only set the fields that are */
/* in the target list, and flag the others as unchanged */
- if ( ogrvariant == OGR_GEOMETRY )
+ if (ogrvariant == OGR_GEOMETRY)
{
OGRErr err;
- if ( nulls[i] )
+ if (nulls[i])
{
#if (GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0))
err = OGR_F_SetGeomFieldDirectly(feat, ogrfldnum, NULL);
@@ -1821,16 +2029,21 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
else
{
OGRGeometryH geom;
- bytea *wkb_bytea = DatumGetByteaP(OidFunctionCall1(col.pgsendfunc, values[i]));
- unsigned char *wkb = (unsigned char *)VARDATA(wkb_bytea);
- int wkbsize = VARSIZE(wkb_bytea) - VARHDRSZ;
+ bytea* wkb_bytea = DatumGetByteaP(OidFunctionCall1(col.pgsendfunc, values[i]));
+ unsigned char* wkb = (unsigned char*)VARDATA_ANY(wkb_bytea);
+ int wkbsize = VARSIZE_ANY_EXHDR(wkb_bytea);
wkbsize = ogrEwkbStripSrid(wkb, wkbsize);
/* TODO, create geometry with SRS of table? */
err = OGR_G_CreateFromWkb(wkb, NULL, &geom, wkbsize);
- if ( wkb_bytea ) pfree(wkb_bytea);
- if ( err != OGRERR_NONE )
+ if (wkb_bytea)
+ {
+ pfree(wkb_bytea);
+ }
+ if (err != OGRERR_NONE)
+ {
return err;
+ }
#if (GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0))
err = OGR_F_SetGeomFieldDirectly(feat, ogrfldnum, geom);
@@ -1839,160 +2052,164 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
#endif
}
}
- else if ( ogrvariant == OGR_FIELD )
+ else if (ogrvariant == OGR_FIELD)
{
/* Ensure that the OGR data type fits the destination Pg column */
pgCanConvertToOgr(pgtype, ogrfldtype, pgname, tbl->tblname);
/* Skip NULL case */
- if ( nulls[i] )
+ if (nulls[i])
{
- OGR_F_UnsetField (feat, ogrfldnum);
+ OGR_F_UnsetField(feat, ogrfldnum);
continue;
}
- switch(pgtype)
+ switch (pgtype)
{
- case BOOLOID:
- {
- int8 val = DatumGetBool(values[i]);
- OGR_F_SetFieldInteger(feat, ogrfldnum, val);
- break;
- }
- case INT2OID:
+ case BOOLOID:
+ {
+ int8 val = DatumGetBool(values[i]);
+ OGR_F_SetFieldInteger(feat, ogrfldnum, val);
+ break;
+ }
+ case INT2OID:
+ {
+ int16 val = DatumGetInt16(values[i]);
+ OGR_F_SetFieldInteger(feat, ogrfldnum, val);
+ break;
+ }
+ case INT4OID:
+ {
+ int32 val = DatumGetInt32(values[i]);
+ OGR_F_SetFieldInteger(feat, ogrfldnum, val);
+ break;
+ }
+ case INT8OID:
+ {
+ int64 val = DatumGetInt64(values[i]);
+#if GDAL_VERSION_MAJOR >= 2
+ OGR_F_SetFieldInteger64(feat, ogrfldnum, val);
+#else
+ if (val < INT_MAX)
{
- int16 val = DatumGetInt16(values[i]);
- OGR_F_SetFieldInteger(feat, ogrfldnum, val);
- break;
+ OGR_F_SetFieldInteger(feat, ogrfldnum, (int32)val);
}
- case INT4OID:
+ else
{
- int32 val = DatumGetInt32(values[i]);
- OGR_F_SetFieldInteger(feat, ogrfldnum, val);
- break;
+ elog(ERROR, "unable to coerce int64 into int32 OGR field");
}
- case INT8OID:
- {
- int64 val = DatumGetInt64(values[i]);
-#if GDAL_VERSION_MAJOR >= 2
- OGR_F_SetFieldInteger64(feat, ogrfldnum, val);
-#else
- if ( val < INT_MAX )
- OGR_F_SetFieldInteger(feat, ogrfldnum, (int32)val);
- else
- elog(ERROR, "unable to coerce int64 into int32 OGR field");
#endif
- break;
+ break;
- }
+ }
- case NUMERICOID:
- {
- Datum d;
- float8 f;
+ case NUMERICOID:
+ {
+ Datum d;
+ float8 f;
- /* Convert to string */
- d = OidFunctionCall1(pgoutputfunc, values[i]);
- /* Convert back to float8 */
- f = DatumGetFloat8(DirectFunctionCall1(float8in, d));
+ /* Convert to string */
+ d = OidFunctionCall1(pgoutputfunc, values[i]);
+ /* Convert back to float8 */
+ f = DatumGetFloat8(DirectFunctionCall1(float8in, d));
- OGR_F_SetFieldDouble(feat, ogrfldnum, f);
- break;
- }
- case FLOAT4OID:
- {
- OGR_F_SetFieldDouble(feat, ogrfldnum, DatumGetFloat4(values[i]));
- break;
- }
- case FLOAT8OID:
- {
- OGR_F_SetFieldDouble(feat, ogrfldnum, DatumGetFloat8(values[i]));
- break;
- }
+ OGR_F_SetFieldDouble(feat, ogrfldnum, f);
+ break;
+ }
+ case FLOAT4OID:
+ {
+ OGR_F_SetFieldDouble(feat, ogrfldnum, DatumGetFloat4(values[i]));
+ break;
+ }
+ case FLOAT8OID:
+ {
+ OGR_F_SetFieldDouble(feat, ogrfldnum, DatumGetFloat8(values[i]));
+ break;
+ }
- case TEXTOID:
- case VARCHAROID:
- case NAMEOID:
- case BPCHAROID: /* char(n) */
- {
- char *varlena = (char *)DatumGetPointer(values[i]);
- size_t varsize = VARSIZE(varlena)-VARHDRSZ;
- char *str = palloc0(varsize+1);
- memcpy(str, VARDATA(varlena), varsize);
- OGR_F_SetFieldString(feat, ogrfldnum, str);
- pfree(str);
- break;
- }
+ case TEXTOID:
+ case VARCHAROID:
+ case NAMEOID:
+ case BPCHAROID: /* char(n) */
+ {
+ bytea* varlena = (bytea*)DatumGetPointer(values[i]);
+ size_t varsize = VARSIZE_ANY_EXHDR(varlena);
+ char* str = palloc0(varsize + 1);
+ memcpy(str, VARDATA_ANY(varlena), varsize);
+ OGR_F_SetFieldString(feat, ogrfldnum, str);
+ pfree(str);
+ break;
+ }
- case CHAROID: /* char */
- {
- char str[2];
- str[0] = DatumGetChar(values[i]);
- str[1] = '\0';
- OGR_F_SetFieldString(feat, ogrfldnum, str);
- break;
- }
+ case CHAROID: /* char */
+ {
+ char str[2];
+ str[0] = DatumGetChar(values[i]);
+ str[1] = '\0';
+ OGR_F_SetFieldString(feat, ogrfldnum, str);
+ break;
+ }
- case BYTEAOID:
- {
- bytea *varlena = PG_DETOAST_DATUM(values[i]);
- size_t varsize = VARSIZE(varlena) - VARHDRSZ;
- OGR_F_SetFieldBinary(feat, ogrfldnum, varsize, (GByte *)VARDATA(varlena));
- break;
- }
+ case BYTEAOID:
+ {
+ bytea* varlena = PG_DETOAST_DATUM(values[i]);
+ size_t varsize = VARSIZE_ANY_EXHDR(varlena);
+ OGR_F_SetFieldBinary(feat, ogrfldnum, varsize, (GByte*)VARDATA_ANY(varlena));
+ break;
+ }
- case DATEOID:
- {
- /* Convert date to timestamp */
- Datum d = DirectFunctionCall1(date_timestamp, values[i]);
-
- /* Read out the parts */
- year = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtyear), d)));
- month = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtmonth), d)));
- day = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtday), d)));
- OGR_F_SetFieldDateTime(feat, ogrfldnum, year, month, day, 0, 0, 0, 0);
- break;
- }
+ case DATEOID:
+ {
+ /* Convert date to timestamp */
+ Datum d = DirectFunctionCall1(date_timestamp, values[i]);
+
+ /* Read out the parts */
+ year = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtyear), d)));
+ month = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtmonth), d)));
+ day = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtday), d)));
+ OGR_F_SetFieldDateTime(feat, ogrfldnum, year, month, day, 0, 0, 0, 0);
+ break;
+ }
- /* TODO: handle time zones explicitly */
- case TIMEOID:
- case TIMETZOID:
- {
- /* Read the parts of the time */
- hour = lround(DatumGetFloat8(DirectFunctionCall2(time_part, PointerGetDatum(txthour), values[i])));
- minute = lround(DatumGetFloat8(DirectFunctionCall2(time_part, PointerGetDatum(txtminute), values[i])));
- second = lround(DatumGetFloat8(DirectFunctionCall2(time_part, PointerGetDatum(txtsecond), values[i])));
- OGR_F_SetFieldDateTime(feat, ogrfldnum, 0, 0, 0, hour, minute, second, 0);
- break;
- }
+ /* TODO: handle time zones explicitly */
+ case TIMEOID:
+ case TIMETZOID:
+ {
+ /* Read the parts of the time */
+ hour = lround(DatumGetFloat8(DirectFunctionCall2(time_part, PointerGetDatum(txthour), values[i])));
+ minute = lround(DatumGetFloat8(DirectFunctionCall2(time_part, PointerGetDatum(txtminute), values[i])));
+ second = lround(DatumGetFloat8(DirectFunctionCall2(time_part, PointerGetDatum(txtsecond), values[i])));
+ OGR_F_SetFieldDateTime(feat, ogrfldnum, 0, 0, 0, hour, minute, second, 0);
+ break;
+ }
- case TIMESTAMPOID:
- case TIMESTAMPTZOID:
- {
- Datum d = values[i];
- year = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtyear), d)));
- month = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtmonth), d)));
- day = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtday), d)));
- hour = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txthour), d)));
- minute = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtminute), d)));
- second = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtsecond), d)));
- OGR_F_SetFieldDateTime(feat, ogrfldnum, year, month, day, hour, minute, second, 0);
- break;
- }
+ case TIMESTAMPOID:
+ case TIMESTAMPTZOID:
+ {
+ Datum d = values[i];
+ year = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtyear), d)));
+ month = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtmonth), d)));
+ day = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtday), d)));
+ hour = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txthour), d)));
+ minute = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtminute), d)));
+ second = lround(DatumGetFloat8(DirectFunctionCall2(timestamp_part, PointerGetDatum(txtsecond), d)));
+ OGR_F_SetFieldDateTime(feat, ogrfldnum, year, month, day, hour, minute, second, 0);
+ break;
+ }
- /* TODO: array types for string, integer, float */
- default:
- {
- elog(ERROR, "OGR FDW unsupported PgSQL column type in \"%s\", %d", pgname, pgtype);
- return OGRERR_FAILURE;
- }
+ /* TODO: array types for string, integer, float */
+ default:
+ {
+ elog(ERROR, "OGR FDW unsupported PgSQL column type in \"%s\", %d", pgname, pgtype);
+ return OGRERR_FAILURE;
+ }
}
}
/* Fill in unmatched columns with NULL */
- else if ( ogrvariant == OGR_UNMATCHED )
+ else if (ogrvariant == OGR_UNMATCHED)
{
- OGR_F_UnsetField (feat, ogrfldnum);
+ OGR_F_UnsetField(feat, ogrfldnum);
}
else
{
@@ -2011,11 +2228,11 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
* Read next record from OGR and store it into the
* ScanTupleSlot as a virtual tuple
*/
-static TupleTableSlot *
-ogrIterateForeignScan(ForeignScanState *node)
+static TupleTableSlot*
+ogrIterateForeignScan(ForeignScanState* node)
{
- OgrFdwExecState *execstate = (OgrFdwExecState *) node->fdw_state;
- TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
+ OgrFdwExecState* execstate = (OgrFdwExecState*) node->fdw_state;
+ TupleTableSlot* slot = node->ss.ss_ScanTupleSlot;
OGRFeatureH feat;
/*
@@ -2029,18 +2246,20 @@ ogrIterateForeignScan(ForeignScanState *node)
* we run out of records, then return a cleared (NULL) slot, to
* notify the core we're done.
*/
- if ( execstate->rownum == 0 )
+ if (execstate->rownum == 0)
{
OGR_L_ResetReading(execstate->ogr.lyr);
}
/* If we rectreive a feature from OGR, copy it over into the slot */
feat = OGR_L_GetNextFeature(execstate->ogr.lyr);
- if ( feat )
+ if (feat)
{
/* convert result to arrays of values and null indicators */
- if ( OGRERR_NONE != ogrFeatureToSlot(feat, slot, execstate) )
+ if (OGRERR_NONE != ogrFeatureToSlot(feat, slot, execstate))
+ {
ogrEreportError("failure reading OGR data source");
+ }
/* store the virtual tuple */
ExecStoreVirtualTuple(slot);
@@ -2060,9 +2279,9 @@ ogrIterateForeignScan(ForeignScanState *node)
* Rescan table, possibly with new parameters
*/
static void
-ogrReScanForeignScan(ForeignScanState *node)
+ogrReScanForeignScan(ForeignScanState* node)
{
- OgrFdwExecState *execstate = (OgrFdwExecState *) node->fdw_state;
+ OgrFdwExecState* execstate = (OgrFdwExecState*) node->fdw_state;
OGR_L_ResetReading(execstate->ogr.lyr);
execstate->rownum = 0;
@@ -2075,13 +2294,13 @@ ogrReScanForeignScan(ForeignScanState *node)
* Finish scanning foreign table and dispose objects used for this scan
*/
static void
-ogrEndForeignScan(ForeignScanState *node)
+ogrEndForeignScan(ForeignScanState* node)
{
- OgrFdwExecState *execstate = (OgrFdwExecState *) node->fdw_state;
+ OgrFdwExecState* execstate = (OgrFdwExecState*) node->fdw_state;
elog(DEBUG2, "processed %d rows from OGR", execstate->rownum);
- ogrFinishConnection( &(execstate->ogr) );
+ ogrFinishConnection(&(execstate->ogr));
return;
}
@@ -2090,8 +2309,6 @@ ogrEndForeignScan(ForeignScanState *node)
/* WRITE SUPPORT */
/* ======================================================== */
-// OgrFdwTable *tbl;
-
/* if the scanning functions above respected the targetlist,
we would only be getting back the SET target=foo columns in the slots below,
so we would need to add the "fid" to all targetlists (and also disallow fid changing
@@ -2113,10 +2330,11 @@ in ogrGetForeignPlan we get a tlist that includes just the attributes we
are interested in, can use that to pare down the request perhaps
*/
-static int ogrGetFidColumn(const TupleDesc td)
+static int
+ogrGetFidColumn(const TupleDesc td)
{
int i;
- for ( i = 0; i < td->natts; i++ )
+ for (i = 0; i < td->natts; i++)
{
#if PG_VERSION_NUM >= 110000
NameData attname = td->attrs[i].attname;
@@ -2125,8 +2343,8 @@ static int ogrGetFidColumn(const TupleDesc td)
NameData attname = td->attrs[i]->attname;
Oid atttypeid = td->attrs[i]->atttypid;
#endif
- if ( (atttypeid == INT4OID || atttypeid == INT8OID) &&
- strcaseeq("fid", attname.data) )
+ if ((atttypeid == INT4OID || atttypeid == INT8OID) &&
+ strcaseeq("fid", attname.data))
{
return i;
}
@@ -2143,21 +2361,24 @@ static int ogrGetFidColumn(const TupleDesc td)
* there could always be a virtual fid travelling with the queries,
* and the FDW table itself wouldn't need such a column?
*/
-static void ogrAddForeignUpdateTargets (Query *parsetree,
- RangeTblEntry *target_rte,
- Relation target_relation)
+static void
+ogrAddForeignUpdateTargets(Query* parsetree,
+ RangeTblEntry* target_rte,
+ Relation target_relation)
{
- ListCell *cell;
+ ListCell* cell;
Form_pg_attribute att;
- Var *var;
- TargetEntry *tle;
+ Var* var;
+ TargetEntry* tle;
TupleDesc tupdesc = target_relation->rd_att;
int fid_column = ogrGetFidColumn(tupdesc);
elog(DEBUG2, "ogrAddForeignUpdateTargets");
- if ( fid_column < 0 )
- elog(ERROR,"table '%s' does not have a 'fid' column", RelationGetRelationName(target_relation));
+ if (fid_column < 0)
+ {
+ elog(ERROR, "table '%s' does not have a 'fid' column", RelationGetRelationName(target_relation));
+ }
#if PG_VERSION_NUM >= 110000
att = &tupdesc->attrs[fid_column];
@@ -2166,23 +2387,23 @@ static void ogrAddForeignUpdateTargets (Query *parsetree,
#endif
/* Make a Var representing the desired value */
var = makeVar(parsetree->resultRelation,
- att->attnum,
- att->atttypid,
- att->atttypmod,
- att->attcollation,
- 0);
+ att->attnum,
+ att->atttypid,
+ att->atttypmod,
+ att->attcollation,
+ 0);
/* Wrap it in a resjunk TLE with the right name ... */
- tle = makeTargetEntry((Expr *)var,
- list_length(parsetree->targetList) + 1,
- pstrdup(NameStr(att->attname)),
- true);
+ tle = makeTargetEntry((Expr*)var,
+ list_length(parsetree->targetList) + 1,
+ pstrdup(NameStr(att->attname)),
+ true);
parsetree->targetList = lappend(parsetree->targetList, tle);
- foreach(cell, parsetree->targetList)
+ foreach (cell, parsetree->targetList)
{
- TargetEntry *target = (TargetEntry *) lfirst(cell);
+ TargetEntry* target = (TargetEntry*) lfirst(cell);
elog(DEBUG4, "parsetree->targetList %s:%d", target->resname, target->resno);
}
@@ -2195,14 +2416,15 @@ static void ogrAddForeignUpdateTargets (Query *parsetree,
* For now the only thing we'll do here is set up the connection
* and pass that on to the next functions.
*/
-static void ogrBeginForeignModify (ModifyTableState *mtstate,
- ResultRelInfo *rinfo,
- List *fdw_private,
- int subplan_index,
- int eflags)
+static void
+ogrBeginForeignModify(ModifyTableState* mtstate,
+ ResultRelInfo* rinfo,
+ List* fdw_private,
+ int subplan_index,
+ int eflags)
{
Oid foreigntableid;
- OgrFdwState *state;
+ OgrFdwState* state;
elog(DEBUG2, "ogrBeginForeignModify");
@@ -2222,12 +2444,13 @@ static void ogrBeginForeignModify (ModifyTableState *mtstate,
* Find out what the fid is, get the OGR feature for that FID,
* and then update the values on that feature.
*/
-static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
- ResultRelInfo *rinfo,
- TupleTableSlot *slot,
- TupleTableSlot *planSlot)
+static TupleTableSlot*
+ogrExecForeignUpdate(EState* estate,
+ ResultRelInfo* rinfo,
+ TupleTableSlot* slot,
+ TupleTableSlot* planSlot)
{
- OgrFdwModifyState *modstate = rinfo->ri_FdwState;
+ OgrFdwModifyState* modstate = rinfo->ri_FdwState;
TupleDesc td = slot->tts_tupleDescriptor;
Relation rel = rinfo->ri_RelationDesc;
Oid foreigntableid = RelationGetRelid(rel);
@@ -2240,8 +2463,14 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
/* Is there a fid column? */
fid_column = ogrGetFidColumn(td);
- if ( fid_column < 0 )
+ if (fid_column < 0)
+ {
elog(ERROR, "cannot find 'fid' column in table '%s'", get_rel_name(foreigntableid));
+ }
+
+#if PG_VERSION_NUM >= 120000
+ slot_getallattrs(slot);
+#endif
/* What is the value of the FID for this record? */
fid_datum = slot->tts_values[fid_column];
@@ -2250,28 +2479,38 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
#else
fid_type = td->attrs[fid_column]->atttypid;
#endif
- if ( fid_type == INT8OID )
+ if (fid_type == INT8OID)
+ {
fid = DatumGetInt64(fid_datum);
+ }
else
+ {
fid = DatumGetInt32(fid_datum);
+ }
elog(DEBUG2, "ogrExecForeignUpdate fid=" OGR_FDW_FRMT_INT64, OGR_FDW_CAST_INT64(fid));
/* Get the OGR feature for this fid */
- feat = OGR_L_GetFeature (modstate->ogr.lyr, fid);
+ feat = OGR_L_GetFeature(modstate->ogr.lyr, fid);
/* If we found a feature, then copy data from the slot onto the feature */
/* and then back into the layer */
- if ( ! feat )
+ if (! feat)
+ {
ogrEreportError("failure reading OGR feature");
+ }
err = ogrSlotToFeature(slot, feat, modstate->table);
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
+ {
ogrEreportError("failure populating OGR feature");
+ }
err = OGR_L_SetFeature(modstate->ogr.lyr, feat);
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
+ {
ogrEreportError("failure writing back OGR feature");
+ }
OGR_F_Destroy(feat);
@@ -2381,39 +2620,55 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
// int location; /* token location, or -1 if unknown */
// } Var;
-static TupleTableSlot *ogrExecForeignInsert (EState *estate,
- ResultRelInfo *rinfo,
- TupleTableSlot *slot,
- TupleTableSlot *planSlot)
+static TupleTableSlot*
+ogrExecForeignInsert(EState* estate,
+ ResultRelInfo* rinfo,
+ TupleTableSlot* slot,
+ TupleTableSlot* planSlot)
{
- OgrFdwModifyState *modstate = rinfo->ri_FdwState;
+ OgrFdwModifyState* modstate = rinfo->ri_FdwState;
OGRFeatureDefnH ogr_fd = OGR_L_GetLayerDefn(modstate->ogr.lyr);
OGRFeatureH feat = OGR_F_Create(ogr_fd);
- TupleDesc td = slot->tts_tupleDescriptor;
int fid_column;
OGRErr err;
GIntBig fid;
elog(DEBUG2, "ogrExecForeignInsert");
+#if PG_VERSION_NUM >= 120000
+ /*
+ * PgSQL 12 passes an unpopulated slot to us, and for now
+ * we force it to populate itself and then read directly
+ * from it. For future, using the slot_getattr() infra
+ * would be cleaner, but version dependent.
+ */
+ slot_getallattrs(slot);
+#endif
+
/* Copy the data from the slot onto the feature */
- if ( ! feat )
+ if (!feat)
+ {
ogrEreportError("failure creating OGR feature");
+ }
err = ogrSlotToFeature(slot, feat, modstate->table);
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
+ {
ogrEreportError("failure populating OGR feature");
+ }
err = OGR_L_CreateFeature(modstate->ogr.lyr, feat);
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
+ {
ogrEreportError("failure writing OGR feature");
+ }
fid = OGR_F_GetFID(feat);
OGR_F_Destroy(feat);
/* Update the FID for RETURNING slot */
- fid_column = ogrGetFidColumn(td);
- if ( fid_column >= 0 )
+ fid_column = ogrGetFidColumn(slot->tts_tupleDescriptor);
+ if (fid_column >= 0)
{
slot->tts_values[fid_column] = Int64GetDatum(fid);
slot->tts_isnull[fid_column] = false;
@@ -2425,12 +2680,13 @@ static TupleTableSlot *ogrExecForeignInsert (EState *estate,
-static TupleTableSlot *ogrExecForeignDelete (EState *estate,
- ResultRelInfo *rinfo,
- TupleTableSlot *slot,
- TupleTableSlot *planSlot)
+static TupleTableSlot*
+ogrExecForeignDelete(EState* estate,
+ ResultRelInfo* rinfo,
+ TupleTableSlot* slot,
+ TupleTableSlot* planSlot)
{
- OgrFdwModifyState *modstate = rinfo->ri_FdwState;
+ OgrFdwModifyState* modstate = rinfo->ri_FdwState;
TupleDesc td = planSlot->tts_tupleDescriptor;
Relation rel = rinfo->ri_RelationDesc;
Oid foreigntableid = RelationGetRelid(rel);
@@ -2442,8 +2698,14 @@ static TupleTableSlot *ogrExecForeignDelete (EState *estate,
/* Is there a fid column? */
fid_column = ogrGetFidColumn(td);
- if ( fid_column < 0 )
+ if (fid_column < 0)
+ {
elog(ERROR, "cannot find 'fid' column in table '%s'", get_rel_name(foreigntableid));
+ }
+
+#if PG_VERSION_NUM >= 120000
+ slot_getallattrs(planSlot);
+#endif
/* What is the value of the FID for this record? */
fid_datum = planSlot->tts_values[fid_column];
@@ -2453,37 +2715,47 @@ static TupleTableSlot *ogrExecForeignDelete (EState *estate,
fid_type = td->attrs[fid_column]->atttypid;
#endif
- if ( fid_type == INT8OID )
+ if (fid_type == INT8OID)
+ {
fid = DatumGetInt64(fid_datum);
+ }
else
+ {
fid = DatumGetInt32(fid_datum);
+ }
elog(DEBUG2, "ogrExecForeignDelete fid=" OGR_FDW_FRMT_INT64, OGR_FDW_CAST_INT64(fid));
/* Delete the OGR feature for this fid */
err = OGR_L_DeleteFeature(modstate->ogr.lyr, fid);
- if ( err != OGRERR_NONE )
+ if (err != OGRERR_NONE)
+ {
return NULL;
+ }
else
+ {
return slot;
+ }
}
-static void ogrEndForeignModify (EState *estate, ResultRelInfo *rinfo)
+static void
+ogrEndForeignModify(EState* estate, ResultRelInfo* rinfo)
{
- OgrFdwModifyState *modstate = rinfo->ri_FdwState;
+ OgrFdwModifyState* modstate = rinfo->ri_FdwState;
elog(DEBUG2, "ogrEndForeignModify");
- ogrFinishConnection( &(modstate->ogr) );
+ ogrFinishConnection(&(modstate->ogr));
return;
}
-static int ogrIsForeignRelUpdatable (Relation rel)
+static int
+ogrIsForeignRelUpdatable(Relation rel)
{
- static int readonly = 0;
- static int updateable = 0;
+ const int readonly = 0;
+ int foreign_rel_updateable = 0;
TupleDesc td = RelationGetDescr(rel);
OgrConnection ogr;
Oid foreigntableid = RelationGetRelid(rel);
@@ -2493,7 +2765,7 @@ static int ogrIsForeignRelUpdatable (Relation rel)
/* Before we say "yes"... */
/* Does the foreign relation have a "fid" column? */
/* Is that column an integer? */
- if ( ogrGetFidColumn(td) < 0 )
+ if (ogrGetFidColumn(td) < 0)
{
elog(NOTICE, "no \"fid\" column in foreign table '%s'", get_rel_name(foreigntableid));
return readonly;
@@ -2501,23 +2773,40 @@ static int ogrIsForeignRelUpdatable (Relation rel)
/* Is it backed by a writable OGR driver? */
/* Can we open the relation in read/write mode? */
- ogr = ogrGetConnectionFromTable(foreigntableid, true);
- if ( ! (ogr.ds && ogr.lyr) )
+ ogr = ogrGetConnectionFromTable(foreigntableid, OGR_UPDATEABLE_TRY);
+
+ /* Something in the open process set the readonly flags */
+ /* Perhaps user has manually set the foreign table option to readonly */
+ if (ogr.ds_updateable == OGR_UPDATEABLE_FALSE ||
+ ogr.lyr_updateable == OGR_UPDATEABLE_FALSE)
+ {
return readonly;
+ }
- if ( OGR_L_TestCapability(ogr.lyr, OLCRandomWrite) )
- updateable |= (1 << CMD_UPDATE);
+ /* No data source or layer objects? Readonly */
+ if (!(ogr.ds && ogr.lyr))
+ {
+ return readonly;
+ }
- if ( OGR_L_TestCapability(ogr.lyr, OLCSequentialWrite) )
- updateable |= (1 << CMD_INSERT);
+ if (OGR_L_TestCapability(ogr.lyr, OLCRandomWrite))
+ {
+ foreign_rel_updateable |= (1 << CMD_UPDATE);
+ }
- if ( OGR_L_TestCapability(ogr.lyr, OLCDeleteFeature) )
- updateable |= (1 << CMD_DELETE);
+ if (OGR_L_TestCapability(ogr.lyr, OLCSequentialWrite))
+ {
+ foreign_rel_updateable |= (1 << CMD_INSERT);
+ }
- ogrFinishConnection(&ogr);
+ if (OGR_L_TestCapability(ogr.lyr, OLCDeleteFeature))
+ {
+ foreign_rel_updateable |= (1 << CMD_DELETE);
+ }
- return updateable;
+ ogrFinishConnection(&ogr);
+ return foreign_rel_updateable;
}
#if PG_VERSION_NUM >= 90500
@@ -2525,12 +2814,12 @@ static int ogrIsForeignRelUpdatable (Relation rel)
/*
* PostgreSQL 9.5 or above. Import a foreign schema
*/
-static List *
-ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
+static List*
+ogrImportForeignSchema(ImportForeignSchemaStmt* stmt, Oid serverOid)
{
- List *commands = NIL;
- ForeignServer *server;
- ListCell *lc;
+ List* commands = NIL;
+ ForeignServer* server;
+ ListCell* lc;
bool import_all = false;
bool launder_column_names, launder_table_names;
OgrConnection ogr;
@@ -2543,32 +2832,36 @@ ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
/* Make connection to server */
server = GetForeignServer(serverOid);
- ogr = ogrGetConnectionFromServer(serverOid, false);
+ ogr = ogrGetConnectionFromServer(serverOid, OGR_UPDATEABLE_FALSE);
/* Launder by default */
launder_column_names = launder_table_names = true;
/* Read user-provided statement laundering options */
- foreach(lc, stmt->options)
+ foreach (lc, stmt->options)
{
- DefElem *def = (DefElem *) lfirst(lc);
+ DefElem* def = (DefElem*) lfirst(lc);
if (streq(def->defname, "launder_column_names"))
+ {
launder_column_names = defGetBoolean(def);
+ }
else if (streq(def->defname, "launder_table_names"))
+ {
launder_table_names = defGetBoolean(def);
+ }
else
ereport(ERROR,
- (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
- errmsg("invalid option \"%s\"", def->defname)));
+ (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
+ errmsg("invalid option \"%s\"", def->defname)));
}
- for ( i = 0; i < GDALDatasetGetLayerCount(ogr.ds); i++ )
+ for (i = 0; i < GDALDatasetGetLayerCount(ogr.ds); i++)
{
bool import_layer = false;
OGRLayerH ogr_lyr = GDALDatasetGetLayer(ogr.ds, i);
- if ( ! ogr_lyr )
+ if (! ogr_lyr)
{
elog(DEBUG1, "Skipping OGR layer %d, unable to read layer", i);
continue;
@@ -2583,35 +2876,43 @@ ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
*/
strncpy(table_name, layer_name, STR_MAX_LEN);
if (launder_table_names)
+ {
ogrStringLaunder(table_name);
+ }
/*
* Only include if we are importing "ogr_all" or
* the layer prefix starts with the remote schema
*/
import_layer = import_all ||
- ( strncmp(layer_name, stmt->remote_schema, strlen(stmt->remote_schema) ) == 0 );
+ (strncmp(layer_name, stmt->remote_schema, strlen(stmt->remote_schema)) == 0);
/* Apply restrictions for LIMIT TO and EXCEPT */
if (import_layer && (
- stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO ||
- stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT ) )
+ stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO ||
+ stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT))
{
/* Limited list? Assume we are taking no items */
if (stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO)
+ {
import_layer = false;
+ }
/* Check the list for our items */
- foreach(lc, stmt->table_list)
+ foreach (lc, stmt->table_list)
{
- RangeVar *rv = (RangeVar *) lfirst(lc);
+ RangeVar* rv = (RangeVar*) lfirst(lc);
/* Found one! */
- if ( streq(rv->relname, table_name) )
+ if (streq(rv->relname, table_name))
{
if (stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO)
+ {
import_layer = true;
+ }
else
+ {
import_layer = false;
+ }
break;
}
@@ -2626,12 +2927,12 @@ ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
stringbuffer_init(&buf);
err = ogrLayerToSQL(ogr_lyr,
- quote_identifier(server->servername),
- launder_table_names,
- launder_column_names,
- ogrGetGeometryOid() != BYTEAOID,
- &buf
- );
+ quote_identifier(server->servername),
+ launder_table_names,
+ launder_column_names,
+ ogrGetGeometryOid() != BYTEAOID,
+ &buf
+ );
if (err != OGRERR_NONE)
{
@@ -2643,14 +2944,14 @@ ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
}
}
- elog(NOTICE, "Number of tables to be created %d", list_length(commands) );
+ elog(NOTICE, "Number of tables to be created %d", list_length(commands));
ogrFinishConnection(&ogr);
return commands;
}
-#endif /* PostgreSQL 9.5+ */
+#endif /* PostgreSQL 9.5+ for ogrImportForeignSchema */
=====================================
ogr_fdw.h
=====================================
@@ -14,6 +14,7 @@
/*
* PostgreSQL
*/
+#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
@@ -37,13 +38,11 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
-#include "nodes/relation.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
-#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "storage/ipc.h"
#include "utils/builtins.h"
@@ -55,6 +54,13 @@
#include "utils/syscache.h"
#include "utils/timestamp.h"
+#if PG_VERSION_NUM < 120000
+#include "nodes/relation.h"
+#include "optimizer/var.h"
+#else
+#include "executor/tuptable.h"
+#endif
+
/* GDAL/OGR includes and compat */
#include "ogr_fdw_gdal.h"
#include "ogr_fdw_common.h"
@@ -78,7 +84,8 @@ typedef enum
typedef enum {
OGR_UPDATEABLE_FALSE,
OGR_UPDATEABLE_TRUE,
- OGR_UPDATEABLE_UNSET
+ OGR_UPDATEABLE_UNSET,
+ OGR_UPDATEABLE_TRY
} OgrUpdateable;
typedef struct OgrFdwColumn
@@ -117,13 +124,13 @@ typedef struct OgrFdwTable
typedef struct OgrConnection
{
- char *ds_str; /* datasource connection string */
- char *dr_str; /* driver (format) name */
+ const char *ds_str; /* datasource connection string */
+ const char *dr_str; /* driver (format) name */
char *lyr_str; /* layer name */
- char *config_options; /* GDAL config options */
- char *open_options; /* GDAL open options */
- bool ds_updateable;
- bool lyr_updateable;
+ const char *config_options; /* GDAL config options */
+ const char *open_options; /* GDAL open options */
+ OgrUpdateable ds_updateable;
+ OgrUpdateable lyr_updateable;
bool lyr_utf8; /* OGR layer will return UTF8 strings */
GDALDatasetH ds; /* GDAL datasource handle */
OGRLayerH lyr; /* OGR layer handle */
=====================================
ogr_fdw_common.c
=====================================
@@ -54,7 +54,7 @@ ogrStringLaunder(char *str)
int i, j = 0;
char tmp[STR_MAX_LEN];
memset(tmp, 0, STR_MAX_LEN);
-
+
for(i = 0; str[i]; i++)
{
char c = tolower(str[i]);
@@ -83,11 +83,11 @@ ogrStringLaunder(char *str)
j = STR_MAX_LEN - 1;
}
strncpy(str, tmp, STR_MAX_LEN);
-
+
}
-static char *
-ogrTypeToPgType(OGRFieldDefnH ogr_fld)
+static void
+ogrTypeToPgType(OGRFieldDefnH ogr_fld, char *pgtype, size_t width)
{
OGRFieldType ogr_type = OGR_Fld_GetType(ogr_fld);
switch(ogr_type)
@@ -95,39 +95,59 @@ ogrTypeToPgType(OGRFieldDefnH ogr_fld)
case OFTInteger:
#if GDAL_VERSION_MAJOR >= 2
if( OGR_Fld_GetSubType(ogr_fld) == OFSTBoolean )
- return "boolean";
+ {
+ snprintf(pgtype, width, "boolean");
+ break;
+ }
else
#endif
- return "integer";
+ snprintf(pgtype, width, "integer");
+ break;
case OFTReal:
- return "real";
+ snprintf(pgtype, width, "double precision");
+ break;
case OFTString:
- return "varchar";
+ {
+ int ogr_fld_width = OGR_Fld_GetWidth(ogr_fld);
+ if (ogr_fld_width > 0)
+ snprintf(pgtype, width, "varchar(%d)", ogr_fld_width);
+ else
+ snprintf(pgtype, width, "varchar");
+ break;
+ }
case OFTBinary:
- return "bytea";
+ snprintf(pgtype, width, "bytea");
+ break;
case OFTDate:
- return "date";
+ snprintf(pgtype, width, "date");
+ break;
case OFTTime:
- return "time";
+ snprintf(pgtype, width, "time");
+ break;
case OFTDateTime:
- return "timestamp";
+ snprintf(pgtype, width, "timestamp");
+ break;
case OFTIntegerList:
- return "integer[]";
+ snprintf(pgtype, width, "integer[]");
+ break;
case OFTRealList:
- return "real[]";
+ snprintf(pgtype, width, "double precision[]");
+ break;
case OFTStringList:
- return "varchar[]";
+ snprintf(pgtype, width, "varchar[]");
+ break;
#if GDAL_VERSION_MAJOR >= 2
case OFTInteger64:
- return "bigint";
+ snprintf(pgtype, width, "bigint");
+ break;
#endif
default:
- CPLError(CE_Failure, CPLE_AssertionFailed,
- "unsupported GDAL type '%s'",
+ CPLError(CE_Failure, CPLE_AssertionFailed,
+ "unsupported GDAL type '%s'",
OGR_GetFieldTypeName(ogr_type));
- return NULL;
+ return;
}
- return NULL;
+ return;
}
static void
@@ -182,13 +202,13 @@ ogrGeomTypeToPgGeomType(stringbuffer_t *buf, OGRwkbGeometryType gtype)
CPLError(CE_Failure, CPLE_AssertionFailed, "Cannot handle OGR geometry type '%d'", gtype);
}
-#if GDAL_VERSION_MAJOR >= 2
+#if GDAL_VERSION_MAJOR >= 2
if ( wkbHasZ(gtype) )
#else
if ( gtype & wkb25DBit )
#endif
stringbuffer_append(buf, "Z");
-
+
#if GDAL_VERSION_MAJOR >= 2 && GDAL_VERSION_MINOR >= 1
if ( wkbHasM(gtype) )
stringbuffer_append(buf, "M");
@@ -226,8 +246,9 @@ ogrColumnNameToSQL (const char *ogrcolname, const char *pgtype, int launder_colu
return OGRERR_NONE;
}
+
OGRErr
-ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
+ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
int launder_table_names, int launder_column_names,
int use_postgis_geometry, stringbuffer_t *buf)
{
@@ -235,7 +256,7 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
char table_name[STR_MAX_LEN];
OGRFeatureDefnH ogr_fd = OGR_L_GetLayerDefn(ogr_lyr);
stringbuffer_t gbuf;
-
+
stringbuffer_init(&gbuf);
if ( ! ogr_fd )
@@ -249,18 +270,18 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
#else
geom_field_count = (OGR_L_GetGeomType(ogr_lyr) != wkbNone);
#endif
-
+
/* Process table name */
strncpy(table_name, OGR_L_GetName(ogr_lyr), STR_MAX_LEN);
if (launder_table_names)
ogrStringLaunder(table_name);
-
+
/* Create table */
stringbuffer_aprintf(buf, "CREATE FOREIGN TABLE %s (\n", quote_identifier(table_name));
-
+
/* For now, every table we auto-create will have a FID */
stringbuffer_append(buf, " fid bigint");
-
+
/* Handle all geometry columns in the OGR source */
for ( i = 0; i < geom_field_count; i++ )
{
@@ -284,11 +305,11 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
/* PostGIS geometry type has lots of complex stuff */
if ( use_postgis_geometry )
- {
+ {
/* Add geometry type info */
stringbuffer_append(&gbuf, "Geometry(");
ogrGeomTypeToPgGeomType(&gbuf, gtype);
-
+
/* See if we have an EPSG code to work with */
if ( gsrs )
{
@@ -303,7 +324,7 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
srid = atoi(charSrsCode);
}
}
-
+
/* Add EPSG number, if figured it out */
if ( srid )
{
@@ -319,7 +340,7 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
{
stringbuffer_append(&gbuf, "bytea");
}
-
+
/* Use geom field name if we have it */
if ( geomfldname && strlen(geomfldname) > 0 )
{
@@ -340,21 +361,21 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
/* Write out attribute fields */
for ( i = 0; i < OGR_FD_GetFieldCount(ogr_fd); i++ )
{
+ char pgtype[128];
OGRFieldDefnH ogr_fld = OGR_FD_GetFieldDefn(ogr_fd, i);
- ogrColumnNameToSQL(OGR_Fld_GetNameRef(ogr_fld),
- ogrTypeToPgType(ogr_fld),
- launder_column_names, buf);
+ ogrTypeToPgType(ogr_fld, pgtype, 128);
+ ogrColumnNameToSQL(OGR_Fld_GetNameRef(ogr_fld), pgtype, launder_column_names, buf);
}
/*
* Add server name and layer-level options. We specify remote
* layer name as option
*/
- stringbuffer_aprintf(buf, "\n) SERVER %s\nOPTIONS (", quote_identifier(fdw_server));
+ stringbuffer_aprintf(buf, "\n) SERVER \"%s\"\nOPTIONS (", quote_identifier(fdw_server));
stringbuffer_append(buf, "layer ");
ogrDeparseStringLiteral(buf, OGR_L_GetName(ogr_lyr));
stringbuffer_append(buf, ");\n");
-
+
return OGRERR_NONE;
}
=====================================
ogr_fdw_deparse.c
=====================================
@@ -5,14 +5,12 @@
*
* Copyright (c) 2014-2015, Paul Ramsey <pramsey at cleverelephant.ca>
*
- * Convert parse tree to a QueryExpression as described at
+ * Convert parse tree to a QueryExpression as described at
* http://gdal.org/ogr_sql.html
*-------------------------------------------------------------------------
*/
-#include "postgres.h"
-
/*
* Local structures
*/
@@ -131,7 +129,7 @@ ogrDeparseConst(Const* constant, OgrDeparseCtx *context)
else if ( constant->consttype == ogrGetGeometryOid() )
{
/*
- * For geometry we need to convert the gserialized constant into
+ * For geometry we need to convert the gserialized constant into
* an OGRGeometry for the OGR spatial filter.
* For that, we can use the type's "send" function
* which takes in gserialized and spits out EWKB.
@@ -152,16 +150,16 @@ ogrDeparseConst(Const* constant, OgrDeparseCtx *context)
*/
getTypeBinaryOutputInfo(constant->consttype, &sendfunction, &typeIsVarlena);
wkbdatum = OidFunctionCall1(sendfunction, constant->constvalue);
-
- /*
- * Convert the WKB into an OGR geometry
+
+ /*
+ * Convert the WKB into an OGR geometry
*/
gser = DatumGetPointer(wkbdatum);
wkb = VARDATA(gser);
wkb_size = VARSIZE(gser) - VARHDRSZ;
err = OGR_G_CreateFromWkb((unsigned char *)wkb, NULL, &ogrgeom, wkb_size);
-
- /*
+
+ /*
* Save the result
*/
if ( err != OGRERR_NONE )
@@ -171,8 +169,8 @@ ogrDeparseConst(Const* constant, OgrDeparseCtx *context)
else
elog(WARNING, "got two geometries in OGR FDW query, only using the first");
}
- /*
- * geometry doesn't play a role in the deparsed SQL
+ /*
+ * geometry doesn't play a role in the deparsed SQL
*/
return false;
}
@@ -205,15 +203,15 @@ ogrIsLegalVarName(const char *varname)
{
size_t len = strlen(varname);
int i;
-
+
for ( i = 0; i < len; i++ )
{
char c = varname[i];
-
+
/* First char must be a-zA-Z */
if ( i == 0 && ! ((c>=97&&c<=122)||(c>=65&&c<=90)) )
return false;
-
+
/* All other chars must be 0-9a-zA-Z_ */
if ( ! ((c>=97&&c<=122)||(c>=65&&c<=90)||(c>=48&&c<=59)||(c==96)) )
return false;
@@ -226,7 +224,7 @@ static bool
ogrDeparseVar(Var *node, OgrDeparseCtx *context)
{
StringInfoData *buf = context->buf;
-
+
if (node->varno == context->foreignrel->relid && node->varlevelsup == 0)
{
/* Var belongs to foreign table */
@@ -246,7 +244,7 @@ ogrDeparseVar(Var *node, OgrDeparseCtx *context)
if ( table->cols[i].pgattnum == node->varattno )
{
const char *fldname = NULL;
-
+
if ( table->cols[i].ogrvariant == OGR_FID )
{
fldname = OGR_L_GetFIDColumn(lyr);
@@ -259,19 +257,19 @@ ogrDeparseVar(Var *node, OgrDeparseCtx *context)
OGRFieldDefnH fld = OGR_FD_GetFieldDefn(fd, table->cols[i].ogrfldnum);
fldname = OGR_Fld_GetNameRef(fld);
}
-
+
if ( fldname )
{
if ( ogrIsLegalVarName(fldname) )
appendStringInfoString(buf, fldname);
else
appendStringInfo(buf, "\"%s\"", fldname);
-
+
done = true;
}
}
}
-
+
return done;
}
else
@@ -279,7 +277,7 @@ ogrDeparseVar(Var *node, OgrDeparseCtx *context)
elog(ERROR, "got to param handling section of ogrDeparseVar");
return false;
}
-
+
return true;
}
@@ -288,7 +286,7 @@ static int ogrOperatorCmpFunc(const void * a, const void * b)
return strcasecmp(*(const char**)a, *(const char**)b);
}
-static bool
+static bool
ogrOperatorIsSupported(const char *opname)
{
/* IMPORTANT */
@@ -296,7 +294,7 @@ ogrOperatorIsSupported(const char *opname)
static const char * ogrOperators[10] = { "!=", "&&", "<", "<=", "<>", "=", ">", ">=", "~~", "~~*" };
elog(DEBUG3, "ogrOperatorIsSupported got operator '%s'", opname);
-
+
if ( bsearch(&opname, ogrOperators, 10, sizeof(char*), ogrOperatorCmpFunc) )
return true;
else
@@ -354,7 +352,7 @@ ogrDeparseOpExpr(OpExpr* node, OgrDeparseCtx *context)
// constant = (Const*)l_arg;
// else
// return false;
-
+
// if ( constant->consttype != ogrGetGeometryOid() )
ReleaseSysCache(tuple);
@@ -385,10 +383,10 @@ ogrDeparseOpExpr(OpExpr* node, OgrDeparseCtx *context)
/* use 'ILIKE' all the time. */
if ( streq(opname, "~~") || streq(opname, "~~*") )
opname = "ILIKE";
-
+
/* Operator symbol */
appendStringInfoString(buf, opname);
-
+
/* Deparse right operand. */
if (oprkind == 'l' || oprkind == 'b')
{
@@ -402,7 +400,7 @@ ogrDeparseOpExpr(OpExpr* node, OgrDeparseCtx *context)
ReleaseSysCache(tuple);
return result;
-
+
}
static bool
@@ -436,9 +434,9 @@ ogrDeparseBoolExpr(BoolExpr *node, OgrDeparseCtx *context)
appendStringInfoChar(buf, '(');
foreach(lc, node->args)
{
-
+
len_save_part = buf->len;
-
+
/* Connect expressions and parenthesize each condition */
if ( ! first )
appendStringInfo(buf, " %s ", op);
@@ -446,7 +444,7 @@ ogrDeparseBoolExpr(BoolExpr *node, OgrDeparseCtx *context)
/* Unparse the expression, if possible */
result = ogrDeparseExpr((Expr *) lfirst(lc), context);
result_total += result;
-
+
/* We can backtrack just this term for AND expressions */
if ( boolop == AND_EXPR && ! result )
setStringInfoLength(buf, len_save_part);
@@ -454,17 +452,17 @@ ogrDeparseBoolExpr(BoolExpr *node, OgrDeparseCtx *context)
/* We have to drop the whole thing if we can't get every part of an OR expression */
if ( boolop == OR_EXPR && ! result )
break;
-
+
/* Don't flip the "first" bit until we get a good expression */
if ( first && result )
first = false;
}
appendStringInfoChar(buf, ')');
-
+
/* We have to drop the whole thing if we can't get every part of an OR expression */
if ( boolop == OR_EXPR && ! result )
setStringInfoLength(buf, len_save_all);
-
+
return result_total > 0;
}
@@ -521,9 +519,15 @@ ogrDeparseExpr(Expr *node, OgrDeparseCtx *context)
/* TODO: Handle this to support the "IN" operator */
elog(NOTICE, "unsupported OGR FDW expression type, T_ScalarArrayOpExpr");
return false;
+#if PG_VERSION_NUM < 120000
case T_ArrayRef:
elog(NOTICE, "unsupported OGR FDW expression type, T_ArrayRef");
return false;
+#else
+ case T_SubscriptingRef:
+ elog(NOTICE, "unsupported OGR FDW expression type, T_SubscriptingRef");
+ return false;
+#endif
case T_ArrayExpr:
elog(NOTICE, "unsupported OGR FDW expression type, T_ArrayExpr");
return false;
@@ -537,7 +541,7 @@ ogrDeparseExpr(Expr *node, OgrDeparseCtx *context)
elog(NOTICE, "unsupported OGR FDW expression type for deparse: %d", (int) nodeTag(node));
return false;
}
-
+
}
@@ -584,13 +588,13 @@ ogrDeparse(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, List *expr
/* Couldn't unparse some portion of the expression, so rewind the stringinfo */
setStringInfoLength(buf, len_save);
}
-
+
/* Don't flip the "first" bit until we get a good expression */
if ( first && result )
first = false;
- }
-
- return true;
+ }
+
+ return true;
}
=====================================
ogr_fdw_gdal.h
=====================================
@@ -2,6 +2,34 @@
#ifndef _OGR_FDW_GDAL_H
#define _OGR_FDW_GDAL_H 1
+/*
+ * Quiet warnings due to double use of
+ * pkgconfig macros in GDAL and PgSQL
+ */
+#ifdef PACKAGE_VERSION
+#undef PACKAGE_VERSION
+#endif
+
+#ifdef PACKAGE_TARNAME
+#undef PACKAGE_TARNAME
+#endif
+
+#ifdef PACKAGE_STRING
+#undef PACKAGE_STRING
+#endif
+
+#ifdef PACKAGE_NAME
+#undef PACKAGE_NAME
+#endif
+
+#ifdef PACKAGE_BUGREPORT
+#undef PACKAGE_BUGREPORT
+#endif
+
+#ifdef PACKAGE_VERSION
+#undef PACKAGE_VERSION
+#endif
+
/*
* OGR library API
*/
@@ -11,11 +39,11 @@
#include "cpl_error.h"
#include "cpl_string.h"
-/*
+/*
* As far as possible code is GDAL2 compliant, and these
* mappings are used to convert to GDAL1-style function
* names. For GDALDatasetH opening, there are specific
- * code blocks to handle version differences between
+ * code blocks to handle version differences between
* GDALOpenEx() and OGROpen()
*/
#if GDAL_VERSION_MAJOR < 2
@@ -39,4 +67,4 @@
#endif /* GDAL 1 support */
-#endif /* _OGR_FDW_GDAL_H */
\ No newline at end of file
+#endif /* _OGR_FDW_GDAL_H */
=====================================
output/file.source
=====================================
@@ -10,7 +10,7 @@ CREATE FOREIGN TABLE pt_1 (
geom bytea,
name varchar,
age integer,
- height real,
+ height double precision,
birthdate date )
SERVER myserver
OPTIONS ( layer 'pt_two' );
@@ -46,6 +46,20 @@ SELECT * FROM pt_3 ORDER BY name;
\x0101000000c00497d1162cb93f8cbaef08a080e63f | Peter
(2 rows)
+------------------------------------------------
+CREATE FOREIGN TABLE poly_1 (
+ fid bigint,
+ geom bytea,
+ id double precision,
+ name varchar(5)
+) SERVER myserver
+OPTIONS (layer 'poly');
+SELECT length(geom) FROM poly_1 WHERE name = 'Three';
+ length
+--------
+ 307
+(1 row)
+
------------------------------------------------
-- Laundering and explicit column naming test
CREATE FOREIGN TABLE column_name_test (
@@ -87,7 +101,7 @@ CREATE FOREIGN TABLE e_1 (
name varchar )
SERVER myserver_latin1
OPTIONS ( layer 'enc' );
-SET client_min_messages = debug1;
+SET client_min_messages = debug1;
SELECT * FROM e_1 WHERE fid = 1;
DEBUG: GDAL config option 'SHAPE_ENCODING' set to 'LATIN1'
DEBUG: OGR SQL: (fid = 1)
@@ -97,7 +111,7 @@ DEBUG: GDAL config option 'SHAPE_ENCODING' set to 'LATIN1'
1 | Pàul
(1 row)
-SET client_min_messages = notice;
+SET client_min_messages = notice;
------------------------------------------------
-- Geometryless test
CREATE SERVER csvserver
@@ -112,9 +126,9 @@ CREATE FOREIGN TABLE no_geom (
value varchar
) SERVER csvserver
OPTIONS (layer 'no_geom');
-SELECT c.*
- FROM generate_series(1,4) g
- JOIN no_geom c
+SELECT c.*
+ FROM generate_series(1,4) g
+ JOIN no_geom c
ON (c.fid = g.g);
fid | name | age | value
-----+---------+-----+-------
=====================================
output/import.source
=====================================
@@ -19,7 +19,7 @@ ORDER BY c.ordinal_position;
geom | bytea |
n2ame | character varying | {column_name=2ame}
age | integer |
- height | real |
+ height | double precision |
b_rthdate | date | {column_name=b-rthdate}
(6 rows)
@@ -46,7 +46,7 @@ ORDER BY c.ordinal_position;
column_name | data_type | attfdwoptions
-------------+-------------------+---------------
fid | bigint |
- id | real |
+ id | double precision |
natural | character varying |
(3 rows)
View it on GitLab: https://salsa.debian.org/debian-gis-team/pgsql-ogr-fdw/compare/570d5b83205ff33028fe2c1a9ba63d4e2a27b3fe...22e03fced0e656fb7df8b5bda1b640a2964136ba
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/pgsql-ogr-fdw/compare/570d5b83205ff33028fe2c1a9ba63d4e2a27b3fe...22e03fced0e656fb7df8b5bda1b640a2964136ba
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20190502/f0cfdc0d/attachment-0001.html>
More information about the Pkg-grass-devel
mailing list