[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