[pgsql-ogr-fdw] 01/04: New upstream version 1.0.4

Michael Fladischer fladi at moszumanska.debian.org
Tue Oct 17 14:40:25 UTC 2017


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository pgsql-ogr-fdw.

commit 6b8e46d710780c099f900ee2128bd61e164434c4
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Tue Oct 17 15:36:15 2017 +0200

    New upstream version 1.0.4
---
 .editorconfig          |  16 +++
 .gitignore             |   2 +
 .travis.yml            |  13 ++-
 README.md              |   4 +-
 data/no_geom_apost.csv |   5 +
 input/import.source    |  44 ++++++++-
 input/pgsql.source     |  32 +++---
 ogr_fdw.c              | 262 +++++++++++++++++++++++++------------------------
 ogr_fdw_common.c       |  10 +-
 ogr_fdw_info.c         |  88 ++++++++---------
 output/import.source   |  88 ++++++++++++-----
 output/pgsql.source    |  69 +++++++------
 stringbuffer.c         |   2 +-
 13 files changed, 383 insertions(+), 252 deletions(-)

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..cea060b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+# http://editorconfig.org
+
+# top-most EditorConfig file
+root = true
+
+# these are the defaults
+[*]
+charset = utf-8
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# C files want tab indentation
+[*.{c,h}]
+indent_style = tab
+
diff --git a/.gitignore b/.gitignore
index f45101a..27e2aa0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,9 @@
 *.a
 *.so
 *.dll
+*.dylib
 *.pc
+ogr_fdw_info.dSYM/
 ogr_fdw_info*
 sql/ogr_fdw.sql
 expected/ogr_fdw.out
diff --git a/.travis.yml b/.travis.yml
index 66ed0c0..9ff02bc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,6 +17,10 @@ matrix:
       language: cpp
       env:
         - GDAL_VERSION=21
+    - os: linux
+      language: cpp
+      env:
+        - GDAL_VERSION=22
 
 before_script:
   - sudo /etc/init.d/postgresql stop
@@ -38,13 +42,16 @@ before_script:
 # Run the Postgres instance under Valgrind and collect Valgrind log
 #  - sudo -u postgres valgrind --trace-children=yes --leak-check=full /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf 2>/tmp/postgres.log &
   - psql --version
-  - if test "$GDAL_VERSION" = "11"; then sudo apt-get install libgdal-dev; fi
-  - if test "$GDAL_VERSION" = "20"; then wget http://download.osgeo.org/gdal/2.0.2/gdal-2.0.2.tar.xz; tar xJf gdal-2.0.2.tar.xz; cd gdal-2.0.2; ./configure --prefix=/usr --enable-debug --without-libtool; make -j4 >/dev/null; sudo make install >/dev/null; cd ..; gdalinfo --version; fi
-  - if test "$GDAL_VERSION" = "21"; then wget http://download.osgeo.org/gdal/2.1.0/gdal-2.1.0.tar.xz; tar xJf gdal-2.1.0.tar.xz; cd gdal-2.1.0; ./configure --prefix=/usr --enable-debug --without-libtool; make -j4 >/dev/null; sudo make install >/dev/null; cd ..; gdalinfo --version; fi
+  - if test "$GDAL_VERSION" = "11"; then sudo apt-get install libgdal1h libgdal-dev; fi
+  - if test "$GDAL_VERSION" = "20"; then wget http://download.osgeo.org/gdal/2.0.3/gdal-2.0.3.tar.xz; tar xJf gdal-2.0.3.tar.xz; cd gdal-2.0.3; ./configure --prefix=/usr --enable-debug --without-libtool; make -j4 >/dev/null; sudo make install >/dev/null; cd ..; gdalinfo --version; fi
+  - if test "$GDAL_VERSION" = "21"; then wget http://download.osgeo.org/gdal/2.1.4/gdal-2.1.4.tar.xz; tar xJf gdal-2.1.4.tar.xz; cd gdal-2.1.4; ./configure --prefix=/usr --enable-debug --without-libtool; make -j4 >/dev/null; sudo make install >/dev/null; cd ..; gdalinfo --version; fi
+  - if test "$GDAL_VERSION" = "22"; then wget http://download.osgeo.org/gdal/2.2.2/gdal-2.2.2.tar.xz; tar xJf gdal-2.2.2.tar.xz; cd gdal-2.2.2; ./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
+  - env
   - PGUSER=postgres make installcheck || (cat regression.diffs && /bin/false)
 # Small delay so that things get flushed
 #  - sleep 5
diff --git a/README.md b/README.md
index a40e0fd..8be2276 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,4 @@
-Travis:
- [![Build Status](https://secure.travis-ci.org/pramsey/pgsql-ogr-fdw.png)]
- (http://travis-ci.org/pramsey/pgsql-ogr-fdw)
+Travis: [![Build Status](https://secure.travis-ci.org/pramsey/pgsql-ogr-fdw.png)](http://travis-ci.org/pramsey/pgsql-ogr-fdw)
 
 # PostgreSQL OGR Foreign Data Wrapper
 
diff --git a/data/no_geom_apost.csv b/data/no_geom_apost.csv
new file mode 100644
index 0000000..abbe412
--- /dev/null
+++ b/data/no_geom_apost.csv
@@ -0,0 +1,5 @@
+name,age,"person's value"
+Peter,34,10.2
+John,77,3.4
+Paul,45,19.2
+Matthew,35,18.2
diff --git a/input/import.source b/input/import.source
index 5181bbf..df3bb20 100644
--- a/input/import.source
+++ b/input/import.source
@@ -1,3 +1,4 @@
+set client_min_messages=NOTICE;
 ------------------------------------------------
 
 CREATE SCHEMA imp1;
@@ -7,8 +8,15 @@ IMPORT FOREIGN SCHEMA ogr_all
   FROM SERVER myserver 
   INTO imp1;
 
-\d imp1.n2launder
-  
+SELECT  c.column_name, c.data_type, attfdwoptions 
+FROM information_schema._pg_foreign_table_columns  AS fc  
+    INNER JOIN information_schema.columns AS c ON 
+        fc.nspname = c.table_schema AND fc.relname = c.table_name 
+        AND fc.attname = c.column_name
+WHERE fc.nspname = 'imp1' and fc.relname = 'n2launder'
+ORDER BY c.ordinal_position;
+
+
 SELECT * FROM imp1.n2launder WHERE fid = 0;
 
 ------------------------------------------------
@@ -20,8 +28,38 @@ IMPORT FOREIGN SCHEMA ogr_all
   FROM SERVER myserver 
   INTO imp2;
 
-\d imp2."natural"
+SELECT  c.column_name, c.data_type, attfdwoptions 
+FROM information_schema._pg_foreign_table_columns  AS fc  
+    INNER JOIN information_schema.columns AS c ON 
+        fc.nspname = c.table_schema AND fc.relname = c.table_name 
+        AND fc.attname = c.column_name
+WHERE fc.nspname = 'imp2' and fc.relname = 'natural'
+ORDER BY c.ordinal_position;
 
 SELECT "natural" FROM imp2."natural";
 
 ------------------------------------------------
+CREATE SERVER svr_test_apost
+  FOREIGN DATA WRAPPER ogr_fdw
+  OPTIONS (
+    datasource '@abs_srcdir@/data/no_geom_apost.csv',
+    format 'CSV' );
+
+CREATE SCHEMA imp3;
+
+IMPORT FOREIGN SCHEMA ogr_all 
+  LIMIT TO (no_geom_apost) 
+  FROM SERVER svr_test_apost
+  INTO imp3;
+
+SELECT  c.column_name, c.data_type, attfdwoptions 
+FROM information_schema._pg_foreign_table_columns  AS fc  
+    INNER JOIN information_schema.columns AS c ON 
+        fc.nspname = c.table_schema AND fc.relname = c.table_name 
+        AND fc.attname = c.column_name
+WHERE fc.nspname = 'imp3' and fc.relname = 'no_geom_apost'
+ORDER BY c.ordinal_position;
+
+SELECT * FROM imp3.no_geom_apost;
+
+------------------------------------------------
diff --git a/input/pgsql.source b/input/pgsql.source
index b0f8d91..3f4d8f9 100644
--- a/input/pgsql.source
+++ b/input/pgsql.source
@@ -9,6 +9,7 @@ CREATE TABLE bytea_local (
   geom bytea,
   name varchar,
   age bigint,
+  size integer,
   value float8,
   num numeric(6,2),
   dt date,
@@ -20,10 +21,12 @@ CREATE TABLE bytea_local (
 
 ----------------------------------------------------------------------
 
-INSERT INTO bytea_local (name, geom, age, value, num, dt, tm, dttm, varch, yn) 
-  VALUES ('Jim', '14232'::bytea, 23, 4.3, 5.5, '2010-10-10'::date, '13:23:21'::time, '2010-10-10 13:23:21'::timestamp, 'this', 'y' );
-INSERT INTO bytea_local (name, geom, age, value, num, dt, tm, dttm, varch, yn) 
-  VALUES ('Marvin', '55555'::bytea, 34, 5.4, 10.13, '2011-11-11'::date, '15:21:45'::time, '2011-11-11 15:21:45'::timestamp, 'that', 'n' );
+INSERT INTO bytea_local (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+  VALUES ('Jim', '14232'::bytea, 23, 1, 4.3, 5.5, '2010-10-10'::date, '13:23:21'::time, '2010-10-10 13:23:21'::timestamp, 'this', 'y' );
+INSERT INTO bytea_local (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+  VALUES ('Marvin', '55555'::bytea, 34, 2, 5.4, 10.13, '2011-11-11'::date, '15:21:45'::time, '2011-11-11 15:21:45'::timestamp, 'that', 'n' );
+INSERT INTO bytea_local (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+  VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
 ----------------------------------------------------------------------
 
@@ -32,6 +35,7 @@ CREATE FOREIGN TABLE bytea_fdw (
   geom bytea,
   name varchar,
   age bigint,
+  size integer,
   value float8,
   num numeric(6,2),
   dt date,
@@ -41,7 +45,7 @@ CREATE FOREIGN TABLE bytea_fdw (
   yn char
 ) SERVER pgserver OPTIONS (layer 'bytea_local');
 
-SELECT fid, name, geom, age, value, num, dt, tm, dttm, varch, yn FROM bytea_fdw;
+SELECT fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn FROM bytea_fdw;
 
 SELECT a.name, b.name 
   FROM bytea_local a 
@@ -49,18 +53,18 @@ SELECT a.name, b.name
   USING (fid);
 
 EXPLAIN VERBOSE 
-  SELECT fid, name, geom, age, value, num, dt, tm, dttm, varch, yn 
+  SELECT fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn
   FROM bytea_fdw;
 
 ----------------------------------------------------------------------
 
-INSERT INTO bytea_fdw (name, geom, age, value, num, dt, tm, dttm, varch, yn) 
-VALUES ('Margaret', '2222'::bytea, 12, 1.4, 19.13, '2001-11-23'::date, '9:12:34'::time, '2001-02-11 09:23:11'::timestamp, 'them', 'y' ) 
-RETURNING fid, name, geom, age, value, num, dt, tm, dttm, varch, yn;
+INSERT INTO bytea_fdw (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+VALUES ('Margaret', '2222'::bytea, 12, 5, 1.4, 19.13, '2001-11-23'::date, '9:12:34'::time, '2001-02-11 09:23:11'::timestamp, 'them', 'y' )
+RETURNING fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn;
 
-SELECT fid, name, geom, age, value, num, dt, tm, dttm, varch, yn 
+SELECT fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn
   FROM bytea_fdw
-  WHERE fid = 3;
+  WHERE fid = 4;
 
 UPDATE bytea_fdw 
   SET name = 'Maggie', num = 45.34, yn = 'n'
@@ -68,7 +72,7 @@ UPDATE bytea_fdw
 
 SELECT fid, name, num, yn
   FROM bytea_fdw
-  WHERE fid = 3;
+  WHERE fid = 4;
 
 UPDATE bytea_fdw 
   SET dt = '2089-12-13', tm = '01:23:45'
@@ -76,10 +80,10 @@ UPDATE bytea_fdw
 
 SELECT fid, dt, tm
   FROM bytea_fdw
-  WHERE fid = 3;
+  WHERE fid = 4;
 
 DELETE FROM bytea_fdw 
-  WHERE fid = 3;
+  WHERE fid = 4;
   
 SELECT a.fid, a.name, b.name 
   FROM bytea_local a 
diff --git a/ogr_fdw.c b/ogr_fdw.c
index f76b2d4..beb4ea0 100644
--- a/ogr_fdw.c
+++ b/ogr_fdw.c
@@ -21,9 +21,17 @@
  */
 #if PG_VERSION_NUM < 90300
 #error "OGR FDW requires PostgreSQL version 9.3 or higher"
+
 #else
 
 /*
+ * Definition of stringToQualifiedNameList
+ */
+#if PG_VERSION_NUM >= 100000
+#include "utils/regproc.h"
+#endif
+
+/*
  * Local structures
  */
 #include "ogr_fdw.h"
@@ -223,7 +231,7 @@ ogr_fdw_handler(PG_FUNCTION_ARGS)
 	fdwroutine->IterateForeignScan = ogrIterateForeignScan;
 	fdwroutine->ReScanForeignScan = ogrReScanForeignScan;
 	fdwroutine->EndForeignScan = ogrEndForeignScan;
-	
+
 	/* Write support */
 	fdwroutine->AddForeignUpdateTargets = ogrAddForeignUpdateTargets;
 	fdwroutine->BeginForeignModify = ogrBeginForeignModify;
@@ -247,7 +255,7 @@ ogr_fdw_handler(PG_FUNCTION_ARGS)
  * and in FDW options validation.
  */
 static GDALDatasetH
-ogrGetDataSource(const char *source, const char *driver, bool updateable, 
+ogrGetDataSource(const char *source, const char *driver, bool updateable,
                  const char *config_options, const char *open_options)
 {
 	GDALDatasetH ogr_ds = NULL;
@@ -255,7 +263,7 @@ ogrGetDataSource(const char *source, const char *driver, bool updateable,
 	char **open_option_list = NULL;
 #if GDAL_VERSION_MAJOR >= 2
 	unsigned int open_flags = GDAL_OF_VECTOR;
-	
+
 	if ( updateable )
 		open_flags |= GDAL_OF_UPDATE;
 	else
@@ -274,7 +282,7 @@ ogrGetDataSource(const char *source, const char *driver, bool updateable,
 			value = CPLParseNameValue(*option_iter, &key);
 			if ( ! (key && value) )
 				elog(ERROR, "bad config option string '%s'", config_options);
-			
+
 			elog(DEBUG1, "GDAL config option '%s' set to '%s'", key, value);
 			CPLSetConfigOption(key, value);
 			CPLFree(key);
@@ -320,9 +328,9 @@ ogrGetDataSource(const char *source, const char *driver, bool updateable,
 #if GDAL_VERSION_MAJOR < 2
 		ogr_ds = OGROpen(source, updateable, &ogr_dr);
 #else
-		ogr_ds = GDALOpenEx(source, 
-		                    open_flags, 
-		                    NULL, 
+		ogr_ds = GDALOpenEx(source,
+		                    open_flags,
+		                    NULL,
 		                    (const char *const *)open_option_list,
 		                    NULL);
 #endif
@@ -346,7 +354,7 @@ ogrGetDataSource(const char *source, const char *driver, bool updateable,
  				 errmsg("unable to connect to data source \"%s\"", source)));
 		}
 	}
-	
+
 	CSLDestroy( open_option_list );
 
 	return ogr_ds;
@@ -367,7 +375,7 @@ ogrCanReallyCountFast(const OgrConnection *con)
 	return false;
 }
 
-static void 
+static void
 ogrEreportError(const char *errstr)
 {
 	const char *ogrerr = CPLGetLastErrorMsg();
@@ -413,7 +421,7 @@ ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
 	memset(&ogr, 0, sizeof(OgrConnection));
 	ogr.ds_updateable = OGR_UPDATEABLE_UNSET;
 	ogr.lyr_updateable = OGR_UPDATEABLE_UNSET;
-	
+
 	server = GetForeignServer(foreignserverid);
 
 	foreach(cell, server->options)
@@ -432,7 +440,7 @@ ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
 			if ( defGetBoolean(def) )
 				ogr.ds_updateable = OGR_UPDATEABLE_TRUE;
 			else
-				ogr.ds_updateable = OGR_UPDATEABLE_FALSE;				
+				ogr.ds_updateable = OGR_UPDATEABLE_FALSE;
 		}
 	}
 
@@ -444,7 +452,7 @@ ogrGetConnectionFromServer(Oid foreignserverid, bool updateable)
 			(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
 	 * connection pool will certainly make things faster.
@@ -488,7 +496,7 @@ ogrGetConnectionFromTable(Oid foreigntableid, bool updateable)
 			if ( defGetBoolean(def) )
 				ogr.lyr_updateable = OGR_UPDATEABLE_TRUE;
 			else
-				ogr.lyr_updateable = OGR_UPDATEABLE_FALSE;				
+				ogr.lyr_updateable = OGR_UPDATEABLE_FALSE;
 		}
 	}
 
@@ -641,8 +649,8 @@ getOgrFdwState(Oid foreigntableid, OgrFdwStateType state_type)
 	OgrFdwState *state;
 	size_t size;
 	bool updateable = false;
-	
-	switch (state_type) 
+
+	switch (state_type)
 	{
 		case OGR_PLAN_STATE:
 			size = sizeof(OgrFdwPlanState);
@@ -659,7 +667,7 @@ getOgrFdwState(Oid foreigntableid, OgrFdwStateType state_type)
 		default:
 			elog(ERROR, "invalid state type");
 	}
-	
+
 	state = palloc0(size);
 	state->type = state_type;
 
@@ -862,7 +870,7 @@ ogrGetForeignPlan(PlannerInfo *root,
 
 static void
 pgCanConvertToOgr(Oid pg_type, OGRFieldType ogr_type, const char *colname, const char *tblname)
-{	
+{
 	if ( pg_type == BOOLOID && ogr_type == OFTInteger )
 		return;
 	else if ( pg_type == INT2OID && ogr_type == OFTInteger )
@@ -872,13 +880,13 @@ pgCanConvertToOgr(Oid pg_type, OGRFieldType ogr_type, const char *colname, const
 	else if ( pg_type == INT8OID )
 	{
 #if GDAL_VERSION_MAJOR >= 2
-		if ( ogr_type == OFTInteger64 ) 
+		if ( ogr_type == OFTInteger64 )
 			return;
 #else
 		if ( ogr_type == OFTInteger )
 			return;
 #endif
-	} 
+	}
 	else if ( pg_type == NUMERICOID && ogr_type == OFTReal )
 		return;
 	else if ( pg_type == FLOAT4OID && ogr_type == OFTReal )
@@ -903,15 +911,13 @@ pgCanConvertToOgr(Oid pg_type, OGRFieldType ogr_type, const char *colname, const
 		return;
 	else if ( pg_type == TIMESTAMPOID && ogr_type == OFTDateTime )
 		return;
-	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))
-			));	
+			));
 }
 
 static void
@@ -989,7 +995,7 @@ ogrCanConvertToPg(OGRFieldType ogr_type, Oid pg_type, const char *colname, const
 
 static char *hexchr = "0123456789ABCDEF";
 
-static char * 
+static char *
 ogrBytesToHex(unsigned char *bytes, size_t size)
 {
 	char *hex;
@@ -1118,7 +1124,7 @@ ogrReadColumnData(OgrFdwState *state)
 		ListCell *lc;
 		OgrFieldEntry *found_entry;
 		OgrFieldEntry entry;
-		
+
 		Form_pg_attribute att_tuple = tupdesc->attrs[i];
 		OgrFdwColumn col = tbl->cols[i];
 		col.pgattnum = att_tuple->attnum;
@@ -1135,7 +1141,7 @@ ogrReadColumnData(OgrFdwState *state)
 		getTypeBinaryInputInfo(col.pgtype, &col.pgrecvfunc, &col.pgrecvioparam);
 		getTypeOutputInfo(col.pgtype, &col.pgoutputfunc, &col.pgoutputvarlena);
 		getTypeBinaryOutputInfo(col.pgtype, &col.pgsendfunc, &col.pgsendvarlena);
-			
+
 		/* Get the PgSQL column name */
 		col.pgname = get_relid_attribute_name(rel->rd_id, att_tuple->attnum);
 
@@ -1150,7 +1156,7 @@ ogrReadColumnData(OgrFdwState *state)
 			tbl->cols[i] = col;
 			continue;
 		}
-		
+
 		/* 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 == GEOMETRYOID )
@@ -1211,7 +1217,7 @@ ogrReadColumnData(OgrFdwState *state)
 	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);
@@ -1221,22 +1227,22 @@ ogrReadColumnData(OgrFdwState *state)
 	return;
 }
 
-/* 
+/*
  * ogrLookupGeometryFunctionOid
- * 
- * Find the procedure Oids of useful functions so we can call 
+ *
+ * Find the procedure Oids of useful functions so we can call
  * them later.
  */
-static Oid 
+static Oid
 ogrLookupGeometryFunctionOid(const char *proname)
 {
 	List *names;
 	FuncCandidateList clist;
-	
+
 	/* This only works if PostGIS is installed */
 	if ( GEOMETRYOID == InvalidOid || GEOMETRYOID == BYTEAOID )
 		return InvalidOid;
-	
+
 	names = stringToQualifiedNameList(proname);
 #if PG_VERSION_NUM < 90400
 	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
@@ -1260,7 +1266,7 @@ ogrLookupGeometryFunctionOid(const char *proname)
 	{
 		return clist->oid;
 	}
-	
+
 	return InvalidOid;
 }
 
@@ -1279,7 +1285,7 @@ ogrBeginForeignScan(ForeignScanState *node, int eflags)
 
 	/* Read the OGR layer definition and PgSQL foreign table definitions */
 	ogrReadColumnData(state);
-	
+
 	/* Collect the procedure Oids for PostGIS functions we might need */
 	execstate->setsridfunc = ogrLookupGeometryFunctionOid("st_setsrid");
 	execstate->typmodsridfunc = ogrLookupGeometryFunctionOid("postgis_typmod_srid");
@@ -1294,7 +1300,7 @@ ogrBeginForeignScan(ForeignScanState *node, int eflags)
 		if ( err != OGRERR_NONE )
 		{
 			const char *ogrerr = CPLGetLastErrorMsg();
-			
+
 			if ( ogrerr && ! streq(ogrerr,"") )
 			{
 				ereport(NOTICE,
@@ -1325,7 +1331,7 @@ ogrBeginForeignScan(ForeignScanState *node, int eflags)
  * Rather than explicitly try and form PgSQL datums, use the type
  * input functions, that accept cstring representations, and convert
  * to the input format. We have to lookup the right input function for
- * each column in the foreign table. 
+ * each column in the foreign table.
  */
 static Datum
 pgDatumFromCString(const char *cstr, Oid pgtype, int pgtypmod, Oid pginputfunc)
@@ -1514,35 +1520,41 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
 				nulls[i] = false;
 				values[i] = OidFunctionCall1(col.pgrecvfunc, PointerGetDatum(&strinfo));
 #endif
-				
-				/* 
+
+				/*
 				 * Apply the typmod restriction to the incoming geometry, so it's
 				 * not really a restriction anymore, it's more like a requirement.
-				 * 
+				 *
 				 * TODO: In the case where the OGR input actually *knows* what SRID
 				 * 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);
-				}			
+				}
 			}
 			else
 			{
 				elog(NOTICE, "conversion to geometry called with column type not equal to bytea or geometry");
 				ogrNullSlot(values, nulls, i);
 			}
-			
+
 		}
 		else if ( ogrvariant == OGR_FIELD )
 		{
+#if (GDAL_VERSION_MAJOR > 2 || (GDAL_VERSION_MAJOR >= 2 && GDAL_VERSION_MINOR >= 2))
+			int field_not_null = OGR_F_IsFieldSet(feat, ogrfldnum) && ! OGR_F_IsFieldNull(feat, ogrfldnum);
+#else
+			int field_not_null = OGR_F_IsFieldSet(feat, ogrfldnum);
+#endif
+
 			/* Ensure that the OGR data type fits the destination Pg column */
 			ogrCanConvertToPg(ogrfldtype, pgtype, pgname, tbl->tblname);
 
 			/* Only convert non-null fields */
-			if ( OGR_F_IsFieldSet(feat, ogrfldnum) )
+			if ( field_not_null )
 			{
 				switch(ogrfldtype)
 				{
@@ -1573,16 +1585,11 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
 						 * Handling numbers directly would be faster, but require a lot of extra code.
 						 * For now, we go via text.
 						 */
-						const char *cstr = OGR_F_GetFieldAsString(feat, ogrfldnum);
-						if ( cstr )
-						{
-							nulls[i] = false;
-							values[i] = pgDatumFromCString(cstr, pgtype, pgtypmod, pginputfunc);
-						}
-						else
-						{
-							ogrNullSlot(values, nulls, i);
-						}
+						const char *cstr_in = OGR_F_GetFieldAsString(feat, ogrfldnum);
+						size_t cstr_len = cstr_in ? strlen(cstr_in) : 0;
+						char *cstr_decoded = pg_any_to_server(cstr_in, cstr_len, PG_UTF8);
+						nulls[i] = false;
+						values[i] = pgDatumFromCString(cstr_decoded, pgtype, pgtypmod, pginputfunc);
 						break;
 					}
 					case OFTDate:
@@ -1613,7 +1620,6 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot *slot, const OgrFdwExecS
 						{
 							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;
@@ -1682,18 +1688,18 @@ ogrEwkbStripSrid(unsigned char *wkb, size_t wkbsize)
 	/* has_z = type & 0x80000000; */
 	/* has_m = type & 0x40000000; */
 	has_srid = type & 0x20000000;
-	
+
 	/* Flatten SRID flag away */
 	type &= 0xDFFFFFFF;
 	memcpy(wkb+1, &type, 4);
-	
+
 	/* If there was an SRID number embedded, overwrite it */
 	if ( has_srid )
 	{
 		newwkbsize -= 4; /* no space for SRID number needed */
 		memmove(wkb+5, wkb+9, newwkbsize - 5);
 	}
-	
+
 	return newwkbsize;
 }
 
@@ -1706,7 +1712,7 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 	TupleDesc tupdesc = slot->tts_tupleDescriptor;
 
 	int year, month, day, hour, minute, second;
-	
+
 	/* Prepare date-time part tokens for use later */
 	char txtyear[STR_MAX_LEN];
 	char txtmonth[STR_MAX_LEN];
@@ -1768,13 +1774,13 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 					elog(ERROR, "unable to handle non-integer fid");
 				}
 			}
-			continue;				
+			continue;
 		}
-		
+
 		/* 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 )
-		{			
+		{
 			OGRErr err;
 			if ( nulls[i] )
 			{
@@ -1792,13 +1798,13 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 				unsigned char *wkb = (unsigned char *)VARDATA(wkb_bytea);
 				int wkbsize = VARSIZE(wkb_bytea) - VARHDRSZ;
 				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 ( err != OGRERR_NONE )
 					return err;
-				
+
 #if GDAL_VERSION_MAJOR >= 2 || GDAL_VERSION_MINOR >= 11
 				err = OGR_F_SetGeomFieldDirectly(feat, ogrfldnum, geom);
 #else
@@ -1841,7 +1847,7 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 				case INT8OID:
 				{
 					int64 val = DatumGetInt64(values[i]);
-#if GDAL_VERSION_MAJOR >= 2					
+#if GDAL_VERSION_MAJOR >= 2
 					OGR_F_SetFieldInteger64(feat, ogrfldnum, val);
 #else
 					if ( val < INT_MAX )
@@ -1850,28 +1856,28 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 						elog(ERROR, "unable to coerce int64 into int32 OGR field");
 #endif
 					break;
-					
+
 				}
-				
+
 				case NUMERICOID:
 				{
 					Datum d;
 					float8 f;
-					
+
 					/* Convert to string */
 					d = OidFunctionCall1(pgoutputfunc, values[i]);
 					/* Convert back to float8 */
 					f = DatumGetFloat8(DirectFunctionCall1(float8in, d));
 
 					OGR_F_SetFieldDouble(feat, ogrfldnum, f);
-					break;					
+					break;
 				}
-				case FLOAT4OID:	
+				case FLOAT4OID:
 				{
 					OGR_F_SetFieldDouble(feat, ogrfldnum, DatumGetFloat4(values[i]));
 					break;
 				}
-				case FLOAT8OID:	
+				case FLOAT8OID:
 				{
 					OGR_F_SetFieldDouble(feat, ogrfldnum, DatumGetFloat8(values[i]));
 					break;
@@ -1890,7 +1896,7 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 					pfree(str);
 					break;
 				}
-				
+
 				case CHAROID: /* char */
 				{
 					char str[2];
@@ -1899,20 +1905,20 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 					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;				
+					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)));
@@ -1920,7 +1926,7 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 					OGR_F_SetFieldDateTime(feat, ogrfldnum, year, month, day, 0, 0, 0, 0);
 					break;
 				}
-				
+
 				/* TODO: handle time zones explicitly */
 				case TIMEOID:
 				case TIMETZOID:
@@ -1953,7 +1959,7 @@ ogrSlotToFeature(const TupleTableSlot *slot, OGRFeatureH feat, const OgrFdwTable
 				{
 					elog(ERROR, "OGR FDW unsupported PgSQL column type in \"%s\", %d", pgname, pgtype);
 					return OGRERR_FAILURE;
-				}				
+				}
 			}
 		}
 		/* Fill in unmatched columns with NULL */
@@ -2058,14 +2064,14 @@ ogrEndForeignScan(ForeignScanState *node)
 
 // OgrFdwTable *tbl;
 
-/* if the scanning functions above respected the targetlist, 
+/* 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
 perhaps).
 
 since we always pull complete tables in the scan functions, the
 slots below are basically full tables, in fact they include (?) one entry
-for each OGR column, even when the table does not include the column, 
+for each OGR column, even when the table does not include the column,
 just nulling out the entries that are not in the table definition
 
 it might be better to update the scan code to properly manage target lists
@@ -2086,7 +2092,7 @@ static int ogrGetFidColumn(const TupleDesc td)
 	{
 		NameData attname = td->attrs[i]->attname;
 		Oid atttypeid = td->attrs[i]->atttypid;
-		if ( (atttypeid == INT4OID || atttypeid == INT8OID) && 
+		if ( (atttypeid == INT4OID || atttypeid == INT8OID) &&
 		     strcaseeq("fid", attname.data) )
 		{
 			return i;
@@ -2097,7 +2103,7 @@ static int ogrGetFidColumn(const TupleDesc td)
 
 /*
  * ogrAddForeignUpdateTargets
- * 
+ *
  * For now we no-op this callback, as we are making the presence of
  * "fid" in the FDW table definition a requirement for any update.
  * It might be possible to add nonexisting "junk" columns? In which case
@@ -2114,14 +2120,14 @@ static void ogrAddForeignUpdateTargets (Query *parsetree,
 	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));
-	
+
 	att = tupdesc->attrs[fid_column];
-	
+
 	/* Make a Var representing the desired value */
 	var = makeVar(parsetree->resultRelation,
 			att->attnum,
@@ -2137,18 +2143,18 @@ static void ogrAddForeignUpdateTargets (Query *parsetree,
 			true);
 
 	parsetree->targetList = lappend(parsetree->targetList, tle);
-	
+
 	foreach(cell, parsetree->targetList)
 	{
 		TargetEntry *target = (TargetEntry *) lfirst(cell);
 		elog(DEBUG4, "parsetree->targetList %s:%d", target->resname, target->resno);
 	}
-	
+
 	return;
 
 }
 
-/* 
+/*
  * ogrBeginForeignModify
  * For now the only thing we'll do here is set up the connection
  * and pass that on to the next functions.
@@ -2161,7 +2167,7 @@ static void ogrBeginForeignModify (ModifyTableState *mtstate,
 {
 	Oid foreigntableid;
 	OgrFdwState *state;
-	
+
 	elog(DEBUG2, "ogrBeginForeignModify");
 
 	foreigntableid = RelationGetRelid(rinfo->ri_RelationDesc);
@@ -2169,7 +2175,7 @@ static void ogrBeginForeignModify (ModifyTableState *mtstate,
 
 	/* Read the OGR layer definition and PgSQL foreign table definitions */
 	ogrReadColumnData(state);
-	
+
 	/* Save OGR connection, etc, for later */
 	rinfo->ri_FdwState = state;
 	return;
@@ -2177,7 +2183,7 @@ static void ogrBeginForeignModify (ModifyTableState *mtstate,
 
 /*
  * ogrExecForeignUpdate
- * Find out what the fid is, get the OGR feature for that FID, 
+ * 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,
@@ -2195,12 +2201,12 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
 	int64 fid;
 	OGRFeatureH feat;
 	OGRErr err;
-	
+
 	/* Is there a fid column? */
 	fid_column = ogrGetFidColumn(td);
 	if ( fid_column < 0 )
 		elog(ERROR, "cannot find 'fid' column in table '%s'", get_rel_name(foreigntableid));
-	
+
 	/* What is the value of the FID for this record? */
 	fid_datum = slot->tts_values[fid_column];
 	fid_type = td->attrs[fid_column]->atttypid;
@@ -2211,7 +2217,7 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
 		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);
 
@@ -2223,15 +2229,15 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
 	err = ogrSlotToFeature(slot, feat, modstate->table);
 	if ( err != OGRERR_NONE )
 		ogrEreportError("failure populating OGR feature");
-	
+
 	err = OGR_L_SetFeature(modstate->ogr.lyr, feat);
 	if ( err != OGRERR_NONE )
 		ogrEreportError("failure writing back OGR feature");
-	
+
 	OGR_F_Destroy(feat);
-	
+
 	/* TODO: slot handling? what happens with RETURNING clauses? */
-	
+
 	return slot;
 }
 
@@ -2265,7 +2271,7 @@ static TupleTableSlot *ogrExecForeignUpdate (EState *estate,
 //     bool        tdhasoid;       /* tuple has oid attribute in its header */
 //     int         tdrefcount;     /* reference count, or -1 if not counting */
 // }   *TupleDesc;
-// 
+//
 
 // typedef struct ResultRelInfo
 // {
@@ -2350,7 +2356,7 @@ static TupleTableSlot *ogrExecForeignInsert (EState *estate,
 	GIntBig fid;
 
 	elog(DEBUG2, "ogrExecForeignInsert");
-	
+
 	/* Copy the data from the slot onto the feature */
 	if ( ! feat )
 		ogrEreportError("failure creating OGR feature");
@@ -2358,12 +2364,12 @@ static TupleTableSlot *ogrExecForeignInsert (EState *estate,
 	err = ogrSlotToFeature(slot, feat, modstate->table);
 	if ( err != OGRERR_NONE )
 		ogrEreportError("failure populating OGR feature");
-				
+
 	err = OGR_L_CreateFeature(modstate->ogr.lyr, feat);
 	if ( err != OGRERR_NONE )
 		ogrEreportError("failure writing OGR feature");
 
-	fid = OGR_F_GetFID(feat);	
+	fid = OGR_F_GetFID(feat);
 	OGR_F_Destroy(feat);
 
 	/* Update the FID for RETURNING slot */
@@ -2374,12 +2380,12 @@ static TupleTableSlot *ogrExecForeignInsert (EState *estate,
 		slot->tts_isnull[fid_column] = false;
 		slot->tts_nvalid++;
 	}
-	
+
 	return slot;
 }
-					
 
-					
+
+
 static TupleTableSlot *ogrExecForeignDelete (EState *estate,
 					ResultRelInfo *rinfo,
 					TupleTableSlot *slot,
@@ -2399,7 +2405,7 @@ static TupleTableSlot *ogrExecForeignDelete (EState *estate,
 	fid_column = ogrGetFidColumn(td);
 	if ( fid_column < 0 )
 		elog(ERROR, "cannot find 'fid' column in table '%s'", get_rel_name(foreigntableid));
-	
+
 	/* What is the value of the FID for this record? */
 	fid_datum = planSlot->tts_values[fid_column];
 	fid_type = td->attrs[fid_column]->atttypid;
@@ -2408,29 +2414,29 @@ static TupleTableSlot *ogrExecForeignDelete (EState *estate,
 		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)
 {
 	OgrFdwModifyState *modstate = rinfo->ri_FdwState;
-	
+
 	elog(DEBUG2, "ogrEndForeignModify");
-	
+
 	ogrFinishConnection( &(modstate->ogr) );
-	
+
 	return;
 }
-				
+
 static int ogrIsForeignRelUpdatable (Relation rel)
 {
 	static int readonly = 0;
@@ -2449,7 +2455,7 @@ static int ogrIsForeignRelUpdatable (Relation rel)
 		elog(NOTICE, "no \"fid\" column in foreign table '%s'", get_rel_name(foreigntableid));
 		return readonly;
 	}
-	
+
 	/*   Is it backed by a writable OGR driver? */
 	/*   Can we open the relation in read/write mode? */
 	ogr = ogrGetConnectionFromTable(foreigntableid, true);
@@ -2461,14 +2467,14 @@ static int ogrIsForeignRelUpdatable (Relation rel)
 
 	if ( OGR_L_TestCapability(ogr.lyr, OLCSequentialWrite) )
 		updateable |= (1 << CMD_INSERT);
-	
+
 	if ( OGR_L_TestCapability(ogr.lyr, OLCDeleteFeature) )
 		updateable |= (1 << CMD_DELETE);
-	
+
 	ogrFinishConnection(&ogr);
-		
+
 	return updateable;
-	
+
 }
 
 #if PG_VERSION_NUM >= 90500
@@ -2575,15 +2581,15 @@ ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
 			OGRErr err;
 			stringbuffer_t buf;
 			stringbuffer_init(&buf);
-			
+
 			err = ogrLayerToSQL(ogr_lyr,
-			         quote_identifier(server->servername), 
-			         launder_table_names, 
+			         quote_identifier(server->servername),
+			         launder_table_names,
 			         launder_column_names,
-			         GEOMETRYOID != BYTEAOID, 
+			         GEOMETRYOID != BYTEAOID,
 			         &buf
 			      );
-					 
+
 			if (err != OGRERR_NONE)
 			{
 				elog(ERROR, "unable to generate IMPORT SQL for '%s'", table_name);
@@ -2595,7 +2601,7 @@ ogrImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
 	}
 
 	elog(NOTICE, "Number of tables to be created %d", list_length(commands) );
-	
+
 	ogrFinishConnection(&ogr);
 
 	return commands;
diff --git a/ogr_fdw_common.c b/ogr_fdw_common.c
index 8ff6dd4..0751ff3 100644
--- a/ogr_fdw_common.c
+++ b/ogr_fdw_common.c
@@ -208,7 +208,11 @@ ogrColumnNameToSQL (const char *ogrcolname, const char *pgtype, int launder_colu
 	{
 		stringbuffer_aprintf(buf, ",\n  %s %s", quote_identifier(pgcolname), pgtype);
 		if ( ! strcaseeq(pgcolname, ogrcolname) )
-			stringbuffer_aprintf(buf, " OPTIONS (column_name '%s')", ogrcolname);
+        {
+            stringbuffer_append(buf, " OPTIONS (column_name ");
+            ogrDeparseStringLiteral(buf, ogrcolname);
+            stringbuffer_append(buf, ")");
+        }
 	}
 	else
 	{
@@ -223,7 +227,7 @@ ogrColumnNameToSQL (const char *ogrcolname, const char *pgtype, int launder_colu
 }
 
 OGRErr
-ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fwd_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)
 {
@@ -346,7 +350,7 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fwd_server,
 	 * Add server name and layer-level options.  We specify remote
 	 * layer name as option
 	 */
-	stringbuffer_aprintf(buf, "\n) SERVER %s\nOPTIONS (", quote_identifier(fwd_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");
diff --git a/ogr_fdw_info.c b/ogr_fdw_info.c
index 4a59041..2a15bf6 100644
--- a/ogr_fdw_info.c
+++ b/ogr_fdw_info.c
@@ -1,8 +1,8 @@
 /*-------------------------------------------------------------------------
  *
  * ogr_fdw_info.c
- *        Commandline utility to read an OGR layer and output a 
- *        SQL "create table" statement.
+ *		Commandline utility to read an OGR layer and output a
+ *		SQL "create table" statement.
  *
  * Copyright (c) 2014-2015, Paul Ramsey <pramsey at cleverelephant.ca>
  *
@@ -22,7 +22,7 @@ static void usage();
 static OGRErr ogrListLayers(const char *source);
 static OGRErr ogrGenerateSQL(const char *source, const char *layer);
 
-#define STR_MAX_LEN 256 
+#define STR_MAX_LEN 256
 
 
 /* Define this no-op here, so that code */
@@ -35,17 +35,17 @@ quote_identifier(const char *ident)
 	return ident;
 }
 
-	
-static void 
+
+static void
 formats()
 {
 	int i;
-	
+
 	GDALAllRegister();
-	
-    printf( "Supported Formats:\n" );
-    for ( i = 0; i < GDALGetDriverCount(); i++ )
-    {
+
+	printf( "Supported Formats:\n" );
+	for ( i = 0; i < GDALGetDriverCount(); i++ )
+	{
 		GDALDriverH ogr_dr = GDALGetDriver(i);
 		int vector = FALSE;
 		int createable = TRUE;
@@ -66,28 +66,28 @@ formats()
 			tmpl = "  -> \"%s\" (read/write)\n";
 		else
 			tmpl = "  -> \"%s\" (readonly)\n";
-		
+
 		printf(tmpl, GDALGetDriverShortName(ogr_dr));
 	}
 
 	exit(0);
 }
-	
+
 static void
 usage()
 {
 	printf(
 		"usage: ogr_fdw_info -s <ogr datasource> -l <ogr layer>\n"
-		"       ogr_fdw_info -s <ogr datasource>\n"
-		"       ogr_fdw_info -f\n"
-		"\n");	
+		"	   ogr_fdw_info -s <ogr datasource>\n"
+		"	   ogr_fdw_info -f\n"
+		"\n");
 	exit(0);
 }
 
 int
 main (int argc, char **argv)
 {
-    int ch;
+	int ch;
 	char *source = NULL, *layer = NULL;
 	OGRErr err = OGRERR_NONE;
 
@@ -115,7 +115,7 @@ main (int argc, char **argv)
 	}
 
 	if ( source && ! layer )
-	{ 
+	{
 		err = ogrListLayers(source);
 	}
 	else if ( source && layer )
@@ -126,7 +126,7 @@ main (int argc, char **argv)
 	{
 		usage();
 	}
-	
+
 	if ( err != OGRERR_NONE )
 	{
 		// printf("OGR Error: %s\n\n", CPLGetLastErrorMsg());
@@ -141,43 +141,43 @@ ogrListLayers(const char *source)
 {
 	GDALDatasetH ogr_ds = NULL;
 	int i;
-	
+
 	GDALAllRegister();
-	
+
 #if GDAL_VERSION_MAJOR < 2
 	ogr_ds = OGROpen(source, FALSE, NULL);
 #else
-	ogr_ds = GDALOpenEx(source, 
-	                    GDAL_OF_VECTOR|GDAL_OF_READONLY, 
-	                    NULL, NULL, NULL);
+	ogr_ds = GDALOpenEx(source,
+						GDAL_OF_VECTOR|GDAL_OF_READONLY,
+						NULL, NULL, NULL);
 #endif
-	
+
 	if ( ! ogr_ds )
 	{
-		CPLError(CE_Failure, CPLE_AppDefined, "Could not conect to source '%s'", source);
-		return OGRERR_FAILURE; 
+		CPLError(CE_Failure, CPLE_AppDefined, "Could not connect to source '%s'", source);
+		return OGRERR_FAILURE;
 	}
 
 	printf("Layers:\n");
 	for ( i = 0; i < GDALDatasetGetLayerCount(ogr_ds); i++ )
 	{
 		OGRLayerH ogr_lyr = GDALDatasetGetLayer(ogr_ds, i);
-		if ( ! ogr_lyr ) 
+		if ( ! ogr_lyr )
 		{
 			return OGRERR_FAILURE;
 		}
 		printf("  %s\n", OGR_L_GetName(ogr_lyr));
 	}
 	printf("\n");
-	
+
 	GDALClose(ogr_ds);
-	
+
 	return OGRERR_NONE;
 }
 
 static OGRErr
 ogrGenerateSQL(const char *source, const char *layer)
-{	
+{
 	OGRErr err;
 	GDALDatasetH ogr_ds = NULL;
 	GDALDriverH ogr_dr = NULL;
@@ -186,19 +186,19 @@ ogrGenerateSQL(const char *source, const char *layer)
 	stringbuffer_t buf;
 
 	GDALAllRegister();
-	
+
 #if GDAL_VERSION_MAJOR < 2
-	ogr_ds = OGROpen(source, FALSE, &ogr_dr);			
+	ogr_ds = OGROpen(source, FALSE, &ogr_dr);
 #else
-	ogr_ds = GDALOpenEx(source, 
-	                    GDAL_OF_VECTOR|GDAL_OF_READONLY, 
-	                    NULL, NULL, NULL);
+	ogr_ds = GDALOpenEx(source,
+						GDAL_OF_VECTOR|GDAL_OF_READONLY,
+						NULL, NULL, NULL);
 #endif
 
 	if ( ! ogr_ds )
 	{
 		CPLError(CE_Failure, CPLE_AppDefined, "Could not connect to source '%s'", source);
-		return OGRERR_FAILURE; 
+		return OGRERR_FAILURE;
 	}
 
 	if ( ! ogr_dr )
@@ -211,32 +211,32 @@ ogrGenerateSQL(const char *source, const char *layer)
 	if ( ! ogr_lyr )
 	{
 		CPLError(CE_Failure, CPLE_AppDefined, "Could not find layer '%s' in source '%s'", layer, source);
-		return OGRERR_FAILURE; 
+		return OGRERR_FAILURE;
 	}
 
 	/* Output SERVER definition */
-	printf("\nCREATE SERVER %s\n" 
+	printf("\nCREATE SERVER %s\n"
 		"  FOREIGN DATA WRAPPER ogr_fdw\n"
 		"  OPTIONS (\n"
-		"    datasource '%s',\n"
-		"    format '%s' );\n",
+		"	datasource '%s',\n"
+		"	format '%s' );\n",
 		server_name, source, GDALGetDriverShortName(ogr_dr));
 
 	stringbuffer_init(&buf);
-	err = ogrLayerToSQL(ogr_lyr, 
-			server_name, 
+	err = ogrLayerToSQL(ogr_lyr,
+			server_name,
 			TRUE, /* launder table names */
 			TRUE, /* launder column names */
 			TRUE, /* use postgis geometry */
 			&buf);
-	
+
 	GDALClose(ogr_ds);
 
 	if ( err != OGRERR_NONE )
 	{
 		return err;
 	}
-	
+
 	printf("\n%s\n", stringbuffer_getstring(&buf));
 	stringbuffer_release(&buf);
 	return OGRERR_NONE;
diff --git a/output/import.source b/output/import.source
index a43baae..b24996a 100644
--- a/output/import.source
+++ b/output/import.source
@@ -1,3 +1,4 @@
+set client_min_messages=NOTICE;
 ------------------------------------------------
 CREATE SCHEMA imp1;
 IMPORT FOREIGN SCHEMA ogr_all 
@@ -5,20 +6,23 @@ IMPORT FOREIGN SCHEMA ogr_all
   FROM SERVER myserver 
   INTO imp1;
 NOTICE:  Number of tables to be created 1
-\d imp1.n2launder
-                    Foreign table "imp1.n2launder"
-  Column   |       Type        | Modifiers |        FDW Options        
------------+-------------------+-----------+---------------------------
- fid       | bigint            |           | 
- geom      | bytea             |           | 
- n2ame     | character varying |           | (column_name '2ame')
- age       | integer           |           | 
- height    | real              |           | 
- b_rthdate | date              |           | (column_name 'b-rthdate')
-Server: myserver
-FDW Options: (layer '2launder')
+SELECT  c.column_name, c.data_type, attfdwoptions 
+FROM information_schema._pg_foreign_table_columns  AS fc  
+    INNER JOIN information_schema.columns AS c ON 
+        fc.nspname = c.table_schema AND fc.relname = c.table_name 
+        AND fc.attname = c.column_name
+WHERE fc.nspname = 'imp1' and fc.relname = 'n2launder'
+ORDER BY c.ordinal_position;
+ column_name |     data_type     |      attfdwoptions      
+-------------+-------------------+-------------------------
+ fid         | bigint            | 
+ geom        | bytea             | 
+ n2ame       | character varying | {column_name=2ame}
+ age         | integer           | 
+ height      | real              | 
+ b_rthdate   | date              | {column_name=b-rthdate}
+(6 rows)
 
-  
 SELECT * FROM imp1.n2launder WHERE fid = 0;
  fid |                     geom                     | n2ame | age | height | b_rthdate  
 -----+----------------------------------------------+-------+-----+--------+------------
@@ -32,15 +36,19 @@ IMPORT FOREIGN SCHEMA ogr_all
   FROM SERVER myserver 
   INTO imp2;
 NOTICE:  Number of tables to be created 1
-\d imp2."natural"
-             Foreign table "imp2.natural"
- Column  |       Type        | Modifiers | FDW Options 
----------+-------------------+-----------+-------------
- fid     | bigint            |           | 
- id      | real              |           | 
- natural | character varying |           | 
-Server: myserver
-FDW Options: (layer 'natural')
+SELECT  c.column_name, c.data_type, attfdwoptions 
+FROM information_schema._pg_foreign_table_columns  AS fc  
+    INNER JOIN information_schema.columns AS c ON 
+        fc.nspname = c.table_schema AND fc.relname = c.table_name 
+        AND fc.attname = c.column_name
+WHERE fc.nspname = 'imp2' and fc.relname = 'natural'
+ORDER BY c.ordinal_position;
+ column_name |     data_type     | attfdwoptions 
+-------------+-------------------+---------------
+ fid         | bigint            | 
+ id          | real              | 
+ natural     | character varying | 
+(3 rows)
 
 SELECT "natural" FROM imp2."natural";
  natural 
@@ -50,3 +58,39 @@ SELECT "natural" FROM imp2."natural";
 (2 rows)
 
 ------------------------------------------------
+CREATE SERVER svr_test_apost
+  FOREIGN DATA WRAPPER ogr_fdw
+  OPTIONS (
+    datasource '@abs_srcdir@/data/no_geom_apost.csv',
+    format 'CSV' );
+CREATE SCHEMA imp3;
+IMPORT FOREIGN SCHEMA ogr_all 
+  LIMIT TO (no_geom_apost) 
+  FROM SERVER svr_test_apost
+  INTO imp3;
+NOTICE:  Number of tables to be created 1
+SELECT  c.column_name, c.data_type, attfdwoptions 
+FROM information_schema._pg_foreign_table_columns  AS fc  
+    INNER JOIN information_schema.columns AS c ON 
+        fc.nspname = c.table_schema AND fc.relname = c.table_name 
+        AND fc.attname = c.column_name
+WHERE fc.nspname = 'imp3' and fc.relname = 'no_geom_apost'
+ORDER BY c.ordinal_position;
+  column_name   |     data_type     |         attfdwoptions          
+----------------+-------------------+--------------------------------
+ fid            | bigint            | 
+ name           | character varying | 
+ age            | character varying | 
+ person_s_value | character varying | {"column_name=person's value"}
+(4 rows)
+
+SELECT * FROM imp3.no_geom_apost;
+ fid |  name   | age | person_s_value 
+-----+---------+-----+----------------
+   1 | Peter   | 34  | 10.2
+   2 | John    | 77  | 3.4
+   3 | Paul    | 45  | 19.2
+   4 | Matthew | 35  | 18.2
+(4 rows)
+
+------------------------------------------------
diff --git a/output/pgsql.source b/output/pgsql.source
index 8843998..dec6f42 100644
--- a/output/pgsql.source
+++ b/output/pgsql.source
@@ -9,6 +9,7 @@ CREATE TABLE bytea_local (
   geom bytea,
   name varchar,
   age bigint,
+  size integer,
   value float8,
   num numeric(6,2),
   dt date,
@@ -18,16 +19,19 @@ CREATE TABLE bytea_local (
   yn char
 );
 ----------------------------------------------------------------------
-INSERT INTO bytea_local (name, geom, age, value, num, dt, tm, dttm, varch, yn) 
-  VALUES ('Jim', '14232'::bytea, 23, 4.3, 5.5, '2010-10-10'::date, '13:23:21'::time, '2010-10-10 13:23:21'::timestamp, 'this', 'y' );
-INSERT INTO bytea_local (name, geom, age, value, num, dt, tm, dttm, varch, yn) 
-  VALUES ('Marvin', '55555'::bytea, 34, 5.4, 10.13, '2011-11-11'::date, '15:21:45'::time, '2011-11-11 15:21:45'::timestamp, 'that', 'n' );
+INSERT INTO bytea_local (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+  VALUES ('Jim', '14232'::bytea, 23, 1, 4.3, 5.5, '2010-10-10'::date, '13:23:21'::time, '2010-10-10 13:23:21'::timestamp, 'this', 'y' );
+INSERT INTO bytea_local (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+  VALUES ('Marvin', '55555'::bytea, 34, 2, 5.4, 10.13, '2011-11-11'::date, '15:21:45'::time, '2011-11-11 15:21:45'::timestamp, 'that', 'n' );
+INSERT INTO bytea_local (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+  VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 ----------------------------------------------------------------------
 CREATE FOREIGN TABLE bytea_fdw (
   fid integer,
   geom bytea,
   name varchar,
   age bigint,
+  size integer,
   value float8,
   num numeric(6,2),
   dt date,
@@ -36,12 +40,13 @@ CREATE FOREIGN TABLE bytea_fdw (
   varch char(8),
   yn char
 ) SERVER pgserver OPTIONS (layer 'bytea_local');
-SELECT fid, name, geom, age, value, num, dt, tm, dttm, varch, yn FROM bytea_fdw;
- fid |  name  |     geom     | age | value |  num  |     dt     |    tm    |           dttm           |  varch   | yn 
------+--------+--------------+-----+-------+-------+------------+----------+--------------------------+----------+----
-   1 | Jim    | \x3134323332 |  23 |   4.3 |  5.50 | 10-10-2010 | 13:23:21 | Sun Oct 10 13:23:21 2010 | this     | y
-   2 | Marvin | \x3535353535 |  34 |   5.4 | 10.13 | 11-11-2011 | 15:21:45 | Fri Nov 11 15:21:45 2011 | that     | n
-(2 rows)
+SELECT fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn FROM bytea_fdw;
+ fid |  name  |     geom     | age | size | value |  num  |     dt     |    tm    |           dttm           |  varch   | yn 
+-----+--------+--------------+-----+------+-------+-------+------------+----------+--------------------------+----------+----
+   1 | Jim    | \x3134323332 |  23 |    1 |   4.3 |  5.50 | 10-10-2010 | 13:23:21 | Sun Oct 10 13:23:21 2010 | this     | y
+   2 | Marvin | \x3535353535 |  34 |    2 |   5.4 | 10.13 | 11-11-2011 | 15:21:45 | Fri Nov 11 15:21:45 2011 | that     | n
+   3 |        |              |     |      |       |       |            |          |                          |          | 
+(3 rows)
 
 SELECT a.name, b.name 
   FROM bytea_local a 
@@ -51,32 +56,33 @@ SELECT a.name, b.name
 --------+--------
  Jim    | Jim
  Marvin | Marvin
-(2 rows)
+        | 
+(3 rows)
 
 EXPLAIN VERBOSE 
-  SELECT fid, name, geom, age, value, num, dt, tm, dttm, varch, yn 
+  SELECT fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn
   FROM bytea_fdw;
                                  QUERY PLAN                                  
 -----------------------------------------------------------------------------
- Foreign Scan on public.bytea_fdw  (cost=25.00..1025.00 rows=1000 width=162)
-   Output: fid, name, geom, age, value, num, dt, tm, dttm, varch, yn
+ Foreign Scan on public.bytea_fdw  (cost=25.00..1025.00 rows=1000 width=166)
+   Output: fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn
 (2 rows)
 
 ----------------------------------------------------------------------
-INSERT INTO bytea_fdw (name, geom, age, value, num, dt, tm, dttm, varch, yn) 
-VALUES ('Margaret', '2222'::bytea, 12, 1.4, 19.13, '2001-11-23'::date, '9:12:34'::time, '2001-02-11 09:23:11'::timestamp, 'them', 'y' ) 
-RETURNING fid, name, geom, age, value, num, dt, tm, dttm, varch, yn;
- fid |   name   |    geom    | age | value |  num  |     dt     |    tm    |           dttm           |  varch   | yn 
------+----------+------------+-----+-------+-------+------------+----------+--------------------------+----------+----
-   3 | Margaret | \x32323232 |  12 |   1.4 | 19.13 | 11-23-2001 | 09:12:34 | Sun Feb 11 09:23:11 2001 | them     | y
+INSERT INTO bytea_fdw (name, geom, age, size, value, num, dt, tm, dttm, varch, yn)
+VALUES ('Margaret', '2222'::bytea, 12, 5, 1.4, 19.13, '2001-11-23'::date, '9:12:34'::time, '2001-02-11 09:23:11'::timestamp, 'them', 'y' )
+RETURNING fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn;
+ fid |   name   |    geom    | age | size | value |  num  |     dt     |    tm    |           dttm           |  varch   | yn 
+-----+----------+------------+-----+------+-------+-------+------------+----------+--------------------------+----------+----
+   4 | Margaret | \x32323232 |  12 |    5 |   1.4 | 19.13 | 11-23-2001 | 09:12:34 | Sun Feb 11 09:23:11 2001 | them     | y
 (1 row)
 
-SELECT fid, name, geom, age, value, num, dt, tm, dttm, varch, yn 
+SELECT fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn
   FROM bytea_fdw
-  WHERE fid = 3;
- fid |   name   |    geom    | age | value |  num  |     dt     |    tm    |           dttm           |  varch   | yn 
------+----------+------------+-----+-------+-------+------------+----------+--------------------------+----------+----
-   3 | Margaret | \x32323232 |  12 |   1.4 | 19.13 | 11-23-2001 | 09:12:34 | Sun Feb 11 09:23:11 2001 | them     | y
+  WHERE fid = 4;
+ fid |   name   |    geom    | age | size | value |  num  |     dt     |    tm    |           dttm           |  varch   | yn 
+-----+----------+------------+-----+------+-------+-------+------------+----------+--------------------------+----------+----
+   4 | Margaret | \x32323232 |  12 |    5 |   1.4 | 19.13 | 11-23-2001 | 09:12:34 | Sun Feb 11 09:23:11 2001 | them     | y
 (1 row)
 
 UPDATE bytea_fdw 
@@ -84,10 +90,10 @@ UPDATE bytea_fdw
   WHERE age = 12;
 SELECT fid, name, num, yn
   FROM bytea_fdw
-  WHERE fid = 3;
+  WHERE fid = 4;
  fid |  name  |  num  | yn 
 -----+--------+-------+----
-   3 | Maggie | 45.34 | n
+   4 | Maggie | 45.34 | n
 (1 row)
 
 UPDATE bytea_fdw 
@@ -95,14 +101,14 @@ UPDATE bytea_fdw
   WHERE num = 45.34;
 SELECT fid, dt, tm
   FROM bytea_fdw
-  WHERE fid = 3;
+  WHERE fid = 4;
  fid |     dt     |    tm    
 -----+------------+----------
-   3 | 12-13-2089 | 01:23:45
+   4 | 12-13-2089 | 01:23:45
 (1 row)
 
 DELETE FROM bytea_fdw 
-  WHERE fid = 3;
+  WHERE fid = 4;
   
 SELECT a.fid, a.name, b.name 
   FROM bytea_local a 
@@ -112,6 +118,7 @@ SELECT a.fid, a.name, b.name
 -----+--------+--------
    1 | Jim    | Jim
    2 | Marvin | Marvin
-(2 rows)
+   3 |        | 
+(3 rows)
 
   
diff --git a/stringbuffer.c b/stringbuffer.c
index f1a30d8..ac75155 100644
--- a/stringbuffer.c
+++ b/stringbuffer.c
@@ -141,7 +141,7 @@ stringbuffer_append(stringbuffer_t *s, const char *a)
 void 
 stringbuffer_append_char(stringbuffer_t *s, char c)
 {
-	stringbuffer_makeroom(s, 1);
+	stringbuffer_makeroom(s, 2); /* space for char + null terminator */
 	*(s->str_end) = c; /* add char */
 	s->str_end += 1;
 	*(s->str_end) = 0; /* null terminate */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pgsql-ogr-fdw.git



More information about the Pkg-grass-devel mailing list