[Git][debian-gis-team/pgsql-ogr-fdw][master] 5 commits: New upstream version 1.1.0

Bas Couwenberg gitlab at salsa.debian.org
Tue Feb 2 05:05:10 GMT 2021



Bas Couwenberg pushed to branch master at Debian GIS Project / pgsql-ogr-fdw


Commits:
1cae9c47 by Bas Couwenberg at 2021-02-02T05:53:01+01:00
New upstream version 1.1.0
- - - - -
b647a701 by Bas Couwenberg at 2021-02-02T05:53:02+01:00
Update upstream source from tag 'upstream/1.1.0'

Update to upstream version '1.1.0'
with Debian dir f3c6ee650fb9c0231b6adbfa41821a5cb1ae9337
- - - - -
e2a9070f by Bas Couwenberg at 2021-02-02T05:56:51+01:00
New upstream release.

- - - - -
2db8a9b4 by Bas Couwenberg at 2021-02-02T05:57:50+01:00
Update copyright file.

- - - - -
ecac22a4 by Bas Couwenberg at 2021-02-02T05:58:11+01:00
Refresh patches.

- - - - -


21 changed files:

- META.json
- Makefile
- README.md
- debian/changelog
- debian/copyright
- debian/patches/hardingflags.patch
- debian/patches/install.patch
- input/file.source
- input/pgsql.source
- + ogr_fdw--1.0--1.1.sql
- ogr_fdw--1.0.sql → ogr_fdw--1.1.sql
- ogr_fdw.c
- ogr_fdw.control
- ogr_fdw.h
- ogr_fdw_common.c
- ogr_fdw_common.h
- ogr_fdw_deparse.c
- + ogr_fdw_func.c
- ogr_fdw_info.c
- output/file.source
- output/pgsql.source


Changes:

=====================================
META.json
=====================================
@@ -2,7 +2,7 @@
    "name": "ogr_fdw",
    "abstract": "OGR foreign data wrapper",
    "description": "OGR FDW allows you to connect to any OGR supported data source.",
-   "version": "1.0.9",
+   "version": "1.1.0",
    "maintainer": [
       "Paul Ramsey <pramsey at cleverelephant.ca>"
    ],
@@ -21,9 +21,9 @@
    },
    "provides": {
      "ogr_fdw": {
-       "file": "ogr_fdw--1.0.sql",
+       "file": "ogr_fdw--1.1.sql",
        "docfile": "README.md",
-       "version": "1.0.9",
+       "version": "1.1.0",
        "abstract": "OGR FDW wrapper"
      }
    },


=====================================
Makefile
=====================================
@@ -1,9 +1,18 @@
 # ogr_fdw/Makefile
 
 MODULE_big = ogr_fdw
-OBJS = ogr_fdw.o ogr_fdw_deparse.o ogr_fdw_common.o stringbuffer_pg.o
+
+OBJS = \
+	ogr_fdw.o \
+	ogr_fdw_deparse.o \
+	ogr_fdw_common.o \
+	ogr_fdw_func.o \
+	stringbuffer_pg.o
+
 EXTENSION = ogr_fdw
-DATA = ogr_fdw--1.0.sql
+DATA = \
+	ogr_fdw--1.0--1.1.sql \
+	ogr_fdw--1.1.sql
 
 REGRESS = ogr_fdw
 


=====================================
README.md
=====================================
@@ -11,7 +11,7 @@ OGR is the **vector** half of the [GDAL](http://www.gdal.org/) spatial data acce
 This implementation currently has the following limitations:
 
 * **PostgreSQL 9.3 or higher.** This wrapper does not support the FDW implementations in older versions of PostgreSQL.
-* **Limited non-spatial query restrictions are pushed down to OGR.** OGR only supports a minimal set of SQL operators (>, <, <=, >=, =).
+* **Limited non-spatial query restrictions are pushed down to OGR.** OGR only supports a [minimal set](https://gdal.org/user/ogr_sql_dialect.html) of SQL operators (>, <, <=, >=, =).
 * **Only bounding box filters (&&) are pushed down.** Spatial filtering is possible, but only bounding boxes, and only using the && operator.
 * **OGR connections every time** Rather than pooling OGR connections, each query makes (and disposes of) **two** new ones, which seems to be the largest performance drag at the moment for restricted (small) queries.
 * **All columns are retrieved every time.** PostgreSQL foreign data wrappers don't require all columns all the time, and some efficiencies can be gained by only requesting the columns needed to fulfill a query. This would be a minimal efficiency improvement, but can be removed given some development time, since the OGR API supports returning a subset of columns.
@@ -58,20 +58,20 @@ Layers:
 
 # ogr_fdw_info -s /tmp/test -l pt_two
 
-CREATE SERVER myserver
+CREATE SERVER "myserver"
   FOREIGN DATA WRAPPER ogr_fdw
   OPTIONS (
     datasource '/tmp/test',
     format 'ESRI Shapefile' );
 
-CREATE FOREIGN TABLE pt_two (
+CREATE FOREIGN TABLE "pt_two" (
   fid integer,
-  geom geometry(Point, 4326),
-  name varchar,
-  age integer,
-  height real,
-  birthdate date )
-  SERVER myserver
+  "geom" geometry(Point, 4326),
+  "name" varchar,
+  "age" integer,
+  "height" real,
+  "birthdate" date )
+  SERVER "myserver"
   OPTIONS (layer 'pt_two');
 ```
 
@@ -200,6 +200,8 @@ Query away!
 ### PostgreSQL FDW
 
 Wraparound action! Handy for testing. Connect your database back to your database and watch the fur fly.
+This is only for testing, for best performance you should use postgres_fdw foreign data wrapper even when querying a PostGIS enabled database.
+
 ```sql
 CREATE TABLE apostles (
   fid serial primary key,
@@ -424,3 +426,38 @@ ALTER SERVER myserver_latin1
   );
 ```
 
+### Utility Functions
+
+To view the current FDW and GDAL version.
+
+```sql
+SELECT ogr_fdw_version();
+```
+
+To view the drivers supported by this GDAL.
+
+```sql
+SELECT unnest(ogr_fdw_drivers());
+```
+
+
+### Character Encoding
+
+To access sources that have a non-UTF-8 encoding, you may need to specify the character encoding in your server creation line. OGR FDW uses the transcoding built into PostgreSQL, and thus supports all the [encodings that PostgreSQL does](https://www.postgresql.org/docs/current/multibyte.html#CHARSET-TABLE).
+
+```sql
+CREATE SERVER odbc_latin1
+  FOREIGN DATA WRAPPER ogr_fdw
+  OPTIONS (
+    datasource 'ODBC:username at servicename',
+    format 'ODBC',
+    character_encoding 'WIN1250'
+  );
+
+CREATE FOREIGN TABLE featuretable_fdw (
+  name text,
+  geom geometry(Point, 4326)
+)
+SERVER odbc_latin1
+  OPTIONS (layer 'featuretable');
+```


=====================================
debian/changelog
=====================================
@@ -1,11 +1,14 @@
-pgsql-ogr-fdw (1.0.12-3) UNRELEASED; urgency=medium
+pgsql-ogr-fdw (1.1.0-1) UNRELEASED; urgency=medium
 
   * Team upload.
+  * New upstream release.
   * Set PG_UPDATECONTROL=yes in rules file.
   * Bump watch file version to 4.
   * Bump Standards-Version to 4.5.1, no changes.
+  * Update copyright file.
+  * Refresh patches.
 
- -- Bas Couwenberg <sebastic at debian.org>  Tue, 03 Nov 2020 12:23:52 +0100
+ -- Bas Couwenberg <sebastic at debian.org>  Tue, 02 Feb 2021 05:56:44 +0100
 
 pgsql-ogr-fdw (1.0.12-2) unstable; urgency=medium
 


=====================================
debian/copyright
=====================================
@@ -4,7 +4,7 @@ Upstream-Contact: Paul Ramsey <pramsey at cleverelephant.ca>
 Source: https://github.com/pramsey/pgsql-ogr-fdw
 
 Files: *
-Copyright: 2014, Paul Ramsey <pramsey at cleverelephant.ca>
+Copyright: 2014, 2020, Paul Ramsey <pramsey at cleverelephant.ca>
 License: Expat
 
 Files: stringbuffer.c


=====================================
debian/patches/hardingflags.patch
=====================================
@@ -3,7 +3,7 @@ Author: Bas Couwenberg <sebastic at debian.org>
 
 --- a/Makefile
 +++ b/Makefile
-@@ -40,7 +40,7 @@ CFLAGS = $(GDAL_CFLAGS)
+@@ -49,7 +49,7 @@ CFLAGS = $(GDAL_CFLAGS)
  LIBS = $(GDAL_LIBS)
  
  ogr_fdw_info$(X): ogr_fdw_info.o ogr_fdw_common.o stringbuffer.o


=====================================
debian/patches/install.patch
=====================================
@@ -7,7 +7,7 @@ Forwarded: no
 
 --- a/Makefile
 +++ b/Makefile
-@@ -46,7 +46,7 @@ clean-exe:
+@@ -55,7 +55,7 @@ clean-exe:
  	rm -f ogr_fdw_info$(X) ogr_fdw_info.o stringbuffer.o
  
  install-exe: all


=====================================
input/file.source
=====================================
@@ -91,9 +91,28 @@ CREATE FOREIGN TABLE e_1 (
   OPTIONS ( layer 'enc' );
 
 SET client_min_messages = debug1;
-SELECT * FROM e_1 WHERE fid = 1;
+SELECT fid, name FROM e_1 WHERE fid = 1;
 SET client_min_messages = notice;
 
+------------------------------------------------
+-- Using encoding option directly
+
+CREATE SERVER myserver_latin1_direct
+  FOREIGN DATA WRAPPER ogr_fdw
+  OPTIONS (
+    datasource '@abs_srcdir@/data',
+    format 'ESRI Shapefile',
+    character_encoding 'LATIN1'
+    );
+
+CREATE FOREIGN TABLE e_2 (
+  fid integer,
+  name varchar )
+  SERVER myserver_latin1_direct
+  OPTIONS ( layer 'enc' );
+
+SELECT fid, name FROM e_2 WHERE fid = 1;
+
 ------------------------------------------------
 -- Geometryless test
 
@@ -143,7 +162,7 @@ CREATE FOREIGN TABLE cities (
 ) SERVER "fgdbserver"
 OPTIONS (layer 'Cities');
 
-SET client_min_messages = DEBUG1;
+SET client_min_messages = LOG;
 
 SELECT fid, city_name, pop1990 FROM cities WHERE pop1990 = 17710;
 SELECT fid, city_name, pop1990 FROM cities WHERE city_name = 'Williston';


=====================================
input/pgsql.source
=====================================
@@ -36,7 +36,7 @@ CREATE SERVER pgserver
     format 'PostgreSQL' );
 
 CREATE FOREIGN TABLE bytea_fdw (
-  fid integer,
+  fid bigint,
   geom bytea,
   name varchar,
   age bigint,


=====================================
ogr_fdw--1.0--1.1.sql
=====================================
@@ -0,0 +1,13 @@
+CREATE OR REPLACE FUNCTION ogr_fdw_version()
+	RETURNS text
+	AS 'MODULE_PATHNAME', 'ogr_fdw_version'
+	LANGUAGE 'c'
+	IMMUTABLE STRICT
+	PARALLEL SAFE;
+
+CREATE OR REPLACE FUNCTION ogr_fdw_drivers()
+	RETURNS text[]
+	AS 'MODULE_PATHNAME', 'ogr_fdw_drivers'
+	LANGUAGE 'c'
+	IMMUTABLE STRICT
+	PARALLEL SAFE;


=====================================
ogr_fdw--1.0.sql → ogr_fdw--1.1.sql
=====================================
@@ -1,18 +1,32 @@
-/* ogr_fdw/ogr_fdw--1.0.sql */
+/* ogr_fdw/ogr_fdw--1.1.sql */
 
 -- complain if script is sourced in psql, rather than via CREATE EXTENSION
 \echo Use "CREATE EXTENSION ogr_fdw" to load this file. \quit
 
 CREATE FUNCTION ogr_fdw_handler()
-RETURNS fdw_handler
-AS 'MODULE_PATHNAME'
-LANGUAGE 'c' STRICT;
+	RETURNS fdw_handler
+	AS 'MODULE_PATHNAME'
+	LANGUAGE 'c' STRICT;
 
 CREATE FUNCTION ogr_fdw_validator(text[], oid)
-RETURNS void
-AS 'MODULE_PATHNAME'
-LANGUAGE 'c' STRICT;
+	RETURNS void
+	AS 'MODULE_PATHNAME'
+	LANGUAGE 'c' STRICT;
 
 CREATE FOREIGN DATA WRAPPER ogr_fdw
-  HANDLER ogr_fdw_handler
-  VALIDATOR ogr_fdw_validator;
+	HANDLER ogr_fdw_handler
+	VALIDATOR ogr_fdw_validator;
+
+CREATE OR REPLACE FUNCTION ogr_fdw_version()
+	RETURNS text
+	AS 'MODULE_PATHNAME', 'ogr_fdw_version'
+	LANGUAGE 'c'
+	IMMUTABLE STRICT
+	PARALLEL SAFE;
+
+CREATE OR REPLACE FUNCTION ogr_fdw_drivers()
+	RETURNS text[]
+	AS 'MODULE_PATHNAME', 'ogr_fdw_drivers'
+	LANGUAGE 'c'
+	IMMUTABLE STRICT
+	PARALLEL SAFE;


=====================================
ogr_fdw.c
=====================================
@@ -56,6 +56,7 @@ struct OgrFdwOption
 #define OPT_CONFIG_OPTIONS "config_options"
 #define OPT_OPEN_OPTIONS "open_options"
 #define OPT_UPDATEABLE "updateable"
+#define OPT_CHAR_ENCODING "character_encoding"
 
 #define OGR_FDW_FRMT_INT64	 "%lld"
 #define OGR_FDW_CAST_INT64(x)	 (long long)(x)
@@ -66,6 +67,8 @@ struct OgrFdwOption
  * ForeignServerRelationId (CREATE SERVER options)
  * UserMappingRelationId (CREATE USER MAPPING options)
  * ForeignTableRelationId (CREATE FOREIGN TABLE options)
+ *
+ * {optname, optcontext, optrequired, optfound}
  */
 static struct OgrFdwOption valid_options[] =
 {
@@ -78,6 +81,7 @@ static struct OgrFdwOption valid_options[] =
 	{OPT_DRIVER, ForeignServerRelationId, false, false},
 	{OPT_UPDATEABLE, ForeignServerRelationId, false, false},
 	{OPT_CONFIG_OPTIONS, ForeignServerRelationId, false, false},
+	{OPT_CHAR_ENCODING, ForeignServerRelationId, false, false},
 #if GDAL_VERSION_MAJOR >= 2
 	{OPT_OPEN_OPTIONS, ForeignServerRelationId, false, false},
 #endif
@@ -542,6 +546,10 @@ ogrGetConnectionFromServer(Oid foreignserverid, OgrUpdateable updateable)
 		{
 			ogr.open_options = defGetString(def);
 		}
+		if (streq(def->defname, OPT_CHAR_ENCODING))
+		{
+			ogr.char_encoding = pg_char_to_encoding(defGetString(def));
+		}
 		if (streq(def->defname, OPT_UPDATEABLE))
 		{
 			if (defGetBoolean(def))
@@ -644,11 +652,16 @@ ogrGetConnectionFromTable(Oid foreigntableid, OgrUpdateable updateable)
 		        : errhint("Does the layer exist?")
 		    ));
 	}
-	ogr.lyr_utf8 = OGR_L_TestCapability(ogr.lyr, OLCStringsAsUTF8);
+
+	if (OGR_L_TestCapability(ogr.lyr, OLCStringsAsUTF8))
+	{
+		ogr.char_encoding = PG_UTF8;
+	}
 
 	return ogr;
 }
 
+
 /*
  * Validate the options given to a FOREIGN DATA WRAPPER, SERVER,
  * USER MAPPING or FOREIGN TABLE that uses ogr_fdw.
@@ -666,13 +679,6 @@ ogr_fdw_validator(PG_FUNCTION_ARGS)
 	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)
-	{
-		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++)
 	{
@@ -1888,9 +1894,9 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot* slot, const OgrFdwExecS
 					if (cstr_in && cstr_len > 0)
 					{
 						char* cstr_decoded;
-						if (execstate->ogr.lyr_utf8)
+						if (execstate->ogr.char_encoding)
 						{
-							cstr_decoded = pg_any_to_server(cstr_in, cstr_len, PG_UTF8);
+							cstr_decoded = pg_any_to_server(cstr_in, cstr_len, execstate->ogr.char_encoding);
 						}
 						else
 						{
@@ -1898,6 +1904,9 @@ ogrFeatureToSlot(const OGRFeatureH feat, TupleTableSlot* slot, const OgrFdwExecS
 						}
 						nulls[i] = false;
 						values[i] = pgDatumFromCString(cstr_decoded, pgtype, pgtypmod, pginputfunc);
+						/* Free cstr_decoded if it is a copy */
+						if (cstr_in != cstr_decoded)
+							pfree(cstr_decoded);
 					}
 					else
 					{
@@ -3011,9 +3020,10 @@ ogrImportForeignSchema(ImportForeignSchemaStmt* stmt, Oid serverOid)
 			stringbuffer_init(&buf);
 
 			err = ogrLayerToSQL(ogr_lyr,
-			                    quote_identifier(server->servername),
+			                    server->servername,
 			                    launder_table_names,
 			                    launder_column_names,
+			                    NULL,
 			                    ogrGetGeometryOid() != BYTEAOID,
 			                    &buf
 			                   );


=====================================
ogr_fdw.control
=====================================
@@ -1,5 +1,5 @@
 # ogr_fdw extension
 comment = 'foreign-data wrapper for GIS data access'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/ogr_fdw'
 relocatable = true


=====================================
ogr_fdw.h
=====================================
@@ -11,6 +11,8 @@
 #ifndef _OGR_FDW_H
 #define _OGR_FDW_H 1
 
+#define OGR_FDW_RELEASE_NAME "1.1"
+
 /*
  * PostgreSQL
  */
@@ -137,7 +139,7 @@ typedef struct OgrConnection
 	const char* open_options;   /* GDAL open options */
 	OgrUpdateable ds_updateable;
 	OgrUpdateable lyr_updateable;
-	bool lyr_utf8;        /* OGR layer will return UTF8 strings */
+	int char_encoding;   /* Is OGR layer UTF? Has user provided encoding open option? */
 	GDALDatasetH ds;      /* GDAL datasource handle */
 	OGRLayerH lyr;        /* OGR layer handle */
 } OgrConnection;


=====================================
ogr_fdw_common.c
=====================================
@@ -11,6 +11,7 @@
 #include "ogr_fdw_gdal.h"
 #include "ogr_fdw_common.h"
 #include "stringbuffer.h"
+#include "pg_config_manual.h"
 
 /* Prototype for function that must be defined in PostgreSQL (it is) */
 /* and in ogr_fdw_info (it is) */
@@ -52,8 +53,8 @@ void
 ogrStringLaunder(char *str)
 {
 	int i, j = 0;
-	char tmp[STR_MAX_LEN];
-	memset(tmp, 0, STR_MAX_LEN);
+	char tmp[NAMEDATALEN];
+	memset(tmp, 0, NAMEDATALEN);
 
 	for(i = 0; str[i]; i++)
 	{
@@ -79,10 +80,10 @@ ogrStringLaunder(char *str)
 		tmp[j++] = c;
 
 		/* Avoid mucking with data beyond the end of our stack-allocated strings */
-		if ( j >= STR_MAX_LEN )
-			j = STR_MAX_LEN - 1;
+		if ( j >= NAMEDATALEN - 1)
+			break;
 	}
-	strncpy(str, tmp, STR_MAX_LEN);
+	strncpy(str, tmp, NAMEDATALEN);
 
 }
 
@@ -220,10 +221,11 @@ ogrGeomTypeToPgGeomType(stringbuffer_t *buf, OGRwkbGeometryType gtype)
 static OGRErr
 ogrColumnNameToSQL (const char *ogrcolname, const char *pgtype, int launder_column_names, stringbuffer_t *buf)
 {
-	char pgcolname[STR_MAX_LEN];
-	strncpy(pgcolname, ogrcolname, STR_MAX_LEN);
+	char pgcolname[NAMEDATALEN];
+	strncpy(pgcolname, ogrcolname, NAMEDATALEN);
 	ogrStringLaunder(pgcolname);
 
+
 	if ( launder_column_names )
 	{
 		stringbuffer_aprintf(buf, ",\n  %s %s", quote_identifier(pgcolname), pgtype);
@@ -250,10 +252,11 @@ ogrColumnNameToSQL (const char *ogrcolname, const char *pgtype, int launder_colu
 OGRErr
 ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
 			   int launder_table_names, int launder_column_names,
+			   const char *fdw_table_name,
 			   int use_postgis_geometry, stringbuffer_t *buf)
 {
 	int geom_field_count, i;
-	char table_name[STR_MAX_LEN];
+	char table_name[NAMEDATALEN];
 	OGRFeatureDefnH ogr_fd = OGR_L_GetLayerDefn(ogr_lyr);
 	stringbuffer_t gbuf;
 
@@ -272,9 +275,15 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
 #endif
 
 	/* Process table name */
-	strncpy(table_name, OGR_L_GetName(ogr_lyr), STR_MAX_LEN);
-	if (launder_table_names)
-		ogrStringLaunder(table_name);
+	if (fdw_table_name == NULL) {
+		strncpy(table_name, OGR_L_GetName(ogr_lyr), NAMEDATALEN);
+
+		if (launder_table_names)
+			ogrStringLaunder(table_name);
+	}
+	else {
+		strncpy(table_name, fdw_table_name, NAMEDATALEN);
+	}
 
 	/* Create table */
 	stringbuffer_aprintf(buf, "CREATE FOREIGN TABLE %s (\n", quote_identifier(table_name));
@@ -361,9 +370,9 @@ 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];
+		char pgtype[NAMEDATALEN];
 		OGRFieldDefnH ogr_fld = OGR_FD_GetFieldDefn(ogr_fd, i);
-		ogrTypeToPgType(ogr_fld, pgtype, 128);
+		ogrTypeToPgType(ogr_fld, pgtype, sizeof(pgtype));
 		ogrColumnNameToSQL(OGR_Fld_GetNameRef(ogr_fld), pgtype, launder_column_names, buf);
 	}
 
@@ -371,7 +380,7 @@ ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fdw_server,
 	 * 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");


=====================================
ogr_fdw_common.h
=====================================
@@ -27,6 +27,7 @@ void ogrStringLaunder(char *str);
 
 OGRErr ogrLayerToSQL (const OGRLayerH ogr_lyr, const char *fwd_server,
                       int launder_table_names, int launder_column_names,
+                      const char *fdw_table_name,
                       int use_postgis_geometry, stringbuffer_t *buf);
 
 #endif /* _OGR_FDW_COMMON_H */


=====================================
ogr_fdw_deparse.c
=====================================
@@ -38,6 +38,13 @@ setStringInfoLength(StringInfo str, int len)
 	str->data[len] = '\0';
 }
 
+static void
+stringInfoReverse(StringInfo str, unsigned int len)
+{
+	if (str->len > len)
+		str->len -= len;
+}
+
 static char*
 ogrStringFromDatum(Datum datum, Oid type)
 {
@@ -331,13 +338,13 @@ ogrOperatorIsSupported(const char* opname)
 	return NULL != bsearch(&opname, ogrOperators, 10, sizeof(char*), ogrOperatorCmpFunc);
 }
 
-
 static bool ogrDeparseOpExprSpatial(OpExpr* node, OgrDeparseCtx* context)
 {
 	Expr* r_arg = lfirst(list_head(node->args));
 	Expr* l_arg = lfirst(list_tail(node->args));
-	Const* constant;
-	Var* var;
+	Expr* exprconst = NULL;
+	Const* constant = NULL;
+	Var* var = NULL;
 	OgrFdwColumn col;
 	OGRLayerH lyr;
 	OGRFeatureDefnH fdh;
@@ -353,20 +360,23 @@ static bool ogrDeparseOpExprSpatial(OpExpr* node, OgrDeparseCtx* context)
 	/* column on the other side that is from the FDW relation */
 	/* Both of those implies and OGR spatial filter can be reasonably */
 	/* set. */
-	if (nodeTag(r_arg) == T_Const && nodeTag(l_arg) == T_Var)
+	if (nodeTag(l_arg) == T_Var)
 	{
-		constant = (Const*)r_arg;
 		var = (Var*)l_arg;
+		exprconst = r_arg;
 	}
-	else if (nodeTag(l_arg) == T_Const && nodeTag(r_arg) == T_Var)
+	else if (nodeTag(r_arg) == T_Var)
 	{
-		constant = (Const*)l_arg;
 		var = (Var*)r_arg;
+		exprconst = l_arg;
 	}
-	else
+	else return false;
+
+	if (nodeTag(exprconst) == T_Const)
 	{
-		return false;
+		constant = (Const*)exprconst;
 	}
+	else return false;
 
 	/* Const isn't a geometry type? Done. */
 	if (constant->consttype != ogrGetGeometryOid() || constant->constisnull || constant->constbyval)
@@ -579,9 +589,17 @@ static bool
 ogrDeparseNullTest(NullTest* node, OgrDeparseCtx* context)
 {
 	StringInfo buf = context->buf;
+	/* Only push down simple "col IS NULL" tests */
+	if (nodeTag(node->arg) != T_Var)
+		return false;
+
+	appendStringInfoString(buf, "(");
+	if(!ogrDeparseVar((Var*)(node->arg), context))
+	{
+		stringInfoReverse(buf, 1);
+		return false;
+	}
 
-	appendStringInfoChar(buf, '(');
-	ogrDeparseExpr(node->arg, context);
 	if (node->nulltesttype == IS_NULL)
 	{
 		appendStringInfoString(buf, " IS NULL)");


=====================================
ogr_fdw_func.c
=====================================
@@ -0,0 +1,89 @@
+
+/*-------------------------------------------------------------------------
+ *
+ * ogr_fdw_func.c
+ *          Helper functions for OGR FDW
+ *
+ * Copyright (c) 2020, Paul Ramsey <pramsey at cleverelephant.ca>
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "ogr_fdw.h"
+#include "ogr_fdw_gdal.h"
+
+#include <postgres.h>
+#include <fmgr.h>
+#include <funcapi.h>
+// #include <catalog/pg_type_d.h>
+#include <utils/array.h>
+#include <utils/builtins.h>
+
+
+/**
+*/
+Datum ogr_fdw_drivers(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ogr_fdw_drivers);
+Datum ogr_fdw_drivers(PG_FUNCTION_ARGS)
+{
+
+	/* Array building */
+	size_t arr_nelems = 0;
+	Datum *arr_elems;
+	ArrayType *arr;
+	Oid elem_type = TEXTOID;
+	int16 elem_len;
+	bool elem_byval;
+	char elem_align;
+	int num_drivers;
+
+	if (GDALGetDriverCount() <= 0)
+		GDALAllRegister();
+
+#if (GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0))
+	num_drivers = GDALGetDriverCount();
+#else
+	num_drivers = OGRGetDriverCount();
+#endif
+
+	if (num_drivers < 1)
+		PG_RETURN_NULL();
+
+ 	arr_elems = palloc0(num_drivers * sizeof(Datum));
+    get_typlenbyvalalign(elem_type, &elem_len, &elem_byval, &elem_align);
+
+	int i;
+	for (i = 0; i < num_drivers; i++) {
+#if GDAL_VERSION_MAJOR <= 1
+		OGRSFDriverH hDriver = OGRGetDriver(i);
+		text *txtName = cstring_to_text(OGR_Dr_GetName(hDriver));
+		arr_elems[arr_nelems++] = PointerGetDatum(txtName);
+#else
+		GDALDriverH hDriver = GDALGetDriver(i);
+		if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, NULL) != NULL) {
+			const char *strName = OGR_Dr_GetName(hDriver);
+			text *txtName = cstring_to_text(strName);
+			arr_elems[arr_nelems++] = PointerGetDatum(txtName);
+		}
+#endif
+	}
+
+	arr = construct_array(arr_elems, arr_nelems, elem_type, elem_len, elem_byval, elem_align);
+	PG_RETURN_ARRAYTYPE_P(arr);
+}
+
+/**
+*/
+Datum ogr_fdw_version(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ogr_fdw_version);
+Datum ogr_fdw_version(PG_FUNCTION_ARGS)
+{
+	const char *gdal_ver = GDAL_RELEASE_NAME;
+	const char *ogr_fdw_ver = OGR_FDW_RELEASE_NAME;
+	char ver_str[256];
+	snprintf(ver_str, sizeof(ver_str), "OGR_FDW=\"%s\" GDAL=\"%s\"", ogr_fdw_ver, gdal_ver);
+	text* ver_txt = cstring_to_text(ver_str);
+	PG_RETURN_TEXT_P(ver_txt);
+}
+
+


=====================================
ogr_fdw_info.c
=====================================
@@ -9,6 +9,9 @@
  *-------------------------------------------------------------------------
  */
 
+/* postgresql */
+#include "pg_config_manual.h"
+
 /* getopt */
 #include <unistd.h>
 
@@ -20,20 +23,60 @@
 
 static void usage();
 static OGRErr ogrListLayers(const char* source);
-static OGRErr ogrGenerateSQL(const char* source, const char* layer);
+static OGRErr ogrFindLayer(const char* source, int layerno, const char** layer);
+static OGRErr ogrGenerateSQL(const char* server, const char* layer, const char* table, const char* source, const char* options);
+static int reserved_word(const char* pgcolumn);
+
+static char *
+ogr_fdw_strupr(char* str)
+{
+	int i;
+  for (i = 0; i < strlen(str); i++) {
+    str[i] = toupper(str[i]);
+  }
+
+  return str;
+}
 
-#define STR_MAX_LEN 256
+static char *
+strip_spaces(char* str)
+{
+	unsigned char *cur = (unsigned char *)str;
+	unsigned char *head = cur;
+	while (*head != '\0') {
+		if (*head != ' ') {
+			*cur = *head;
+			++cur;
+		}
+		++head;
+	}
+	*cur = '\0';
 
+	return str;
+}
 
 /* Define this no-op here, so that code */
 /* in the ogr_fdw_common module works */
 const char* quote_identifier(const char* ident);
 
+char identifier[NAMEDATALEN+3];
+
 const char*
 quote_identifier(const char* ident)
 {
-	return ident;
+	int len = (int)MIN(strlen(ident), NAMEDATALEN - 1);
+
+	if (reserved_word(ident))
+	{
+		sprintf(identifier,"\"%*s\"", len, ident);
+	}
+	else
+	{
+		sprintf(identifier,"%*s", len, ident);
+	}
+  return identifier;
 }
+char config_options[STR_MAX_LEN] = {0};
 
 
 static void
@@ -84,10 +127,16 @@ 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");
+		"usage: ogr_fdw_info -s <ogr datasource> -l <ogr layer name> -i <ogr layer index (numeric)> -t <output table name> -n <output server name> -o <config options>\n"
+		"       ogr_fdw_info -s <ogr datasource>\n"
+		"usage: ogr_fdw_info -f\n"
+		"       Show what input file formats are supported.\n"
+		"\n");
+	printf(
+		"note (1): You can specify either -l (layer name) or -i (layer index) if you specify both -l will be used\n"
+		"note (2): config options are specified as a comma deliminated list without the OGR_<driver>_ prefix\n"
+		"so OGR_XLSX_HEADERS = FORCE OGR_XLSX_FIELD_TYPES = STRING would become:\n\"HEADERS = FORCE,FIELD_TYPES = STRING\""
+		"\n");
 	exit(0);
 }
 
@@ -95,7 +144,9 @@ int
 main(int argc, char** argv)
 {
 	int ch;
-	char* source = NULL, *layer = NULL;
+	char* source = NULL;
+	const char* layer = NULL, *server = NULL, *table = NULL, *options = NULL;
+	int layer_index = -1;
 	OGRErr err = OGRERR_NONE;
 
 	/* If no options are specified, display usage */
@@ -104,7 +155,7 @@ main(int argc, char** argv)
 		usage();
 	}
 
-	while ((ch = getopt(argc, argv, "h?s:l:f")) != -1)
+	while ((ch = getopt(argc, argv, "h?s:l:f:t:n:i:o:")) != -1)
 	{
 		switch (ch)
 		{
@@ -117,6 +168,18 @@ main(int argc, char** argv)
 		case 'f':
 			formats();
 			break;
+		case 't':
+			table = optarg;
+			break;
+		case 'n':
+			server = optarg;
+			break;
+		case 'i':
+			layer_index = atoi(optarg) - 1;
+			break;
+		case 'o':
+			options = optarg;
+			break;
 		case '?':
 		case 'h':
 		default:
@@ -125,13 +188,21 @@ main(int argc, char** argv)
 		}
 	}
 
-	if (source && ! layer)
+	if (source && ! layer && layer_index == -1)
 	{
 		err = ogrListLayers(source);
 	}
-	else if (source && layer)
+	else if (source && (layer || layer_index > -1))
 	{
-		err = ogrGenerateSQL(source, layer);
+		if (! layer)
+		{
+			err = ogrFindLayer(source, layer_index, &layer);
+		}
+
+		if (err == OGRERR_NONE)
+		{
+			err = ogrGenerateSQL(server, layer, table, source, options);
+		}
 	}
 	else if (! source && ! layer)
 	{
@@ -140,7 +211,8 @@ main(int argc, char** argv)
 
 	if (err != OGRERR_NONE)
 	{
-		// printf("OGR Error: %s\n\n", CPLGetLastErrorMsg());
+		printf("OGR Error: %s\n\n", CPLGetLastErrorMsg());
+		exit(1);
 	}
 
 	OGRCleanupAll();
@@ -168,6 +240,7 @@ ogrListLayers(const char* source)
 		CPLError(CE_Failure, CPLE_AppDefined, "Could not connect to source '%s'", source);
 		return OGRERR_FAILURE;
 	}
+	printf("Format: %s\n\n", GDALGetDriverShortName(GDALGetDatasetDriver(ogr_ds)));
 
 	printf("Layers:\n");
 	for (i = 0; i < GDALDatasetGetLayerCount(ogr_ds); i++)
@@ -187,15 +260,18 @@ ogrListLayers(const char* source)
 }
 
 static OGRErr
-ogrGenerateSQL(const char* source, const char* layer)
+ogrGenerateSQL(const char* server, const char* layer, const char* table, const char* source, const char* options)
 {
 	OGRErr err;
 	GDALDatasetH ogr_ds = NULL;
 	GDALDriverH ogr_dr = NULL;
 	OGRLayerH ogr_lyr = NULL;
-	char server_name[STR_MAX_LEN];
+	char server_name[NAMEDATALEN];
 	stringbuffer_t buf;
 
+	char **option_iter;
+	char **option_list;
+
 	GDALAllRegister();
 
 #if GDAL_VERSION_MAJOR < 2
@@ -213,12 +289,49 @@ ogrGenerateSQL(const char* source, const char* layer)
 	}
 
 	if (! ogr_dr)
-	{
 		ogr_dr = GDALGetDatasetDriver(ogr_ds);
+
+	strcpy(server_name, server == NULL ? "myserver" : server);
+
+	if (options != NULL) {
+		char *p;
+		char stripped_config_options[STR_MAX_LEN] = {0};
+		char option[NAMEDATALEN];
+		const char *short_name = GDALGetDriverShortName(ogr_dr);
+
+		strncpy(stripped_config_options, options, STR_MAX_LEN - 1);
+		p = strtok(strip_spaces(stripped_config_options), ",");
+
+		while (p != NULL) {
+			if (strcmp(short_name, "XLSX") == 0 || strcmp(short_name, "XLSX") == 0 || strcmp(short_name, "ODS") == 0)
+			{
+				/* Unify the handling of the options of spreadsheet file options as they are all the same except they have their
+				 * Driver Short Name included in the option
+				 */
+				sprintf(option, "OGR_%s_%s ", short_name, ogr_fdw_strupr(p));
+			}
+			else {
+				sprintf(option, "%s ", ogr_fdw_strupr(p));
+			}
+
+			strcat(config_options, option);
+			p = strtok(NULL, ",");
+		}
 	}
 
-	/* There should be a nicer way to do this */
-	strcpy(server_name, "myserver");
+	option_list = CSLTokenizeString(config_options);
+	for ( option_iter = option_list; option_iter && *option_iter; option_iter++ )
+	{
+		char *key;
+		const char *value;
+		value = CPLParseNameValue(*option_iter, &key);
+		if (! (key && value))
+			CPLError(CE_Failure, CPLE_AppDefined, "bad config option string '%s'", config_options);
+
+		CPLSetConfigOption(key, value);
+		CPLFree(key);
+	}
+	CSLDestroy( option_list );
 
 	ogr_lyr = GDALDatasetGetLayerByName(ogr_ds, layer);
 	if (! ogr_lyr)
@@ -231,15 +344,25 @@ ogrGenerateSQL(const char* source, const char* layer)
 	printf("\nCREATE SERVER %s\n"
 	       "  FOREIGN DATA WRAPPER ogr_fdw\n"
 	       "  OPTIONS (\n"
-	       "	datasource '%s',\n"
-	       "	format '%s' );\n",
-	       server_name, source, GDALGetDriverShortName(ogr_dr));
+	       "    datasource '%s',\n"
+	       "    format '%s'",
+	       quote_identifier(server_name), source, GDALGetDriverShortName(ogr_dr));
+
+	if (strlen(config_options) > 0)
+	{
+		printf(",\n    config_options '%s');\n", config_options);
+	}
+	else
+	{
+		printf(");\n");
+	}
 
 	stringbuffer_init(&buf);
 	err = ogrLayerToSQL(ogr_lyr,
 	                    server_name,
 	                    TRUE, /* launder table names */
 	                    TRUE, /* launder column names */
+	                    table,/* output table name */
 	                    TRUE, /* use postgis geometry */
 	                    &buf);
 
@@ -255,3 +378,96 @@ ogrGenerateSQL(const char* source, const char* layer)
 	return OGRERR_NONE;
 }
 
+static OGRErr
+ogrFindLayer(const char *source, int layerno, const char** layer)
+{
+	GDALDatasetH ogr_ds = NULL;
+	int i;
+	char **option_iter;
+	char **option_list;
+
+	GDALAllRegister();
+
+	option_list = CSLTokenizeString(config_options);
+	for (option_iter = option_list; option_iter && *option_iter; option_iter++)
+	{
+		char *key;
+		const char *value;
+		value = CPLParseNameValue(*option_iter, &key);
+		if (! (key && value))
+			CPLError(CE_Failure, CPLE_AppDefined, "bad config option string '%s'", config_options);
+
+		CPLSetConfigOption(key, value);
+		CPLFree(key);
+	}
+	CSLDestroy(option_list);
+
+
+	#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);
+	#endif
+
+	if (! ogr_ds)
+	{
+		CPLError(CE_Failure, CPLE_AppDefined, "Could not connect to source '%s'", source);
+		return OGRERR_FAILURE;
+	}
+
+	for (i = 0; i < GDALDatasetGetLayerCount(ogr_ds); i++)
+	{
+		if (i == layerno) {
+			OGRLayerH ogr_lyr = GDALDatasetGetLayer(ogr_ds, i);
+			if (! ogr_lyr)
+			{
+				return OGRERR_FAILURE;
+			}
+			*layer = OGR_L_GetName(ogr_lyr);
+			return OGRERR_NONE;
+		}
+	}
+
+	GDALClose(ogr_ds);
+
+	return OGRERR_FAILURE;
+}
+
+static int
+reserved_word(const char * pgcolumn)
+{
+	char* reserved[] = {
+	"all", "analyse", "analyze", "and", "any", "array", "as", "asc", "asymmetric", "authorization",
+	"binary", "both",
+	"case", "cast", "check", "collate", "collation", "column", "concurrently", "constraint", "create", "cross", "current_catalog", "current_date", "current_role",
+	"current_schema", "current_time", "current_timestamp", "current_user",
+	"default", "deferrable", "desc", "distinct", "do",
+	"else", "end", "except",
+	"false", "fetch", "for", "foreign", "freeze", "from", "full",
+	"grant", "group",
+	"having",
+	"ilike", "in", "initially", "inner", "intersect", "into", "is", "isnull",
+	"join",
+	"lateral", "leading", "left", "like", "limit", "localtime", "localtimestamp",
+	"natural", "not", "notnull", "null",
+	"offset", "on", "only", "or", "order", "outer", "overlaps",
+	"placing", "primary",
+	"references", "returning", "right",
+	"select", "session_user", "similar", "some", "symmetric",
+	"table", "tablesample", "then", "to", "trailing", "true",
+	"union", "unique", "user", "using",
+	"variadic", "verbose",
+	"when", "where", "window", "with"
+	};
+
+	int i;
+	for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); i++)
+	{
+		if (strcmp(pgcolumn, reserved[i]) == 0)
+			return 1;
+	}
+
+	return 0;
+}


=====================================
output/file.source
=====================================
@@ -102,7 +102,7 @@ CREATE FOREIGN TABLE e_1 (
   SERVER myserver_latin1
   OPTIONS ( layer 'enc' );
 SET client_min_messages = debug1;
-SELECT * FROM e_1 WHERE fid = 1;
+SELECT fid, name FROM e_1 WHERE fid = 1;
 DEBUG:  GDAL config option 'SHAPE_ENCODING' set to 'LATIN1'
 DEBUG:  OGR SQL: (fid = 1)
 DEBUG:  GDAL config option 'SHAPE_ENCODING' set to 'LATIN1'
@@ -112,6 +112,26 @@ DEBUG:  GDAL config option 'SHAPE_ENCODING' set to 'LATIN1'
 (1 row)
 
 SET client_min_messages = notice;
+------------------------------------------------
+-- Using encoding option directly
+CREATE SERVER myserver_latin1_direct
+  FOREIGN DATA WRAPPER ogr_fdw
+  OPTIONS (
+    datasource '@abs_srcdir@/data',
+    format 'ESRI Shapefile',
+    character_encoding 'LATIN1'
+    );
+CREATE FOREIGN TABLE e_2 (
+  fid integer,
+  name varchar )
+  SERVER myserver_latin1_direct
+  OPTIONS ( layer 'enc' );
+SELECT fid, name FROM e_2 WHERE fid = 1;
+ fid | name 
+-----+------
+   1 | Pàul
+(1 row)
+
 ------------------------------------------------
 -- Geometryless test
 CREATE SERVER csvserver
@@ -160,16 +180,14 @@ CREATE FOREIGN TABLE cities (
   popcat integer
 ) SERVER "fgdbserver"
 OPTIONS (layer 'Cities');
-SET client_min_messages = DEBUG1;
+SET client_min_messages = LOG;
 SELECT fid, city_name, pop1990 FROM cities WHERE pop1990 = 17710;
-DEBUG:  OGR SQL: (POP1990 = 17710)
  fid |  city_name   | pop1990 
 -----+--------------+---------
    9 | Port Angeles |   17710
 (1 row)
 
 SELECT fid, city_name, pop1990 FROM cities WHERE city_name = 'Williston';
-DEBUG:  OGR SQL: ("CITY_NAME" = 'Williston')
  fid | city_name | pop1990 
 -----+-----------+---------
    8 | Williston |   13131


=====================================
output/pgsql.source
=====================================
@@ -30,7 +30,7 @@ CREATE SERVER pgserver
     datasource 'PG:dbname=contrib_regression host=localhost',
     format 'PostgreSQL' );
 CREATE FOREIGN TABLE bytea_fdw (
-  fid integer,
+  fid bigint,
   geom bytea,
   name varchar,
   age bigint,
@@ -67,7 +67,7 @@ EXPLAIN VERBOSE
   FROM bytea_fdw;
                                  QUERY PLAN                                  
 -----------------------------------------------------------------------------
- Foreign Scan on public.bytea_fdw  (cost=25.00..1025.00 rows=1000 width=166)
+ Foreign Scan on public.bytea_fdw  (cost=25.00..1025.00 rows=1000 width=170)
    Output: fid, name, geom, age, size, value, num, dt, tm, dttm, varch, yn
 (2 rows)
 



View it on GitLab: https://salsa.debian.org/debian-gis-team/pgsql-ogr-fdw/-/compare/c1aa7e8b86b3b2138698f507f2b25e9e72d000b0...ecac22a4b8fec5d7ee5258e419aadd86933f7d40

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/pgsql-ogr-fdw/-/compare/c1aa7e8b86b3b2138698f507f2b25e9e72d000b0...ecac22a4b8fec5d7ee5258e419aadd86933f7d40
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/20210202/efede90b/attachment-0001.html>


More information about the Pkg-grass-devel mailing list