[spatialite] 02/09: Imported Upstream version 4.4.0~rc0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Tue Dec 15 21:45:24 UTC 2015


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

sebastic pushed a commit to branch experimental
in repository spatialite.

commit d86ca046a4aadde8bab275f0086202d560536dfd
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Tue Dec 15 20:42:54 2015 +0100

    Imported Upstream version 4.4.0~rc0
---
 config.h.in                                        |    10 +-
 configure                                          |   218 +-
 configure.ac                                       |    56 +-
 examples/Makefile.am                               |     5 +
 examples/Makefile.in                               |     5 +-
 spatialite-sql-latest.html                         |   693 +-
 src/Makefile.am                                    |    20 +-
 src/Makefile.in                                    |    32 +-
 src/connection_cache/alloc_cache.c                 |   448 +-
 src/connection_cache/cache_aux_1.h                 |   131 +-
 src/connection_cache/generator/code_generator.c    |     7 +-
 src/cutter/Makefile.am                             |    17 +
 {examples => src/cutter}/Makefile.in               |   115 +-
 src/cutter/gaia_cutter.c                           |  7394 +++++++++++++
 src/gaiageo/gg_geodesic.c                          |    38 +-
 src/gaiageo/gg_geometries.c                        |   255 +-
 src/gaiageo/gg_geoscvt.c                           |   196 +
 src/gaiageo/gg_lwgeom.c                            |   150 +-
 src/gaiageo/gg_relations.c                         |   286 +-
 src/gaiageo/gg_relations_ext.c                     |   481 +-
 src/gaiageo/gg_shape.c                             |     9 +-
 src/gaiageo/gg_voronoj.c                           |     8 +-
 src/gaiageo/gg_xml.c                               |   360 +-
 src/geopackage/gaia_cvt_gpkg.c                     |     2 +-
 src/geopackage/gpkgAddGeometryColumn.c             |     9 +
 src/geopackage/gpkgCreateBaseTables.c              |     5 +-
 src/headers/Makefile.am                            |     9 +-
 src/headers/Makefile.in                            |    63 +-
 src/headers/spatialite.h                           |    66 +-
 src/headers/spatialite/gaia_network.h              |   587 ++
 src/headers/spatialite/gaia_topology.h             |   846 ++
 src/headers/spatialite/gg_advanced.h               |    15 +
 src/headers/spatialite/gg_formats.h                |     1 +
 src/headers/spatialite/gg_xml.h                    |    58 +-
 src/headers/spatialite/spatialite.h                |     1 +
 src/headers/spatialite_private.h                   |   304 +-
 src/shapefiles/shapefiles.c                        |    16 +-
 src/shapefiles/validator.c                         |     4 +-
 src/spatialite/Makefile.am                         |     3 +-
 src/spatialite/Makefile.in                         |    24 +-
 src/spatialite/spatialite.c                        |  2709 ++---
 src/spatialite/spatialite_init.c                   |     9 +
 src/spatialite/srid_aux.c                          |    16 +-
 src/spatialite/statistics.c                        |   107 +-
 src/spatialite/table_cloner.c                      |    24 +-
 src/spatialite/virtualknn.c                        |  1587 +++
 src/spatialite/virtualshape.c                      |    17 +-
 src/srsinit/epsg_inlined_prussian.c                |     8 +-
 src/srsinit/epsg_update/Makefile.am                |     2 +-
 src/srsinit/epsg_update/Makefile.in                |     2 +-
 src/srsinit/epsg_update/README.txt                 |    13 +
 src/srsinit/epsg_update/auto_epsg.c                |     8 +-
 src/srsinit/epsg_update/auto_epsg_ext.c            |     8 +-
 src/srsinit/epsg_update/check_srid_spatialite.sh   |   240 +
 src/topology/Makefile.am                           |    37 +
 {examples => src/topology}/Makefile.in             |   223 +-
 src/topology/gaia_auxnet.c                         |  3833 +++++++
 src/topology/gaia_auxtopo.c                        | 10507 +++++++++++++++++++
 src/topology/gaia_netstmts.c                       |   378 +
 src/topology/gaia_network.c                        |  4189 ++++++++
 src/topology/gaia_topology.c                       |  5479 ++++++++++
 src/topology/gaia_topostmts.c                      |   642 ++
 src/topology/lwn_network.c                         |  1900 ++++
 src/topology/lwn_network.h                         |   872 ++
 .../lwn_network_private.h}                         |    66 +-
 src/topology/net_callbacks.c                       |  2333 ++++
 src/topology/network_private.h                     |   214 +
 src/topology/topo_callbacks.c                      |  5299 ++++++++++
 src/topology/topology_private.h                    |   406 +
 test/000323485.gpx                                 |    43 +
 test/Gpx-sample.gpx                                |   421 +
 test/Makefile.am                                   |    22 +-
 test/Makefile.in                                   |   204 +-
 test/asprintf4win.h                                |    83 -
 test/check_bufovflw.c                              |    34 +-
 test/check_control_points.c                        |     2 +-
 test/check_create.c                                |    36 +-
 test/check_cutter.c                                |  2765 +++++
 test/check_dxf.c                                   |    11 +
 test/check_extension.c                             |    64 +-
 test/check_fdo1.c                                  |     7 +
 test/check_gaia_utf8.c                             |    16 +-
 test/check_gaia_util.c                             |   112 +-
 test/check_gpkgInsertEpsgSRID.c                    |     6 +-
 test/check_gpkgVirtual.c                           |     2 +-
 test/check_libxml2.c                               |   155 +-
 test/check_multithread.c                           |     7 +-
 test/check_network2d.c                             |  2277 ++++
 test/check_network3d.c                             |  2277 ++++
 test/check_network_log.c                           |  1028 ++
 test/check_relations_fncts.c                       |     3 +
 test/check_sql_stmt.c                              |    91 +-
 test/check_topology2d.c                            |  3073 ++++++
 test/check_topology3d.c                            |  2998 ++++++
 test/check_topoplus.c                              |  3643 +++++++
 test/check_virtualknn.c                            |   620 ++
 test/check_virtualtable1.c                         |    11 +-
 test/check_virtualtable2.c                         |   116 +-
 test/check_virtualtable3.c                         |   116 +-
 test/check_virtualtable4.c                         |    25 +-
 test/elba-ln.dbf                                   |   Bin 0 -> 650 bytes
 test/elba-ln.shp                                   |   Bin 0 -> 242300 bytes
 test/elba-ln.shx                                   |   Bin 0 -> 180 bytes
 test/elba-pg.dbf                                   |   Bin 0 -> 438 bytes
 test/elba-pg.shp                                   |   Bin 0 -> 242300 bytes
 test/elba-pg.shx                                   |   Bin 0 -> 180 bytes
 test/gpkg_test.sqlite                              |   Bin 444416 -> 444416 bytes
 test/sql_stmt_geos_tests/Makefile.am               |    34 +-
 test/sql_stmt_geos_tests/Makefile.in               |    34 +-
 test/sql_stmt_geos_tests/acuttermessage.testcase   |     7 +
 test/sql_stmt_geos_tests/createtopo1.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo10.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo12.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo13.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo14.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo15.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo16.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo17.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo18.testcase     |     7 -
 test/sql_stmt_geos_tests/createtopo2.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo3.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo4.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo5.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo6.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo7.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo8.testcase      |     7 -
 test/sql_stmt_geos_tests/createtopo9.testcase      |     7 -
 test/sql_stmt_geos_tests/cutter1.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter10.testcase         |     7 +
 test/sql_stmt_geos_tests/cutter11.testcase         |     7 +
 test/sql_stmt_geos_tests/cutter12.testcase         |     7 +
 test/sql_stmt_geos_tests/cutter13.testcase         |     7 +
 test/sql_stmt_geos_tests/cutter14.testcase         |     7 +
 test/sql_stmt_geos_tests/cutter15.testcase         |     7 +
 test/sql_stmt_geos_tests/cutter2.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter3.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter4.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter5.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter6.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter7.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter8.testcase          |     7 +
 test/sql_stmt_geos_tests/cutter9.testcase          |     7 +
 test/sql_stmt_geosadvanced_tests/Makefile.am       |    21 +-
 test/sql_stmt_geosadvanced_tests/Makefile.in       |    21 +-
 test/sql_stmt_libxml2_tests/Makefile.am            |    13 +
 test/sql_stmt_libxml2_tests/Makefile.in            |    13 +
 test/sql_stmt_libxml2_tests/isgpx1.testcase        |     8 +
 test/sql_stmt_libxml2_tests/isgpx2.testcase        |     8 +
 test/sql_stmt_libxml2_tests/isgpx3.testcase        |     8 +
 test/sql_stmt_libxml2_tests/isgpx4.testcase        |     8 +
 test/sql_stmt_libxml2_tests/isgpx5.testcase        |     8 +
 test/sql_stmt_libxml2_tests/isgpx6.testcase        |     8 +
 test/sql_stmt_libxml2_tests/isgpx7.testcase        |     8 +
 .../xmlblobgetgeometry4.testcase                   |     6 +-
 .../xmlblobgetgeometry5.testcase                   |     2 +-
 .../xmlblobmlinegpx1.testcase}                     |     7 +-
 .../xmlblobmlinegpx2.testcase}                     |     7 +-
 .../xmlblobmlinegpx3.testcase}                     |     7 +-
 .../xmlblobmlinegpx4.testcase                      |     8 +
 .../xmlblobmlinegpx5.testcase                      |     8 +
 .../xmlblobmlinegpx6.testcase                      |     8 +
 test/sql_stmt_lwgeom_20_tests/Makefile.am          |     5 +
 .../sql_stmt_lwgeom_20_tests}/Makefile.in          |    12 +-
 .../st_asx3d25.testcase                            |     0
 .../st_asx3d26.testcase                            |     0
 .../st_asx3d30.testcase                            |     0
 .../st_split8.testcase                             |     0
 test/sql_stmt_lwgeom_22_tests/Makefile.am          |   931 ++
 test/sql_stmt_lwgeom_22_tests/Makefile.in          |  1378 +++
 .../addedgemodface1.testcase                       |     7 +
 .../addedgemodface10.testcase                      |     7 +
 .../addedgemodface11.testcase                      |     7 +
 .../addedgemodface12.testcase                      |     7 +
 .../addedgemodface13.testcase                      |     7 +
 .../addedgemodface14.testcase                      |     7 +
 .../addedgemodface15.testcase                      |     7 +
 .../addedgemodface16.testcase                      |     7 +
 .../addedgemodface17.testcase                      |     7 +
 .../addedgemodface18.testcase                      |     7 +
 .../addedgemodface19.testcase                      |     7 +
 .../addedgemodface2.testcase                       |     7 +
 .../addedgemodface20.testcase                      |     7 +
 .../addedgemodface3.testcase                       |     7 +
 .../addedgemodface4.testcase                       |     7 +
 .../addedgemodface5.testcase                       |     7 +
 .../addedgemodface6.testcase                       |     7 +
 .../addedgemodface7.testcase                       |     7 +
 .../addedgemodface8.testcase                       |     7 +
 .../addedgemodface9.testcase                       |     7 +
 .../addedgenewfaces1.testcase                      |     7 +
 .../addedgenewfaces10.testcase                     |     7 +
 .../addedgenewfaces11.testcase                     |     7 +
 .../addedgenewfaces12.testcase                     |     7 +
 .../addedgenewfaces13.testcase                     |     7 +
 .../addedgenewfaces14.testcase                     |     7 +
 .../addedgenewfaces15.testcase                     |     7 +
 .../addedgenewfaces16.testcase                     |     7 +
 .../addedgenewfaces17.testcase                     |     7 +
 .../addedgenewfaces18.testcase                     |     7 +
 .../addedgenewfaces19.testcase                     |     7 +
 .../addedgenewfaces2.testcase                      |     7 +
 .../addedgenewfaces20.testcase                     |     7 +
 .../addedgenewfaces3.testcase                      |     7 +
 .../addedgenewfaces4.testcase                      |     7 +
 .../addedgenewfaces5.testcase                      |     7 +
 .../addedgenewfaces6.testcase                      |     7 +
 .../addedgenewfaces7.testcase                      |     7 +
 .../addedgenewfaces8.testcase                      |     7 +
 .../addedgenewfaces9.testcase                      |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge1.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge10.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge11.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge12.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge13.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge14.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge15.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge16.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge17.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge18.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge19.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisoedge20.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge3.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge4.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge5.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge6.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge7.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge8.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisoedge9.testcase |     7 +
 .../addisonetnode1.testcase                        |     7 +
 .../addisonetnode2.testcase                        |     7 +
 .../addisonetnode3.testcase                        |     7 +
 .../addisonetnode4.testcase                        |     7 +
 .../addisonetnode5.testcase                        |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode1.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode10.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode11.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode12.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode13.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode14.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode15.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode16.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/addisonode17.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode2.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode3.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode4.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode5.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode6.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode7.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode8.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addisonode9.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink1.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink10.testcase   |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink11.testcase   |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink12.testcase   |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink13.testcase   |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink2.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink3.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink4.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink5.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink6.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink7.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink8.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/addlink9.testcase    |     7 +
 .../changeedgegeom1.testcase                       |     7 +
 .../changeedgegeom10.testcase                      |     7 +
 .../changeedgegeom11.testcase                      |     7 +
 .../changeedgegeom12.testcase                      |     7 +
 .../changeedgegeom13.testcase                      |     7 +
 .../changeedgegeom14.testcase                      |     7 +
 .../changeedgegeom15.testcase                      |     7 +
 .../changeedgegeom16.testcase                      |     7 +
 .../changeedgegeom17.testcase                      |     7 +
 .../changeedgegeom2.testcase                       |     7 +
 .../changeedgegeom3.testcase                       |     7 +
 .../changeedgegeom4.testcase                       |     7 +
 .../changeedgegeom5.testcase                       |     7 +
 .../changeedgegeom6.testcase                       |     7 +
 .../changeedgegeom7.testcase                       |     7 +
 .../changeedgegeom8.testcase                       |     7 +
 .../changeedgegeom9.testcase                       |     7 +
 .../changelinkgeom1.testcase                       |     7 +
 .../changelinkgeom2.testcase                       |     7 +
 .../changelinkgeom3.testcase                       |     7 +
 .../changelinkgeom4.testcase                       |     7 +
 .../changelinkgeom5.testcase                       |     7 +
 .../changelinkgeom6.testcase                       |     7 +
 .../changelinkgeom7.testcase                       |     7 +
 .../changelinkgeom8.testcase                       |     7 +
 .../createnetwork1.testcase                        |     7 +
 .../createnetwork10.testcase                       |     7 +
 .../createnetwork11.testcase                       |     7 +
 .../createnetwork12.testcase                       |     7 +
 .../createnetwork13.testcase                       |     7 +
 .../createnetwork14.testcase                       |     7 +
 .../createnetwork15.testcase                       |     7 +
 .../createnetwork16.testcase                       |     7 +
 .../createnetwork17.testcase                       |     7 +
 .../createnetwork18.testcase                       |     7 +
 .../createnetwork19.testcase                       |     7 +
 .../createnetwork2.testcase                        |     7 +
 .../createnetwork20.testcase                       |     7 +
 .../createnetwork21.testcase                       |     7 +
 .../createnetwork22.testcase                       |     7 +
 .../createnetwork23.testcase                       |     7 +
 .../createnetwork24.testcase                       |     7 +
 .../createnetwork25.testcase                       |     7 +
 .../createnetwork3.testcase                        |     7 +
 .../createnetwork4.testcase                        |     7 +
 .../createnetwork5.testcase                        |     7 +
 .../createnetwork6.testcase                        |     7 +
 .../createnetwork7.testcase                        |     7 +
 .../createnetwork8.testcase                        |     7 +
 .../createnetwork9.testcase                        |     7 +
 .../createtopogeo1.testcase                        |     7 +
 .../createtopogeo10.testcase                       |     7 +
 .../createtopogeo2.testcase                        |     7 +
 .../createtopogeo3.testcase                        |     7 +
 .../createtopogeo4.testcase                        |     7 +
 .../createtopogeo5.testcase                        |     7 +
 .../createtopogeo6.testcase                        |     7 +
 .../createtopogeo7.testcase                        |     7 +
 .../createtopogeo8.testcase                        |     7 +
 .../createtopogeo9.testcase                        |     7 +
 .../createtopolayer1.testcase                      |     7 +
 .../createtopolayer10.testcase                     |     7 +
 .../createtopolayer11.testcase                     |     7 +
 .../createtopolayer12.testcase                     |     7 +
 .../createtopolayer13.testcase                     |     7 +
 .../createtopolayer14.testcase                     |     7 +
 .../createtopolayer15.testcase                     |     7 +
 .../createtopolayer16.testcase                     |     7 +
 .../createtopolayer17.testcase                     |     7 +
 .../createtopolayer18.testcase                     |     7 +
 .../createtopolayer19.testcase                     |     7 +
 .../createtopolayer2.testcase                      |     7 +
 .../createtopolayer20.testcase                     |     7 +
 .../createtopolayer21.testcase                     |     7 +
 .../createtopolayer22.testcase                     |     7 +
 .../createtopolayer23.testcase                     |     7 +
 .../createtopolayer24.testcase                     |     7 +
 .../createtopolayer25.testcase                     |     7 +
 .../createtopolayer26.testcase                     |     7 +
 .../createtopolayer3.testcase                      |     7 +
 .../createtopolayer4.testcase                      |     7 +
 .../createtopolayer5.testcase                      |     7 +
 .../createtopolayer6.testcase                      |     7 +
 .../createtopolayer7.testcase                      |     7 +
 .../createtopolayer8.testcase                      |     7 +
 .../createtopolayer9.testcase                      |     7 +
 .../createtopology1.testcase                       |     7 +
 .../createtopology10.testcase                      |     7 +
 .../createtopology11.testcase                      |     7 +
 .../createtopology12.testcase                      |     7 +
 .../createtopology13.testcase                      |     7 +
 .../createtopology14.testcase                      |     7 +
 .../createtopology15.testcase                      |     7 +
 .../createtopology16.testcase                      |     7 +
 .../createtopology17.testcase                      |     7 +
 .../createtopology18.testcase                      |     7 +
 .../createtopology19.testcase                      |     7 +
 .../createtopology2.testcase                       |     7 +
 .../createtopology20.testcase                      |     7 +
 .../createtopology3.testcase                       |     7 +
 .../createtopology4.testcase                       |     7 +
 .../createtopology5.testcase                       |     7 +
 .../createtopology6.testcase                       |     7 +
 .../createtopology7.testcase                       |     7 +
 .../createtopology8.testcase                       |     7 +
 .../createtopology9.testcase                       |     7 +
 .../sql_stmt_lwgeom_22_tests/dropnetwork1.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/dropnetwork2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/dropnetwork3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/dropnetwork4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/dropnetwork5.testcase |     7 +
 .../droptopology1.testcase                         |     7 +
 .../droptopology2.testcase                         |     7 +
 .../droptopology3.testcase                         |     7 +
 .../droptopology4.testcase                         |     7 +
 .../droptopology5.testcase                         |     7 +
 .../exporttopolayer1.testcase                      |     7 +
 .../exporttopolayer10.testcase                     |     7 +
 .../exporttopolayer11.testcase                     |     7 +
 .../exporttopolayer12.testcase                     |     7 +
 .../exporttopolayer13.testcase                     |     7 +
 .../exporttopolayer14.testcase                     |     7 +
 .../exporttopolayer15.testcase                     |     7 +
 .../exporttopolayer16.testcase                     |     7 +
 .../exporttopolayer17.testcase                     |     7 +
 .../exporttopolayer18.testcase                     |     7 +
 .../exporttopolayer19.testcase                     |     7 +
 .../exporttopolayer2.testcase                      |     7 +
 .../exporttopolayer20.testcase                     |     7 +
 .../exporttopolayer21.testcase                     |     7 +
 .../exporttopolayer22.testcase                     |     7 +
 .../exporttopolayer23.testcase                     |     7 +
 .../exporttopolayer3.testcase                      |     7 +
 .../exporttopolayer4.testcase                      |     7 +
 .../exporttopolayer5.testcase                      |     7 +
 .../exporttopolayer6.testcase                      |     7 +
 .../exporttopolayer7.testcase                      |     7 +
 .../exporttopolayer8.testcase                      |     7 +
 .../exporttopolayer9.testcase                      |     7 +
 .../featuretopolayer1.testcase                     |     7 +
 .../featuretopolayer10.testcase                    |     7 +
 .../featuretopolayer11.testcase                    |     7 +
 .../featuretopolayer12.testcase                    |     7 +
 .../featuretopolayer13.testcase                    |     7 +
 .../featuretopolayer14.testcase                    |     7 +
 .../featuretopolayer15.testcase                    |     7 +
 .../featuretopolayer16.testcase                    |     7 +
 .../featuretopolayer17.testcase                    |     7 +
 .../featuretopolayer2.testcase                     |     7 +
 .../featuretopolayer3.testcase                     |     7 +
 .../featuretopolayer4.testcase                     |     7 +
 .../featuretopolayer5.testcase                     |     7 +
 .../featuretopolayer6.testcase                     |     7 +
 .../featuretopolayer7.testcase                     |     7 +
 .../featuretopolayer8.testcase                     |     7 +
 .../featuretopolayer9.testcase                     |     7 +
 .../getedgebypoint1.testcase                       |     7 +
 .../getedgebypoint10.testcase                      |     7 +
 .../getedgebypoint11.testcase                      |     7 +
 .../getedgebypoint12.testcase                      |     7 +
 .../getedgebypoint13.testcase                      |     7 +
 .../getedgebypoint14.testcase                      |     7 +
 .../getedgebypoint15.testcase                      |     7 +
 .../getedgebypoint16.testcase                      |     7 +
 .../getedgebypoint17.testcase                      |     7 +
 .../getedgebypoint2.testcase                       |     7 +
 .../getedgebypoint3.testcase                       |     7 +
 .../getedgebypoint4.testcase                       |     7 +
 .../getedgebypoint5.testcase                       |     7 +
 .../getedgebypoint6.testcase                       |     7 +
 .../getedgebypoint7.testcase                       |     7 +
 .../getedgebypoint8.testcase                       |     7 +
 .../getedgebypoint9.testcase                       |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed1.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed5.testcase |     7 +
 .../getedgeseed6.testcase}                         |     8 +-
 .../sql_stmt_lwgeom_22_tests/getedgeseed7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getedgeseed9.testcase |     7 +
 .../getfacebypoint1.testcase                       |     7 +
 .../getfacebypoint10.testcase                      |     7 +
 .../getfacebypoint11.testcase                      |     7 +
 .../getfacebypoint12.testcase                      |     7 +
 .../getfacebypoint13.testcase                      |     7 +
 .../getfacebypoint14.testcase                      |     7 +
 .../getfacebypoint15.testcase                      |     7 +
 .../getfacebypoint16.testcase                      |     7 +
 .../getfacebypoint17.testcase                      |     7 +
 .../getfacebypoint2.testcase                       |     7 +
 .../getfacebypoint3.testcase                       |     7 +
 .../getfacebypoint4.testcase                       |     7 +
 .../getfacebypoint5.testcase                       |     7 +
 .../getfacebypoint6.testcase                       |     7 +
 .../getfacebypoint7.testcase                       |     7 +
 .../getfacebypoint8.testcase                       |     7 +
 .../getfacebypoint9.testcase                       |     7 +
 .../getfaceedges1.testcase                         |     7 +
 .../getfaceedges2.testcase                         |     7 +
 .../getfaceedges3.testcase                         |     7 +
 .../getfaceedges4.testcase                         |     7 +
 .../getfaceedges5.testcase                         |     7 +
 .../getfaceedges6.testcase                         |     7 +
 .../getfaceedges7.testcase                         |     7 +
 .../getfaceedges8.testcase                         |     7 +
 .../getfaceedges9.testcase                         |     7 +
 .../getfacegeometry1.testcase                      |     7 +
 .../getfacegeometry2.testcase                      |     7 +
 .../getfacegeometry3.testcase                      |     7 +
 .../getfacegeometry4.testcase                      |     7 +
 .../getfacegeometry5.testcase                      |     7 +
 .../getfacegeometry6.testcase                      |     7 +
 .../getfacegeometry7.testcase                      |     7 +
 .../getfacegeometry8.testcase                      |     7 +
 .../getfacegeometry9.testcase                      |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed1.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getfaceseed9.testcase |     7 +
 .../getlinkbypoint1.testcase                       |     7 +
 .../getlinkbypoint10.testcase                      |     7 +
 .../getlinkbypoint11.testcase                      |     7 +
 .../getlinkbypoint12.testcase                      |     7 +
 .../getlinkbypoint13.testcase                      |     7 +
 .../getlinkbypoint14.testcase                      |     7 +
 .../getlinkbypoint15.testcase                      |     7 +
 .../getlinkbypoint16.testcase                      |     7 +
 .../getlinkbypoint17.testcase                      |     7 +
 .../getlinkbypoint2.testcase                       |     7 +
 .../getlinkbypoint3.testcase                       |     7 +
 .../getlinkbypoint4.testcase                       |     7 +
 .../getlinkbypoint5.testcase                       |     7 +
 .../getlinkbypoint6.testcase                       |     7 +
 .../getlinkbypoint7.testcase                       |     7 +
 .../getlinkbypoint8.testcase                       |     7 +
 .../getlinkbypoint9.testcase                       |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed1.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/getlinkseed9.testcase |     7 +
 .../getnetnodebypoint1.testcase                    |     7 +
 .../getnetnodebypoint10.testcase                   |     7 +
 .../getnetnodebypoint11.testcase                   |     7 +
 .../getnetnodebypoint12.testcase                   |     7 +
 .../getnetnodebypoint13.testcase                   |     7 +
 .../getnetnodebypoint14.testcase                   |     7 +
 .../getnetnodebypoint15.testcase                   |     7 +
 .../getnetnodebypoint16.testcase                   |     7 +
 .../getnetnodebypoint17.testcase                   |     7 +
 .../getnetnodebypoint2.testcase                    |     7 +
 .../getnetnodebypoint3.testcase                    |     7 +
 .../getnetnodebypoint4.testcase                    |     7 +
 .../getnetnodebypoint5.testcase                    |     7 +
 .../getnetnodebypoint6.testcase                    |     7 +
 .../getnetnodebypoint7.testcase                    |     7 +
 .../getnetnodebypoint8.testcase                    |     7 +
 .../getnetnodebypoint9.testcase                    |     7 +
 .../getnodebypoint1.testcase                       |     7 +
 .../getnodebypoint10.testcase                      |     7 +
 .../getnodebypoint11.testcase                      |     7 +
 .../getnodebypoint12.testcase                      |     7 +
 .../getnodebypoint13.testcase                      |     7 +
 .../getnodebypoint14.testcase                      |     7 +
 .../getnodebypoint15.testcase                      |     7 +
 .../getnodebypoint16.testcase                      |     7 +
 .../getnodebypoint17.testcase                      |     7 +
 .../getnodebypoint2.testcase                       |     7 +
 .../getnodebypoint3.testcase                       |     7 +
 .../getnodebypoint4.testcase                       |     7 +
 .../getnodebypoint5.testcase                       |     7 +
 .../getnodebypoint6.testcase                       |     7 +
 .../getnodebypoint7.testcase                       |     7 +
 .../getnodebypoint8.testcase                       |     7 +
 .../getnodebypoint9.testcase                       |     7 +
 .../inittopolayer1.testcase                        |     7 +
 .../inittopolayer10.testcase                       |     7 +
 .../inittopolayer11.testcase                       |     7 +
 .../inittopolayer12.testcase                       |     7 +
 .../inittopolayer13.testcase                       |     7 +
 .../inittopolayer14.testcase                       |     7 +
 .../inittopolayer15.testcase                       |     7 +
 .../inittopolayer16.testcase                       |     7 +
 .../inittopolayer17.testcase                       |     7 +
 .../inittopolayer2.testcase                        |     7 +
 .../inittopolayer3.testcase                        |     7 +
 .../inittopolayer4.testcase                        |     7 +
 .../inittopolayer5.testcase                        |     7 +
 .../inittopolayer6.testcase                        |     7 +
 .../inittopolayer7.testcase                        |     7 +
 .../inittopolayer8.testcase                        |     7 +
 .../inittopolayer9.testcase                        |     7 +
 .../loginetfromtgeo1.testcase                      |     7 +
 .../loginetfromtgeo2.testcase                      |     7 +
 .../loginetfromtgeo3.testcase                      |     7 +
 .../loginetfromtgeo4.testcase                      |     7 +
 .../loginetfromtgeo5.testcase                      |     7 +
 .../loginetfromtgeo6.testcase                      |     7 +
 .../loginetfromtgeo7.testcase                      |     7 +
 .../loginetfromtgeo8.testcase                      |     7 +
 .../loginetfromtgeo9.testcase                      |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal1.testcase |     7 +
 .../modedgeheal10.testcase                         |     7 +
 .../modedgeheal11.testcase                         |     7 +
 .../modedgeheal12.testcase                         |     7 +
 .../modedgeheal13.testcase                         |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modedgeheal9.testcase |     7 +
 .../modedgesplit1.testcase                         |     7 +
 .../modedgesplit10.testcase                        |     7 +
 .../modedgesplit11.testcase                        |     7 +
 .../modedgesplit12.testcase                        |     7 +
 .../modedgesplit13.testcase                        |     7 +
 .../modedgesplit14.testcase                        |     7 +
 .../modedgesplit15.testcase                        |     7 +
 .../modedgesplit16.testcase                        |     7 +
 .../modedgesplit2.testcase                         |     7 +
 .../modedgesplit3.testcase                         |     7 +
 .../modedgesplit4.testcase                         |     7 +
 .../modedgesplit5.testcase                         |     7 +
 .../modedgesplit6.testcase                         |     7 +
 .../modedgesplit7.testcase                         |     7 +
 .../modedgesplit8.testcase                         |     7 +
 .../modedgesplit9.testcase                         |     7 +
 .../modgeolinksplit1.testcase                      |     7 +
 .../modgeolinksplit2.testcase                      |     7 +
 .../modgeolinksplit3.testcase                      |     7 +
 .../modgeolinksplit4.testcase                      |     7 +
 .../modgeolinksplit5.testcase                      |     7 +
 .../modgeolinksplit6.testcase                      |     7 +
 .../modgeolinksplit7.testcase                      |     7 +
 .../modgeolinksplit8.testcase                      |     7 +
 .../modgeolinksplit9.testcase                      |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal1.testcase |     7 +
 .../modlinkheal10.testcase                         |     7 +
 .../modlinkheal11.testcase                         |     7 +
 .../modlinkheal12.testcase                         |     7 +
 .../modlinkheal13.testcase                         |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/modlinkheal9.testcase |     7 +
 .../modloglinksplit1.testcase                      |     7 +
 .../modloglinksplit2.testcase                      |     7 +
 .../modloglinksplit3.testcase                      |     7 +
 .../modloglinksplit4.testcase                      |     7 +
 .../modloglinksplit5.testcase                      |     7 +
 .../modloglinksplit6.testcase                      |     7 +
 .../modloglinksplit7.testcase                      |     7 +
 .../modloglinksplit8.testcase                      |     7 +
 .../modloglinksplit9.testcase                      |     7 +
 .../moveisonetnode1.testcase                       |     7 +
 .../moveisonetnode2.testcase                       |     7 +
 .../moveisonetnode3.testcase                       |     7 +
 .../moveisonetnode4.testcase                       |     7 +
 .../moveisonetnode5.testcase                       |     7 +
 .../moveisonetnode6.testcase                       |     7 +
 .../moveisonetnode7.testcase                       |     7 +
 .../moveisonetnode8.testcase                       |     7 +
 .../moveisonetnode9.testcase                       |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode1.testcase |     7 +
 .../moveisonode10.testcase                         |     7 +
 .../moveisonode11.testcase                         |     7 +
 .../moveisonode12.testcase                         |     7 +
 .../moveisonode13.testcase                         |     7 +
 .../moveisonode14.testcase                         |     7 +
 .../moveisonode15.testcase                         |     7 +
 .../moveisonode16.testcase                         |     7 +
 .../moveisonode17.testcase                         |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/moveisonode9.testcase |     7 +
 .../netexception1.testcase                         |     7 +
 .../netexception2.testcase                         |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal1.testcase |     7 +
 .../newedgeheal10.testcase                         |     7 +
 .../newedgeheal11.testcase                         |     7 +
 .../newedgeheal12.testcase                         |     7 +
 .../newedgeheal13.testcase                         |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newedgeheal9.testcase |     7 +
 .../newedgessplit1.testcase                        |     7 +
 .../newedgessplit10.testcase                       |     7 +
 .../newedgessplit11.testcase                       |     7 +
 .../newedgessplit12.testcase                       |     7 +
 .../newedgessplit13.testcase                       |     7 +
 .../newedgessplit14.testcase                       |     7 +
 .../newedgessplit15.testcase                       |     7 +
 .../newedgessplit16.testcase                       |     7 +
 .../newedgessplit2.testcase                        |     7 +
 .../newedgessplit3.testcase                        |     7 +
 .../newedgessplit4.testcase                        |     7 +
 .../newedgessplit5.testcase                        |     7 +
 .../newedgessplit6.testcase                        |     7 +
 .../newedgessplit7.testcase                        |     7 +
 .../newedgessplit8.testcase                        |     7 +
 .../newedgessplit9.testcase                        |     7 +
 .../newgeolinksplit1.testcase                      |     7 +
 .../newgeolinksplit2.testcase                      |     7 +
 .../newgeolinksplit3.testcase                      |     7 +
 .../newgeolinksplit4.testcase                      |     7 +
 .../newgeolinksplit5.testcase                      |     7 +
 .../newgeolinksplit6.testcase                      |     7 +
 .../newgeolinksplit7.testcase                      |     7 +
 .../newgeolinksplit8.testcase                      |     7 +
 .../newgeolinksplit9.testcase                      |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal1.testcase |     7 +
 .../newlinkheal10.testcase                         |     7 +
 .../newlinkheal11.testcase                         |     7 +
 .../newlinkheal12.testcase                         |     7 +
 .../newlinkheal13.testcase                         |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal2.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal3.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal4.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal5.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal6.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal7.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal8.testcase |     7 +
 .../sql_stmt_lwgeom_22_tests/newlinkheal9.testcase |     7 +
 .../newloglinksplit1.testcase                      |     7 +
 .../newloglinksplit2.testcase                      |     7 +
 .../newloglinksplit3.testcase                      |     7 +
 .../newloglinksplit4.testcase                      |     7 +
 .../newloglinksplit5.testcase                      |     7 +
 .../newloglinksplit6.testcase                      |     7 +
 .../newloglinksplit7.testcase                      |     7 +
 .../newloglinksplit8.testcase                      |     7 +
 .../newloglinksplit9.testcase                      |     7 +
 .../remedgemodface1.testcase                       |     7 +
 .../remedgemodface2.testcase                       |     7 +
 .../remedgemodface3.testcase                       |     7 +
 .../remedgemodface4.testcase                       |     7 +
 .../remedgemodface5.testcase                       |     7 +
 .../remedgemodface6.testcase                       |     7 +
 .../remedgemodface7.testcase                       |     7 +
 .../remedgemodface8.testcase                       |     7 +
 .../remedgemodface9.testcase                       |     7 +
 .../remedgenewface1.testcase                       |     7 +
 .../remedgenewface2.testcase                       |     7 +
 .../remedgenewface3.testcase                       |     7 +
 .../remedgenewface4.testcase                       |     7 +
 .../remedgenewface5.testcase                       |     7 +
 .../remedgenewface6.testcase                       |     7 +
 .../remedgenewface7.testcase                       |     7 +
 .../remedgenewface8.testcase                       |     7 +
 .../remedgenewface9.testcase                       |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge1.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge2.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge3.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge4.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge5.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge6.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge7.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge8.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisoedge9.testcase |     7 +
 .../remisonetnode1.testcase                        |     7 +
 .../remisonetnode2.testcase                        |     7 +
 .../remisonetnode3.testcase                        |     7 +
 .../remisonetnode4.testcase                        |     7 +
 .../remisonetnode5.testcase                        |     7 +
 .../remisonetnode6.testcase                        |     7 +
 .../remisonetnode7.testcase                        |     7 +
 .../remisonetnode8.testcase                        |     7 +
 .../remisonetnode9.testcase                        |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode1.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode2.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode3.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode4.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode5.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode6.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode7.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode8.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remisonode9.testcase |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink1.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink2.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink3.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink4.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink5.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink6.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink7.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink8.testcase    |     7 +
 test/sql_stmt_lwgeom_22_tests/remlink9.testcase    |     7 +
 .../removetopolayer1.testcase                      |     7 +
 .../removetopolayer2.testcase                      |     7 +
 .../removetopolayer3.testcase                      |     7 +
 .../removetopolayer4.testcase                      |     7 +
 .../removetopolayer5.testcase                      |     7 +
 .../removetopolayer6.testcase                      |     7 +
 .../removetopolayer7.testcase                      |     7 +
 .../removetopolayer8.testcase                      |     7 +
 .../removetopolayer9.testcase                      |     7 +
 .../spatnetfromgeom1.testcase                      |     7 +
 .../spatnetfromgeom10.testcase                     |     7 +
 .../spatnetfromgeom2.testcase                      |     7 +
 .../spatnetfromgeom3.testcase                      |     7 +
 .../spatnetfromgeom4.testcase                      |     7 +
 .../spatnetfromgeom5.testcase                      |     7 +
 .../spatnetfromgeom6.testcase                      |     7 +
 .../spatnetfromgeom7.testcase                      |     7 +
 .../spatnetfromgeom8.testcase                      |     7 +
 .../spatnetfromgeom9.testcase                      |     7 +
 .../spatnetfromtgeo1.testcase                      |     7 +
 .../spatnetfromtgeo2.testcase                      |     7 +
 .../spatnetfromtgeo3.testcase                      |     7 +
 .../spatnetfromtgeo4.testcase                      |     7 +
 .../spatnetfromtgeo5.testcase                      |     7 +
 .../spatnetfromtgeo6.testcase                      |     7 +
 .../spatnetfromtgeo7.testcase                      |     7 +
 .../spatnetfromtgeo8.testcase                      |     7 +
 .../spatnetfromtgeo9.testcase                      |     7 +
 .../st_asx3d25.testcase                            |     2 +-
 .../st_asx3d26.testcase                            |     2 +-
 .../st_asx3d30.testcase                            |     3 +-
 test/sql_stmt_lwgeom_22_tests/st_split8.testcase   |     7 +
 .../topoexception1.testcase                        |     7 +
 .../topoexception2.testcase                        |     7 +
 .../topogeoaddline1.testcase                       |     7 +
 .../topogeoaddline10.testcase                      |     7 +
 .../topogeoaddline11.testcase                      |     7 +
 .../topogeoaddline12.testcase                      |     7 +
 .../topogeoaddline13.testcase                      |     7 +
 .../topogeoaddline14.testcase                      |     7 +
 .../topogeoaddline15.testcase                      |     7 +
 .../topogeoaddline16.testcase                      |     7 +
 .../topogeoaddline17.testcase                      |     7 +
 .../topogeoaddline2.testcase                       |     7 +
 .../topogeoaddline3.testcase                       |     7 +
 .../topogeoaddline4.testcase                       |     7 +
 .../topogeoaddline5.testcase                       |     7 +
 .../topogeoaddline6.testcase                       |     7 +
 .../topogeoaddline7.testcase                       |     7 +
 .../topogeoaddline8.testcase                       |     7 +
 .../topogeoaddline9.testcase                       |     7 +
 .../topogeoaddpoint1.testcase                      |     7 +
 .../topogeoaddpoint10.testcase                     |     7 +
 .../topogeoaddpoint11.testcase                     |     7 +
 .../topogeoaddpoint12.testcase                     |     7 +
 .../topogeoaddpoint13.testcase                     |     7 +
 .../topogeoaddpoint14.testcase                     |     7 +
 .../topogeoaddpoint15.testcase                     |     7 +
 .../topogeoaddpoint16.testcase                     |     7 +
 .../topogeoaddpoint17.testcase                     |     7 +
 .../topogeoaddpoint2.testcase                      |     7 +
 .../topogeoaddpoint3.testcase                      |     7 +
 .../topogeoaddpoint4.testcase                      |     7 +
 .../topogeoaddpoint5.testcase                      |     7 +
 .../topogeoaddpoint6.testcase                      |     7 +
 .../topogeoaddpoint7.testcase                      |     7 +
 .../topogeoaddpoint8.testcase                      |     7 +
 .../topogeoaddpoint9.testcase                      |     7 +
 .../topogeoclone1.testcase                         |     7 +
 .../topogeoclone10.testcase                        |     7 +
 .../topogeoclone11.testcase                        |     7 +
 .../topogeoclone12.testcase                        |     7 +
 .../topogeoclone2.testcase                         |     7 +
 .../topogeoclone3.testcase                         |     7 +
 .../topogeoclone4.testcase                         |     7 +
 .../topogeoclone5.testcase                         |     7 +
 .../topogeoclone6.testcase                         |     7 +
 .../topogeoclone7.testcase                         |     7 +
 .../topogeoclone8.testcase                         |     7 +
 .../topogeoclone9.testcase                         |     7 +
 .../topogeofromtable1.testcase                     |     7 +
 .../topogeofromtable10.testcase                    |     7 +
 .../topogeofromtable11.testcase                    |     7 +
 .../topogeofromtable12.testcase                    |     7 +
 .../topogeofromtable13.testcase                    |     7 +
 .../topogeofromtable14.testcase                    |     7 +
 .../topogeofromtable15.testcase                    |     7 +
 .../topogeofromtable16.testcase                    |     7 +
 .../topogeofromtable17.testcase                    |     7 +
 .../topogeofromtable18.testcase                    |     7 +
 .../topogeofromtable19.testcase                    |     7 +
 .../topogeofromtable2.testcase                     |     7 +
 .../topogeofromtable20.testcase                    |     7 +
 .../topogeofromtable21.testcase                    |     7 +
 .../topogeofromtable22.testcase                    |     7 +
 .../topogeofromtable23.testcase                    |     7 +
 .../topogeofromtable24.testcase                    |     7 +
 .../topogeofromtable25.testcase                    |     7 +
 .../topogeofromtable26.testcase                    |     7 +
 .../topogeofromtable27.testcase                    |     7 +
 .../topogeofromtable28.testcase                    |     7 +
 .../topogeofromtable29.testcase                    |     7 +
 .../topogeofromtable3.testcase                     |     7 +
 .../topogeofromtable30.testcase                    |     7 +
 .../topogeofromtable4.testcase                     |     7 +
 .../topogeofromtable5.testcase                     |     7 +
 .../topogeofromtable6.testcase                     |     7 +
 .../topogeofromtable7.testcase                     |     7 +
 .../topogeofromtable8.testcase                     |     7 +
 .../topogeofromtable9.testcase                     |     7 +
 .../topogeosplitline1.testcase                     |     7 +
 .../topogeosplitline10.testcase                    |     7 +
 .../topogeosplitline11.testcase                    |     7 +
 .../topogeosplitline12.testcase                    |     7 +
 .../topogeosplitline13.testcase                    |     7 +
 .../topogeosplitline14.testcase                    |     7 +
 .../topogeosplitline15.testcase                    |     7 +
 .../topogeosplitline16.testcase                    |     7 +
 .../topogeosplitline2.testcase                     |     7 +
 .../topogeosplitline3.testcase                     |     7 +
 .../topogeosplitline4.testcase                     |     7 +
 .../topogeosplitline5.testcase                     |     7 +
 .../topogeosplitline6.testcase                     |     7 +
 .../topogeosplitline7.testcase                     |     7 +
 .../topogeosplitline8.testcase                     |     7 +
 .../topogeosplitline9.testcase                     |     7 +
 .../topogeototable1.testcase                       |     7 +
 .../topogeototable10.testcase                      |     7 +
 .../topogeototable11.testcase                      |     7 +
 .../topogeototable12.testcase                      |     7 +
 .../topogeototable13.testcase                      |     7 +
 .../topogeototable14.testcase                      |     7 +
 .../topogeototable15.testcase                      |     7 +
 .../topogeototable16.testcase                      |     7 +
 .../topogeototable17.testcase                      |     7 +
 .../topogeototable18.testcase                      |     7 +
 .../topogeototable19.testcase                      |     7 +
 .../topogeototable2.testcase                       |     7 +
 .../topogeototable20.testcase                      |     7 +
 .../topogeototable21.testcase                      |     7 +
 .../topogeototable22.testcase                      |     7 +
 .../topogeototable23.testcase                      |     7 +
 .../topogeototable24.testcase                      |     7 +
 .../topogeototable25.testcase                      |     7 +
 .../topogeototable26.testcase                      |     7 +
 .../topogeototable3.testcase                       |     7 +
 .../topogeototable4.testcase                       |     7 +
 .../topogeototable5.testcase                       |     7 +
 .../topogeototable6.testcase                       |     7 +
 .../topogeototable7.testcase                       |     7 +
 .../topogeototable8.testcase                       |     7 +
 .../topogeototable9.testcase                       |     7 +
 .../topogeototablegen1.testcase                    |     7 +
 .../topogeototablegen10.testcase                   |     7 +
 .../topogeototablegen11.testcase                   |     7 +
 .../topogeototablegen12.testcase                   |     7 +
 .../topogeototablegen13.testcase                   |     7 +
 .../topogeototablegen14.testcase                   |     7 +
 .../topogeototablegen15.testcase                   |     7 +
 .../topogeototablegen16.testcase                   |     7 +
 .../topogeototablegen17.testcase                   |     7 +
 .../topogeototablegen18.testcase                   |     7 +
 .../topogeototablegen19.testcase                   |     7 +
 .../topogeototablegen2.testcase                    |     7 +
 .../topogeototablegen20.testcase                   |     7 +
 .../topogeototablegen21.testcase                   |     7 +
 .../topogeototablegen22.testcase                   |     7 +
 .../topogeototablegen23.testcase                   |     7 +
 .../topogeototablegen24.testcase                   |     7 +
 .../topogeototablegen25.testcase                   |     7 +
 .../topogeototablegen26.testcase                   |     7 +
 .../topogeototablegen27.testcase                   |     7 +
 .../topogeototablegen28.testcase                   |     7 +
 .../topogeototablegen29.testcase                   |     7 +
 .../topogeototablegen3.testcase                    |     7 +
 .../topogeototablegen30.testcase                   |     7 +
 .../topogeototablegen31.testcase                   |     7 +
 .../topogeototablegen4.testcase                    |     7 +
 .../topogeototablegen5.testcase                    |     7 +
 .../topogeototablegen6.testcase                    |     7 +
 .../topogeototablegen7.testcase                    |     7 +
 .../topogeototablegen8.testcase                    |     7 +
 .../topogeototablegen9.testcase                    |     7 +
 .../topogeoupdateseeds1.testcase                   |     7 +
 .../topogeoupdateseeds10.testcase                  |     7 +
 .../topogeoupdateseeds2.testcase                   |     7 +
 .../topogeoupdateseeds3.testcase                   |     7 +
 .../topogeoupdateseeds4.testcase                   |     7 +
 .../topogeoupdateseeds5.testcase                   |     7 +
 .../topogeoupdateseeds6.testcase                   |     7 +
 .../topogeoupdateseeds7.testcase                   |     7 +
 .../topogeoupdateseeds8.testcase                   |     7 +
 .../topogeoupdateseeds9.testcase                   |     7 +
 .../toponetclone1.testcase                         |     7 +
 .../toponetclone10.testcase                        |     7 +
 .../toponetclone11.testcase                        |     7 +
 .../toponetclone12.testcase                        |     7 +
 .../toponetclone2.testcase                         |     7 +
 .../toponetclone3.testcase                         |     7 +
 .../toponetclone4.testcase                         |     7 +
 .../toponetclone5.testcase                         |     7 +
 .../toponetclone6.testcase                         |     7 +
 .../toponetclone7.testcase                         |     7 +
 .../toponetclone8.testcase                         |     7 +
 .../toponetclone9.testcase                         |     7 +
 .../toponetfromtable1.testcase                     |     7 +
 .../toponetfromtable10.testcase                    |     7 +
 .../toponetfromtable11.testcase                    |     7 +
 .../toponetfromtable12.testcase                    |     7 +
 .../toponetfromtable13.testcase                    |     7 +
 .../toponetfromtable14.testcase                    |     7 +
 .../toponetfromtable15.testcase                    |     7 +
 .../toponetfromtable16.testcase                    |     7 +
 .../toponetfromtable17.testcase                    |     7 +
 .../toponetfromtable2.testcase                     |     7 +
 .../toponetfromtable3.testcase                     |     7 +
 .../toponetfromtable4.testcase                     |     7 +
 .../toponetfromtable5.testcase                     |     7 +
 .../toponetfromtable6.testcase                     |     7 +
 .../toponetfromtable7.testcase                     |     7 +
 .../toponetfromtable8.testcase                     |     7 +
 .../toponetfromtable9.testcase                     |     7 +
 .../toponettotable1.testcase                       |     7 +
 .../toponettotable10.testcase                      |     7 +
 .../toponettotable11.testcase                      |     7 +
 .../toponettotable12.testcase                      |     7 +
 .../toponettotable13.testcase                      |     7 +
 .../toponettotable14.testcase                      |     7 +
 .../toponettotable15.testcase                      |     7 +
 .../toponettotable16.testcase                      |     7 +
 .../toponettotable17.testcase                      |     7 +
 .../toponettotable18.testcase                      |     7 +
 .../toponettotable19.testcase                      |     7 +
 .../toponettotable2.testcase                       |     7 +
 .../toponettotable20.testcase                      |     7 +
 .../toponettotable21.testcase                      |     7 +
 .../toponettotable22.testcase                      |     7 +
 .../toponettotable23.testcase                      |     7 +
 .../toponettotable24.testcase                      |     7 +
 .../toponettotable25.testcase                      |     7 +
 .../toponettotable26.testcase                      |     7 +
 .../toponettotable3.testcase                       |     7 +
 .../toponettotable4.testcase                       |     7 +
 .../toponettotable5.testcase                       |     7 +
 .../toponettotable6.testcase                       |     7 +
 .../toponettotable7.testcase                       |     7 +
 .../toponettotable8.testcase                       |     7 +
 .../toponettotable9.testcase                       |     7 +
 .../toponettotablegen1.testcase                    |     7 +
 .../toponettotablegen10.testcase                   |     7 +
 .../toponettotablegen11.testcase                   |     7 +
 .../toponettotablegen12.testcase                   |     7 +
 .../toponettotablegen13.testcase                   |     7 +
 .../toponettotablegen14.testcase                   |     7 +
 .../toponettotablegen15.testcase                   |     7 +
 .../toponettotablegen16.testcase                   |     7 +
 .../toponettotablegen17.testcase                   |     7 +
 .../toponettotablegen18.testcase                   |     7 +
 .../toponettotablegen19.testcase                   |     7 +
 .../toponettotablegen2.testcase                    |     7 +
 .../toponettotablegen20.testcase                   |     7 +
 .../toponettotablegen21.testcase                   |     7 +
 .../toponettotablegen22.testcase                   |     7 +
 .../toponettotablegen23.testcase                   |     7 +
 .../toponettotablegen24.testcase                   |     7 +
 .../toponettotablegen25.testcase                   |     7 +
 .../toponettotablegen26.testcase                   |     7 +
 .../toponettotablegen27.testcase                   |     7 +
 .../toponettotablegen28.testcase                   |     7 +
 .../toponettotablegen29.testcase                   |     7 +
 .../toponettotablegen3.testcase                    |     7 +
 .../toponettotablegen30.testcase                   |     7 +
 .../toponettotablegen31.testcase                   |     7 +
 .../toponettotablegen4.testcase                    |     7 +
 .../toponettotablegen5.testcase                    |     7 +
 .../toponettotablegen6.testcase                    |     7 +
 .../toponettotablegen7.testcase                    |     7 +
 .../toponettotablegen8.testcase                    |     7 +
 .../toponettotablegen9.testcase                    |     7 +
 .../validatetopogeo1.testcase                      |     7 +
 .../validatetopogeo2.testcase                      |     7 +
 .../validatetopogeo3.testcase                      |     7 +
 .../validatetopogeo4.testcase                      |     7 +
 .../validatetopogeo5.testcase                      |     7 +
 .../validlogicalnet1.testcase                      |     7 +
 .../validlogicalnet2.testcase                      |     7 +
 .../validlogicalnet3.testcase                      |     7 +
 .../validlogicalnet4.testcase                      |     7 +
 .../validlogicalnet5.testcase                      |     7 +
 .../validspatialnet1.testcase                      |     7 +
 .../validspatialnet2.testcase                      |     7 +
 .../validspatialnet3.testcase                      |     7 +
 .../validspatialnet4.testcase                      |     7 +
 .../validspatialnet5.testcase                      |     7 +
 .../3dlength1.testcase}                            |     6 +-
 .../3dlength2.testcase}                            |     6 +-
 .../3dlength3.testcase}                            |     6 +-
 .../3dlength4.testcase}                            |     6 +-
 test/sql_stmt_lwgeom_tests/3dlength5.testcase      |     7 +
 test/sql_stmt_lwgeom_tests/3dlength6.testcase      |     7 +
 test/sql_stmt_lwgeom_tests/3dlength7.testcase      |     7 +
 test/sql_stmt_lwgeom_tests/3dlength8.testcase      |     7 +
 test/sql_stmt_lwgeom_tests/Makefile.am             |    12 +-
 test/sql_stmt_lwgeom_tests/Makefile.in             |    12 +-
 test/sql_stmt_lwgeom_tests/st_split9.testcase      |     4 +-
 test/sql_stmt_tests/Makefile.am                    |    15 +
 test/sql_stmt_tests/Makefile.in                    |    15 +
 test/sql_stmt_tests/collect10.testcase             |     2 +-
 test/sql_stmt_tests/collect11.testcase             |     2 +-
 test/sql_stmt_tests/collect13.testcase             |     2 +-
 test/sql_stmt_tests/collect14.testcase             |     2 +-
 test/sql_stmt_tests/collect15.testcase             |     2 +-
 test/sql_stmt_tests/collect17.testcase             |     2 +-
 test/sql_stmt_tests/collect24.testcase             |     3 +-
 test/sql_stmt_tests/collect25.testcase             |     3 +-
 test/sql_stmt_tests/collect26.testcase             |     3 +-
 test/sql_stmt_tests/collect28.testcase             |     1 -
 test/sql_stmt_tests/collect29.testcase             |     3 +-
 test/sql_stmt_tests/collect30.testcase             |     3 +-
 test/sql_stmt_tests/collect34.testcase             |     3 +-
 test/sql_stmt_tests/collect35.testcase             |     3 +-
 test/sql_stmt_tests/collect41.testcase             |     3 +-
 test/sql_stmt_tests/collect42.testcase             |     3 +-
 test/sql_stmt_tests/collect44.testcase             |     3 +-
 test/sql_stmt_tests/collect45.testcase             |     3 +-
 test/sql_stmt_tests/collect46.testcase             |     3 +-
 test/sql_stmt_tests/collect48.testcase             |     3 +-
 test/sql_stmt_tests/collect49.testcase             |     3 +-
 test/sql_stmt_tests/collect9.testcase              |     3 +-
 test/sql_stmt_tests/createclonetable1.testcase     |     7 +
 test/sql_stmt_tests/createclonetable10.testcase    |     7 +
 test/sql_stmt_tests/createclonetable11.testcase    |     7 +
 test/sql_stmt_tests/createclonetable12.testcase    |     7 +
 test/sql_stmt_tests/createclonetable13.testcase    |     7 +
 test/sql_stmt_tests/createclonetable14.testcase    |     7 +
 test/sql_stmt_tests/createclonetable15.testcase    |     7 +
 test/sql_stmt_tests/createclonetable2.testcase     |     7 +
 test/sql_stmt_tests/createclonetable3.testcase     |     7 +
 test/sql_stmt_tests/createclonetable4.testcase     |     7 +
 test/sql_stmt_tests/createclonetable5.testcase     |     7 +
 test/sql_stmt_tests/createclonetable6.testcase     |     7 +
 test/sql_stmt_tests/createclonetable7.testcase     |     7 +
 test/sql_stmt_tests/createclonetable8.testcase     |     7 +
 test/sql_stmt_tests/createclonetable9.testcase     |     7 +
 test/sql_stmt_voronoj1_tests/Makefile.am           |    20 +
 .../sql_stmt_voronoj1_tests}/Makefile.in           |    27 +-
 .../voronoj1.testcase                              |     0
 .../voronoj10.testcase                             |     0
 .../voronoj11.testcase                             |     0
 .../voronoj12.testcase                             |     0
 .../voronoj13.testcase                             |     0
 .../voronoj14.testcase                             |     0
 .../voronoj15.testcase                             |     0
 .../voronoj16.testcase                             |     0
 .../voronoj17.testcase                             |     0
 .../voronoj18.testcase                             |     0
 .../voronoj19.testcase                             |     0
 .../voronoj2.testcase                              |     0
 .../voronoj20.testcase                             |     0
 .../voronoj3.testcase                              |     0
 .../voronoj4.testcase                              |     0
 .../voronoj5.testcase                              |     0
 .../voronoj6.testcase                              |     0
 .../voronoj8.testcase                              |     0
 .../voronoj9.testcase                              |     0
 test/sql_stmt_voronoj2_tests/Makefile.am           |    20 +
 .../sql_stmt_voronoj2_tests}/Makefile.in           |    27 +-
 .../voronoj1.testcase                              |     0
 .../voronoj10.testcase                             |     0
 .../voronoj11.testcase                             |     0
 .../voronoj12.testcase                             |     0
 .../voronoj13.testcase                             |     0
 .../voronoj14.testcase                             |     0
 test/sql_stmt_voronoj2_tests/voronoj15.testcase    |     7 +
 test/sql_stmt_voronoj2_tests/voronoj16.testcase    |     7 +
 test/sql_stmt_voronoj2_tests/voronoj17.testcase    |     7 +
 test/sql_stmt_voronoj2_tests/voronoj18.testcase    |     7 +
 test/sql_stmt_voronoj2_tests/voronoj19.testcase    |     7 +
 .../voronoj2.testcase                              |     0
 test/sql_stmt_voronoj2_tests/voronoj20.testcase    |     7 +
 .../voronoj3.testcase                              |     0
 .../voronoj4.testcase                              |     0
 .../voronoj5.testcase                              |     0
 .../voronoj6.testcase                              |     0
 .../voronoj8.testcase                              |     0
 .../voronoj9.testcase                              |     0
 1164 files changed, 81026 insertions(+), 2836 deletions(-)

diff --git a/config.h.in b/config.h.in
index 268e638..e3ff281 100644
--- a/config.h.in
+++ b/config.h.in
@@ -15,8 +15,11 @@
 /* Should be defined in order to enable GEOS_ADVANCED support. */
 #undef GEOS_ADVANCED
 
-/* Should be defined in order to enable GEOS_TRUNK experimental support. */
-#undef GEOS_TRUNK
+/* Should be defined in order to fully disable GEOS non-thread-safe API. */
+#undef GEOS_ONLY_REENTRANT
+
+/* Should be defined in order to enable GEOS_REENTRANT (fully thread-safe). */
+#undef GEOS_REENTRANT
 
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
@@ -199,6 +202,9 @@
 /* Should be defined when linking liblwgeom from PostGIS 2.1 (or later). */
 #undef POSTGIS_2_1
 
+/* Should be defined when linking liblwgeom from PostGIS 2.2 (or later). */
+#undef POSTGIS_2_2
+
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
diff --git a/configure b/configure
index aafdad5..de617d7 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libspatialite 4.3.0a.
+# Generated by GNU Autoconf 2.69 for libspatialite 4.4.0-RC0.
 #
 # Report bugs to <a.furieri at lqt.it>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='libspatialite'
 PACKAGE_TARNAME='libspatialite'
-PACKAGE_VERSION='4.3.0a'
-PACKAGE_STRING='libspatialite 4.3.0a'
+PACKAGE_VERSION='4.4.0-RC0'
+PACKAGE_STRING='libspatialite 4.4.0-RC0'
 PACKAGE_BUGREPORT='a.furieri at lqt.it'
 PACKAGE_URL=''
 
@@ -640,6 +640,8 @@ MACOSX_FALSE
 MACOSX_TRUE
 MINGW_FALSE
 MINGW_TRUE
+MODULE_ONLY_FALSE
+MODULE_ONLY_TRUE
 ENABLE_EXAMPLES_FALSE
 ENABLE_EXAMPLES_TRUE
 ENABLE_GEOPACKAGE_FALSE
@@ -799,11 +801,14 @@ enable_geos
 with_geosconfig
 enable_gcp
 enable_geosadvanced
+enable_geosreentrant
+with_geosonlyreentrant
 enable_lwgeom
 enable_libxml2
 enable_geopackage
 enable_gcov
 enable_examples
+enable_module_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1363,7 +1368,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libspatialite 4.3.0a to adapt to many kinds of systems.
+\`configure' configures libspatialite 4.4.0-RC0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1433,7 +1438,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libspatialite 4.3.0a:";;
+     short | recursive ) echo "Configuration of libspatialite 4.4.0-RC0:";;
    esac
   cat <<\_ACEOF
 
@@ -1464,11 +1469,14 @@ Optional Features:
   --enable-geos           enables GEOS inclusion [default=yes]
   --enable-gcp            enables Control Points (from Grass GIS) [default=no]
   --enable-geosadvanced   enables GEOS advanced features [default=yes]
+  --enable-geosreentrant  enables GEOS reentrant (fully thread safe)
+                          [default=yes]
   --enable-lwgeom         enables LWGEOM support [default=no]
   --enable-libxml2        enables libxml2 inclusion [default=yes]
   --enable-geopackage     enables GeoPackage support [default=yes]
   --enable-gcov           turn on code coverage analysis tools
   --enable-examples       enables building examples [default=yes]
+  --enable-module-only    builds only mod_spatialite alone [default=no]
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1479,6 +1487,9 @@ Optional Packages:
   --with-sysroot=DIR Search for dependent libraries within DIR
                         (or the compiler's sysroot if not specified).
   --with-geosconfig=FILE  specify an alternative geos-config file
+  --with-geosonlyreentrant
+                          completely disables GEOS non-thread safe API
+                          [default=no]
 
 Some influential environment variables:
   CC          C compiler command
@@ -1568,7 +1579,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libspatialite configure 4.3.0a
+libspatialite configure 4.4.0-RC0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2112,7 +2123,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libspatialite $as_me 4.3.0a, which was
+It was created by libspatialite $as_me 4.4.0-RC0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2983,7 +2994,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='libspatialite'
- VERSION='4.3.0a'
+ VERSION='4.4.0-RC0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3135,6 +3146,8 @@ $as_echo "#define NDEBUG 1" >>confdefs.h
 
 
 
+
+
 # Checks for header files.
 DEPDIR="${am__leading_dot}deps"
 
@@ -17353,7 +17366,7 @@ else
 fi
 
 
-ac_config_files="$ac_config_files Makefile src/Makefile src/headers/Makefile src/gaiaaux/Makefile src/gaiaexif/Makefile src/gaiageo/Makefile src/gaiageo/flex/Makefile src/gaiageo/lemon/Makefile src/gaiageo/lemon/lemon_src/Makefile src/geopackage/Makefile src/spatialite/Makefile src/shapefiles/Makefile src/dxf/Makefile src/md5/Makefile src/control_points/Makefile src/srsinit/Makefile src/srsinit/epsg_update/Makefile src/connection_cache/Makefile src/connection_cache/generator/Makefile src [...]
+ac_config_files="$ac_config_files Makefile src/Makefile src/headers/Makefile src/gaiaaux/Makefile src/gaiaexif/Makefile src/gaiageo/Makefile src/gaiageo/flex/Makefile src/gaiageo/lemon/Makefile src/gaiageo/lemon/lemon_src/Makefile src/geopackage/Makefile src/spatialite/Makefile src/shapefiles/Makefile src/dxf/Makefile src/md5/Makefile src/control_points/Makefile src/cutter/Makefile src/topology/Makefile src/srsinit/Makefile src/srsinit/epsg_update/Makefile src/connection_cache/Makefile s [...]
 
 
 # exporting the TARGET_CPU string
@@ -18207,7 +18220,7 @@ if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
 else
-  as_fn_error $? "'libgeos_c' (>= v.3.4.0) is required but it doesn't seem to be installed on this system." "$LINENO" 5
+  as_fn_error $? "'libgeos_c' (>= v.3.4.0) is required but it doesn't seem to be installed on this system. You may need to try re-running configure with a --disable-geosadvanced parameter." "$LINENO" 5
 fi
 
 	  $as_echo "#define GEOS_ADVANCED 1" >>confdefs.h
@@ -18215,6 +18228,95 @@ fi
   fi
 
   #-----------------------------------------------------------------------
+  #   --enable-geosreentrant
+  #
+  # Check whether --enable-geosreentrant was given.
+if test "${enable_geosreentrant+set}" = set; then :
+  enableval=$enable_geosreentrant;
+else
+  enable_geosreentrant=yes
+fi
+
+  if test x"$enable_geosreentrant" != "xno"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing GEOSContext_setErrorMessageHandler_r" >&5
+$as_echo_n "checking for library containing GEOSContext_setErrorMessageHandler_r... " >&6; }
+if ${ac_cv_search_GEOSContext_setErrorMessageHandler_r+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char GEOSContext_setErrorMessageHandler_r ();
+int
+main ()
+{
+return GEOSContext_setErrorMessageHandler_r ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' geos_c; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_GEOSContext_setErrorMessageHandler_r=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_GEOSContext_setErrorMessageHandler_r+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_GEOSContext_setErrorMessageHandler_r+:} false; then :
+
+else
+  ac_cv_search_GEOSContext_setErrorMessageHandler_r=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_GEOSContext_setErrorMessageHandler_r" >&5
+$as_echo "$ac_cv_search_GEOSContext_setErrorMessageHandler_r" >&6; }
+ac_res=$ac_cv_search_GEOSContext_setErrorMessageHandler_r
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+  as_fn_error $? "'libgeos_c' (>= v.3.5.0) is required but it doesn't seem to be installed on this system. You may need to try re-running configure with a --disable-geosreentrant parameter." "$LINENO" 5
+fi
+
+	  $as_echo "#define GEOS_REENTRANT 1" >>confdefs.h
+
+  fi
+
+  #-----------------------------------------------------------------------
+  #   --with-geosonlyreentrant
+  #
+
+# Check whether --with-geosonlyreentrant was given.
+if test "${with_geosonlyreentrant+set}" = set; then :
+  withval=$with_geosonlyreentrant;
+else
+  with_geosonlyreentrant=no
+fi
+
+  if test x"$with_geosonlyreentrant" != "xno"; then
+	  $as_echo "#define GEOS_ONLY_REENTRANT 1" >>confdefs.h
+
+  fi
+
+  #-----------------------------------------------------------------------
   #   --enable-lwgeom
   #
   # Check whether --enable-lwgeom was given.
@@ -18316,6 +18418,66 @@ if test "$ac_res" != no; then :
 
 fi
 
+	#
+	# testing for PostGIS 2.2 - lwt_AddIsoNode
+	#
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lwt_AddIsoNode" >&5
+$as_echo_n "checking for library containing lwt_AddIsoNode... " >&6; }
+if ${ac_cv_search_lwt_AddIsoNode+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char lwt_AddIsoNode ();
+int
+main ()
+{
+return lwt_AddIsoNode ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' geos_c; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_lwt_AddIsoNode=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_lwt_AddIsoNode+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_lwt_AddIsoNode+:} false; then :
+
+else
+  ac_cv_search_lwt_AddIsoNode=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lwt_AddIsoNode" >&5
+$as_echo "$ac_cv_search_lwt_AddIsoNode" >&6; }
+ac_res=$ac_cv_search_lwt_AddIsoNode
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+  $as_echo "#define POSTGIS_2_2 1" >>confdefs.h
+
+fi
+
   fi
 else
   $as_echo "#define OMIT_GEOS 1" >>confdefs.h
@@ -18589,6 +18751,26 @@ fi
 
 #-----------------------------------------------------------------------
 
+#-----------------------------------------------------------------------
+#   --enable-module-only
+#
+# Check whether --enable-module-only was given.
+if test "${enable_module_only+set}" = set; then :
+  enableval=$enable_module_only;
+else
+  enable_module_only=no
+fi
+
+ if test x"$enable_module_only" != "xno"; then
+  MODULE_ONLY_TRUE=
+  MODULE_ONLY_FALSE='#'
+else
+  MODULE_ONLY_TRUE='#'
+  MODULE_ONLY_FALSE=
+fi
+
+#-----------------------------------------------------------------------
+
 # Checking for MinGW
  if test "$target_alias" = "mingw32"; then
   MINGW_TRUE=
@@ -18769,6 +18951,10 @@ if test -z "${ENABLE_EXAMPLES_TRUE}" && test -z "${ENABLE_EXAMPLES_FALSE}"; then
   as_fn_error $? "conditional \"ENABLE_EXAMPLES\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${MODULE_ONLY_TRUE}" && test -z "${MODULE_ONLY_FALSE}"; then
+  as_fn_error $? "conditional \"MODULE_ONLY\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then
   as_fn_error $? "conditional \"MINGW\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -19178,7 +19364,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libspatialite $as_me 4.3.0a, which was
+This file was extended by libspatialite $as_me 4.4.0-RC0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -19244,7 +19430,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libspatialite config.status 4.3.0a
+libspatialite config.status 4.4.0-RC0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -19770,6 +19956,8 @@ do
     "src/dxf/Makefile") CONFIG_FILES="$CONFIG_FILES src/dxf/Makefile" ;;
     "src/md5/Makefile") CONFIG_FILES="$CONFIG_FILES src/md5/Makefile" ;;
     "src/control_points/Makefile") CONFIG_FILES="$CONFIG_FILES src/control_points/Makefile" ;;
+    "src/cutter/Makefile") CONFIG_FILES="$CONFIG_FILES src/cutter/Makefile" ;;
+    "src/topology/Makefile") CONFIG_FILES="$CONFIG_FILES src/topology/Makefile" ;;
     "src/srsinit/Makefile") CONFIG_FILES="$CONFIG_FILES src/srsinit/Makefile" ;;
     "src/srsinit/epsg_update/Makefile") CONFIG_FILES="$CONFIG_FILES src/srsinit/epsg_update/Makefile" ;;
     "src/connection_cache/Makefile") CONFIG_FILES="$CONFIG_FILES src/connection_cache/Makefile" ;;
@@ -19784,12 +19972,16 @@ do
     "test/sql_stmt_proj_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_proj_tests/Makefile" ;;
     "test/sql_stmt_mathsql_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_mathsql_tests/Makefile" ;;
     "test/sql_stmt_lwgeom_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_lwgeom_tests/Makefile" ;;
+    "test/sql_stmt_lwgeom_20_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_lwgeom_20_tests/Makefile" ;;
+    "test/sql_stmt_lwgeom_22_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_lwgeom_22_tests/Makefile" ;;
     "test/sql_stmt_libxml2_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_libxml2_tests/Makefile" ;;
     "test/sql_stmt_security_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_security_tests/Makefile" ;;
     "test/sql_stmt_xmlsec_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_xmlsec_tests/Makefile" ;;
     "test/sql_stmt_freexl_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_freexl_tests/Makefile" ;;
     "test/sql_stmt_cache_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_cache_tests/Makefile" ;;
     "test/sql_stmt_nocache_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_nocache_tests/Makefile" ;;
+    "test/sql_stmt_voronoj1_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_voronoj1_tests/Makefile" ;;
+    "test/sql_stmt_voronoj2_tests/Makefile") CONFIG_FILES="$CONFIG_FILES test/sql_stmt_voronoj2_tests/Makefile" ;;
     "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
     "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;;
     "spatialite.pc") CONFIG_FILES="$CONFIG_FILES spatialite.pc" ;;
@@ -21344,7 +21536,7 @@ if test x"$gpl_escalation" != xno; then
     echo "You have selected --enable-lwgeom and/or --enable-gcp"
     echo
     echo "Both modules strictly depend on code released under the GPLv2+"
-    echo "license, wich is virally infective by definition."
+    echo "license, wich takes precedence over any other license."
     echo "Consequently the copy of libspatialite you are going to build"
     echo "if configured this way *must* be released under the GPLv2+ license."
     echo
diff --git a/configure.ac b/configure.ac
index 06ebe98..2b92677 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.61)
-AC_INIT(libspatialite, 4.3.0a, a.furieri at lqt.it)
+AC_INIT(libspatialite, 4.4.0-RC0, a.furieri at lqt.it)
 AC_LANG(C)
 AC_CONFIG_MACRO_DIR([m4])
 
@@ -31,8 +31,10 @@ AH_TEMPLATE([OMIT_GEOS],
             [Should be defined in order to disable GEOS support.])
 AH_TEMPLATE([GEOS_ADVANCED],
             [Should be defined in order to enable GEOS_ADVANCED support.])
-AH_TEMPLATE([GEOS_TRUNK],
-            [Should be defined in order to enable GEOS_TRUNK experimental support.])
+AH_TEMPLATE([GEOS_REENTRANT],
+            [Should be defined in order to enable GEOS_REENTRANT (fully thread-safe).])
+AH_TEMPLATE([GEOS_ONLY_REENTRANT],
+            [Should be defined in order to fully disable GEOS non-thread-safe API.])
 AH_TEMPLATE([ENABLE_LWGEOM],
             [Should be defined in order to enable LWGEOM support.])
 AH_TEMPLATE([ENABLE_GCP],
@@ -55,6 +57,8 @@ AH_TEMPLATE([ENABLE_GEOPACKAGE],
             [Should be defined in order to enable GeoPackage support.])
 AH_TEMPLATE([POSTGIS_2_1],
             [Should be defined when linking liblwgeom from PostGIS 2.1 (or later).])
+AH_TEMPLATE([POSTGIS_2_2],
+            [Should be defined when linking liblwgeom from PostGIS 2.2 (or later).])
 AH_TEMPLATE([TARGET_CPU],
             [Should contain a text-string describing the intended target CPU])
 
@@ -121,6 +125,8 @@ AC_CONFIG_FILES([Makefile \
 		src/dxf/Makefile \
 		src/md5/Makefile \
 		src/control_points/Makefile \
+		src/cutter/Makefile \
+		src/topology/Makefile \
 		src/srsinit/Makefile \
 		src/srsinit/epsg_update/Makefile \
 		src/connection_cache/Makefile \
@@ -135,12 +141,16 @@ AC_CONFIG_FILES([Makefile \
 		test/sql_stmt_proj_tests/Makefile \
 		test/sql_stmt_mathsql_tests/Makefile \
 		test/sql_stmt_lwgeom_tests/Makefile \
+		test/sql_stmt_lwgeom_20_tests/Makefile \
+		test/sql_stmt_lwgeom_22_tests/Makefile \
 		test/sql_stmt_libxml2_tests/Makefile \
 		test/sql_stmt_security_tests/Makefile \
 		test/sql_stmt_xmlsec_tests/Makefile \
 		test/sql_stmt_freexl_tests/Makefile \
 		test/sql_stmt_cache_tests/Makefile \
 		test/sql_stmt_nocache_tests/Makefile \
+		test/sql_stmt_voronoj1_tests/Makefile \
+		test/sql_stmt_voronoj2_tests/Makefile \
 		examples/Makefile \
 		Doxyfile \
 		spatialite.pc])
@@ -298,11 +308,32 @@ if test x"$enable_geos" != "xno"; then
 	  [--enable-geosadvanced], [enables GEOS advanced features [default=yes]])],
 	  [], [enable_geosadvanced=yes])
   if test x"$enable_geosadvanced" != "xno"; then
-	  AC_SEARCH_LIBS(GEOSDelaunayTriangulation,geos_c,,AC_MSG_ERROR(['libgeos_c' (>= v.3.4.0) is required but it doesn't seem to be installed on this system.]))
+	  AC_SEARCH_LIBS(GEOSDelaunayTriangulation,geos_c,,AC_MSG_ERROR(['libgeos_c' (>= v.3.4.0) is required but it doesn't seem to be installed on this system. You may need to try re-running configure with a --disable-geosadvanced parameter.]))
 	  AC_DEFINE(GEOS_ADVANCED)
   fi
 
   #-----------------------------------------------------------------------
+  #   --enable-geosreentrant
+  #
+  AC_ARG_ENABLE(geosreentrant, [AS_HELP_STRING(
+	  [--enable-geosreentrant], [enables GEOS reentrant (fully thread safe) [default=yes]])],
+	  [], [enable_geosreentrant=yes])
+  if test x"$enable_geosreentrant" != "xno"; then
+	  AC_SEARCH_LIBS(GEOSContext_setErrorMessageHandler_r,geos_c,,AC_MSG_ERROR(['libgeos_c' (>= v.3.5.0) is required but it doesn't seem to be installed on this system. You may need to try re-running configure with a --disable-geosreentrant parameter.]))
+	  AC_DEFINE(GEOS_REENTRANT)
+  fi
+
+  #-----------------------------------------------------------------------
+  #   --with-geosonlyreentrant
+  #
+  AC_ARG_WITH(geosonlyreentrant, [AS_HELP_STRING(
+	  [--with-geosonlyreentrant], [completely disables GEOS non-thread safe API [default=no]])],
+	  [], [with_geosonlyreentrant=no])
+  if test x"$with_geosonlyreentrant" != "xno"; then
+	  AC_DEFINE(GEOS_ONLY_REENTRANT)
+  fi
+
+  #-----------------------------------------------------------------------
   #   --enable-lwgeom
   #
   AC_ARG_ENABLE(lwgeom, [AS_HELP_STRING(
@@ -322,6 +353,10 @@ if test x"$enable_geos" != "xno"; then
 	# testing for PostGIS 2.1 - lwgeom_set_handlers
 	#
 	  AC_SEARCH_LIBS(lwgeom_set_handlers,geos_c,AC_DEFINE(POSTGIS_2_1))
+	#
+	# testing for PostGIS 2.2 - lwt_AddIsoNode
+	#
+	  AC_SEARCH_LIBS(lwt_AddIsoNode,geos_c,AC_DEFINE(POSTGIS_2_2))
   fi
 else
   AC_DEFINE(OMIT_GEOS)
@@ -373,6 +408,15 @@ AC_ARG_ENABLE(examples, [AS_HELP_STRING(
 AM_CONDITIONAL(ENABLE_EXAMPLES, [test x"$enable_examples" != "xno"])
 #-----------------------------------------------------------------------
 
+#-----------------------------------------------------------------------
+#   --enable-module-only
+#
+AC_ARG_ENABLE(module-only, [AS_HELP_STRING(
+       [--enable-module-only], [builds only mod_spatialite alone [default=no]])],
+       [], [enable_module_only=no])
+AM_CONDITIONAL(MODULE_ONLY, [test x"$enable_module_only" != "xno"])
+#-----------------------------------------------------------------------
+
 # Checking for MinGW
 AM_CONDITIONAL([MINGW], [test "$target_alias" = "mingw32"])
 # Checking for Mac OsX
@@ -401,7 +445,7 @@ if test x"$gpl_escalation" != xno; then
     echo "You have selected --enable-lwgeom and/or --enable-gcp"
     echo
     echo "Both modules strictly depend on code released under the GPLv2+"
-    echo "license, wich is virally infective by definition."
+    echo "license, wich takes precedence over any other license."
     echo "Consequently the copy of libspatialite you are going to build"
     echo "if configured this way *must* be released under the GPLv2+ license."
     echo
@@ -409,5 +453,5 @@ if test x"$gpl_escalation" != xno; then
     echo "simply have to reconfigure by specifying the following options:"
     echo "        --disable-lwgeom --disable-gcp"
     echo "=============================================================="
-    
+  
 fi
diff --git a/examples/Makefile.am b/examples/Makefile.am
index f796a97..8a7f02f 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,4 +1,9 @@
+
+if MODULE_ONLY
+noinst_PROGRAMS = 
+else
 noinst_PROGRAMS = demo1 demo2 demo3 demo4 demo5
+endif
 
 AM_CFLAGS = -I at srcdir@/../src/headers 
 AM_LDFLAGS = -L../src -lspatialite -lm $(GCOV_FLAGS)
diff --git a/examples/Makefile.in b/examples/Makefile.in
index 7255a75..339807c 100644
--- a/examples/Makefile.in
+++ b/examples/Makefile.in
@@ -88,8 +88,9 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = demo1$(EXEEXT) demo2$(EXEEXT) demo3$(EXEEXT) \
-	demo4$(EXEEXT) demo5$(EXEEXT)
+ at MODULE_ONLY_FALSE@noinst_PROGRAMS = demo1$(EXEEXT) demo2$(EXEEXT) \
+ at MODULE_ONLY_FALSE@	demo3$(EXEEXT) demo4$(EXEEXT) \
+ at MODULE_ONLY_FALSE@	demo5$(EXEEXT)
 subdir = examples
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
diff --git a/spatialite-sql-latest.html b/spatialite-sql-latest.html
index 97597b5..ed9e472 100644
--- a/spatialite-sql-latest.html
+++ b/spatialite-sql-latest.html
@@ -9,7 +9,7 @@
 			i {color:navy;}
 		</style>
 	</head><body bgcolor="#fffff0">
-		<h2>SpatiaLite 4.3.0          SQL functions reference list</h2>
+		<h2>SpatiaLite 4.4.0-RC0          SQL functions reference list</h2>
 		<a href="https://www.gaia-gis.it/fossil/libspatialite">back</a>
 		<ul>
 			<li><a href="#version">SQL Version Info [and build options testing] functions</a></li>
@@ -55,6 +55,8 @@
 			<li><a href="#p18">SQL functions for R*Tree-based queries (Geometry Callbacks)</a></li>
 			<li><a href="#xmlBlob">SQL functions supporting XmlBLOB</a></li>
 			<li><a href="#srid">SQL functions supporting SRID inspection</a></li>
+			<li><a href="#topology">SQL functions supporting Topology-Geometry</a></li>
+			<li><a href="#network">SQL functions supporting Topology-Network</a></li>
 			<li><a href="#advanced">miscellaneous advanced SQL functions</a></li>
 		</ul>
 		<table bgcolor="#e2eae2" border="1" cellpadding="2" cellspacing="2" width="100%">
@@ -110,6 +112,12 @@
 			<tr><td><b>HasGeosTrunk</b></td>
 				<td>HasGeosTrunk( void ) : <i>Boolean</i></td>
 				<td colspan="3">TRUE if the underlaying library was built enabling <b>GEOSTRUNK</b></td></tr>
+			<tr><td><b>HasGeosReentrant</b></td>
+				<td>HasGeosReentrant( void ) : <i>Boolean</i></td>
+				<td colspan="3">TRUE if the underlaying library was built enabling <b>GEOSREENTRANT</b></td></tr>
+			<tr><td><b>HasGeosOnlyReentrant</b></td>
+				<td>HasGeosOnlyReentrant( void ) : <i>Boolean</i></td>
+				<td colspan="3">TRUE if the underlaying library was built enabling <b>GEOSONLYREENTRANT</b></td></tr>
 			<tr><td><b>HasLwGeom</b></td>
 				<td>HasLwGeom( void ) : <i>Boolean</i></td>
 				<td colspan="3">TRUE if the underlaying library was built enabling <b>LWGEOM</b></td></tr>
@@ -124,7 +132,14 @@
 				<td colspan="3">TRUE if the underlaying library was built enabling <b>FREEXL</b></td></tr>
 			<tr><td><b>HasGeoPackage</b></td>
 				<td>HasGeoPackage( void ) : <i>Boolean</i></td>
-				<td colspan="3">TRUE if the underlaying library was built enabling <b>GeoPackage</b> support (<b>GPKG</b>)</b>)</td></tr>
+				<td colspan="3">TRUE if the underlaying library was built enabling <b>GeoPackage</b> support (<b>GPKG</b>)</td></tr>
+			<tr><td><b>HasGCP</b></td>
+				<td>HasGCP( void ) : <i>Boolean</i><hr>
+				    HasGroundControlPoints ( void ) : <i>Boolean</i></td>
+				<td colspan="3">TRUE if the underlaying library was built enabling <b>Ground Control Points</b> support (<b>GGP</b>)</td></tr>
+			<tr><td><b>HasTopology</b></td>
+				<td>HasTopology( void ) : <i>Boolean</i></td>
+				<td colspan="3">TRUE if the underlaying library was built enabling <b>Topology</b> support</td></tr>
 			<tr><td colspan="5" align="center" bgcolor="#f0e0c0">
 				<h3><a name="generic">Generic SQL functions</a></h3></td></tr>
 			<tr><th bgcolor="#d0d0d0">Function</th>
@@ -1481,14 +1496,14 @@ calculations;
 				ST_Generalize( c <i>Curve</i> , tolerance <i>Double precision</i> ) : <i>Curve</i></td>
 				<td></td>
 				<td align="center" bgcolor="#f0d0d0">GEOS</td>
-				<td>return a geometric object representing a simplified version of <i>c</i> applying the Douglas-Peukert 
+				<td>return a geometric object representing a simplified version of <i>c</i> applying the Douglas-Peuker 
 algorithm with given <i>tolerance</i></td></tr>
 			<tr><td><b>SimplifyPreserveTopology</b></td>
 				<td>SimplifyPreserveTopology( c <i>Curve</i> , tolerance <i>Double precision</i> ) : <i>Curve</i><hr>
                                 ST_SimplifyPreserveTopology( c <i>Curve</i> , tolerance <i>Double precision</i> ) : <i>Curve</i></td></td>
 				<td></td>
 				<td align="center" bgcolor="#f0d0d0">GEOS</td>
-				<td>return a geometric object representing a simplified version of <i>c</i> applying the Douglas-Peukert 
+				<td>return a geometric object representing a simplified version of <i>c</i> applying the Douglas-Peuker
 algorithm with given <i>tolerance</i> and respecting topology</td></tr>
 			<tr><td colspan="5" align="center" bgcolor="#f0f0c0">
 				<h3><a name="p7">SQL functions on type LineString</a></h3></td></tr>
@@ -1944,8 +1959,8 @@ This function only supports Long/Lat coordinates, and will return NULL for any p
 					Second and third arguments are expected to be in the range between <b>0.0</b> and <b>1.0</b>.<br>
 					NULL is returned for invalid arguments</td></tr>
 			<tr><td><b>ClosestPoint</b></td>
-				<td>ClosesetPoint( geom1 <i>Geometry</i> , geom2 <i>Geometry</i> ) : <i>Point</i><hr>
-					ST_ClosesetPoint( geom1 <i>Geometry</i> , geom2 <i>Geometry</i> ) : <i>Point</i></td>
+				<td>ClosestPoint( geom1 <i>Geometry</i> , geom2 <i>Geometry</i> ) : <i>Point</i><hr>
+					ST_ClosestPoint( geom1 <i>Geometry</i> , geom2 <i>Geometry</i> ) : <i>Point</i></td>
 				<td></td>
 				<td align="center" bgcolor="#f0d0d0">GEOS</td>
 				<td>Returns the Point on geom1 that is closest to geom2.<br>
@@ -2254,12 +2269,20 @@ This function only supports Long/Lat coordinates, and will return NULL for any p
                                         All collapsed geometries will be stripped from the returned Geometry.<br>
 					NULL is returned on failure.</td></tr>
 			<tr><td><b>GeoHash</b></td>
-				<td>GeoHash( geom <i>Geometry</i> ) : <i>String</i><hr>
-					ST_GeoHash( geom <i>Geometry</i> ) : <i>String</i></td>
+				<td>GeoHash( geom <i>Geometry</i> [ , precision <i>Integer</i> ] ) : <i>String</i><hr>
+					ST_GeoHash( geom <i>Geometry</i> [ , precision <i>Integer</i> ] ) : <i>String</i></td>
 				<td></td>
 				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
 				<td>Return a GeoHash representation (geohash.org) of the geometry.<br>
-                                    A GeoHash encodes a point into a text form that is sortable and searchable based on prefixing.<hr>
+                                    A GeoHash encodes a point into a text form that is sortable and searchable based on prefixing.<br>
+                                    <ul>
+										<li>If no <i>precision</i> is specficified ST_GeoHash returns a GeoHash based on full precision of the input geometry type.<br>
+                                        Points return a GeoHash with 20 characters of precision (about enough to hold the full double precision of the input).</li>
+                                        <li>Other types return a GeoHash with a variable amount of precision, based on the size of the feature.
+                                        Larger features are represented with less precision, smaller features with more precision.
+                                        The idea is that the box implied by the GeoHash will always contain the input feature.</li>
+                                        <li>When explicitly set the <i>precision</i> argument will determine how many characters should by used by the returned GeoHash.</li>
+                                    </ul><hr>
                                     ST_GeoHash will not work with geometries that are not in geographic (lon/lat) coordinates</td></tr>
 			<tr><td><b>AsX3D</b></td>
 				<td>AsX3D( geom <i>Geometry</i> ) : <i>String</i><br>
@@ -2290,6 +2313,12 @@ This function only supports Long/Lat coordinates, and will return NULL for any p
 				<td></td>
 				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
 				<td>return the max 3D-distance between geom1 and geom2 (Z coordinates will be considered)</td></tr>
+			<tr><td><b>3dLength</b></td>
+				<td>ST_3dLength( geom <i>Geometry</i> ) : <i>Double precision</i></td>
+				<td></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td>return the total 2D or 3D-length of <i>Linestring</i> or <i>MultiLinestring</i> geometry.<br>
+				Z coordinates if eventually present will be considered leading to a 3D measured length; otherwise a 2D length will be computed.</td></tr>
 			<tr><td><b>ST_Node</b></td>
 				<td>ST_Node( geom <i>Geometry</i> ) : <i>Geometry</i></td>
 				<td></td>
@@ -2745,20 +2774,6 @@ the return type is Integer, with a return value of 1 for TRUE or 0 for FALSE</td
 					<li>otherwise the returned Envelope will simply reflect the current values stored into the Statics tables as they are (<b>OPTIMISTIC</b> strategy, adopted by default).</li>
 					</ul><hr>
                                         NULL will be returned if any error occurs or if the required table isn't a Layer.</td></tr>
-		<tr><td><b>CreateTopologyTables</b></td>
-				<td>CreateTopologyTables( SRID <i>Integer</i> , dims : <i>String</i> ) : <i>Integer</i><hr>
-					CreateTopologyTables( prefix <i>String</i> , SRID <i>Integer</i> , dims : <i>String</i> ) : <i>Integer</i></td>
-				<td></td>
-				<td align="center" bgcolor="#d0f0d0">base</td>
-				<td>Creates a set of <b>Topology</b> tables
-				<ul>
-					<li><b>SRID</b> argument is mandatory</li>
-					<li><b>dims</b> argument must be <b>'XY'</b> or <b>'XYZ'</b>:<br>
-						<b>2</b> or <b>3</b> are valid aliases</li>
-					<li>the <i>optional</i> argument <b>prefix</b> can be used to support more Topology sets on the same DB:<br>
-						if omitted a <b>"topo_"</b> prefix will be assumed by default</li>
-				</ul><hr>
-the return type is Integer, with a return value of 1 for TRUE (success) or 0 for FALSE (failure)</td></tr>
 		<tr><td><b>CreateRasterCoveragesTable</b></td>
 				<td>CreateRasterCoveragesTable( <i>void</i> ) : <i>Integer</i></td>
 				<td></td>
@@ -3811,6 +3826,12 @@ the return type is Integer, with a return value of 1 for TRUE, 0 for FALSE</td><
 				<td align="center" bgcolor="#99d099">libxml2</td>
 				<td>The return type is Integer, with a return value of 1 for TRUE, 0 for FALSE, and –1 for UNKNOWN
 					corresponding to a function invocation on NULL arguments.</td></tr>
+			<tr><td><b>XB_IsGpx</b></td>
+				<td>XB_IsGpx( xmlObject <i>XmlBLOB</i> ) : <i>Integer</i></td>
+				<td></td>
+				<td align="center" bgcolor="#99d099">libxml2</td>
+				<td>The return type is Integer, with a return value of 1 for TRUE, 0 for FALSE, and –1 for UNKNOWN
+					corresponding to a function invocation on NULL arguments.</td></tr>
 			<tr><td><b>XB_GetDocumentSize</b></td>
 				<td>XB_GetDocumentSize( xmlObject <i>XmlBLOB</i> ) : <i>Integer</i></td>
 				<td></td>
@@ -3898,6 +3919,13 @@ the return type is Integer, with a return value of 1 for TRUE, 0 for FALSE</td><
 				<td align="center" bgcolor="#99d099">libxml2</td>
 				<td>Will return the Geometry (Bounding Box) defined within the XmlBLOB (if any).<hr>
 				<b>NULL</b> will be returned for any invalid input (not a valid XmlBLOB object), or when no Bounding Box is defined.<hr>Supported only on ISO Metadata XML Documents.</td></tr>
+			<tr><td><b>XB_MLineFromGPX</b></td>
+				<td>XB_MLineFromGPX( xmlObject <i>XmlBLOB</i> ) : <i>Geometry</i></td>
+				<td></td>
+				<td align="center" bgcolor="#99d099">libxml2</td>
+				<td>Will return a Geometry of the <b>MULTILINESTRING XYZM</b> type by parsing an XmlBLOB corresponding to a GPX document.<hr>
+				<b>NULL</b> will be returned for any invalid input (not a valid XmlBLOB object), or when a valid XmlBLOB does not contains a GPX document, or when a valid GPX
+				does not contains any <b><trk></b> tag.</td></tr>
 			<tr><td><b>XB_GetLastParseError</b></td>
 				<td>XB_GetLastParseError( <i>void</i> ) : <i>String</i></td>
 				<td></td>
@@ -4013,6 +4041,579 @@ the return type is Integer, with a return value of 1 for TRUE, 0 for FALSE</td><
 				<td colspan="3">Will inspect the SRID definitions then returning the appropriate <b>Orientation</b> for its <b>second</b> axis.<br>
 					<b>NULL</b> will be returned on invalid argument or if the SRID is undefined.</td></tr>
 			<tr><td colspan="5" align="center" bgcolor="#f0e0c0">
+				<h3><a name="topology">SQL functions supporting Topology-Geometry</a></h3></td></tr>
+			<tr><th bgcolor="#d0d0d0">Function</th>
+				<th bgcolor="#d0d0d0">Syntax</th>
+				<th bgcolor="#d0d0d0">ISO 13249-3<br>defined</th>
+				<th bgcolor="#d0d0d0">required<br>module</th>
+				<th bgcolor="#d0d0d0" colspan="3">Summary</th></tr>
+			<tr><td><b>GetLastTopologyException</b></td>
+				<td>GetLastTopologyException( toponame <i>Text</i> ) : <i>Text</i></i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will return the most recent exception raised by this Topo-Geo, or <b>NULL</b> if no exception is currently pending.</td></tr>
+			<tr><td><b>InitTopoGeo</b></td>
+				<td>ST_InitTopoGeo( toponame <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">This SQL function is explicitly required by <b>ISO 13249-3</b>, anyway it's simply implemented as an <i>alias-name</i> for <b>CreateTopology ( toponame )</b>.<hr>
+					Will return <i>1</i> on success) or <i>0</i> on failure: <i>-1</i> will be returned on invalid arguments.</td></tr>
+			<tr><td><b>CreateTopology</b></td>
+				<td>CreateTopology( toponame <i>Text</i> ) : <i>Integer</i><hr>
+				    CreateTopology( toponame <i>Text</i> , srid <i>Integer</i> ) : <i>Integer</i><hr>
+				    CreateTopology( toponame <i>Text</i> , srid <i>Integer</i> , tolerance <i>Double precision</i> ) : <i>Integer</i><hr>
+				    CreateTopology( toponame <i>Text</i> , srid <i>Integer</i> , tolerance <i>Double precision</i> , has_z <i>Boolean</i>) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create all DBMS objects (tables, triggers, indices and alike) required in order to store a separate Topo-Geo.
+				<ul>
+					<li><i>toponame</i>: the individual unique name of this Topo-Geo: all subordinated tables will use it as a prefix.</li>
+					<li><i>srid</i>: the Spatial Reference System supporting this Topo-Geo (<b>-1</b> by default).</li>
+					<li><i>tolerence</i>: just a placeholder, at least since now. (<b>0.0</b> by default).</li>
+					<li><i>has_z</i>: if set to <b>TRUE</b> this Topo-Geo will support <b>3D - XYZ</b> coordinates (<b>FALSE</b> by default).</li>
+				</ul></td></tr>
+			<tr><td><b>DropTopology</b></td>
+				<td>DropTopology( toponame <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Completely removes a Topo-Geo (and all data it contains) from the DBMS: to be invoked very cautiously and only if you are absolutely sure of what you are doing.<hr>
+					Will return <i>1</i> on success) or <i>0</i> on failure: <i>-1</i> will be returned on invalid arguments.</td></tr>
+			<tr><td><b>AddIsoNode</b></td>
+				<td>ST_AddIsoNode( toponame <i>Text</i> , face-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will add a new isolated Node; <i>face-id</i> is expected to exactly match the ID of the Face containing <i>point</i>; by passing a 
+					<b>NULL face-id</b> the function itself will take care to identify the appropriate Face.<hr>
+					Will return the <b>ID</b> of the inserted Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>MoveIsoNode</b></td>
+				<td>ST_MoveIsoNode( toponame <i>Text</i> , node-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will move an isolated Node from a point to another.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>RemIsoNode</b></td>
+				<td>ST_RemIsoNode( toponame <i>Text</i> , node-id <i>Integer</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will remove an isolated Node.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>AddIsoEdge</b></td>
+				<td>ST_AddIsoEdge( toponame <i>Text</i> , startnode-id <i>Integer</i> , endnode-id <i>Integer</i> , linestring <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will add a new isolated Edge connecting two isolated Nodes.<hr>
+					Will return the <b>ID</b> of the inserted Edge on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ChangeEdgeGeom</b></td>
+				<td>ST_ChangeEdgeGeom( toponame <i>Text</i> , edge-id <i>Integer</i> , linestring <i>Geometry</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will change the geometry of an Edge without affecting Topology relationships.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>RemIsoEdge</b></td>
+				<td>ST_RemIsoEdge( toponame <i>Text</i> , edge-id <i>Integer</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will remove an isolated Edge.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>NewEdgesSplit</b></td>
+				<td>ST_NewEdgesSplit( toponame <i>Text</i> , edge-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will split an Edge by creating a new intermediate Node. The original Edge will be deleted and will be replaced by two new Edges.<hr>
+					Will return the <b>ID</b> of the inserted Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ModEdgeSplit</b></td>
+				<td>ST_ModEdgeSplit( toponame <i>Text</i> , edge-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will split an Edge by creating a new intermediate Node. The original Edge will be modified and a new Edge will be inserted.<hr>
+					Will return the <b>ID</b> of the inserted Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>NewEdgeHeal</b></td>
+				<td>ST_NewEdgeHeal( toponame <i>Text</i> , edge1-id <i>Integer</i> , edge2-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will heal two Edges by deleting the Node connecting them. Both the original Edges will be deleted and will be replaced by
+					a new Edge preserving the same orientation of the first Edge provided.<hr>
+					Will return the <b>ID</b> of the removed Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ModEdgeHeal</b></td>
+				<td>ST_ModEdgeHeal( toponame <i>Text</i> , edge1-id <i>Integer</i> , edge2-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will heal two Edges by deleting the Node connecting them. The first Edge provided will be modified and the second deleted.<hr>
+					Will return the <b>ID</b> of the removed Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>AddEdgeNewFaces</b></td>
+				<td>ST_AddEdgeNewFaces( toponame <i>Text</i> , startnode-id <i>Integer</i> , endnode-id <i>Integer</i> , linestring <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will add a new Edge connecting two Nodes. If this new Edge splits a Face the original Face will be deleted and replaced by two new Faces.<hr>
+					Will return the <b>ID</b> of the inserted Edge on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>AddEdgeModFace</b></td>
+				<td>ST_AddEdgeModFace( toponame <i>Text</i> , startnode-id <i>Integer</i> , endnode-id <i>Integer</i> , linestring <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will add a new Edge connecting two Nodes. If this new Edge splits a Face the original Face will be modified and a new Face will be inserted.<hr>
+					Will return the <b>ID</b> of the inserted Edge on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>RemEdgeNewFace</b></td>
+				<td>ST_RemEdgeNewFace( toponame <i>Text</i> , edge-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will remove an Edge. If the removed Edge separated two Faces the original Faces will be deleted and replaced by a new Face.<hr>
+					Will return the <b>ID</b> of the inserted Face on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>RemEdgeModFace</b></td>
+				<td>ST_RemEdgeModFace( toponame <i>Text</i> , edge-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will remove an Edge. If the removed Edge separated two Faces one of then will be modified and the other deleted.<hr>
+					Will return the <b>ID</b> of the surviving Face on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>GetFaceGeometry</b></td>
+				<td>ST_GetFaceGeometry( toponame <i>Text</i> , face-id <i>Integer</i> ) : <i>Geometry</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will return the exact Geometry of a Face.<hr>
+					Will return a <b>Polygon</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>GetFaceEdges</b></td>
+				<td>ST_GetFaceEdges( toponame <i>Text</i> , face-id <i>Integer</i> ) : <i>DB-table</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will update a DB-Table containing the ordered list of all Edges delimiting the given Face. 
+					The orientation will always be counterclockwise, and all Edges traversed in the opposite direction (i.e. from <u>end</u> to <u>start</u>) will be marked by a <b>negative sign</b>.<hr>
+					Will return <b>NULL</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ValidateTopoGeo</b></td>
+				<td>ST_ValidateTopoGeo( toponame <i>Text</i> ) : <i>DB-table</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create a DB-Table containing a validation report for the given TopoGeo: if the output table is empty and no exception was raised
+					the Topology is assumed to be fully valid, otherwise a row will be inserted into the table for each detected Topology invalidity.<br>
+					If the destination table already exists it will be dropped and created yet again.<hr>
+					Will return <b>NULL</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>CreateTopoGeo</b></td>
+				<td>ST_CreateTopoGeo( toponame <i>Text</i> , geometry <i>BLOB</i> )</td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will populate a full Topology by importing a collection of arbitrary Geometries.<br>
+					The destination Topology must already exists and must be empty; both SRID and dimensions of input Geometries must match SRID and dimensions declared by Topology.<hr>
+					Will return <b>NULL</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>GetNodeByPoint</b></td>
+				<td>GetNodeByPoint( toponame <i>Text</i> , point <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to find the ID of a Node located at Point.<hr>
+					Will return the ID of the Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>GetEdgeByPoint</b></td>
+				<td>GetEdgeByPoint( toponame <i>Text</i> , point <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to find the ID of an Edge intersecting the given Point.<hr>
+					Will return the ID of the Edge on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>GetFaceByPoint</b></td>
+				<td>GetFaceByPoint( toponame <i>Text</i> , point <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to find the ID of a Face intersecting the given Point.<hr>
+					Will return the ID of the Face on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_AddPoint</b></td>
+				<td>TopoGeo_AddPoint( toponame <i>Text</i> , point <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to add a <b>Point</b> (or even a <b>MultiPoint</b>) to an already existing Topology, possibly splitting existing Edges.<hr>
+					Will return a comma separated list of all IDs of corresponding Nodes on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_AddLineString</b></td>
+				<td>TopoGeo_AddLineString( toponame <i>Text</i> , linestring <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to add a <b>Linestring</b> (or even a <b>MultiLinestring</b>) to an already existing Topology, possibly splitting existing Edges/Faces.<hr>
+					Will return a comma separated list of all IDs of the corresponding Edges on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_SubdivideLines</b></td>
+				<td>TopoGeo_SubdivideLines( input <i>Geometry</i> , line_max_points <i>Integer</i> , line_max_length <i>Double precision</i> ) : <i>MultiLinestring</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to split a <b>Linestring</b> (or even a <b>MultiLinestring</b>, <b>Polygon</b> or <b>Multipolygon</b>) into a collection 
+					of shorter LineStrings fully respecting Topology consistency.
+					<ul>
+						<li>if argument <i>line_max_points</i> is set to a <u>positive</u> value then all input Linestrings will be split into many
+						shorter lines having no more than the required number of points.</li>
+						<li>if argument <i>line_max_length</i> is set to a <u>positive</u> value, in units of the SRID, then a separate output line will be split every time
+						that it becomes longer than the allowed limit.</li>
+						<li>if both <i>line_max_point</i> and <i>line_max_length</i> are active at the same time then the first limit encountered will apply.</li>
+						<li>in any other case all input Linestrings will be simply copied into the output collection exactly as they are.</li>
+					</ul><hr>
+					Will return a <b>MultiLinestring</b> Geometry on success; <b>NULL</b> on failure.</td></tr>
+			<tr><td><b>TopoGeo_FromGeoTable</b></td>
+				<td>TopoGeo_FromGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , table-name <i>Text</i> , column-name <i>Text</i>, tolerance <i>Double precision</i> ) : <i>Integer</i><hr>
+				    TopoGeo_FromGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , table-name <i>Text</i> , column-name <i>Text</i>, tolerance <i>Double precision</i> ,
+				    line_max_points <i>Integer</i> , line_max_length <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to import all Geometries from an input GeoTable identified by <i>db-prefix</i>, <i>table-name</i> and <i>column-name</i> into an already existing Topology-Geometry.
+					<ul>
+						<li><i>db-prefix</i> can be <b>NULL</b>, and in this case the input GeoTable is expected to be located within the <b>"MAIN"</b> database.</li>
+						<li><i>column-name</i> too can be <b>NULL</b>, and in this case the name of the column containing Geometries will be automatically retrieved;
+						if <b>"db"."table"</b> does not contains any Geometry column, or if it contains two or more Geometries an exception will be raised.</li>
+						<li>the input GeoTable must be properly registered and must match both <b>SRID</b> and <b>dimensions</b> declared by the target Topology.</li>
+						<li>this function accepts input Geometries of any class: <b>Point</b>, <b>MultiPoint</b>, <b>Linestring</b>, <b>MultiLinestring</b>,
+						<b>Polygon</b>, <b>MultiPolygon</b>, <b>GeometryCollection</b> and <b>Geometry</b>.</li>
+						<li>The optional arguments <i>line_max_points</i> and <i>line_max_length</i> will be interpreted in the same way adopted by <b>TopoGeo_SubdivideLines()</b> 
+						(default for both: <b>-1</b>).</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_Clone</b></td>
+				<td>TopoGeo_Clone( toponame <i>Text</i> , new-toponame <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will clone an existing Topology into another; the destionation Topology shall not exist and will be automatically created.<hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_GetEdgeSeed</b></td>
+				<td>TopoGeo_GetEdgeSeed( toponame <i>Text</i> , edge-id <i>Integer</i> ) : <i>Geometry</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will return a Point Geometry uniquely identifying an Edge (i.e. spatially intersecting the Edge).<hr>
+					Will return a <b>Point</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_GetFaceSeed</b></td>
+				<td>TopoGeo_GetFaceSeed( toponame <i>Text</i> , face-id <i>Integer</i> ) : <i>Geometry</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will return a Point Geometry uniquely identifying a Face (i.e. spatially intersecting the Face).<hr>
+					Will return a <b>Point</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_UpdateSeeds</b></td>
+				<td>TopoGeo_UpdateSeeds( toponame <i>Text</i> ) : <i>Integer</i><hr>
+				    TopoGeo_UpdateSeeds( toponame <i>Text</i> , incremental-mode <i>Integer</i> ) : <i>Integer</i> </td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will update all persistent Edge- and Face-Seeds so to correctly represent the current state of the underlaying Topology.
+					<ul>
+						<li>if the optional argument <i>incremental-mode</i> is set to TRUE an incremental update (faster) will be applied,
+						otherwise all persistent Seeds will be rebuilt from scratch (slower).</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_ToGeoTable</b></td>
+				<td>TopoGeo_ToGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> ) : <i>Integer</i><hr>
+				    TopoGeo_ToGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> , with-spatial-index <i>Boolenan</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to export into an Output GeoTable all Geometries out from a Topology-Geometry matching (via Seed-based references) a given
+				    Reference-GeoTable containing information attributes. 
+					<ul>
+						<li><i>db-prefix</i> can be <b>NULL</b>, and in this case the reference GeoTable is expected to be located within the <b>"MAIN"</b> database.</li>
+						<li><i>ref-column-name</i> too can be <b>NULL</b>, and in this case the name of the column containing Geometries will be automatically retrieved;
+						if <b>"db"."table"</b> does not contains any Geometry column, or if it contains two or more Geometries an exception will be raised.</li>
+						<li>the reference GeoTable must be properly registered and must match both <b>SRID</b> and <b>dimensions</b> declared by the target Topology.</li>
+						<li>this function accepts input Geometries of any class: <b>Point</b>, <b>MultiPoint</b>, <b>Linestring</b>, <b>MultiLinestring</b>,
+						<b>Polygon</b>, <b>MultiPolygon</b>, <b>GeometryCollection</b> and <b>Geometry</b>.</li>
+						<li>the output GeoTable will be always located on the <b>"MAIN"</b> DB and must not exists; it will be automatically created with the same identical
+						    attributes of the reference GeoTable.</li>
+						<li>all spatial features found into the reference GeoTable will be copied into the output GeoTable. All information attributes will be preserved
+						    exactly as they are, and the feature's Geometry will be built by aggregating all Topology objects matching the reference Geometry by Seed correspondences.<br>
+						    If no matching Topology objectes are found the result will be a <b>NULL</b> output Geometry.</li>
+						<li><i><u>Please note</u></i>: this function will automatically invoke <b>TopoGeo_UpdateSeeds()</b> (<i>incremental mode</i>).</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_ToGeoTableGeneralize</b></td>
+				<td>TopoGeo_ToGeoTableGeneralize( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> , tolerance <i>Double precision</i> ) : <i>Integer</i><hr>
+				    TopoGeo_ToGeoTableGeneralize( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> , tolerance <i>Double precision</i> , with-spatial-index <i>Boolean</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Exactly the same as <b>TopoGeo_ToGeoTable()</b> except in that all exported geometries will be simplified / generalized still maintaining full topological consistency. 
+					<ul>
+						<li><i>tolerance</i> represents the approximation radius required by the Douglas-Peuker simplification algorithm.</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_CreateTopoLayer</b></td>
+				<td>TopoGeo_CreateTopoLayer( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, topolayer-name <i>Text</i> ) : <i>Integer</i><hr>
+				    TopoGeo_CreateTopoLayer( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, topolayer-name <i>Text</i> , is-view <i>Boolean</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create a fully defined new <b>TopoLayer</b> starting from a reference GeoTable:
+					<ul>
+						<li><i>db-prefix</i> can be <b>NULL</b>, and in this case the reference GeoTable is expected to be located within the <b>"MAIN"</b> database.</li>
+						<li><i>ref-column-name</i> too can be <b>NULL</b>, and in this case the name of the column containing Geometries will be automatically retrieved;
+						if <b>"db"."table"</b> does not contains any Geometry column, or if it contains two or more Geometries an exception will be raised.</li>
+						<li>the reference GeoTable must be properly registered and must match both <b>SRID</b> and <b>dimensions</b> declared by the target Topology.</li>
+						<li>this function accepts input Geometries of any class: <b>Point</b>, <b>MultiPoint</b>, <b>Linestring</b>, <b>MultiLinestring</b>,
+						<b>Polygon</b>, <b>MultiPolygon</b>, <b>GeometryCollection</b> and <b>Geometry</b>.</li>
+						<li>if the optional boolean argument <b>is-view</b> is set to <b>TRUE</b> (any other value different from zero) then a View or a Table containing a unregistered Geometry column will
+						    be accepted (<b>FALSE</b> by default).<br>
+						    In this case <b>ref-column</b> must be always explicitly defined, and must contain all Geometries matching both <b>SRID</b> and <b>dimensions</b> declared by the target Topology.</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_InitTopoLayer</b></td>
+				<td>TopoGeo_InitTopoLayer( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , topolayer-name <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will initialize a partialy defined new <b>TopoLayer</b> starting from a reference plain Table or View:
+					<ul>
+						<li><i>db-prefix</i> can be <b>NULL</b>, and in this case the reference Table or View is expected to be located within the <b>"MAIN"</b> database.</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_RemoveTopoLayer</b></td>
+				<td>TopoGeo_RemoveTopoLayer( toponame <i>Text</i> , topolayer-name <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will completely remove an existing <b>TopoLayer</b>.<hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_ExportTopoLayer</b></td>
+				<td>TopoGeo_ExportTopoLayer( toponame <i>Text</i> , topolayer-name <i>Text</i> , out-table <i>Text</i> ) : <i>Integer</i><hr>
+				    TopoGeo_ExportTopoLayer( toponame <i>Text</i> , topolayer-name <i>Text</i> , out-table <i>Text</i> , with-spatial-index <i>Boolean</i> ) : <i>Integer</i><hr>
+				    TopoGeo_ExportTopoLayer( toponame <i>Text</i> , topolayer-name <i>Text</i> , out-table <i>Text</i> , with-spatial-index <i>Boolean</i> , create-only <i>Boolean</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create and populate a GeoTable corresponding to a <b>TopoLayer</b>.
+					<ul>
+						<li>if the optional boolean argument <b>with-spatial-index</b> is set to <b>TRUE</b> (any other value different from zero) then a <b>Spatial Index</b> supporting
+						the output GeoTable will be automatically created (<b>FALSE</b> by default).</li>
+						<li>if the optional boolean argument <b>create-only</b> is set to <b>TRUE</b> (any other value different from zero) then the output GeoTable will be created 
+						but will not be populated thus remaining completely empty (<b>FALSE</b> by default).</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoGeo_InsertFeatureFromTopoLayer</b></td>
+				<td>TopoGeo_InsertFeatureFrom( toponame <i>Text</i> , topolayer-name <i>Text</i> , out-table <i>Text</i> , fid <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will inserting a single TopoFeature identified by is <b>fid</b> into a GeoTable corresponding to a <b>TopoLayer</b>.
+					<ul>
+						<li>the output GeoTable must exist and is expected to be created by a previous call to <b>TopoGeo_ExportTopoLayer()</b>.</li>
+						<li>the TopoFeature identified by <b>fid</b> must exist and a corresponding row must not be already inserted into the output GeoTable.</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td colspan="5" align="center" bgcolor="#f0e0c0">
+				<h3><a name="network">SQL functions supporting Topology-Network</a></h3></td></tr>
+			<tr><th bgcolor="#d0d0d0">Function</th>
+				<th bgcolor="#d0d0d0">Syntax</th>
+				<th bgcolor="#d0d0d0">ISO 13249-3<br>defined</th>
+				<th bgcolor="#d0d0d0">required<br>module</th>
+				<th bgcolor="#d0d0d0" colspan="3">Summary</th></tr>
+			<tr><td><b>GetLastNetworkException</b></td>
+				<td>GetLastNetworkException( netname <i>Text</i> ) : <i>Text</i></i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will return the most recent exception raised by this Topo-Net, or <b>NULL</b> if no exception is currently pending.</td></tr>
+			<tr><td><b>InitTopoNet</b></td>
+				<td>ST_InitTopoNet( netname <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">This SQL function is explicitly required by <b>ISO 13249-3</b>, anyway it's simply implemented as an <i>alias-name</i> for <b>CreateNetwork ( netname )</b>.<hr>
+					Will return <i>1</i> on success) or <i>0</i> on failure: <i>-1</i> will be returned on invalid arguments.</td></tr>
+			<tr><td><b>CreateNetwork</b></td>
+				<td>CreateNetwork( netname <i>Text</i> ) : <i>Integer</i><hr>
+				    CreateNetwork( netname <i>Text</i> , spatial <i>Boolean</i> ) : <i>Integer</i><hr>
+				    CreateNetwork( netname <i>Text</i> , spatial <i>Boolean</i> , srid <i>Integer</i> ) : <i>Integer</i><hr>
+				    CreateNetwork( netname <i>Text</i> , spatial <i>Boolean</i> , srid <i>Integer</i> , has_z <i>Boolean</i> ) : <i>Integer</i><hr>
+				    CreateNetwork( netname <i>Text</i> , spatial <i>Boolean</i> , srid <i>Integer</i> , has_z <i>Boolean</i> , allow_coincident <i>Boolean</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create all DBMS objects (tables, triggers, indices and alike) required in order to store a separate Topo-Net.
+				<ul>
+					<li><i>netname</i>: the individual unique name of this Topo-Net: all subordinated tables will use it as a prefix.</li>
+					<li><i>spatial</i>: if set to <b>TRUE</b> this Topo-Net will be considered a <b>Spatial-Network</b>, otherwise a <b>Logical-Network</b> will be assumed (<b>FALSE</b> by default).</li>
+					<li><i>srid</i>: the Spatial Reference System supporting this Topo-Net (<b>-1</b> by default).</li>
+					<li><i>has_z</i>: if set to <b>TRUE</b> this Topo-Net will support <b>3D - XYZ</b> coordinates (<b>FALSE</b> by default).</li>
+					<li><i>allow_coincident</i>: if set to <b>FALSE</b> all <u>Node-on-Node</u>, <u>Link-on-Node</u> or <u>Node-on-Link</u> conditions will raise an exception (<b>TRUE</b> by default).</li>
+				</ul></td></tr>
+			<tr><td><b>DropNetwork</b></td>
+				<td>DropNetwork( netname <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Completely removes a Topo-Net (and all data it contains) from the DBMS: to be invoked very cautiously and only if you are absolutely sure of what you are doing.<hr>
+					Will return <i>1</i> on success) or <i>0</i> on failure: <i>-1</i> will be returned on invalid arguments.</td></tr>
+			<tr><td><b>AddIsoNetNode</b></td>
+				<td>ST_AddIsoNetNode( netname <i>Text</i> , point <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will add a new isolated NetNode.<hr>
+					Will return the <b>ID</b> of the inserted NetNode on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>MoveIsoNetNode</b></td>
+				<td>ST_MoveIsoNetNode( netname <i>Text</i> , node-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will move an isolated NetNode from a point to another.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>RemIsoNetNode</b></td>
+				<td>ST_RemIsoNetNode( netname <i>Text</i> , node-id <i>Integer</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will remove an isolated NetNode.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>AddLink</b></td>
+				<td>ST_AddLink( netname <i>Text</i> , startnode-id <i>Integer</i> , endnode-id <i>Integer</i> , linestring <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will add a new Link connecting two NetNodes.<hr>
+					Will return the <b>ID</b> of the inserted Link on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ChangeLinkGeom</b></td>
+				<td>ST_ChangeLinkGeom( netname <i>Text</i> , link-id <i>Integer</i> , linestring <i>Geometry</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will change the geometry of a Link without affecting Topology relationships.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>RemoveLink</b></td>
+				<td>ST_RemoveLink( netname <i>Text</i> , link-id <i>Integer</i> ) : <i>Text</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will remove a Link.<hr>
+					Will return a <b>text message</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>NewLogLinkSplit</b></td>
+				<td>ST_NewLogLinkSplit( netname <i>Text</i> , link-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will split a Link (of the <u>Logical</u> type) by creating a new intermediate NetNode. The original Link will be deleted and will be replaced by two new Links.<hr>
+					Will return the <b>ID</b> of the inserted Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ModLogLinkSplit</b></td>
+				<td>ST_ModLogLingSplit( netname <i>Text</i> , link-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will split a Link (of the <u>Logical</u> type) by creating a new intermediate NetNode. The original Link will be modified and a new Link will be inserted.<hr>
+					Will return the <b>ID</b> of the inserted Node on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>NewGeoLinkSplit</b></td>
+				<td>ST_NewGeoLinkSplit( netame <i>Text</i> , link-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will split a Link (of the <u>Spatial</u> type) by creating a new intermediate NetNode. The original Link will be deleted and will be replaced by two new Links.<hr>
+					Will return the <b>ID</b> of the inserted NetNode on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ModGeoLinkSplit</b></td>
+				<td>ST_ModGeoLingSplit( netame <i>Text</i> , link-id <i>Integer</i> , point <i>Geometry</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will split a Link (of the <u>Spatial</u> type) by creating a new intermediate NetNode. The original Link will be modified and a new Link will be inserted.<hr>
+					Will return the <b>ID</b> of the inserted NetNode on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>NewLinkHeal</b></td>
+				<td>ST_NewLinkHeal( netname <i>Text</i> , link1-id <i>Integer</i> , link2-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will heal two Links by deleting the NetNode connecting them. Both the original Links will be deleted and will be replaced by
+					a new Link preserving the same orientation of the first Link provided.<hr>
+					Will return the <b>ID</b> of the removed NetNode on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ModLinkHeal</b></td>
+				<td>ST_ModLinkHeal( netname <i>Text</i> , link1-id <i>Integer</i> , link2-id <i>Integer</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will heal two Links by deleting the NetNode connecting them. The first Link provided will be modified and the second deleted.<hr>
+					Will return the <b>ID</b> of the removed NetNode on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>LogiNetFromTGeo</b></td>
+				<td>ST_LogiNetFromTGeo( netname <i>Text</i> , toponame <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create a <b>Logical Topology-Network</b> from an existing <b>Topology-Geometry</b>.<br>
+					The destination <i>TopoNet</i> is expected to exist and to be completely empty.<hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.<br>
+					Calling this function on behalf of some Network of the Spatial type will raise an exception.</td></tr>
+			<tr><td><b>SpatNetFromTGeo</b></td>
+				<td>ST_SpatNetFromTGeo( netname <i>Text</i> , toponame <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create a <b>Spatial Topology-Network</b> from an existing <b>Topology-Geometry</b>.<br>
+					The destination <i>TopoNet</i> is expected to exist and to be completely empty.<hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.<br>
+					Calling this function on behalf of some Network of the Logical type will raise an exception; both the <i>TopoNet</i>
+					and the <i>TopoGeo</i> are expected to declared the same identical <b>SRID</b> and <b>dimensions</b> (<i>2D</i> or <i>3D</i>),
+					otherwise an exception will be raised.</td></tr>
+			<tr><td><b>SpatNetFromGeom</b></td>
+				<td>ST_SpatNetFromGeom( netname <i>Text</i> , geometry <i>BLOB</i> )</td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will populate a full Network by importing a collection of arbitrary Geometries.<br>
+					The destination Network must already exists and must be empty; both SRID and dimensions of input Geometries must match SRID and dimensions declared by Network.<br>
+					Calling this function on behalf of some Network of the Logical type will raise an exception<hr>
+					Will return <b>NULL</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>ValidLogicalNet</b></td>
+				<td>ST_ValidLogicalNet( netname <i>Text</i> ) : <i>DB-table</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create a DB-Table containing a validation report for the given TopoNet of the Logical type: if the output table is empty and no exception was raised
+					the Network is assumed to be fully valid, otherwise a row will be inserted into the table for each detected Topology invalidity.<br>
+					If the destination table already exists it will be dropped and created yet again.<hr>
+					Will return <b>NULL</b> on success; an exception will be raised on failure.<br>
+					Calling this function on behalf of some Network of the Spatial type will raise an exception.</td></tr>
+			<tr><td><b>ValidSpatialNet</b></td>
+				<td>ST_ValidSpatialNet( netname <i>Text</i> ) : <i>DB-table</i></td>
+				<td align="center" bgcolor="#d0f0d0">X</td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will create a DB-Table containing a validation report for the given TopoNet of the Spatial type: if the output table is empty and no exception was raised
+					the Network is assumed to be fully valid, otherwise a row will be inserted into the table for each detected Topology invalidity.<br>
+					If the destination table already exists it will be dropped and created yet again.<hr>
+					Will return <b>NULL</b> on success; an exception will be raised on failure.<br>
+					Calling this function on behalf of some Network of the Logical type will raise an exception.</td></tr>
+			<tr><td><b>GetNetNodeByPoint</b></td>
+				<td>GetNetNodeByPoint( netname <i>Text</i> , point <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to find the ID of a NetNode located at Point.<hr>
+					Will return the ID of the NetNode on success; an exception will be raised on failure.<br>
+					<b>Note</b>: this function cannot be applied to a <i>Logical Network</i></td></tr>
+			<tr><td><b>GetLinkByPoint</b></td>
+				<td>GetLinkByPoint( netname <i>Text</i> , point <i>Geometry</i> , tolerance <i>Double precision</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to find the ID of a Link intersecting the given Point.<hr>
+					Will return the ID of the Link on success; an exception will be raised on failure.<br>
+					<b>Note</b>: this function cannot be applied to a <i>Logical Network</i></td></tr>
+			<tr><td><b>TopoNet_FromGeoTable</b></td>
+				<td>TopoNet_FromGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , table-name <i>Text</i> , column-name <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to import all Geometries from an input GeoTable identified by <i>db-prefix</i>, <i>table-name</i> and <i>column-name</i> into an already existing Topology-Network.
+					<ul>
+						<li><i>db-prefix</i> can be <b>NULL</b>, and in this case the input GeoTable is expected to be located within the <b>"MAIN"</b> database.</li>
+						<li><i>column-name</i> too can be <b>NULL</b>, and in this case the name of the column containing Geometries will be automatically retrieved;
+						if <b>"db"."table"</b> does not contains any Geometry column, or if it contains two or more Geometries an exception will be raised.</li>
+						<li>the input GeoTable must be properly registered and must match both <b>SRID</b> and <b>dimensions</b> declared by the target Topology.</li>
+						<li>this function only accepts input Geometries of the <b>Linestring</b> or <b>MultiLinestring</b> classes.</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoNet_Clone</b></td>
+				<td>TopoNet_Clone( netname <i>Text</i> , new-netname <i>Text</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will clone an existing Network into another; the destionation Network shall not exist and will be automatically created.<hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoNet_GetLinkSeed</b></td>
+				<td>TopoNet_GetLinkSeed( netname <i>Text</i> , link-id <i>Integer</i> ) : <i>Geometry</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will return a Point Geometry uniquely identifying a Link (i.e. spatially intersecting the Link).<hr>
+					Will return a <b>Point</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoNet_UpdateSeeds</b></td>
+				<td>TopoNet_UpdateSeeds( netname <i>Text</i> ) : <i>Integer</i><hr>
+				    TopoNet_UpdateSeeds( netname <i>Text</i> , incremental-mode <i>Integer</i> ) : <i>Integer</i> </td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will update all persistent Link-Seeds so to correctly represent the current state of the underlaying Network.
+					<ul>
+						<li>if the optional argument <i>incremental-mode</i> is set to TRUE an incremental update (faster) will be applied,
+						otherwise all persistent Seeds will be rebuilt from scratch (slower).</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoNet_ToGeoTable</b></td>
+				<td>TopoNet_ToGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> ) : <i>Integer</i><hr>
+				    TopoNet_ToGeoTable( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> , with-spatial-index <i>Boolean</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Will attempt to export into an Output GeoTable all Geometries out from a Topology-Network matching (via Seed-based references) a given
+				    Reference-GeoTable containing information attributes. 
+					<ul>
+						<li><i>db-prefix</i> can be <b>NULL</b>, and in this case the reference GeoTable is expected to be located within the <b>"MAIN"</b> database.</li>
+						<li><i>ref-column-name</i> too can be <b>NULL</b>, and in this case the name of the column containing Geometries will be automatically retrieved;
+						if <b>"db"."table"</b> does not contains any Geometry column, or if it contains two or more Geometries an exception will be raised.</li>
+						<li>the reference GeoTable must be properly registered and must match both <b>SRID</b> and <b>dimensions</b> declared by the target Network.</li>
+						<li>this function accepts input Geometries of the following classes: <b>Point</b>, <b>MultiPoint</b>, <b>Linestring</b>, <b>MultiLinestring</b>,
+						<b>GeometryCollection</b> and <b>Geometry</b>.<br>
+						All areal Geometries (<i>Polygon</i>, <i>MultiPolygon</i>) will be always ignored.</li>
+						<li>the output GeoTable will be always located on the <b>"MAIN"</b> DB and must not exists; it will be automatically created with the same identical
+						    attributes of the reference GeoTable.</li>
+						<li>all spatial features found into the reference GeoTable will be copied into the output GeoTable. All information attributes will be preserved
+						    exactly as they are, and the feature's Geometry will be built by aggregating all Topology objects matching the reference Geometry by Seed correspondences.<br>
+						    If no matching Topology objectes are found the result will be a <b>NULL</b> output Geometry.</li>
+						<li><i><u>Please note</u></i>: this function will automatically invoke <b>TopoNet_UpdateSeeds()</b> (<i>incremental mode</i>).</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td><b>TopoNet_ToGeoTableGeneralize</b></td>
+				<td>TopoNet_ToGeoTableGeneralize( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> , tolerance <i>Double precision</i> ) : <i>Integer</i><hr>
+				    TopoNet_ToGeoTableGeneralize( toponame <i>Text</i> , db-prefix <i>Text</i> , ref-table-name <i>Text</i> , ref-column-name <i>Text</i>, out-table <i>Text</i> , tolerance <i>Double precision</i> , with-spatial-index <i>Boolean</i> ) : <i>Integer</i></td>
+				<td align="center" bgcolor="#d0f0d0"></td>
+				<td align="center" bgcolor="#f0d0f0">LWGEOM</td>
+				<td colspan="3">Exactly the same as <b>TopoNet_ToGeoTable()</b> except in that all exported geometries will be simplified / generalized still maintaining full topological consistency. 
+					<ul>
+						<li><i>tolerance</i> represents the approximation radius required by the Douglas-Peuker simplification algorithm.</li>
+					</ul><hr>
+					Will return <b>1</b> on success; an exception will be raised on failure.</td></tr>
+			<tr><td colspan="5" align="center" bgcolor="#f0e0c0">
 				<h3><a name="advanced">miscellaneous advanced SQL functions</a></h3></td></tr>
 			<tr><th bgcolor="#d0d0d0">Function</th>
 				<th bgcolor="#d0d0d0">Syntax</th>
@@ -4045,6 +4646,15 @@ the return type is Integer, with a return value of 1 for TRUE, 0 for FALSE</td><
 				</ul>
 				<hr>
 				Will return <b>0</b> (i.e. <b>FALSE</b>) on failure, any other value (i.e. <b>TRUE</b>) on success. <b>NULL</b> will be returned on invalid arguments.</td></tr>
+			<tr><td><b>CreateClonedTable</b></td>
+				<td>CreateClonedTable( db-prefix <i>Text</i> , input_table <i>Text</i> , output_table <i>Text</i> , 
+				transaction <i>Integer</i> ) : <i>Integer</i><hr>
+				CreateClonedTable(  db-prefix <i>Text</i> , input_table <i>Text</i> , output_table <i>Text</i> , 
+				transaction <i>Integer</i> , option_1 <i>Text</i> [ , ... , option_10 <i>Text</i> ] ) : <i>Integer</i></td>
+				<td colspan="3">A strict derivative of <b>CloneTable()</b> accepting the same arguments with identical meaning.<br>
+				The only difference is in that this second variant will just create the output Table completely avoiding to copy any row betweem the two tables. 
+				<hr>
+				Will return <b>0</b> (i.e. <b>FALSE</b>) on failure, any other value (i.e. <b>TRUE</b>) on success. <b>NULL</b> will be returned on invalid arguments.</td></tr>
 			<tr><td><b>CheckDuplicateRows</b></td>
 				<td>CheckDuplicateRows( table <i>Text</i> ) : <i>Integer</i></td>
 				<td colspan="3">Will check if the given <b>table</b> does contain duplicate rows, i.e. rows presenting identical 
@@ -4316,7 +4926,42 @@ the return type is Integer, with a return value of 1 for TRUE, 0 for FALSE</td><
 					</ul>
 					Will return <b>0</b> (i.e. <b>FALSE</b>) on failure, any other value (i.e. <b>TRUE</b>) on success.<hr>
                     <u>Please note well</u>: this SQL function open the doors to many potential security issues, and thus is always <i>disabled by default</i>.<br>
-                    Explicitly setting the environment variable <b>SPATIALITE_SECURITY=relaxed</b> is absolutely required in order to effectively enable this function.</td></tr>	
+                    Explicitly setting the environment variable <b>SPATIALITE_SECURITY=relaxed</b> is absolutely required in order to effectively enable this function.</td></tr>		
+			<tr><td><b>ST_Cutter()</b></td>
+				<td>ST_Cutter( input-db-prefix <i>String</i> , input-table <i>String</i> , input-geometry <i>String</i> , blade-db-prefix <i>String</i> ,
+				    blade-table <i>String</i> , blade-geom <i>String</i> , output-table <i>String</i>
+				    [ , transaction <i>Boolean</i> [ , ram-temp-storage <i>Boolean</i> ] ] ) : <i>Integer</i></td>
+				<td colspan="3">Will precisely cut in a topological consistent way a whole <b>Input dataset</b> using a <b>Blade dataset</b> (i.e. an arbitrary <i>polygonal</i> dataset).<br>
+				    All cut fragments will be stored into a further <b>Output dataset</b>, and all <i>mother-child relationships</i> will be fully preserved by saving the <i>Primary Key values</i> allowing
+				    to trace back <i>Input</i> and <i>Blade</i> pairs giving birth to each single fragment.<br>
+				    Any cut fragment stored into the <i>Output dataset</i> eventually falling outside any Blade will reference a conventional <b>NULL</b> Blade.
+				    <ul>
+                    <li>The <i>Input</i> dataset is always expected to declare a <b>Primary Key</b> and must declare a <i>POINT</i>, <i>LINESTRING</i>, <i>POLYGON</i>,
+                    <i>MULTIPOINT</i>, <i>MULTILINESTRING</i> or <i>MULTIPOLYGON</i> Geometry type.<br>
+                    It could be indifferently located on the <b>MAIN</b> database or on any other <b>attached DB</b>, and is fully identified by the <b>input-db-prefix</b>,
+                    <b>input-table</b> and <b>input-geometry</b> arguments.</li>
+                    <li>The <i>Blade</i> dataset is always expected to declare a <b>Primary Key</b> and must declare a <i>POLYGON</i> or <i>MULTIPOLYGON</i> Geometry type.<br>
+                    It could be indifferently located on the <b>MAIN</b> database or on any other <b>attached DB</b>, and is fully identified by the <b>blade-db-prefix</b>,
+                    <b>blade-table</b> and <b>blade-geometry</b> arguments.<br>
+                    <u>Note</u>: both the <i>Input</i> and <i>Blade</i> Geometries must share the same identical <i>SRID</i> value.</li>
+                    <li>The <i>Output</i> dataset will be always located into the <b>MAIN</b> database.<br>
+                    The Output Geometry will always preserve the name and SRID declared by <b>input-geom</b>: the Geometry type will be always be one between
+                    <i>POINT</i>, <i>LINESTRING</i> or <i>POLYGON</i> (all cut fragments will be stored as simple features on distinct rows).</li>
+					</ul>
+					<ul>
+					<li>Both the <b>input-db-prefix</b> and <b>blade-db-prefix</b> arguments could be legitimately declared as <b>NULL</b>, and in this case the <b>MAIN</b> database will be always assumed.</li>
+					<li>and also the <b>input-geom</b> and <b>blade-geom</b> arguments could be legitimately declared as <b>NULL</b>.<br>
+					In this case the appropriate Geometry column name will be implicitly determined, but only if the corresponding table declares just a single Geometry column, otherwise an exception will be raised.</li>
+					<li>The <i>optional</i> argument <b>transaction</b> determines if an internal SQL Transaction should be automatically started or not (the default setting if not explicitly overridden is FALSE).</li>
+					<li>The <i>optional</i> argument <b>ram-tmp-storage</b> determines if the intermediate <i>temporary tables</i> internally used by this function should be created in RAM or not 
+					(the default setting if not explicitly overridden is FALSE).</li>
+					</ul>
+					Will return <b>-1</b> on invalid arguments, <b>0</b> on failure, <b>1</b> on full success and <b>2</b> on partial success (i.e.when the output table contains
+					one or more <i>invalid geometries</i>).</td></tr>			
+			<tr><td><b>GetCutterMessage()</b></td>
+				<td>GetCutterMessage( <i>void</i> ) : <i>String</i></td>
+				<td colspan="3">Will return the most <i>recent diagnostic message</i> emitted by <b>ST_Cutter()</b>.<br>
+				<b>NULL</b> will be returned if no such message currently exists.</td></tr>	
 		</tbody></table>
 		<a href="https://www.gaia-gis.it/fossil/libspatialite">back</a>
 	</body></html>
diff --git a/src/Makefile.am b/src/Makefile.am
index 41ed3c4..64b688f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,13 +13,19 @@ SUBDIRS = headers \
 	wfs \
 	dxf \
 	md5 \
-	control_points
+	control_points \
+	cutter \
+	topology
 
 AM_CPPFLAGS = @CFLAGS@
 AM_CPPFLAGS += -I$(top_srcdir)/src/headers
 AM_CPPFLAGS += -I$(top_srcdir)
 
+if MODULE_ONLY
+lib_LTLIBRARIES = mod_spatialite.la
+else
 lib_LTLIBRARIES = libspatialite.la mod_spatialite.la
+endif
 
 libspatialite_la_SOURCES = versioninfo/version.c
 
@@ -31,21 +37,23 @@ libspatialite_la_LIBADD = ./gaiaaux/libgaiaaux.la \
 	./shapefiles/libshapefiles.la \
 	./dxf/libdxf.la \
 	./md5/libmd5.la  \
-	./control_points/libcontrol_points.la\
+	./control_points/libcontrol_points.la \
+	./cutter/libcutter.la \
+	./topology/libtopology.la \
 	./srsinit/libsrsinit.la \
 	./connection_cache/libconnection_cache.la \
 	./virtualtext/libvirtualtext.la \
 	./wfs/libwfs.la @LIBXML2_LIBS@
 
 if MINGW
-libspatialite_la_LDFLAGS = -version-info 4:3:0 -no-undefined
+libspatialite_la_LDFLAGS = -version-info 4:4:0 -no-undefined
 libspatialite_la_LIBADD += -lm
 else 
 if ANDROID
-libspatialite_la_LDFLAGS = -version-info 8:0:1
+libspatialite_la_LDFLAGS = -version-info 8:1:1
 libspatialite_la_LIBADD += -ldl -lm
 else
-libspatialite_la_LDFLAGS = -version-info 8:0:1
+libspatialite_la_LDFLAGS = -version-info 8:1:1
 libspatialite_la_LIBADD += -lpthread -ldl -lm
 endif
 endif
@@ -61,6 +69,8 @@ mod_spatialite_la_LIBADD = ./gaiaaux/gaiaaux.la \
 	./dxf/dxf.la \
 	./md5/md5.la \
 	./control_points/control_points.la \
+	./cutter/cutter.la \
+	./topology/topology.la \
 	./srsinit/srsinit.la \
 	./connection_cache/connection_cache.la \
 	./virtualtext/virtualtext.la \
diff --git a/src/Makefile.in b/src/Makefile.in
index fe72ed6..3f19d47 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -141,7 +141,8 @@ libspatialite_la_DEPENDENCIES = ./gaiaaux/libgaiaaux.la \
 	./gaiaexif/libgaiaexif.la ./gaiageo/libgaiageo.la \
 	./geopackage/libgeopackage.la ./spatialite/libsplite.la \
 	./shapefiles/libshapefiles.la ./dxf/libdxf.la ./md5/libmd5.la \
-	./control_points/libcontrol_points.la ./srsinit/libsrsinit.la \
+	./control_points/libcontrol_points.la ./cutter/libcutter.la \
+	./topology/libtopology.la ./srsinit/libsrsinit.la \
 	./connection_cache/libconnection_cache.la \
 	./virtualtext/libvirtualtext.la ./wfs/libwfs.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -157,11 +158,13 @@ libspatialite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_CFLAGS) $(CFLAGS) $(libspatialite_la_LDFLAGS) $(LDFLAGS) \
 	-o $@
+ at MODULE_ONLY_FALSE@am_libspatialite_la_rpath = -rpath $(libdir)
 mod_spatialite_la_DEPENDENCIES = ./gaiaaux/gaiaaux.la \
 	./gaiaexif/gaiaexif.la ./gaiageo/gaiageo.la \
 	./geopackage/geopackage.la ./spatialite/splite.la \
 	./shapefiles/shapefiles.la ./dxf/dxf.la ./md5/md5.la \
-	./control_points/control_points.la ./srsinit/srsinit.la \
+	./control_points/control_points.la ./cutter/cutter.la \
+	./topology/topology.la ./srsinit/srsinit.la \
 	./connection_cache/connection_cache.la \
 	./virtualtext/virtualtext.la ./wfs/wfs.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -173,6 +176,8 @@ mod_spatialite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(mod_spatialite_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
 	$(CCLD) $(AM_CFLAGS) $(CFLAGS) $(mod_spatialite_la_LDFLAGS) \
 	$(LDFLAGS) -o $@
+ at MODULE_ONLY_FALSE@am_mod_spatialite_la_rpath = -rpath $(libdir)
+ at MODULE_ONLY_TRUE@am_mod_spatialite_la_rpath = -rpath $(libdir)
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -421,28 +426,33 @@ SUBDIRS = headers \
 	wfs \
 	dxf \
 	md5 \
-	control_points
+	control_points \
+	cutter \
+	topology
 
 AM_CPPFLAGS = @CFLAGS@ -I$(top_srcdir)/src/headers -I$(top_srcdir)
-lib_LTLIBRARIES = libspatialite.la mod_spatialite.la
+ at MODULE_ONLY_FALSE@lib_LTLIBRARIES = libspatialite.la mod_spatialite.la
+ at MODULE_ONLY_TRUE@lib_LTLIBRARIES = mod_spatialite.la
 libspatialite_la_SOURCES = versioninfo/version.c
 libspatialite_la_LIBADD = ./gaiaaux/libgaiaaux.la \
 	./gaiaexif/libgaiaexif.la ./gaiageo/libgaiageo.la \
 	./geopackage/libgeopackage.la ./spatialite/libsplite.la \
 	./shapefiles/libshapefiles.la ./dxf/libdxf.la ./md5/libmd5.la \
-	./control_points/libcontrol_points.la ./srsinit/libsrsinit.la \
+	./control_points/libcontrol_points.la ./cutter/libcutter.la \
+	./topology/libtopology.la ./srsinit/libsrsinit.la \
 	./connection_cache/libconnection_cache.la \
 	./virtualtext/libvirtualtext.la ./wfs/libwfs.la @LIBXML2_LIBS@ \
 	$(am__append_1) $(am__append_2) $(am__append_3)
- at ANDROID_FALSE@@MINGW_FALSE at libspatialite_la_LDFLAGS = -version-info 8:0:1
- at ANDROID_TRUE@@MINGW_FALSE at libspatialite_la_LDFLAGS = -version-info 8:0:1
- at MINGW_TRUE@libspatialite_la_LDFLAGS = -version-info 4:3:0 -no-undefined
+ at ANDROID_FALSE@@MINGW_FALSE at libspatialite_la_LDFLAGS = -version-info 8:1:1
+ at ANDROID_TRUE@@MINGW_FALSE at libspatialite_la_LDFLAGS = -version-info 8:1:1
+ at MINGW_TRUE@libspatialite_la_LDFLAGS = -version-info 4:4:0 -no-undefined
 mod_spatialite_la_SOURCES = versioninfo/version.c
 mod_spatialite_la_LIBADD = ./gaiaaux/gaiaaux.la ./gaiaexif/gaiaexif.la \
 	./gaiageo/gaiageo.la ./geopackage/geopackage.la \
 	./spatialite/splite.la ./shapefiles/shapefiles.la ./dxf/dxf.la \
 	./md5/md5.la ./control_points/control_points.la \
-	./srsinit/srsinit.la ./connection_cache/connection_cache.la \
+	./cutter/cutter.la ./topology/topology.la ./srsinit/srsinit.la \
+	./connection_cache/connection_cache.la \
 	./virtualtext/virtualtext.la ./wfs/wfs.la @LIBXML2_LIBS@ \
 	$(am__append_4) $(am__append_5) $(am__append_6)
 mod_spatialite_la_CPPFLAGS = @CFLAGS@ -I$(top_srcdir)/src/headers -I. \
@@ -530,12 +540,12 @@ versioninfo/version.lo: versioninfo/$(am__dirstamp) \
 	versioninfo/$(DEPDIR)/$(am__dirstamp)
 
 libspatialite.la: $(libspatialite_la_OBJECTS) $(libspatialite_la_DEPENDENCIES) $(EXTRA_libspatialite_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(libspatialite_la_LINK) -rpath $(libdir) $(libspatialite_la_OBJECTS) $(libspatialite_la_LIBADD) $(LIBS)
+	$(AM_V_CCLD)$(libspatialite_la_LINK) $(am_libspatialite_la_rpath) $(libspatialite_la_OBJECTS) $(libspatialite_la_LIBADD) $(LIBS)
 versioninfo/mod_spatialite_la-version.lo: versioninfo/$(am__dirstamp) \
 	versioninfo/$(DEPDIR)/$(am__dirstamp)
 
 mod_spatialite.la: $(mod_spatialite_la_OBJECTS) $(mod_spatialite_la_DEPENDENCIES) $(EXTRA_mod_spatialite_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(mod_spatialite_la_LINK) -rpath $(libdir) $(mod_spatialite_la_OBJECTS) $(mod_spatialite_la_LIBADD) $(LIBS)
+	$(AM_V_CCLD)$(mod_spatialite_la_LINK) $(am_mod_spatialite_la_rpath) $(mod_spatialite_la_OBJECTS) $(mod_spatialite_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
diff --git a/src/connection_cache/alloc_cache.c b/src/connection_cache/alloc_cache.c
index af3a9ed..b942819 100644
--- a/src/connection_cache/alloc_cache.c
+++ b/src/connection_cache/alloc_cache.c
@@ -72,6 +72,11 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include <spatialite/gaiamatrix.h>
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -79,7 +84,9 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include <proj_api.h>
 #endif
 
+#ifndef GEOS_REENTRANT		/* only when using the obsolete partially thread-safe mode */
 #include "cache_aux_1.h"
+#endif /* end GEOS_REENTRANT */
 
 /* GLOBAL variables */
 extern char *gaia_geos_error_msg;
@@ -98,51 +105,84 @@ static pthread_mutex_t gaia_lwgeom_semaphore = PTHREAD_MUTEX_INITIALIZER;
 #define GAIA_CONN_RESERVED	(char *)1
 
 static void
-setGeosErrorMsg (int pool_index, const char *msg)
+conn_geos_error (const char *msg, void *userdata)
 {
-/* setting the latest GEOS error message */
-    struct splite_connection *p = &(splite_connection_pool[pool_index]);
+/* reporting some GEOS error - thread safe */
     int len;
-    if (p->gaia_geos_error_msg != NULL)
-	free (p->gaia_geos_error_msg);
-    p->gaia_geos_error_msg = NULL;
-    if (msg == NULL)
-	return;
-    len = strlen (msg);
-    p->gaia_geos_error_msg = malloc (len + 1);
-    strcpy (p->gaia_geos_error_msg, msg);
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) userdata;
+    if (cache == NULL)
+	goto invalid_cache;
+    if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
+	goto invalid_cache;
+
+    if (cache->gaia_geos_error_msg != NULL)
+	free (cache->gaia_geos_error_msg);
+    cache->gaia_geos_error_msg = NULL;
+    if (msg)
+      {
+	  spatialite_e ("GEOS error: %s\n", msg);
+	  len = strlen (msg);
+	  cache->gaia_geos_error_msg = malloc (len + 1);
+	  strcpy (cache->gaia_geos_error_msg, msg);
+      }
+    return;
+
+  invalid_cache:
+    if (msg)
+	spatialite_e ("GEOS error: %s\n", msg);
 }
 
 static void
-setGeosWarningMsg (int pool_index, const char *msg)
+conn_geos_warning (const char *msg, void *userdata)
+{
+/* reporting some GEOS warning - thread safe */
+    int len;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) userdata;
+    if (cache == NULL)
+	goto invalid_cache;
+    if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
+	goto invalid_cache;
+
+    if (cache->gaia_geos_warning_msg != NULL)
+	free (cache->gaia_geos_warning_msg);
+    cache->gaia_geos_warning_msg = NULL;
+    if (msg)
+      {
+	  spatialite_e ("GEOS warning: %s\n", msg);
+	  len = strlen (msg);
+	  cache->gaia_geos_warning_msg = malloc (len + 1);
+	  strcpy (cache->gaia_geos_warning_msg, msg);
+      }
+    return;
+
+  invalid_cache:
+    if (msg)
+	spatialite_e ("GEOS warning: %s\n", msg);
+}
+
+#ifndef GEOS_REENTRANT		/* only when using the obsolete partially thread-safe mode */
+static void
+setGeosErrorMsg (int pool_index, const char *msg)
 {
 /* setting the latest GEOS error message */
     struct splite_connection *p = &(splite_connection_pool[pool_index]);
-    int len;
-    if (p->gaia_geos_warning_msg != NULL)
-	free (p->gaia_geos_warning_msg);
-    p->gaia_geos_warning_msg = NULL;
-    if (msg == NULL)
-	return;
-    len = strlen (msg);
-    p->gaia_geos_warning_msg = malloc (len + 1);
-    strcpy (p->gaia_geos_warning_msg, msg);
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) (p->conn_ptr);
+    conn_geos_error (msg, cache);
 }
 
 static void
-setGeosAuxErrorMsg (int pool_index, const char *msg)
+setGeosWarningMsg (int pool_index, const char *msg)
 {
-/* setting the latest GEOS (auxiliary) error message */
+/* setting the latest GEOS error message */
     struct splite_connection *p = &(splite_connection_pool[pool_index]);
-    int len;
-    if (p->gaia_geosaux_error_msg != NULL)
-	free (p->gaia_geosaux_error_msg);
-    p->gaia_geosaux_error_msg = NULL;
-    if (msg == NULL)
-	return;
-    len = strlen (msg);
-    p->gaia_geosaux_error_msg = malloc (len + 1);
-    strcpy (p->gaia_geosaux_error_msg, msg);
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) (p->conn_ptr);
+    conn_geos_warning (msg, cache);
 }
 
 static void
@@ -210,22 +250,112 @@ invalidate (int i)
 {
 /* definitely releasing the slot */
     struct splite_connection *p = &(splite_connection_pool[i]);
-    if (p->gaia_geos_error_msg != NULL)
-	free (p->gaia_geos_error_msg);
-    if (p->gaia_geos_warning_msg != NULL)
-	free (p->gaia_geos_warning_msg);
-    if (p->gaia_geosaux_error_msg != NULL)
-	free (p->gaia_geosaux_error_msg);
-    p->gaia_geos_error_msg = NULL;
-    p->gaia_geos_warning_msg = NULL;
-    p->gaia_geosaux_error_msg = NULL;
     p->conn_ptr = NULL;
 }
+#endif /* END obsolete partially thread-safe mode */
+
+#ifdef GEOS_REENTRANT		/* reentrant (thread-safe) initialization */
+static void *
+spatialite_alloc_reentrant ()
+{
+/* 
+ * allocating and initializing an empty internal cache 
+ * fully reentrant (thread-safe) version requiring GEOS >= 3.5.0
+*/
+    struct splite_internal_cache *cache = NULL;
+    gaiaOutBufferPtr out;
+    int i;
+    struct splite_geos_cache_item *p;
+    struct splite_xmlSchema_cache_item *p_xmlSchema;
+
+/* attempting to implicitly initialize the library */
+    spatialite_initialize ();
+
+    cache = malloc (sizeof (struct splite_internal_cache));
+    if (cache == NULL)
+	goto done;
+    cache->magic1 = SPATIALITE_CACHE_MAGIC1;
+    cache->magic2 = SPATIALITE_CACHE_MAGIC2;
+    cache->gpkg_mode = 0;
+    cache->gpkg_amphibious_mode = 0;
+    cache->decimal_precision = -1;
+    cache->GEOS_handle = NULL;
+    cache->PROJ_handle = NULL;
+    cache->cutterMessage = NULL;
+    cache->pool_index = -1;
+    cache->gaia_geos_error_msg = NULL;
+    cache->gaia_geos_warning_msg = NULL;
+    cache->gaia_geosaux_error_msg = NULL;
+/* initializing an empty linked list of Topologies */
+    cache->firstTopology = NULL;
+    cache->lastTopology = NULL;
+    cache->next_topo_savepoint = 0;
+    cache->topo_savepoint_name = NULL;
+    cache->firstNetwork = NULL;
+    cache->lastNetwork = NULL;
+    cache->next_network_savepoint = 0;
+    cache->network_savepoint_name = NULL;
+/* initializing the XML error buffers */
+    out = malloc (sizeof (gaiaOutBuffer));
+    gaiaOutBufferInitialize (out);
+    cache->xmlParsingErrors = out;
+    out = malloc (sizeof (gaiaOutBuffer));
+    gaiaOutBufferInitialize (out);
+    cache->xmlSchemaValidationErrors = out;
+    out = malloc (sizeof (gaiaOutBuffer));
+    gaiaOutBufferInitialize (out);
+    cache->xmlXPathErrors = out;
+/* initializing the GEOS cache */
+    p = &(cache->cacheItem1);
+    memset (p->gaiaBlob, '\0', 64);
+    p->gaiaBlobSize = 0;
+    p->crc32 = 0;
+    p->geosGeom = NULL;
+    p->preparedGeosGeom = NULL;
+    p = &(cache->cacheItem2);
+    memset (p->gaiaBlob, '\0', 64);
+    p->gaiaBlobSize = 0;
+    p->crc32 = 0;
+    p->geosGeom = NULL;
+    p->preparedGeosGeom = NULL;
+    for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
+      {
+	  /* initializing the XmlSchema cache */
+	  p_xmlSchema = &(cache->xmlSchemaCache[i]);
+	  p_xmlSchema->timestamp = 0;
+	  p_xmlSchema->schemaURI = NULL;
+	  p_xmlSchema->schemaDoc = NULL;
+	  p_xmlSchema->parserCtxt = NULL;
+	  p_xmlSchema->schema = NULL;
+      }
+
+/* initializing GEOS and PROJ.4 handles */
+
+#ifndef OMIT_GEOS		/* initializing GEOS */
+    cache->GEOS_handle = initGEOS_r (NULL, NULL);
+    GEOSContext_setNoticeMessageHandler_r (cache->GEOS_handle,
+					   conn_geos_warning, cache);
+    GEOSContext_setErrorMessageHandler_r (cache->GEOS_handle, conn_geos_error,
+					  cache);
+#endif /* end GEOS  */
+
+#ifndef OMIT_PROJ		/* initializing the PROJ.4 context */
+    cache->PROJ_handle = pj_ctx_alloc ();
+#endif /* end PROJ.4  */
+
+  done:
+    return cache;
+}
+#endif /* end GEOS_REENTRANT */
 
 SPATIALITE_DECLARE void *
 spatialite_alloc_connection ()
 {
 /* allocating and initializing an empty internal cache */
+
+#ifdef GEOS_REENTRANT		/* reentrant (thread-safe) initialization */
+    return spatialite_alloc_reentrant ();
+#else /* end GEOS_REENTRANT */
     gaiaOutBufferPtr out;
     int i;
     struct splite_internal_cache *cache = NULL;
@@ -257,8 +387,21 @@ spatialite_alloc_connection ()
     cache->decimal_precision = -1;
     cache->GEOS_handle = NULL;
     cache->PROJ_handle = NULL;
+    cache->cutterMessage = NULL;
     cache->pool_index = pool_index;
     confirm (pool_index, cache);
+    cache->gaia_geos_error_msg = NULL;
+    cache->gaia_geos_warning_msg = NULL;
+    cache->gaia_geosaux_error_msg = NULL;
+/* initializing an empty linked list of Topologies */
+    cache->firstTopology = NULL;
+    cache->lastTopology = NULL;
+    cache->next_topo_savepoint = 0;
+    cache->topo_savepoint_name = NULL;
+    cache->firstNetwork = NULL;
+    cache->lastNetwork = NULL;
+    cache->next_network_savepoint = 0;
+    cache->network_savepoint_name = NULL;
 /* initializing the XML error buffers */
     out = malloc (sizeof (gaiaOutBuffer));
     gaiaOutBufferInitialize (out);
@@ -309,6 +452,36 @@ spatialite_alloc_connection ()
 /* unlocking the semaphore */
     splite_cache_semaphore_unlock ();
     return cache;
+#endif
+}
+
+SPATIALITE_DECLARE void
+spatialite_finalize_topologies (const void *ptr)
+{
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+/* freeing all Topology Accessor Objects */
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) ptr;
+    if (cache == NULL)
+	return;
+    if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
+	return;
+    free_internal_cache_topologies (cache->firstTopology);
+    cache->firstTopology = NULL;
+    cache->lastTopology = NULL;
+    if (cache->topo_savepoint_name != NULL)
+	sqlite3_free (cache->topo_savepoint_name);
+    cache->topo_savepoint_name = NULL;
+    free_internal_cache_networks (cache->firstNetwork);
+    cache->firstNetwork = NULL;
+    cache->lastTopology = NULL;
+    if (cache->network_savepoint_name != NULL)
+	sqlite3_free (cache->network_savepoint_name);
+    cache->network_savepoint_name = NULL;
+#else
+    if (ptr == NULL)
+	return;			/* silencing stupid compiler warnings */
+#endif /* end TOPOLOGY conditionals */
 }
 
 SPATIALITE_PRIVATE void
@@ -345,6 +518,14 @@ free_internal_cache (struct splite_internal_cache *cache)
     cache->PROJ_handle = NULL;
 #endif
 
+/* freeing GEOS error buffers */
+    if (cache->gaia_geos_error_msg)
+	free (cache->gaia_geos_error_msg);
+    if (cache->gaia_geos_warning_msg)
+	free (cache->gaia_geos_warning_msg);
+    if (cache->gaia_geosaux_error_msg)
+	free (cache->gaia_geosaux_error_msg);
+
 /* freeing the XML error buffers */
     gaiaOutBufferReset (cache->xmlParsingErrors);
     gaiaOutBufferReset (cache->xmlSchemaValidationErrors);
@@ -367,8 +548,16 @@ free_internal_cache (struct splite_internal_cache *cache)
       }
 #endif
 
+    if (cache->cutterMessage != NULL)
+	sqlite3_free (cache->cutterMessage);
+    cache->cutterMessage = NULL;
+
+    spatialite_finalize_topologies (cache);
+
+#ifndef GEOS_REENTRANT		/* only partially thread-safe mode */
 /* releasing the connection pool object */
     invalidate (cache->pool_index);
+#endif /* end GEOS_REENTRANT */
 
 /* freeing the cache itself */
     free (cache);
@@ -378,80 +567,72 @@ GAIAGEO_DECLARE void
 gaiaResetGeosMsg_r (const void *p_cache)
 {
 /* resets the GEOS error and warning messages */
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
+	return;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
 	return;
-    if (p->gaia_geos_error_msg != NULL)
-	free (p->gaia_geos_error_msg);
-    if (p->gaia_geos_warning_msg != NULL)
-	free (p->gaia_geos_warning_msg);
-    if (p->gaia_geosaux_error_msg != NULL)
-	free (p->gaia_geosaux_error_msg);
-    p->gaia_geos_error_msg = NULL;
-    p->gaia_geos_warning_msg = NULL;
-    p->gaia_geosaux_error_msg = NULL;
+    if (cache->gaia_geos_error_msg != NULL)
+	free (cache->gaia_geos_error_msg);
+    if (cache->gaia_geos_warning_msg != NULL)
+	free (cache->gaia_geos_warning_msg);
+    if (cache->gaia_geosaux_error_msg != NULL)
+	free (cache->gaia_geosaux_error_msg);
+    cache->gaia_geos_error_msg = NULL;
+    cache->gaia_geos_warning_msg = NULL;
+    cache->gaia_geosaux_error_msg = NULL;
 }
 
 GAIAGEO_DECLARE const char *
 gaiaGetGeosErrorMsg_r (const void *p_cache)
 {
 /* return the latest GEOS error message */
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
+	return NULL;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
 	return NULL;
-    return p->gaia_geos_error_msg;
+    return cache->gaia_geos_error_msg;
 }
 
 GAIAGEO_DECLARE const char *
 gaiaGetGeosWarningMsg_r (const void *p_cache)
 {
 /* return the latest GEOS error message */
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
+	return NULL;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
 	return NULL;
-    return p->gaia_geos_warning_msg;
+    return cache->gaia_geos_warning_msg;
 }
 
 GAIAGEO_DECLARE const char *
 gaiaGetGeosAuxErrorMsg_r (const void *p_cache)
 {
 /* return the latest GEOS (auxialiary) error message */
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
+	return NULL;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
 	return NULL;
-    return p->gaia_geosaux_error_msg;
+    return cache->gaia_geosaux_error_msg;
 }
 
 GAIAGEO_DECLARE void
@@ -459,25 +640,23 @@ gaiaSetGeosErrorMsg_r (const void *p_cache, const char *msg)
 {
 /* setting the latest GEOS error message */
     int len;
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
+	return;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
 	return;
-    if (p->gaia_geos_error_msg != NULL)
-	free (p->gaia_geos_error_msg);
-    p->gaia_geos_error_msg = NULL;
+    if (cache->gaia_geos_error_msg != NULL)
+	free (cache->gaia_geos_error_msg);
+    cache->gaia_geos_error_msg = NULL;
     if (msg == NULL)
 	return;
     len = strlen (msg);
-    p->gaia_geos_error_msg = malloc (len + 1);
-    strcpy (p->gaia_geos_error_msg, msg);
+    cache->gaia_geos_error_msg = malloc (len + 1);
+    strcpy (cache->gaia_geos_error_msg, msg);
 }
 
 GAIAGEO_DECLARE void
@@ -485,25 +664,23 @@ gaiaSetGeosWarningMsg_r (const void *p_cache, const char *msg)
 {
 /* setting the latest GEOS error message */
     int len;
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
+	return;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
 	return;
-    if (p->gaia_geos_warning_msg != NULL)
-	free (p->gaia_geos_warning_msg);
-    p->gaia_geos_warning_msg = NULL;
+    if (cache->gaia_geos_warning_msg != NULL)
+	free (cache->gaia_geos_warning_msg);
+    cache->gaia_geos_warning_msg = NULL;
     if (msg == NULL)
 	return;
     len = strlen (msg);
-    p->gaia_geos_warning_msg = malloc (len + 1);
-    strcpy (p->gaia_geos_warning_msg, msg);
+    cache->gaia_geos_warning_msg = malloc (len + 1);
+    strcpy (cache->gaia_geos_warning_msg, msg);
 }
 
 GAIAGEO_DECLARE void
@@ -511,25 +688,23 @@ gaiaSetGeosAuxErrorMsg_r (const void *p_cache, const char *msg)
 {
 /* setting the latest GEOS (auxiliary) error message */
     int len;
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+    if (cache == NULL)
 	return;
-    if (p->gaia_geosaux_error_msg != NULL)
-	free (p->gaia_geosaux_error_msg);
-    p->gaia_geosaux_error_msg = NULL;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
+	return;
+    if (cache->gaia_geosaux_error_msg != NULL)
+	free (cache->gaia_geosaux_error_msg);
+    cache->gaia_geosaux_error_msg = NULL;
     if (msg == NULL)
 	return;
     len = strlen (msg);
-    p->gaia_geosaux_error_msg = malloc (len + 1);
-    strcpy (p->gaia_geosaux_error_msg, msg);
+    cache->gaia_geosaux_error_msg = malloc (len + 1);
+    strcpy (cache->gaia_geosaux_error_msg, msg);
 }
 
 static char *
@@ -651,20 +826,20 @@ gaiaCriticalPointFromGEOSmsg_r (const void *p_cache)
     double y;
     gaiaGeomCollPtr geom;
     const char *msg;
-    struct splite_connection *p = NULL;
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
-    if (cache != NULL)
-      {
-	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
-	      || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
-	      p = &(splite_connection_pool[cache->pool_index]);
-      }
-    if (p == NULL)
+
+    if (cache == NULL)
 	return NULL;
-    msg = p->gaia_geos_error_msg;
+    if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
+	;
+    else
+	return NULL;
+
+    msg = cache->gaia_geos_error_msg;
     if (msg == NULL)
-	msg = p->gaia_geos_warning_msg;
+	msg = cache->gaia_geos_warning_msg;
     if (msg == NULL)
 	return NULL;
     if (!check_geos_critical_point (msg, &x, &y))
@@ -737,7 +912,9 @@ SPATIALITE_DECLARE void
 spatialite_shutdown (void)
 {
 /* finalizes the library */
+#ifndef GEOS_REENTRANT
     int i;
+#endif
     if (!gaia_already_initialized)
 	return;
 
@@ -750,11 +927,14 @@ spatialite_shutdown (void)
     xmlCleanupParser ();
 #endif /* end LIBXML2 conditional */
 
+#ifndef GEOS_REENTRANT		/* only when using the obsolete partially thread-safe mode */
     for (i = 0; i < SPATIALITE_MAX_CONNECTIONS; i++)
       {
 	  struct splite_connection *p = &(splite_connection_pool[i]);
 	  if (p->conn_ptr != NULL && p->conn_ptr != GAIA_CONN_RESERVED)
 	      free_internal_cache (p->conn_ptr);
       }
+#endif /* end GEOS_REENTRANT */
+
     gaia_already_initialized = 0;
 }
diff --git a/src/connection_cache/cache_aux_1.h b/src/connection_cache/cache_aux_1.h
index fb2060f..15755b0 100644
--- a/src/connection_cache/cache_aux_1.h
+++ b/src/connection_cache/cache_aux_1.h
@@ -4,73 +4,70 @@ struct splite_connection
 {
 /* connections pool */
 	void *conn_ptr;
-	char *gaia_geos_error_msg;
-	char *gaia_geos_warning_msg;
-	char *gaia_geosaux_error_msg;
 } splite_connection_pool[SPATIALITE_MAX_CONNECTIONS] =
 {
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL},
-	{NULL, NULL, NULL, NULL}
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL},
+	{NULL}
 };
diff --git a/src/connection_cache/generator/code_generator.c b/src/connection_cache/generator/code_generator.c
index 717836e..1e358cc 100644
--- a/src/connection_cache/generator/code_generator.c
+++ b/src/connection_cache/generator/code_generator.c
@@ -75,17 +75,14 @@ main (int argc, char *argv[])
     fprintf (out, "struct splite_connection\n{\n");
     fprintf (out, "/* connections pool */\n");
     fprintf (out, "\tvoid *conn_ptr;\n");
-    fprintf (out, "\tchar *gaia_geos_error_msg;\n");
-    fprintf (out, "\tchar *gaia_geos_warning_msg;\n");
-    fprintf (out, "\tchar *gaia_geosaux_error_msg;\n");
     fprintf (out,
 	     "} splite_connection_pool[" "SPATIALITE_MAX_CONNECTIONS] =\n{\n");
     for (i = 0; i < max; i++)
       {
 	  if (i == (max - 1))
-	      fprintf (out, "\t{NULL, NULL, NULL, NULL}\n");
+	      fprintf (out, "\t{NULL}\n");
 	  else
-	      fprintf (out, "\t{NULL, NULL, NULL, NULL},\n");
+	      fprintf (out, "\t{NULL},\n");
       }
     fprintf (out, "};\n");
     fclose (out);
diff --git a/src/cutter/Makefile.am b/src/cutter/Makefile.am
new file mode 100644
index 0000000..89a2fb7
--- /dev/null
+++ b/src/cutter/Makefile.am
@@ -0,0 +1,17 @@
+
+AM_CPPFLAGS = @CFLAGS@
+AM_CPPFLAGS += -I$(top_srcdir)/src/headers -I.
+
+noinst_LTLIBRARIES = libcutter.la cutter.la
+
+libcutter_la_SOURCES = gaia_cutter.c
+
+cutter_la_SOURCES = gaia_cutter.c
+
+cutter_la_CPPFLAGS = @CFLAGS@
+cutter_la_CPPFLAGS += -I$(top_srcdir)/src/headers -I.
+cutter_la_CPPFLAGS += -DLOADABLE_EXTENSION
+cutter_la_LDFLAGS = -module
+cutter_la_LIBTOOLFLAGS = --tag=disable-static
+
+MOSTLYCLEANFILES = *.gcna *.gcno *.gcda
diff --git a/examples/Makefile.in b/src/cutter/Makefile.in
similarity index 84%
copy from examples/Makefile.in
copy to src/cutter/Makefile.in
index 7255a75..16007bb 100644
--- a/examples/Makefile.in
+++ b/src/cutter/Makefile.in
@@ -88,9 +88,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = demo1$(EXEEXT) demo2$(EXEEXT) demo3$(EXEEXT) \
-	demo4$(EXEEXT) demo5$(EXEEXT)
-subdir = examples
+subdir = src/cutter
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -103,31 +101,20 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-PROGRAMS = $(noinst_PROGRAMS)
-demo1_SOURCES = demo1.c
-demo1_OBJECTS = demo1.$(OBJEXT)
-demo1_LDADD = $(LDADD)
-demo1_DEPENDENCIES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+cutter_la_LIBADD =
+am_cutter_la_OBJECTS = cutter_la-gaia_cutter.lo
+cutter_la_OBJECTS = $(am_cutter_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-demo2_SOURCES = demo2.c
-demo2_OBJECTS = demo2.$(OBJEXT)
-demo2_LDADD = $(LDADD)
-demo2_DEPENDENCIES =
-demo3_SOURCES = demo3.c
-demo3_OBJECTS = demo3.$(OBJEXT)
-demo3_LDADD = $(LDADD)
-demo3_DEPENDENCIES =
-demo4_SOURCES = demo4.c
-demo4_OBJECTS = demo4.$(OBJEXT)
-demo4_LDADD = $(LDADD)
-demo4_DEPENDENCIES =
-demo5_SOURCES = demo5.c
-demo5_OBJECTS = demo5.$(OBJEXT)
-demo5_LDADD = $(LDADD)
-demo5_DEPENDENCIES =
+cutter_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(cutter_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(cutter_la_LDFLAGS) $(LDFLAGS) -o $@
+libcutter_la_LIBADD =
+am_libcutter_la_OBJECTS = gaia_cutter.lo
+libcutter_la_OBJECTS = $(am_libcutter_la_OBJECTS)
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -162,8 +149,8 @@ AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = demo1.c demo2.c demo3.c demo4.c demo5.c
-DIST_SOURCES = demo1.c demo2.c demo3.c demo4.c demo5.c
+SOURCES = $(cutter_la_SOURCES) $(libcutter_la_SOURCES)
+DIST_SOURCES = $(cutter_la_SOURCES) $(libcutter_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -319,11 +306,15 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-AM_CFLAGS = -I at srcdir@/../src/headers 
-AM_LDFLAGS = -L../src -lspatialite -lm $(GCOV_FLAGS)
-LDADD = @LIBXML2_LIBS@
+AM_CPPFLAGS = @CFLAGS@ -I$(top_srcdir)/src/headers -I.
+noinst_LTLIBRARIES = libcutter.la cutter.la
+libcutter_la_SOURCES = gaia_cutter.c
+cutter_la_SOURCES = gaia_cutter.c
+cutter_la_CPPFLAGS = @CFLAGS@ -I$(top_srcdir)/src/headers -I. \
+	-DLOADABLE_EXTENSION
+cutter_la_LDFLAGS = -module
+cutter_la_LIBTOOLFLAGS = --tag=disable-static
 MOSTLYCLEANFILES = *.gcna *.gcno *.gcda
-EXTRA_DIST = examples.doxy
 all: all-am
 
 .SUFFIXES:
@@ -337,9 +328,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/cutter/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign examples/Makefile
+	  $(AUTOMAKE) --foreign src/cutter/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -358,34 +349,22 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
 
-clean-noinstPROGRAMS:
-	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
-	echo " rm -f" $$list; \
-	rm -f $$list || exit $$?; \
-	test -n "$(EXEEXT)" || exit 0; \
-	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
-	echo " rm -f" $$list; \
-	rm -f $$list
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
 
-demo1$(EXEEXT): $(demo1_OBJECTS) $(demo1_DEPENDENCIES) $(EXTRA_demo1_DEPENDENCIES) 
-	@rm -f demo1$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo1_OBJECTS) $(demo1_LDADD) $(LIBS)
+cutter.la: $(cutter_la_OBJECTS) $(cutter_la_DEPENDENCIES) $(EXTRA_cutter_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(cutter_la_LINK)  $(cutter_la_OBJECTS) $(cutter_la_LIBADD) $(LIBS)
 
-demo2$(EXEEXT): $(demo2_OBJECTS) $(demo2_DEPENDENCIES) $(EXTRA_demo2_DEPENDENCIES) 
-	@rm -f demo2$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo2_OBJECTS) $(demo2_LDADD) $(LIBS)
-
-demo3$(EXEEXT): $(demo3_OBJECTS) $(demo3_DEPENDENCIES) $(EXTRA_demo3_DEPENDENCIES) 
-	@rm -f demo3$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo3_OBJECTS) $(demo3_LDADD) $(LIBS)
-
-demo4$(EXEEXT): $(demo4_OBJECTS) $(demo4_DEPENDENCIES) $(EXTRA_demo4_DEPENDENCIES) 
-	@rm -f demo4$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo4_OBJECTS) $(demo4_LDADD) $(LIBS)
-
-demo5$(EXEEXT): $(demo5_OBJECTS) $(demo5_DEPENDENCIES) $(EXTRA_demo5_DEPENDENCIES) 
-	@rm -f demo5$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo5_OBJECTS) $(demo5_LDADD) $(LIBS)
+libcutter.la: $(libcutter_la_OBJECTS) $(libcutter_la_DEPENDENCIES) $(EXTRA_libcutter_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libcutter_la_OBJECTS) $(libcutter_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -393,11 +372,8 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo1.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo2.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo3.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo4.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo5.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cutter_la-gaia_cutter.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_cutter.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -420,6 +396,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+cutter_la-gaia_cutter.lo: gaia_cutter.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cutter_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cutter_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cutter_la-gaia_cutter.lo -MD -MP -MF $(DEPDIR)/cutter_la-gaia_cutter.Tpo -c -o cutter_la-gaia_cutter.lo `test -f 'gaia_cutter.c' || echo '$(srcdir)/'`gaia_cutter.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cutter_la-gaia_cutter.Tpo $(DEPDIR)/cutter_la-gaia_cutter.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_cutter.c' object='cutter_la-gaia_cutter.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cutter_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cutter_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cutter_la-gaia_cutter.lo `test -f 'gaia_cutter.c' || echo '$(srcdir)/'`gaia_cutter.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -510,7 +493,7 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile $(PROGRAMS)
+all-am: Makefile $(LTLIBRARIES)
 installdirs:
 install: install-am
 install-exec: install-exec-am
@@ -545,7 +528,7 @@ maintainer-clean-generic:
 	@echo "it deletes files that may require special tools to rebuild."
 clean: clean-am
 
-clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
 	mostlyclean-am
 
 distclean: distclean-am
@@ -617,7 +600,7 @@ uninstall-am:
 .MAKE: install-am install-strip
 
 .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-	clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
 	ctags-am distclean distclean-compile distclean-generic \
 	distclean-libtool distclean-tags distdir dvi dvi-am html \
 	html-am info info-am install install-am install-data \
diff --git a/src/cutter/gaia_cutter.c b/src/cutter/gaia_cutter.c
new file mode 100644
index 0000000..0333f7b
--- /dev/null
+++ b/src/cutter/gaia_cutter.c
@@ -0,0 +1,7394 @@
+/*
+
+ gaia_cutter.c -- implementation of the Cutter module
+    
+ version 4.3, 2015 July 2
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/*
+ 
+CREDITS:
+
+this module has been completely funded by:
+Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
+(Cutter module)
+
+CIG: 6038019AE5 
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+#include <spatialite/gaiaaux.h>
+
+#ifndef OMIT_GEOS		/* only if GEOS is enabled */
+
+#define GAIA_CUTTER_OUTPUT_PK	1
+#define GAIA_CUTTER_INPUT_PK	2
+#define GAIA_CUTTER_BLADE_PK	3
+#define GAIA_CUTTER_NORMAL		4
+
+#define GAIA_CUTTER_POINT		1
+#define GAIA_CUTTER_LINESTRING	2
+#define GAIA_CUTTER_POLYGON		3
+
+struct output_column
+{
+/* a struct wrapping an Output Table Column */
+    char *base_name;
+    char *real_name;
+    char *type;
+    int notnull;
+    int role;
+    int order_nr;
+    struct output_column *next;
+};
+
+struct output_table
+{
+/* a struct wrapping the Output Table */
+    struct output_column *first;
+    struct output_column *last;
+};
+
+struct multivar
+{
+/* a struct wrapping a generic SQLite value */
+    int progr_id;
+    int type;
+    union multivalue
+    {
+	sqlite3_int64 intValue;
+	double doubleValue;
+	char *textValue;
+    } value;
+    struct multivar *next;
+};
+
+struct temporary_row
+{
+/* a struct wrapping a row from the TMP #1 resultset */
+    struct multivar *first_input;
+    struct multivar *last_input;
+    struct multivar *first_blade;
+    struct multivar *last_blade;
+};
+
+struct child_row
+{
+/* a struct wrapping a resultset row */
+    struct multivar *first;
+    struct multivar *last;
+    gaiaGeomCollPtr geom;
+    gaiaGeomCollPtr geom2;
+    struct child_row *next;
+};
+
+struct pending_rows
+{
+/* a struct containing groups of pending rows to be processed */
+    struct multivar *first;
+    struct multivar *last;
+    gaiaGeomCollPtr geom;
+    gaiaGeomCollPtr geom2;
+    struct child_row *first_child;
+    struct child_row *last_child;
+};
+
+struct cut_item
+{
+/* a struct wrapping a Cut Solution Item */
+    struct multivar *first;
+    struct multivar *last;
+    gaiaGeomCollPtr geom;
+    struct cut_item *next;
+};
+
+struct cut_solution
+{
+/* a struct containing a Cut Solution */
+    struct cut_item *first;
+    struct cut_item *last;
+};
+
+static struct multivar *
+alloc_multivar (void)
+{
+/* allocating a NULL SQLite value */
+    struct multivar *var = malloc (sizeof (struct multivar));
+    var->progr_id = 0;
+    var->type = SQLITE_NULL;
+    var->value.textValue = NULL;
+    var->next = NULL;
+    return var;
+}
+
+static void
+destroy_multivar (struct multivar *var)
+{
+/* destroying a generic SQLite values */
+    if (var == NULL)
+	return;
+    if (var->type == SQLITE_TEXT)
+      {
+	  if (var->value.textValue != NULL)
+	      free (var->value.textValue);
+      }
+    free (var);
+}
+
+static void
+reset_temporary_row (struct temporary_row *row)
+{
+/* memory cleanup - resetting a temporary row */
+    struct multivar *var;
+    struct multivar *var_n;
+    if (row == NULL)
+	return;
+
+    var = row->first_input;
+    while (var != NULL)
+      {
+	  var_n = var->next;
+	  destroy_multivar (var);
+	  var = var_n;
+      }
+    var = row->first_blade;
+    while (var != NULL)
+      {
+	  var_n = var->next;
+	  destroy_multivar (var);
+	  var = var_n;
+      }
+}
+
+static void
+do_set_null_blade_columns (struct temporary_row *row)
+{
+/* setting a NULL value for all Blade PK columns */
+    struct multivar *var;
+    if (row == NULL)
+	return;
+
+    var = row->first_blade;
+    while (var != NULL)
+      {
+	  if (var->type == SQLITE_TEXT)
+	    {
+		if (var->value.textValue != NULL)
+		    free (var->value.textValue);
+		var->value.textValue = NULL;
+	    }
+	  var->type = SQLITE_NULL;
+	  var = var->next;
+      }
+}
+
+static struct multivar *
+find_input_pk_value (struct temporary_row *row, int idx)
+{
+/* finding an Input column value by its relative position */
+    int count = 0;
+    struct multivar *var;
+    if (row == NULL)
+	return NULL;
+
+    var = row->first_input;
+    while (var != NULL)
+      {
+	  if (count == idx)
+	      return var;
+	  count++;
+	  var = var->next;
+      }
+    return NULL;
+}
+
+static struct multivar *
+find_blade_pk_value (struct temporary_row *row, int idx)
+{
+/* finding a Bladecolumn value by its relative position */
+    int count = 0;
+    struct multivar *var;
+    if (row == NULL)
+	return NULL;
+
+    var = row->first_blade;
+    while (var != NULL)
+      {
+	  if (count == idx)
+	      return var;
+	  count++;
+	  var = var->next;
+      }
+    return NULL;
+}
+
+static void
+add_int_pk_value (struct temporary_row *row, char table, int progr_id,
+		  sqlite3_int64 value)
+{
+/* storing an INT-64 value into a ROW object */
+    struct multivar *var = alloc_multivar ();
+    var->progr_id = progr_id;
+    var->type = SQLITE_INTEGER;
+    var->value.intValue = value;
+    if (table == 'B')
+      {
+	  /* from the Blade Table */
+	  if (row->first_blade == NULL)
+	      row->first_blade = var;
+	  if (row->last_blade != NULL)
+	      row->last_blade->next = var;
+	  row->last_blade = var;
+      }
+    else
+      {
+	  /* from the Input Table */
+	  if (row->first_input == NULL)
+	      row->first_input = var;
+	  if (row->last_input != NULL)
+	      row->last_input->next = var;
+	  row->last_input = var;
+      }
+}
+
+static void
+add_double_pk_value (struct temporary_row *row, char table, int progr_id,
+		     double value)
+{
+/* storing a FLOAT DOUBLE value into a ROW object */
+    struct multivar *var = alloc_multivar ();
+    var->progr_id = progr_id;
+    var->type = SQLITE_FLOAT;
+    var->value.doubleValue = value;
+    if (table == 'B')
+      {
+	  /* from the Blade Table */
+	  if (row->first_blade == NULL)
+	      row->first_blade = var;
+	  if (row->last_blade != NULL)
+	      row->last_blade->next = var;
+	  row->last_blade = var;
+      }
+    else
+      {
+	  /* from the Input Table */
+	  if (row->first_input == NULL)
+	      row->first_input = var;
+	  if (row->last_input != NULL)
+	      row->last_input->next = var;
+	  row->last_input = var;
+      }
+}
+
+static void
+add_text_pk_value (struct temporary_row *row, char table, int progr_id,
+		   const char *value)
+{
+/* storing a TEXT value into a ROW object */
+    int len;
+    struct multivar *var = alloc_multivar ();
+    var->progr_id = progr_id;
+    var->type = SQLITE_TEXT;
+    len = strlen (value);
+    var->value.textValue = malloc (len + 1);
+    strcpy (var->value.textValue, value);
+    if (table == 'B')
+      {
+	  /* from the Blade Table */
+	  if (row->first_blade == NULL)
+	      row->first_blade = var;
+	  if (row->last_blade != NULL)
+	      row->last_blade->next = var;
+	  row->last_blade = var;
+      }
+    else
+      {
+	  /* from the Input Table */
+	  if (row->first_input == NULL)
+	      row->first_input = var;
+	  if (row->last_input != NULL)
+	      row->last_input->next = var;
+	  row->last_input = var;
+      }
+}
+
+static void
+add_null_pk_value (struct temporary_row *row, char table, int progr_id)
+{
+/* storing a NULL value into a ROW object */
+    struct multivar *var = alloc_multivar ();
+    var->progr_id = progr_id;
+    if (table == 'B')
+      {
+	  /* from the Blade Table */
+	  if (row->first_blade == NULL)
+	      row->first_blade = var;
+	  if (row->last_blade != NULL)
+	      row->last_blade->next = var;
+	  row->last_blade = var;
+      }
+    else
+      {
+	  /* from the Input Table */
+	  if (row->first_input == NULL)
+	      row->first_input = var;
+	  if (row->last_input != NULL)
+	      row->last_input->next = var;
+	  row->last_input = var;
+      }
+}
+
+static int
+eval_multivar (struct multivar *var1, struct multivar *var2)
+{
+/* comparing to generic SQLite values */
+    if (var1->type != var2->type)
+	return 0;
+    switch (var1->type)
+      {
+      case SQLITE_INTEGER:
+	  if (var1->value.intValue == var2->value.intValue)
+	      return 1;
+	  break;
+      case SQLITE_FLOAT:
+	  if (var1->value.doubleValue == var2->value.doubleValue)
+	      return 1;
+	  break;
+      case SQLITE_TEXT:
+	  if (strcmp (var1->value.textValue, var2->value.textValue) == 0)
+	      return 1;
+	  break;
+      default:
+	  return 1;
+      };
+    return 0;
+}
+
+static int
+check_same_input (struct temporary_row *prev_row, struct temporary_row *row)
+{
+/* checks if the current row is the same of the previous row - Input PK columns */
+    int ok = 1;
+    struct multivar *var1;
+    struct multivar *var2;
+
+    var1 = prev_row->first_input;
+    var2 = row->first_input;
+    while (1)
+      {
+	  if (var1 == NULL)
+	    {
+		ok = 0;
+		break;
+	    }
+	  if (var2 == NULL)
+	    {
+		ok = 0;
+		break;
+	    }
+	  if (!eval_multivar (var1, var2))
+	    {
+		ok = 0;
+		break;
+	    }
+	  var1 = var1->next;
+	  var2 = var2->next;
+	  if (var1 == NULL && var2 == NULL)
+	      break;
+      }
+    return ok;
+}
+
+static void
+copy_input_values (struct temporary_row *orig, struct temporary_row *dest)
+{
+/* copying all values from origin to destination */
+    struct multivar *var;
+    int pos = 0;
+
+    reset_temporary_row (dest);
+    dest->first_input = NULL;
+    dest->last_input = NULL;
+    dest->first_blade = NULL;
+    dest->last_blade = NULL;
+    var = orig->first_input;
+    while (var)
+      {
+	  switch (var->type)
+	    {
+	    case SQLITE_INTEGER:
+		add_int_pk_value (dest, 'I', pos, var->value.intValue);
+		break;
+	    case SQLITE_FLOAT:
+		add_double_pk_value (dest, 'I', pos, var->value.doubleValue);
+		break;
+	    case SQLITE_TEXT:
+		add_text_pk_value (dest, 'I', pos, var->value.textValue);
+		break;
+	    default:
+		add_null_pk_value (dest, 'I', pos);
+	    };
+	  pos++;
+	  var = var->next;
+      }
+}
+
+static struct output_column *
+alloc_output_table_column (const char *name, const char *type, int notnull,
+			   int role, int order_nr)
+{
+/* creating an Output Table Column */
+    int len;
+    struct output_column *col = malloc (sizeof (struct output_column));
+    if (col == NULL)
+	return NULL;
+    len = strlen (name);
+    col->base_name = malloc (len + 1);
+    strcpy (col->base_name, name);
+    col->real_name = NULL;
+    len = strlen (type);
+    col->type = malloc (len + 1);
+    strcpy (col->type, type);
+    col->notnull = notnull;
+    col->role = role;
+    col->order_nr = order_nr;
+    col->next = NULL;
+    return col;
+}
+
+static void
+destroy_output_table_column (struct output_column *col)
+{
+/* destroying an Output Table Column */
+    if (col == NULL)
+	return;
+    if (col->base_name != NULL)
+	free (col->base_name);
+    if (col->real_name != NULL)
+	sqlite3_free (col->real_name);
+    if (col->type != NULL)
+	free (col->type);
+    free (col);
+}
+
+static struct output_table *
+alloc_output_table (void)
+{
+/* creating the Output Table struct */
+    struct output_table *ptr = malloc (sizeof (struct output_table));
+    if (ptr == NULL)
+	return NULL;
+    ptr->first = NULL;
+    ptr->last = NULL;
+    return ptr;
+}
+
+static void
+destroy_output_table (struct output_table *tbl)
+{
+/* memory cleanup - destroying the Output Table struct */
+    struct output_column *col;
+    struct output_column *col_n;
+
+    if (tbl == NULL)
+	return;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  col_n = col->next;
+	  destroy_output_table_column (col);
+	  col = col_n;
+      }
+    free (tbl);
+}
+
+static struct output_column *
+add_column_to_output_table (struct output_table *tbl, const char *name,
+			    const char *type, int notnull, int role,
+			    int order_nr)
+{
+/* adding a column to the Output Table */
+    struct output_column *col;
+
+    if (tbl == NULL)
+	return NULL;
+    col = alloc_output_table_column (name, type, notnull, role, order_nr);
+    if (col == NULL)
+	return NULL;
+    if (tbl->first == NULL)
+	tbl->first = col;
+    if (tbl->last != NULL)
+	tbl->last->next = col;
+    tbl->last = col;
+    return col;
+}
+
+static void
+do_reset_message (char **ptr)
+{
+/* resetting the message string */
+    if (ptr == NULL)
+	return;
+    if (*ptr != NULL)
+	sqlite3_free (*ptr);
+    *ptr = NULL;
+}
+
+static void
+do_update_message (char **ptr, const char *message)
+{
+/* updating the message string */
+    if (ptr == NULL)
+	return;
+    if (*ptr != NULL)
+	return;
+    *ptr = sqlite3_mprintf ("%s", message);
+}
+
+static void
+do_update_sql_error (char **ptr, const char *message, const char *sql_err)
+{
+/* printing some SQL error */
+    if (ptr == NULL)
+	return;
+    if (*ptr != NULL)
+	return;
+    *ptr = sqlite3_mprintf ("%s %s", message, sql_err);
+}
+
+static void
+do_print_message2 (char **ptr, const char *message, const char *prefix,
+		   const char *table)
+{
+/* printing the message string - 2 args */
+    if (ptr == NULL)
+	return;
+    if (*ptr != NULL)
+	return;
+    *ptr = sqlite3_mprintf (message, prefix, table);
+}
+
+static void
+do_print_message3 (char **ptr, const char *message, const char *prefix,
+		   const char *table, const char *geometry)
+{
+/* printing the message string - 3 args */
+    if (ptr == NULL)
+	return;
+    if (*ptr != NULL)
+	return;
+    *ptr = sqlite3_mprintf (message, prefix, table, geometry);
+}
+
+static int
+do_check_input (sqlite3 * handle, const char *db_prefix, const char *table,
+		const char *xgeometry, char **geometry, int *srid, int *type,
+		char **message)
+{
+/* checking the input table for validity */
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int count = 0;
+    char *geom_name = NULL;
+    int geom_srid;
+    int geom_type;
+    int pk = 0;
+    int i;
+    int ret;
+
+    *geometry = NULL;
+    *srid = -1;
+    *type = GAIA_UNKNOWN;
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* checking if the table really exists */
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *value = results[(i * columns) + 5];
+	  if (atoi (value) > 0)
+	      pk = 1;
+	  count++;
+      }
+    sqlite3_free_table (results);
+    if (count == 0)
+      {
+	  do_print_message2 (message, "ERROR: table %s.%s does not exists",
+			     db_prefix, table);
+	  goto error;
+      }
+    if (pk == 0)
+      {
+	  do_print_message2 (message,
+			     "ERROR: table %s.%s lacks any Primary Key",
+			     db_prefix, table);
+	  goto error;
+      }
+
+/* checking geometry_columns */
+    count = 0;
+    if (xgeometry == NULL)
+	sql = sqlite3_mprintf ("SELECT f_geometry_column, srid, geometry_type "
+			       "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q)",
+			       xprefix, table, xgeometry);
+    else
+	sql = sqlite3_mprintf ("SELECT f_geometry_column, srid, geometry_type "
+			       "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) "
+			       "AND Lower(f_geometry_column) = Lower(%Q)",
+			       xprefix, table, xgeometry);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT geometry_columns", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *value = results[(i * columns) + 0];
+	  if (count == 0)
+	    {
+		int len = strlen (value);
+		geom_name = malloc (len + 1);
+		strcpy (geom_name, value);
+	    }
+	  value = results[(i * columns) + 1];
+	  geom_srid = atoi (value);
+	  value = results[(i * columns) + 2];
+	  geom_type = atoi (value);
+	  count++;
+      }
+    sqlite3_free_table (results);
+    if (count == 0)
+      {
+	  do_print_message2 (message,
+			     "ERROR: table %s.%s lacks any registered Geometry",
+			     db_prefix, table);
+	  goto error;
+      }
+    if (count > 1)
+      {
+	  do_print_message2 (message,
+			     "ERROR: table %s.%s has multiple Geometries and a NULL name was passed",
+			     db_prefix, table);
+	  goto error;
+      }
+    switch (geom_type)
+      {
+      case GAIA_POINT:
+      case GAIA_LINESTRING:
+      case GAIA_POLYGON:
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_POINTZ:
+      case GAIA_LINESTRINGZ:
+      case GAIA_POLYGONZ:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_POINTM:
+      case GAIA_LINESTRINGM:
+      case GAIA_POLYGONM:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTIPOLYGONM:
+      case GAIA_POINTZM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOINTZM:
+      case GAIA_MULTILINESTRINGZM:
+      case GAIA_MULTIPOLYGONZM:
+	  break;
+      default:
+	  do_print_message3 (message,
+			     "ERROR: table %s.%s Geometry %s has an invalid Type",
+			     db_prefix, table, geom_name);
+	  goto error;
+      };
+    *geometry = geom_name;
+    *srid = geom_srid;
+    *type = geom_type;
+
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    if (geom_name != NULL)
+	free (geom_name);
+    return 0;
+}
+
+static int
+do_check_blade (sqlite3 * handle, const char *db_prefix, const char *table,
+		const char *xgeometry, char **geometry, int *srid,
+		char **message)
+{
+/* checking the blade table for validity */
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int count = 0;
+    char *geom_name = NULL;
+    int geom_srid;
+    int geom_type;
+    int pk = 0;
+    int i;
+    int ret;
+
+    *geometry = NULL;
+    *srid = -1;
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* checking if the table really exists */
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *value = results[(i * columns) + 5];
+	  if (atoi (value) > 0)
+	      pk = 1;
+	  count++;
+      }
+    sqlite3_free_table (results);
+    if (count == 0)
+      {
+	  do_print_message2 (message, "ERROR: table %s.%s does not exists",
+			     db_prefix, table);
+	  goto error;
+      }
+    if (pk == 0)
+      {
+	  do_print_message2 (message,
+			     "ERROR: table %s.%s lacks any Primary Key",
+			     db_prefix, table);
+	  goto error;
+      }
+
+/* checking geometry_columns */
+    count = 0;
+    if (xgeometry == NULL)
+	sql = sqlite3_mprintf ("SELECT f_geometry_column, srid, geometry_type "
+			       "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q)",
+			       xprefix, table, xgeometry);
+    else
+	sql = sqlite3_mprintf ("SELECT f_geometry_column, srid, geometry_type "
+			       "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) "
+			       "AND Lower(f_geometry_column) = Lower(%Q)",
+			       xprefix, table, xgeometry);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT geometry_columns", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *value = results[(i * columns) + 0];
+	  if (count == 0)
+	    {
+		int len = strlen (value);
+		geom_name = malloc (len + 1);
+		strcpy (geom_name, value);
+	    }
+	  value = results[(i * columns) + 1];
+	  geom_srid = atoi (value);
+	  value = results[(i * columns) + 2];
+	  geom_type = atoi (value);
+	  count++;
+      }
+    sqlite3_free_table (results);
+    if (count == 0)
+      {
+	  do_print_message2 (message,
+			     "ERROR: table %s.%s lacks any registered Geometry",
+			     db_prefix, table);
+	  goto error;
+      }
+    if (count > 1)
+      {
+	  do_print_message2 (message,
+			     "ERROR: table %s.%s has multiple Geometries and a NULL name was passed",
+			     db_prefix, table);
+	  goto error;
+      }
+    switch (geom_type)
+      {
+      case GAIA_POLYGON:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_POLYGONZ:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_POLYGONM:
+      case GAIA_MULTIPOLYGONM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGONZM:
+	  break;
+      default:
+	  do_print_message3 (message,
+			     "ERROR: table %s.%s Geometry %s isn't of the POLYGON or MULTIPOLYGON Type",
+			     db_prefix, table, geom_name);
+	  goto error;
+      };
+    *geometry = geom_name;
+    *srid = geom_srid;
+
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    if (geom_name != NULL)
+	free (geom_name);
+    return 0;
+}
+
+static int
+do_check_nulls (sqlite3 * handle, const char *db_prefix, const char *table,
+		const char *geom, const char *which, char **message)
+{
+/* testing for NULL PK values and NULL Geoms */
+    int ret;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn;
+    char *sql;
+    char *prev;
+    char **results;
+    int rows;
+    int columns;
+    int i;
+    char *errMsg = NULL;
+    sqlite3_stmt *stmt = NULL;
+    int icol;
+    int count = 0;
+    int null_geom = 0;
+    int null_pk = 0;
+
+/* composing the SQL query */
+    xcolumn = gaiaDoubleQuotedSql (geom);
+    sql = sqlite3_mprintf ("SELECT \"%s\"", geom);
+    free (xcolumn);
+    prev = sql;
+
+/* retrieving all PK columns */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *name = results[(i * columns) + 1];
+	  const char *value = results[(i * columns) + 5];
+	  if (atoi (value) > 0)
+	    {
+		/* found a PK column */
+		xcolumn = gaiaDoubleQuotedSql (name);
+		sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn);
+		free (xcolumn);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+      }
+    sqlite3_free_table (results);
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("%s FROM \"%s\".\"%s\"", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+
+/* creating the prepared statement */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "CHECK NULLS ",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		count++;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
+		    null_geom++;
+		for (icol = 1; icol < sqlite3_column_count (stmt); icol++)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
+			  null_pk++;
+		  }
+		if (null_geom || null_pk)
+		    break;
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: CHECK NULLS",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    stmt = NULL;
+
+    if (null_geom)
+      {
+	  sql =
+	      sqlite3_mprintf ("Invalid %s: found NULL Geometries !!!", which);
+	  do_update_message (message, sql);
+	  sqlite3_free (sql);
+	  goto error;
+      }
+    if (null_pk)
+      {
+	  sql = sqlite3_mprintf ("Invalid %s: found NULL PK Values !!!", which);
+	  do_update_message (message, sql);
+	  sqlite3_free (sql);
+	  goto error;
+      }
+    if (!count)
+      {
+	  sql = sqlite3_mprintf ("Invalid %s: empty table !!!", which);
+	  do_update_message (message, sql);
+	  sqlite3_free (sql);
+	  goto error;
+      }
+
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+static int
+do_check_valid (sqlite3 * handle, const char *out_table, const char *input_geom,
+		char **message)
+{
+/* checking for Invalid Output Geoms */
+    int ret;
+    char *sql;
+    char *xcolumn;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    int i;
+    char *errMsg = NULL;
+    int count;
+
+/* inspecting the table */
+    xcolumn = gaiaDoubleQuotedSql (input_geom);
+    xtable = gaiaDoubleQuotedSql (out_table);
+    sql =
+	sqlite3_mprintf
+	("SELECT Count(*) FROM MAIN.\"%s\" WHERE ST_IsValid(\"%s\") <> 1",
+	 xtable, xcolumn);
+    free (xtable);
+    free (xcolumn);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 1;
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *value = results[(i * columns) + 0];
+	  count = atoi (value);
+      }
+    sqlite3_free_table (results);
+    if (count > 0)
+      {
+	  do_update_message (message,
+			     "The OUTPUT table contains INVALID Geometries");
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+check_spatial_index (sqlite3 * handle, const char *db_prefix,
+		     const char *idx_name, char **message)
+{
+/* testing if some Spatial Index do really exists */
+    int ret;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    int i;
+    char *errMsg = NULL;
+    int ok_pkid = 0;
+    int ok_xmin = 0;
+    int ok_xmax = 0;
+    int ok_ymin = 0;
+    int ok_ymax = 0;
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* inspecting the table */
+    xtable = gaiaDoubleQuotedSql (idx_name);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *name = results[(i * columns) + 1];
+	  if (strcasecmp (name, "pkid") == 0)
+	      ok_pkid = 1;
+	  if (strcasecmp (name, "xmin") == 0)
+	      ok_xmin = 1;
+	  if (strcasecmp (name, "xmax") == 0)
+	      ok_xmax = 1;
+	  if (strcasecmp (name, "ymin") == 0)
+	      ok_ymin = 1;
+	  if (strcasecmp (name, "ymax") == 0)
+	      ok_ymax = 1;
+      }
+    sqlite3_free_table (results);
+    if (!ok_pkid || !ok_xmin || !ok_xmax || !ok_ymin || !ok_ymax)
+	goto error;
+
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    return 0;
+}
+
+static int
+do_verify_blade_spatial_index (sqlite3 * handle, const char *db_prefix,
+			       const char *table, const char *geometry,
+			       char **spatial_index_prefix,
+			       char **spatial_index, int *drop_spatial_index,
+			       char **message)
+{
+/* verifying the Spatial Index supporting the Blade Geometry */
+    int ret;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char *xgeometry;
+    char *idx_prefix;
+    char *idx_name;
+    char **results;
+    int rows;
+    int columns;
+    int i;
+    int declared = 0;
+    char *errMsg = NULL;
+    time_t now;
+    pid_t pid;
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* inspecting the table */
+    sql = sqlite3_mprintf ("SELECT spatial_index_enabled "
+			   "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) "
+			   "AND Lower(f_geometry_column) = Lower(%Q)",
+			   xprefix, table, geometry);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT geometry_columns", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *value = results[(i * columns) + 0];
+	  if (atoi (value) == 1)
+	      declared = 1;
+      }
+    sqlite3_free_table (results);
+
+    if (!declared)
+	goto create_default;
+
+    idx_name = sqlite3_mprintf ("idx_%s_%s", table, geometry);
+    if (check_spatial_index (handle, db_prefix, idx_name, message))
+      {
+	  idx_prefix = malloc (strlen (db_prefix) + 1);
+	  strcpy (idx_prefix, db_prefix);
+	  *spatial_index_prefix = idx_prefix;
+	  *spatial_index = idx_name;
+	  *drop_spatial_index = 0;
+	  goto end;
+      }
+    sqlite3_free (idx_name);
+
+  create_default:
+/* creating a transient Spatial Index */
+    pid = getpid ();
+    time (&now);
+    idx_name = sqlite3_mprintf ("tmpidx_%u_%u", pid, now);
+    xtable = gaiaDoubleQuotedSql (idx_name);
+    sql = sqlite3_mprintf ("CREATE VIRTUAL TABLE TEMP.\"%s\" USING "
+			   "rtree(pkid, xmin, xmax, ymin, ymax)", xtable);
+    free (xtable);
+
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "CREATE SPATIAL INDEX", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+
+/* populating the transient Spatial Index */
+    xtable = gaiaDoubleQuotedSql (table);
+    xgeometry = gaiaDoubleQuotedSql (geometry);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO TEMP.\"%s\" (pkid, xmin, xmax, ymin, ymax) "
+	 "SELECT ROWID, MbrMinX(\"%s\"), MbrMaxX(\"%s\"), MbrMinY(\"%s\"), MbrMaxY(\"%s\") "
+	 "FROM \"%s\".\"%s\"", idx_name, xgeometry, xgeometry, xgeometry,
+	 xgeometry, xprefix, xtable);
+    free (xtable);
+    free (xgeometry);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "POPULATE SPATIAL INDEX", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+
+    *spatial_index = idx_name;
+    idx_prefix = malloc (5);
+    strcpy (idx_prefix, "TEMP");
+    *spatial_index_prefix = idx_prefix;
+    *drop_spatial_index = 1;
+
+  end:
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    return 0;
+}
+
+static int
+do_drop_blade_spatial_index (sqlite3 * handle, const char *spatial_index,
+			     char **message)
+{
+/* dropping the transient Spatial Index supporting the Blade table */
+    int ret;
+    char *sql;
+    char *xtable;
+    char *errMsg = NULL;
+    xtable = gaiaDoubleQuotedSql (spatial_index);
+    sql = sqlite3_mprintf ("DROP TABLE TEMP.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "DROP SPATIAL INDEX", errMsg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+do_drop_tmp_table (sqlite3 * handle, const char *tmp_table, char **message)
+{
+/* dropping the Temporary helper table */
+    int ret;
+    char *sql;
+    char *xtable;
+    char *errMsg = NULL;
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("DROP TABLE TEMP.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "DROP TEMPORAY TABLE", errMsg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+do_check_output (sqlite3 * handle, const char *db_prefix, const char *table,
+		 const char *geometry, char **message)
+{
+/* checking the output table for validity */
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int count = 0;
+    int i;
+    int ret;
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* checking if the table already exists */
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+    if (count != 0)
+      {
+	  do_print_message2 (message, "ERROR: table %s.%s do already exists",
+			     db_prefix, table);
+	  goto error;
+      }
+
+/* checking geometry_columns */
+    count = 0;
+    sql = sqlite3_mprintf ("SELECT f_geometry_column, srid, geometry_type "
+			   "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) "
+			   "AND Lower(f_geometry_column) = Lower(%Q)",
+			   xprefix, table, geometry);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT geometry_columns", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+    if (count != 0)
+      {
+	  do_print_message3 (message,
+			     "ERROR: table %s.%s Geometry %s is already registered",
+			     db_prefix, table, geometry);
+	  goto error;
+      }
+
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    return 0;
+}
+
+static int
+do_get_input_pk (struct output_table *tbl, sqlite3 * handle,
+		 const char *db_prefix, const char *table, char **message)
+{
+/* retrieving the input table PK columns */
+    int ret;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    int i;
+    char *errMsg = NULL;
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* inspecting the table */
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *name = results[(i * columns) + 1];
+	  const char *type = results[(i * columns) + 2];
+	  const char *notnull = results[(i * columns) + 3];
+	  const char *value = results[(i * columns) + 5];
+	  if (atoi (value) > 0)
+	    {
+		if (add_column_to_output_table
+		    (tbl, name, type, atoi (notnull), GAIA_CUTTER_INPUT_PK,
+		     atoi (value)) == NULL)
+		  {
+		      do_print_message2 (message,
+					 "ERROR: insufficient memory (OutputTable wrapper/Input PK)",
+					 db_prefix, table);
+		      goto error;
+		  }
+	    }
+      }
+    sqlite3_free_table (results);
+
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    return 0;
+}
+
+static int
+do_get_blade_pk (struct output_table *tbl, sqlite3 * handle,
+		 const char *db_prefix, const char *table, char **message)
+{
+/* retrieving the blade table PK columns */
+    int ret;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char **results;
+    int rows;
+    int columns;
+    int i;
+    char *errMsg = NULL;
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+
+/* inspecting the table */
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA table_info", errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *name = results[(i * columns) + 1];
+	  const char *type = results[(i * columns) + 2];
+	  const char *notnull = results[(i * columns) + 3];
+	  const char *value = results[(i * columns) + 5];
+	  if (atoi (value) > 0)
+	    {
+		if (add_column_to_output_table
+		    (tbl, name, type, atoi (notnull), GAIA_CUTTER_BLADE_PK,
+		     atoi (value)) == NULL)
+		  {
+		      do_print_message2 (message,
+					 "ERROR: insufficient memory (OutputTable wrapper/Blade PK)",
+					 db_prefix, table);
+		      goto error;
+		  }
+	    }
+      }
+    sqlite3_free_table (results);
+
+    free (xprefix);
+    return 1;
+
+  error:
+    free (xprefix);
+    return 0;
+}
+
+static void
+make_lowercase (char *name)
+{
+/* making a column name all lowercase */
+    char *p = name;
+    while (*p != '\0')
+      {
+	  if (*p >= 'A' && *p <= 'Z')
+	      *p = *p - 'A' + 'a';
+	  p++;
+      }
+}
+
+static int
+do_create_output_table (struct output_table *tbl, sqlite3 * handle,
+			const char *table, const char *input_table,
+			const char *blade_table, char **message)
+{
+/* attempting to create the Output Table */
+    int ret;
+    char *errMsg = NULL;
+    char *sql;
+    char *prev;
+    char *xtable;
+    char *xcolumn;
+    char *zcolumn;
+    char *zzcolumn;
+    struct output_column *col;
+
+/* composing the CREATE TABLE statement */
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* adding a column to the table */
+	  xcolumn = gaiaDoubleQuotedSql (col->base_name);
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		/* Input PK column */
+		zcolumn =
+		    sqlite3_mprintf ("input_%s_%s", input_table,
+				     col->base_name);
+		make_lowercase (zcolumn);
+		zzcolumn = gaiaDoubleQuotedSql (zcolumn);
+		col->real_name = zcolumn;
+		sql =
+		    sqlite3_mprintf ("%s,\n\t\"%s\" %s%s", prev, zzcolumn,
+				     col->type,
+				     (col->notnull) ? " NOT NULL" : "");
+		free (zzcolumn);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  else if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		/* Blade PK column */
+		zcolumn =
+		    sqlite3_mprintf ("blade_%s_%s", blade_table,
+				     col->base_name);
+		make_lowercase (zcolumn);
+		zzcolumn = gaiaDoubleQuotedSql (zcolumn);
+		col->real_name = zcolumn;
+		sql =
+		    sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev, zzcolumn,
+				     col->type);
+		free (zzcolumn);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  else if (col->role == GAIA_CUTTER_OUTPUT_PK)
+	    {
+		/* output table primary column */
+		sql =
+		    sqlite3_mprintf ("%s\n\t\"%s\" %s PRIMARY KEY", prev,
+				     xcolumn, col->type);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  else
+	    {
+		/* ordinary column */
+		sql =
+		    sqlite3_mprintf ("%s,\n\t\"%s\" %s%s", prev, xcolumn,
+				     col->type,
+				     (col->notnull) ? " NOT NULL" : "");
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  free (xcolumn);
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s)", prev);
+    sqlite3_free (prev);
+
+/* creating the Output Table */
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "CREATE TABLE", errMsg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_output_geometry (sqlite3 * handle, const char *table,
+			   const char *geometry, int srid, int geom_type,
+			   char **message)
+{
+/* attempting to create the Output Geometry */
+    int ret;
+    int retcode = 0;
+    sqlite3_stmt *stmt = NULL;
+    char *sql;
+    const char *type;
+    const char *dims;
+
+    switch (geom_type)
+      {
+      case GAIA_POINT:
+      case GAIA_POINTZ:
+      case GAIA_POINTM:
+      case GAIA_POINTZM:
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTIPOINTZM:
+	  type = "POINT";
+	  break;
+      case GAIA_LINESTRING:
+      case GAIA_LINESTRINGZ:
+      case GAIA_LINESTRINGM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTILINESTRINGZM:
+	  type = "LINESTRING";
+	  break;
+      case GAIA_POLYGON:
+      case GAIA_POLYGONZ:
+      case GAIA_POLYGONM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_MULTIPOLYGONM:
+      case GAIA_MULTIPOLYGONZM:
+	  type = "POLYGON";
+	  break;
+      };
+    switch (geom_type)
+      {
+      case GAIA_POINT:
+      case GAIA_LINESTRING:
+      case GAIA_POLYGON:
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_POINTM:
+      case GAIA_LINESTRINGM:
+      case GAIA_POLYGONM:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTIPOLYGONM:
+	  dims = "XY";
+	  break;
+      case GAIA_POINTZ:
+      case GAIA_LINESTRINGZ:
+      case GAIA_POLYGONZ:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_POINTZM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOINTZM:
+      case GAIA_MULTILINESTRINGZM:
+      case GAIA_MULTIPOLYGONZM:
+	  dims = "XYZ";
+	  break;
+      };
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(Lower(%Q), Lower(%Q), %d, %Q, %Q)", table,
+	 geometry, srid, type, dims);
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "AddGeometryTable",
+			       sqlite3_errmsg (handle));
+	  goto end;
+      }
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_INTEGER)
+		  {
+		      /* testing for success */
+		      if (sqlite3_column_int (stmt, 0) != 0)
+			  retcode = 1;
+		  }
+	    }
+      }
+
+  end:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return retcode;
+}
+
+static gaiaGeomCollPtr
+do_read_input_geometry (struct output_table *tbl, const void *cache,
+			sqlite3_stmt * stmt_in, sqlite3 * handle,
+			struct temporary_row *row, char **message,
+			unsigned char **blob, int *blob_sz)
+{
+/* reading an Input Geometry */
+    int ret;
+    int icol2 = 0;
+    int icol = 1;
+    struct multivar *var;
+    struct output_column *col;
+    gaiaGeomCollPtr geom = NULL;
+    const unsigned char *blob_value;
+    int size;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+    *blob = NULL;
+    *blob_sz = 0;
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		var = find_input_pk_value (row, icol2);
+		if (var == NULL)
+		    return NULL;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Input Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_in, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_in, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_in, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_in, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    while (1)
+      {
+	  /* scrolling the result set rows - Input */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_BLOB)
+		  {
+		      blob_value = sqlite3_column_blob (stmt_in, 0);
+		      size = sqlite3_column_bytes (stmt_in, 0);
+		      geom =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob_value, size,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		      *blob = (unsigned char *) blob_value;
+		      *blob_sz = size;
+		      return geom;
+		  }
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT Geometry FROM INPUT",
+				     sqlite3_errmsg (handle));
+		if (geom != NULL)
+		    gaiaFreeGeomColl (geom);
+		return NULL;
+	    }
+      }
+
+    if (geom == NULL)
+	do_update_message (message, "found unexpected NULL Input Geometry");
+    return geom;
+}
+
+static gaiaGeomCollPtr
+do_read_blade_geometry (struct output_table *tbl, const void *cache,
+			sqlite3_stmt * stmt_in, sqlite3 * handle,
+			struct temporary_row *row, char **message,
+			unsigned char **blob, int *blob_sz)
+{
+/* reading an Blase Geometry */
+    int ret;
+    int icol2 = 0;
+    int icol = 1;
+    struct multivar *var;
+    struct output_column *col;
+    gaiaGeomCollPtr geom = NULL;
+    const unsigned char *blob_value;
+    int size;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+    *blob = NULL;
+    *blob_sz = 0;
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		var = find_blade_pk_value (row, icol2);
+		if (var == NULL)
+		    return NULL;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Blade Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_in, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_in, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_in, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_in, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    while (1)
+      {
+	  /* scrolling the result set rows - Input */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_BLOB)
+		  {
+		      blob_value = sqlite3_column_blob (stmt_in, 0);
+		      size = sqlite3_column_bytes (stmt_in, 0);
+		      geom =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob_value, size,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		      *blob = (unsigned char *) blob_value;
+		      *blob_sz = size;
+		      return geom;
+		  }
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT Geometry FROM BLADE",
+				     sqlite3_errmsg (handle));
+		if (geom != NULL)
+		    gaiaFreeGeomColl (geom);
+		return NULL;
+	    }
+      }
+
+    if (geom == NULL)
+	do_update_message (message, "found unexpected NULL Blade Geometry");
+    return geom;
+}
+
+static gaiaGeomCollPtr
+do_prepare_point (gaiaPointPtr pt, int srid)
+{
+/* normalizing a Point Geometry */
+    gaiaGeomCollPtr new_geom = NULL;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+      {
+	  new_geom = gaiaAllocGeomCollXYZ ();
+	  gaiaAddPointToGeomCollXYZ (new_geom, pt->X, pt->Y, pt->Z);
+      }
+    else
+      {
+	  new_geom = gaiaAllocGeomColl ();
+	  gaiaAddPointToGeomColl (new_geom, pt->X, pt->Y);
+      }
+    if (new_geom->MinX > pt->X)
+	new_geom->MinX = pt->X;
+    if (new_geom->MaxX < pt->X)
+	new_geom->MaxX = pt->X;
+    if (new_geom->MinY > pt->Y)
+	new_geom->MinY = pt->Y;
+    if (new_geom->MaxY < pt->Y)
+	new_geom->MaxY = pt->Y;
+    new_geom->Srid = srid;
+    new_geom->DeclaredType = GAIA_POINT;
+    return new_geom;
+}
+
+static gaiaGeomCollPtr
+do_prepare_linestring (gaiaLinestringPtr ln, int srid)
+{
+/* normalizing a Linestring Geometry */
+    gaiaGeomCollPtr new_geom = NULL;
+    gaiaLinestringPtr new_ln;
+    int iv;
+    double x;
+    double y;
+    double z;
+    double m;
+
+    if (ln->DimensionModel == GAIA_XY_Z || ln->DimensionModel == GAIA_XY_Z_M)
+	new_geom = gaiaAllocGeomCollXYZ ();
+    else
+	new_geom = gaiaAllocGeomColl ();
+    new_geom->Srid = srid;
+    new_geom->DeclaredType = GAIA_LINESTRING;
+
+    new_ln = gaiaAddLinestringToGeomColl (new_geom, ln->Points);
+    for (iv = 0; iv < ln->Points; iv++)
+      {
+	  if (ln->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (ln->Coords, iv, &x, &y);
+	    }
+	  if (new_geom->MinX > x)
+	      new_geom->MinX = x;
+	  if (new_geom->MaxX < x)
+	      new_geom->MaxX = x;
+	  if (new_geom->MinY > y)
+	      new_geom->MinY = y;
+	  if (new_geom->MaxY < y)
+	      new_geom->MaxY = y;
+	  if (new_ln->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
+	    }
+	  else
+	    {
+		gaiaSetPoint (new_ln->Coords, iv, x, y);
+	    }
+      }
+    return new_geom;
+}
+
+static gaiaGeomCollPtr
+do_prepare_polygon (gaiaPolygonPtr pg, int srid)
+{
+/* normalizing a Polygon Geometry */
+    gaiaGeomCollPtr new_geom = NULL;
+    gaiaPolygonPtr new_pg;
+    gaiaRingPtr rng;
+    gaiaRingPtr new_rng;
+    int iv;
+    int ib;
+    double x;
+    double y;
+    double z;
+    double m;
+
+    if (pg->DimensionModel == GAIA_XY_Z || pg->DimensionModel == GAIA_XY_Z_M)
+	new_geom = gaiaAllocGeomCollXYZ ();
+    else
+	new_geom = gaiaAllocGeomColl ();
+    new_geom->Srid = srid;
+    new_geom->DeclaredType = GAIA_POLYGON;
+
+/* Exterior Ring */
+    rng = pg->Exterior;
+    new_pg = gaiaAddPolygonToGeomColl (new_geom, rng->Points, pg->NumInteriors);
+    new_rng = new_pg->Exterior;
+    for (iv = 0; iv < rng->Points; iv++)
+      {
+	  if (rng->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
+	    }
+	  else if (rng->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
+	    }
+	  else if (rng->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (rng->Coords, iv, &x, &y);
+	    }
+	  if (new_geom->MinX > x)
+	      new_geom->MinX = x;
+	  if (new_geom->MaxX < x)
+	      new_geom->MaxX = x;
+	  if (new_geom->MinY > y)
+	      new_geom->MinY = y;
+	  if (new_geom->MaxY < y)
+	      new_geom->MaxY = y;
+	  if (new_rng->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaSetPointXYZ (new_rng->Coords, iv, x, y, z);
+	    }
+	  else
+	    {
+		gaiaSetPoint (new_rng->Coords, iv, x, y);
+	    }
+      }
+    for (ib = 0; ib < pg->NumInteriors; ib++)
+      {
+	  /* Interior Rings */
+	  rng = pg->Interiors + ib;
+	  new_rng = gaiaAddInteriorRing (new_pg, ib, rng->Points);
+	  for (iv = 0; iv < rng->Points; iv++)
+	    {
+		if (rng->DimensionModel == GAIA_XY_Z)
+		  {
+		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
+		  }
+		else if (rng->DimensionModel == GAIA_XY_M)
+		  {
+		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
+		  }
+		else if (rng->DimensionModel == GAIA_XY_Z_M)
+		  {
+		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
+		  }
+		else
+		  {
+		      gaiaGetPoint (rng->Coords, iv, &x, &y);
+		  }
+		if (new_rng->DimensionModel == GAIA_XY_Z)
+		  {
+		      gaiaSetPointXYZ (new_rng->Coords, iv, x, y, z);
+		  }
+		else
+		  {
+		      gaiaSetPoint (new_rng->Coords, iv, x, y);
+		  }
+	    }
+      }
+    return new_geom;
+}
+
+static int
+do_insert_output_row (struct output_table *tbl, const void *cache,
+		      sqlite3_stmt * stmt_out, sqlite3 * handle,
+		      struct temporary_row *row, int n_geom, int res_prog,
+		      int geom_type, void *item, int srid, char **message)
+{
+/* inserting into the Output table */
+    int ret;
+    int icol2 = 0;
+    int icol = 1;
+    struct multivar *var;
+    struct output_column *col;
+    gaiaGeomCollPtr geom = NULL;
+    gaiaPointPtr pt;
+    gaiaLinestringPtr ln;
+    gaiaPolygonPtr pg;
+    unsigned char *blob;
+    int size;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    sqlite3_reset (stmt_out);
+    sqlite3_clear_bindings (stmt_out);
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		/* binding Input PK values */
+		var = find_input_pk_value (row, icol2);
+		if (var == NULL)
+		    return 0;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Input Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_out, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_out, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_out, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_out, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    icol2 = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		/* binding Blade PK values */
+		var = find_blade_pk_value (row, icol2);
+		if (var == NULL)
+		    return 0;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Blade Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_out, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_out, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_out, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_out, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+/* binding "n_geom" and "res_prog" columns */
+    sqlite3_bind_int (stmt_out, icol, n_geom);
+    icol++;
+    sqlite3_bind_int (stmt_out, icol, res_prog);
+    icol++;
+    switch (geom_type)
+      {
+	  /* preparing the Output Geometry */
+      case GAIA_CUTTER_POINT:
+	  pt = (gaiaPointPtr) item;
+	  geom = do_prepare_point (pt, srid);
+	  break;
+      case GAIA_CUTTER_LINESTRING:
+	  ln = (gaiaLinestringPtr) item;
+	  geom = do_prepare_linestring (ln, srid);
+	  break;
+      case GAIA_CUTTER_POLYGON:
+	  pg = (gaiaPolygonPtr) item;
+	  geom = do_prepare_polygon (pg, srid);
+	  break;
+      default:
+	  do_update_message (message, "ILLEGAL OUTPUT GEOMETRY");
+	  return 0;
+      };
+    if (geom == NULL)
+      {
+	  do_update_message (message, "UNEXPECTED NULL OUTPUT GEOMETRY");
+	  return 0;
+      }
+    gaiaToSpatiaLiteBlobWkbEx (geom, &blob, &size, gpkg_mode);
+    if (blob == NULL)
+      {
+	  do_update_message (message, "UNEXPECTED NULL OUTPUT BLOB GEOMETRY");
+	  gaiaFreeGeomColl (geom);
+	  return 0;
+      }
+    sqlite3_bind_blob (stmt_out, icol, blob, size, free);
+    gaiaFreeGeomColl (geom);
+
+    ret = sqlite3_step (stmt_out);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	return 1;
+
+/* some error occurred */
+    do_update_sql_error (message, "INSERT INTO OUTPUT",
+			 sqlite3_errmsg (handle));
+    return 0;
+}
+
+static int
+do_create_input_statement (struct output_table *tbl, sqlite3 * handle,
+			   const char *input_db_prefix, const char *input_table,
+			   const char *input_geom, sqlite3_stmt ** stmt_in,
+			   char **message)
+{
+/* creating a Prepared Statemet - SELECT geometry FROM Input */
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+
+/* composing the SQL statement */
+    xcolumn = gaiaDoubleQuotedSql (input_geom);
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\" WHERE", xcolumn,
+			 xprefix, xtable);
+    free (xcolumn);
+    free (xprefix);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s AND \"%s\" = ?", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" = ?", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT GEOMETRY FROM INPUT",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    *stmt_in = stmt;
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+static int
+do_create_output_statement (struct output_table *tbl, sqlite3 * handle,
+			    const char *out_table, sqlite3_stmt ** stmt_out,
+			    char **message)
+{
+/* creating a Prepared Statemet - INSERT INTO Output */
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *xtable;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+
+/* composing the SQL statement */
+    xtable = gaiaDoubleQuotedSql (out_table);
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" VALUES (NULL", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s, ?, ?, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO OUTPUT",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    *stmt_out = stmt;
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+static int
+do_prepare_temp_points (struct output_table *tbl, sqlite3 * handle,
+			const char *input_db_prefix, const char *input_table,
+			const char *input_geom, const char *blade_db_prefix,
+			const char *blade_table, const char *blade_geom,
+			const char *spatial_index_prefix,
+			const char *spatial_index, char **tmp_table,
+			char **message)
+{
+/* creating and populating the temporary helper table - POINTs */
+    int ret;
+    char *errMsg = NULL;
+    char *temporary_table;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    time_t now;
+    pid_t pid;
+    struct output_column *col;
+    int comma = 0;
+
+    *tmp_table = NULL;
+/* composing the SQL statement */
+    pid = getpid ();
+    time (&now);
+    temporary_table = sqlite3_mprintf ("tmpcuttertbl_%u_%u", pid, now);
+    xtable = gaiaDoubleQuotedSql (temporary_table);
+
+    sql = sqlite3_mprintf ("CREATE TEMPORARY TABLE \"%s\" AS SELECT", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, i.\"%s\" AS \"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s i.\"%s\" AS \"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, b.\"%s\" AS \"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s b.\"%s\" AS \"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the "Touches" column */
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    xcolumn2 = gaiaDoubleQuotedSql (blade_geom);
+    sql =
+	sqlite3_mprintf ("%s, ST_Touches(i.\"%s\", b.\"%s\") AS touches", prev,
+			 xcolumn1, xcolumn2);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql = sqlite3_mprintf ("%s FROM \"%s\".\"%s\" AS i", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("%s LEFT JOIN \"%s\".\"%s\" AS b ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    xcolumn2 = gaiaDoubleQuotedSql (blade_geom);
+    sql =
+	sqlite3_mprintf ("%sST_CoveredBy(i.\"%s\", b.\"%s\") = 1 ", prev,
+			 xcolumn1, xcolumn2);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    sql = sqlite3_mprintf ("%s AND b.ROWID IN (SELECT pkid FROM ", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (spatial_index_prefix);
+    xtable = gaiaDoubleQuotedSql (spatial_index);
+    sql = sqlite3_mprintf ("%s \"%s\".\"%s\" WHERE", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    sql =
+	sqlite3_mprintf
+	("%s xmin <= MbrMaxX(i.\"%s\") AND xmax >= MbrMinX(i.\"%s\") ", prev,
+	 xcolumn1, xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    sql =
+	sqlite3_mprintf
+	("%s AND ymin <= MbrMaxY(i.\"%s\") AND ymax >= MbrMinY(i.\"%s\")))",
+	 prev, xcolumn1, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+
+/* executing the SQL Query */
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "CREATE TEMPORARY TABLE POINT #0",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+
+    *tmp_table = temporary_table;
+    return 1;
+
+  error:
+    if (temporary_table != NULL)
+	sqlite3_free (temporary_table);
+    return 0;
+}
+
+static int
+do_create_temp_linestrings (struct output_table *tbl, sqlite3 * handle,
+			    char **tmp_table, char **message)
+{
+/* creating and populating the temporary helper table - LINESTRINGs */
+    int ret;
+    char *errMsg = NULL;
+    char *temporary_table;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    time_t now;
+    pid_t pid;
+    struct output_column *col;
+    int comma = 0;
+
+    *tmp_table = NULL;
+/* composing the SQL statement */
+    pid = getpid ();
+    time (&now);
+    temporary_table = sqlite3_mprintf ("tmpcuttertbl_%u_%u", pid, now);
+    xtable = gaiaDoubleQuotedSql (temporary_table);
+
+    sql = sqlite3_mprintf ("CREATE TEMPORARY TABLE \"%s\" (", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, \"%s\" GENERIC", prev, xcolumn2);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" GENERIC", prev, xcolumn2);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the n_geom column */ ;
+    xprefix = sqlite3_mprintf ("%s_n_geom", temporary_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s, \"%s\" INTEGER", prev, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s, \"%s\" GENERIC", prev, xcolumn2);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the nodes-geometry */
+    xprefix = sqlite3_mprintf ("%s_nodes_geom", temporary_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s, \"%s\" BLOB", prev, xcolumn2);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+/* adding the cut-geometry */
+    xprefix = sqlite3_mprintf ("%s_geom", temporary_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s, \"%s\" BLOB)", prev, xcolumn2);
+    free (xcolumn2);
+    sqlite3_free (prev);
+
+/* executing the SQL Query */
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "CREATE TEMPORARY TABLE LINESTRINGS",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+
+    *tmp_table = temporary_table;
+    return 1;
+
+  error:
+    if (temporary_table != NULL)
+	sqlite3_free (temporary_table);
+    return 0;
+}
+
+static int
+do_create_temp_polygons (struct output_table *tbl, sqlite3 * handle,
+			 char **tmp_table, char **message)
+{
+/* creating and populating the temporary helper table - POLYGONs */
+    int ret;
+    char *errMsg = NULL;
+    char *temporary_table;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    time_t now;
+    pid_t pid;
+    struct output_column *col;
+    int comma = 0;
+
+    *tmp_table = NULL;
+/* composing the SQL statement */
+    pid = getpid ();
+    time (&now);
+    temporary_table = sqlite3_mprintf ("tmpcuttertbl_%u_%u", pid, now);
+    xtable = gaiaDoubleQuotedSql (temporary_table);
+
+    sql = sqlite3_mprintf ("CREATE TEMPORARY TABLE \"%s\" (", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, \"%s\" GENERIC", prev, xcolumn2);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" GENERIC", prev, xcolumn2);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the n_geom column */ ;
+    xprefix = sqlite3_mprintf ("%s_n_geom", temporary_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s, \"%s\" INTEGER", prev, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s, \"%s\" GENERIC", prev, xcolumn2);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the cut-geometry */
+    xprefix = sqlite3_mprintf ("%s_geom", temporary_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s, \"%s\" BLOB)", prev, xcolumn2);
+    free (xcolumn2);
+    sqlite3_free (prev);
+
+/* executing the SQL Query */
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "CREATE TEMPORARY TABLE POLYGONS",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  goto error;
+      }
+
+    *tmp_table = temporary_table;
+    return 1;
+
+  error:
+    if (temporary_table != NULL)
+	sqlite3_free (temporary_table);
+    return 0;
+}
+
+static int
+is_null_blade (struct temporary_row *row)
+{
+/* testing for a NULL Blade reference */
+    struct multivar *var = row->first_blade;
+    while (var != NULL)
+      {
+	  if (var->type != SQLITE_NULL)
+	      return 0;
+	  var = var->next;
+      }
+    return 1;
+}
+
+static int
+is_covered_by (const void *cache, gaiaGeomCollPtr input_g,
+	       unsigned char *input_blob, int input_blob_sz,
+	       gaiaGeomCollPtr blade_g, unsigned char *blade_blob,
+	       int blade_blob_sz)
+{
+/* testing if the Input geometry is completely Covered By the Blade Geometry */
+    return gaiaGeomCollPreparedCoveredBy (cache, input_g, input_blob,
+					  input_blob_sz, blade_g, blade_blob,
+					  blade_blob_sz);
+}
+
+static int
+do_insert_temporary_linestrings (struct output_table *tbl, sqlite3 * handle,
+				 const void *cache, sqlite3_stmt * stmt_out,
+				 struct temporary_row *row,
+				 gaiaGeomCollPtr geom, char **message,
+				 int ngeom)
+{
+/* inserting a resolved Geometry in the Linestrings Helper Table */
+    int ret;
+    gaiaLinestringPtr ln;
+    struct output_column *col;
+    struct multivar *var;
+    int icol2 = 0;
+    int icol = 1;
+    int n_geom = 0;
+    unsigned char *blob;
+    int size;
+    int gpkg_mode = 0;
+    gaiaGeomCollPtr g;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    if (ngeom < 0)
+	n_geom = 0;
+    else
+	n_geom = ngeom;
+
+    ln = geom->FirstLinestring;
+    while (ln != NULL)
+      {
+	  /* separating elementary geometries */
+	  icol2 = 0;
+	  icol = 1;
+	  if (ngeom < 0)
+	      n_geom++;
+	  g = do_prepare_linestring (ln, geom->Srid);
+	  sqlite3_reset (stmt_out);
+	  sqlite3_clear_bindings (stmt_out);
+	  col = tbl->first;
+	  while (col != NULL)
+	    {
+		if (col->role == GAIA_CUTTER_INPUT_PK)
+		  {
+		      /* binding Input PK values */
+		      var = find_input_pk_value (row, icol2);
+		      if (var == NULL)
+			  return 0;
+		      icol2++;
+		      switch (var->type)
+			{
+			    /* Input Primary Key Column(s) */
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_out, icol,
+						var->value.intValue);
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_out, icol,
+						 var->value.doubleValue);
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_out, icol,
+					       var->value.textValue,
+					       strlen (var->value.textValue),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_out, icol);
+			    break;
+			};
+		      icol++;
+		  }
+		col = col->next;
+	    }
+	  /* binding n_geom */
+	  sqlite3_bind_int (stmt_out, icol, n_geom);
+	  icol++;
+	  icol2 = 0;
+	  col = tbl->first;
+	  while (col != NULL)
+	    {
+		if (col->role == GAIA_CUTTER_BLADE_PK)
+		  {
+		      /* binding Blade PK values */
+		      var = find_blade_pk_value (row, icol2);
+		      if (var == NULL)
+			  return 0;
+		      icol2++;
+		      switch (var->type)
+			{
+			    /* Blade Primary Key Column(s) */
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_out, icol,
+						var->value.intValue);
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_out, icol,
+						 var->value.doubleValue);
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_out, icol,
+					       var->value.textValue,
+					       strlen (var->value.textValue),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_out, icol);
+			    break;
+			};
+		      icol++;
+		  }
+		col = col->next;
+	    }
+	  /* binding Nodes */
+	  sqlite3_bind_null (stmt_out, icol);
+	  icol++;
+	  /* binding Geometry */
+	  gaiaToSpatiaLiteBlobWkbEx (g, &blob, &size, gpkg_mode);
+	  if (blob == NULL)
+	    {
+		do_update_message (message,
+				   "UNEXPECTED NULL TEMPORARY LINESTRING BLOB GEOMETRY");
+		gaiaFreeGeomColl (geom);
+		return 0;
+	    }
+	  sqlite3_bind_blob (stmt_out, icol, blob, size, free);
+	  gaiaFreeGeomColl (g);
+	  ret = sqlite3_step (stmt_out);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      ;
+	  else
+	    {
+		/* some error occurred */
+		do_update_sql_error (message,
+				     "INSERT INTO TEMPORARY LINSTRINGS",
+				     sqlite3_errmsg (handle));
+		return 0;
+	    }
+	  ln = ln->Next;
+      }
+    return 1;
+}
+
+static int
+do_insert_temporary_linestring_intersection (struct output_table *tbl,
+					     sqlite3 * handle,
+					     const void *cache,
+					     sqlite3_stmt * stmt_out,
+					     struct temporary_row *row,
+					     int n_geom, gaiaGeomCollPtr nodes,
+					     char **message)
+{
+/* inserting an Input/Blade intersection into the Linestrings Helper Table */
+    int ret;
+    struct output_column *col;
+    struct multivar *var;
+    int icol2 = 0;
+    int icol = 1;
+    unsigned char *blob;
+    int size;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    sqlite3_reset (stmt_out);
+    sqlite3_clear_bindings (stmt_out);
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		/* binding Input PK values */
+		var = find_input_pk_value (row, icol2);
+		if (var == NULL)
+		    return 0;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Input Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_out, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_out, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_out, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_out, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    /* binding n_geom */
+    sqlite3_bind_int (stmt_out, icol, n_geom);
+    icol++;
+    icol2 = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		/* binding Blade PK values */
+		var = find_blade_pk_value (row, icol2);
+		if (var == NULL)
+		    return 0;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Blade Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_out, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_out, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_out, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_out, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    /* binding Nodes */
+    gaiaToSpatiaLiteBlobWkbEx (nodes, &blob, &size, gpkg_mode);
+    if (blob == NULL)
+      {
+	  do_update_message (message,
+			     "UNEXPECTED NULL TEMPORARY LINESTRING NODES BLOB GEOMETRY");
+	  return 0;
+      }
+    sqlite3_bind_blob (stmt_out, icol, blob, size, free);
+    icol++;
+    /* binding NULL geometry */
+    sqlite3_bind_null (stmt_out, icol);
+    ret = sqlite3_step (stmt_out);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	return 1;
+
+    /* some error occurred */
+    do_update_sql_error (message, "INSERT INTO TEMPORARY LINESTRINGS",
+			 sqlite3_errmsg (handle));
+    return 0;
+}
+
+static gaiaGeomCollPtr
+do_extract_linestring_nodes (const void *cache, sqlite3_stmt * stmt_nodes,
+			     gaiaLinestringPtr input_ln, int srid,
+			     gaiaGeomCollPtr blade_g)
+{
+/* finding the points of intersection between tweo lines (nodes) */
+    int ret;
+    gaiaGeomCollPtr input_g;
+    gaiaGeomCollPtr result = NULL;
+    unsigned char *input_blob = NULL;
+    int input_blob_sz;
+    unsigned char *blade_blob = NULL;
+    int blade_blob_sz;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    sqlite3_reset (stmt_nodes);
+    sqlite3_clear_bindings (stmt_nodes);
+    input_g = do_prepare_linestring (input_ln, srid);
+    gaiaToSpatiaLiteBlobWkbEx (input_g, &input_blob, &input_blob_sz, gpkg_mode);
+    gaiaFreeGeomColl (input_g);
+    gaiaToSpatiaLiteBlobWkbEx (blade_g, &blade_blob, &blade_blob_sz, gpkg_mode);
+    sqlite3_bind_blob (stmt_nodes, 1, input_blob, input_blob_sz, free);
+    sqlite3_bind_blob (stmt_nodes, 2, blade_blob, blade_blob_sz, free);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_nodes);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		if (sqlite3_column_type (stmt_nodes, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_nodes, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt_nodes, 0);
+		      result =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+	    }
+      }
+
+    return result;
+}
+
+static int
+do_populate_temp_linestrings (struct output_table *tbl, sqlite3 * handle,
+			      const void *cache, const char *input_db_prefix,
+			      const char *input_table, const char *input_geom,
+			      const char *blade_db_prefix,
+			      const char *blade_table, const char *blade_geom,
+			      const char *spatial_index_prefix,
+			      const char *spatial_index, const char *tmp_table,
+			      int type, char **message)
+{
+/* populating the temporary helper table - LINESTRINGs */
+    int ret;
+    sqlite3_stmt *stmt_main = NULL;
+    sqlite3_stmt *stmt_input = NULL;
+    sqlite3_stmt *stmt_blade = NULL;
+    sqlite3_stmt *stmt_tmp = NULL;
+    sqlite3_stmt *stmt_nodes = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+    int cast2d = 0;
+    int cast3d = 0;
+
+    switch (type)
+      {
+      case GAIA_LINESTRINGM:
+      case GAIA_MULTILINESTRINGM:
+	  cast2d = 1;
+	  break;
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRINGZM:
+	  cast3d = 1;
+	  break;
+      };
+
+/* composing the SQL statement - main SELECT query */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, i.\"%s\"", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s i.\"%s\"", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		sql = sqlite3_mprintf ("%s, b.\"%s\"", prev, xcolumn);
+		free (xcolumn);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql = sqlite3_mprintf ("%s FROM \"%s\".\"%s\" AS i", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS b ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    sql = sqlite3_mprintf ("%sb.ROWID IN (SELECT pkid FROM ", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (spatial_index_prefix);
+    xtable = gaiaDoubleQuotedSql (spatial_index);
+    sql = sqlite3_mprintf ("%s \"%s\".\"%s\" WHERE", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xcolumn = gaiaDoubleQuotedSql (input_geom);
+    sql =
+	sqlite3_mprintf
+	("%s xmin <= MbrMaxX(i.\"%s\") AND xmax >= MbrMinX(i.\"%s\") ", prev,
+	 xcolumn, xcolumn);
+    sqlite3_free (prev);
+    prev = sql;
+    sql =
+	sqlite3_mprintf
+	("%s AND ymin <= MbrMaxY(i.\"%s\") AND ymax >= MbrMinY(i.\"%s\")))",
+	 prev, xcolumn, xcolumn);
+    free (xcolumn);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - main SELECT query */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_main, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "QUERYING LINESTRING INTERSECTIONS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - SELECT geometry FROM Input */
+    xcolumn = gaiaDoubleQuotedSql (input_geom);
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\" WHERE", xcolumn,
+			 xprefix, xtable);
+    free (xcolumn);
+    free (xprefix);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s AND \"%s\" = ?", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" = ?", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT geometry FROM Input */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_input, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT GEOMETRY FROM INPUT",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - SELECT geometry FROM Blade */
+    xcolumn = gaiaDoubleQuotedSql (blade_geom);
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\" WHERE", xcolumn,
+			 xprefix, xtable);
+    free (xcolumn);
+    free (xprefix);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s AND \"%s\" = ?", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" = ?", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT geometry FROM Blade */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_blade, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT GEOMETRY FROM BLADE",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - Inserting into TMP */
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("INSERT INTO TEMP.\"%s\" VALUES (", xtable);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, ?", prev);
+		else
+		    sql = sqlite3_mprintf ("%s?", prev);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the n_geom column */
+    sql = sqlite3_mprintf ("%s, ?", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the nodes columns */
+    sql = sqlite3_mprintf ("%s, ?", prev);
+    sqlite3_free (prev);
+    prev = sql;
+/* adding the geom columns */
+    if (cast2d)
+	sql = sqlite3_mprintf ("%s, CastToXY(?))", prev);
+    else if (cast3d)
+	sql = sqlite3_mprintf ("%s, CastToXYZ(?))", prev);
+    else
+	sql = sqlite3_mprintf ("%s, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - INSERT INTO TMP LINESTRINGS */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_tmp, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO TMP LINESTRINGS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - finding NODES */
+    sql =
+	sqlite3_mprintf ("SELECT CollectionExtract(ST_Intersection(?, ?), 1)");
+
+/* creating a Prepared Statement - finding NODES */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_nodes, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "FINDING LINESTRING NODES",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - checking matching Input/Blade pairs */
+	  ret = sqlite3_step (stmt_main);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		gaiaGeomCollPtr input_g = NULL;
+		gaiaGeomCollPtr blade_g = NULL;
+		gaiaGeomCollPtr linear_blade_g = NULL;
+		gaiaLinestringPtr ln;
+		int n_geom = 0;
+		unsigned char *input_blob;
+		unsigned char *blade_blob;
+		int input_blob_sz;
+		int blade_blob_sz;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_main, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_main, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_main, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_main, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_main, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_main, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_main, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_main, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+
+		/* reading the Input Geometry */
+		input_g =
+		    do_read_input_geometry (tbl, cache, stmt_input, handle,
+					    &row, message, &input_blob,
+					    &input_blob_sz);
+		if (input_g == NULL)
+		    goto error;
+
+		if (is_null_blade (&row))
+		  {
+		      /* Input doesn't matches any Blade */
+		      if (!do_insert_temporary_linestrings
+			  (tbl, handle, cache, stmt_tmp, &row, input_g,
+			   message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    goto error;
+			}
+		      goto skip;
+		  }
+
+		/* reading the Blade Geometry */
+		blade_g =
+		    do_read_blade_geometry (tbl, cache, stmt_blade, handle,
+					    &row, message, &blade_blob,
+					    &blade_blob_sz);
+		if (blade_g == NULL)
+		    goto error;
+
+		if (is_covered_by
+		    (cache, input_g, input_blob, input_blob_sz, blade_g,
+		     blade_blob, blade_blob_sz))
+		  {
+		      /* Input is completely Covered By Blade */
+		      if (!do_insert_temporary_linestrings
+			  (tbl, handle, cache, stmt_tmp, &row, input_g,
+			   message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    gaiaFreeGeomColl (blade_g);
+			    goto error;
+			}
+		      goto skip;
+		  }
+
+		linear_blade_g = gaiaLinearize (blade_g, 1);
+		ln = input_g->FirstLinestring;
+		while (ln != NULL)
+		  {
+		      gaiaGeomCollPtr nodes;
+		      n_geom++;
+		      nodes =
+			  do_extract_linestring_nodes (cache, stmt_nodes, ln,
+						       input_g->Srid,
+						       linear_blade_g);
+		      if (nodes != NULL)
+			{
+			    /* saving an Input/Blade intersection */
+			    if (!do_insert_temporary_linestring_intersection
+				(tbl, handle, cache, stmt_tmp, &row, n_geom,
+				 nodes, message))
+			      {
+				  reset_temporary_row (&row);
+				  gaiaFreeGeomColl (input_g);
+				  gaiaFreeGeomColl (blade_g);
+				  gaiaFreeGeomColl (linear_blade_g);
+				  gaiaFreeGeomColl (nodes);
+				  goto error;
+			      }
+			    gaiaFreeGeomColl (nodes);
+			}
+		      ln = ln->Next;
+		  }
+		gaiaFreeGeomColl (linear_blade_g);
+
+	      skip:
+		reset_temporary_row (&row);
+		gaiaFreeGeomColl (input_g);
+		gaiaFreeGeomColl (blade_g);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: MAIN LINESTRINGS LOOP",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_main);
+    sqlite3_finalize (stmt_input);
+    sqlite3_finalize (stmt_blade);
+    sqlite3_finalize (stmt_tmp);
+    sqlite3_finalize (stmt_nodes);
+    return 1;
+
+  error:
+    if (stmt_main == NULL)
+	sqlite3_finalize (stmt_main);
+    if (stmt_input == NULL)
+	sqlite3_finalize (stmt_input);
+    if (stmt_blade == NULL)
+	sqlite3_finalize (stmt_blade);
+    if (stmt_tmp == NULL)
+	sqlite3_finalize (stmt_tmp);
+    if (stmt_nodes == NULL)
+	sqlite3_finalize (stmt_nodes);
+    return 0;
+}
+
+static int
+do_update_tmp_cut_linestring (sqlite3 * handle, sqlite3_stmt * stmt_upd,
+			      sqlite3_int64 pk, const unsigned char *blob,
+			      int blob_sz, char **message)
+{
+/* saving an Input Linestring cut against a renoded Blade */
+    int ret;
+
+    sqlite3_reset (stmt_upd);
+    sqlite3_clear_bindings (stmt_upd);
+/* binding the cut Input geometry */
+    sqlite3_bind_blob (stmt_upd, 1, blob, blob_sz, free);
+    sqlite3_bind_int64 (stmt_upd, 2, pk);
+    /* updating the TMP table */
+    ret = sqlite3_step (stmt_upd);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	return 1;
+
+    /* some error occurred */
+    do_update_sql_error (message,
+			 "step: UPDATE TMP SET cut-Polygon",
+			 sqlite3_errmsg (handle));
+    return 0;
+}
+
+static int
+do_cut_tmp_linestrings (sqlite3 * handle, const void *cache,
+			sqlite3_stmt * stmt_in, sqlite3_stmt * stmt_upd,
+			struct temporary_row *row, char **message,
+			const unsigned char *blade_blob, int blade_blob_sz)
+{
+/* cutting all Input Linestrings intersecting the renoded Blade */
+    int ret;
+    struct multivar *var;
+    int icol = 1;
+    gaiaGeomCollPtr blade_g;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    blade_g = gaiaFromSpatiaLiteBlobWkbEx (blade_blob, blade_blob_sz,
+					   gpkg_mode, gpkg_amphibious);
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    var = row->first_blade;
+    while (var != NULL)
+      {
+	  /* binding Primary Key values (from Blade) */
+	  switch (var->type)
+	    {
+	    case SQLITE_INTEGER:
+		sqlite3_bind_int64 (stmt_in, icol, var->value.intValue);
+		break;
+	    case SQLITE_FLOAT:
+		sqlite3_bind_double (stmt_in, icol, var->value.doubleValue);
+		break;
+	    case SQLITE_TEXT:
+		sqlite3_bind_text (stmt_in, icol,
+				   var->value.textValue,
+				   strlen (var->value.textValue),
+				   SQLITE_STATIC);
+		break;
+	    default:
+		sqlite3_bind_null (stmt_in, icol);
+		break;
+	    };
+	  icol++;
+	  var = var->next;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - cut Linestrings */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		sqlite3_int64 pk = 0;
+		unsigned char *blob = NULL;
+		int blob_sz;
+		gaiaGeomCollPtr input_g;
+		gaiaGeomCollPtr result;
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER
+		    && sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
+		  {
+		      pk = sqlite3_column_int64 (stmt_in, 0);
+		      blob = (unsigned char *) sqlite3_column_blob (stmt_in, 1);
+		      blob_sz = sqlite3_column_bytes (stmt_in, 1);
+		      input_g = gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+							     gpkg_mode,
+							     gpkg_amphibious);
+		      result =
+			  gaiaGeometryIntersection_r (cache, input_g, blade_g);
+		      if (result != NULL)
+			{
+			    gaiaToSpatiaLiteBlobWkbEx (result, &blob, &blob_sz,
+						       gpkg_mode);
+			    gaiaFreeGeomColl (result);
+			}
+		      gaiaFreeGeomColl (input_g);
+		  }
+		if (blob != NULL)
+		  {
+		      if (!do_update_tmp_cut_linestring
+			  (handle, stmt_upd, pk, blob, blob_sz, message))
+			  goto error;
+		  }
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: cut Linestrings",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+    gaiaFreeGeomColl (blade_g);
+    return 1;
+
+  error:
+    gaiaFreeGeomColl (blade_g);
+    return 0;
+}
+
+static int
+do_split_linestrings (struct output_table *tbl, sqlite3 * handle,
+		      const void *cache, const char *input_db_prefix,
+		      const char *input_table, const char *input_geom,
+		      const char *blade_db_prefix, const char *blade_table,
+		      const char *blade_geom, const char *tmp_table,
+		      char **message)
+{
+/* cutting all Input Linestrings intersecting some Blade */
+    int ret;
+    sqlite3_stmt *stmt_blades = NULL;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_upd = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+
+/* composing the SQL statement - SELECT FROM Blades */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, t.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s t.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xcolumn1 = gaiaDoubleQuotedSql (blade_geom);
+    xprefix = sqlite3_mprintf ("%s_nodes_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf
+	("%s, ST_Snap(b.\"%s\", ST_UnaryUnion(ST_Collect(t.\"%s\")), 0.000000001)",
+	 prev, xcolumn1, xcolumn2);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("%s FROM TEMP.\"%s\" AS t", prev, xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS b ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND b.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s b.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("%s) WHERE t.\"%s\" IS NULL GROUP BY", prev, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, t.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s t.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT FROM Blades */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_blades, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM BLADES",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - SELECT Input */
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    xprefix = sqlite3_mprintf ("%s_n_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT t.ROWID, ST_GeometryN(i.\"%s\", t.\"%s\") FROM TEMP.\"%s\" AS t",
+	 xcolumn1, xcolumn2, xtable);
+    free (xcolumn1);
+    free (xcolumn2);
+    free (xtable);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS i ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s) WHERE t.\"%s\" IS NULL", prev, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s AND t.\"%s\" = ?", prev, xcolumn1);
+		free (xcolumn1);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT Input */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT INPUT FROM TMP",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - UPDATE tmp SET cut-Geom */
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("UPDATE TEMP.\"%s\" SET \"%s\" = ? WHERE ROWID = ?",
+			 xtable, xcolumn1);
+    free (xcolumn1);
+    free (xtable);
+
+/* creating a Prepared Statement - UPDATE tmp SET cut-Geom */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_upd, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "UPDATE TMP cut-Geometries",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - renoded Blades */
+	  ret = sqlite3_step (stmt_blades);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_blades, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_blades, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_blades, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_blades, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the Blade */
+		if (sqlite3_column_type (stmt_blades, icol) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_blades, icol);
+		      int blob_sz = sqlite3_column_bytes (stmt_blades, icol);
+		      /* cutting all Input geoms intersecting the Blade */
+		      if (!do_cut_tmp_linestrings
+			  (handle, cache, stmt_in, stmt_upd, &row, message,
+			   blob, blob_sz))
+			{
+			    reset_temporary_row (&row);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      do_update_message (message, "Unexpected NULL Blade\n");
+		      reset_temporary_row (&row);
+		      goto error;
+		  }
+
+		reset_temporary_row (&row);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: BLADES", sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_blades);
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_upd);
+    return 1;
+
+  error:
+    if (stmt_blades != NULL)
+	sqlite3_finalize (stmt_blades);
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_upd != NULL)
+	sqlite3_finalize (stmt_upd);
+    return 0;
+}
+
+static int
+do_insert_temporary_polygons (struct output_table *tbl, sqlite3 * handle,
+			      const void *cache, sqlite3_stmt * stmt_out,
+			      struct temporary_row *row, gaiaGeomCollPtr geom,
+			      char **message, int ngeom)
+{
+/* inserting a resolved Geometry in the Polygons Helper Table */
+    int ret;
+    gaiaPolygonPtr pg;
+    struct output_column *col;
+    struct multivar *var;
+    int icol2 = 0;
+    int icol = 1;
+    int n_geom = 0;
+    unsigned char *blob;
+    int size;
+    int gpkg_mode = 0;
+    gaiaGeomCollPtr g;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    if (ngeom < 0)
+	n_geom = 0;
+    else
+	n_geom = ngeom;
+
+    pg = geom->FirstPolygon;
+    while (pg != NULL)
+      {
+	  /* separating elementary geometries */
+	  icol2 = 0;
+	  icol = 1;
+	  if (ngeom < 0)
+	      n_geom++;
+	  g = do_prepare_polygon (pg, geom->Srid);
+	  sqlite3_reset (stmt_out);
+	  sqlite3_clear_bindings (stmt_out);
+	  col = tbl->first;
+	  while (col != NULL)
+	    {
+		if (col->role == GAIA_CUTTER_INPUT_PK)
+		  {
+		      /* binding Input PK values */
+		      var = find_input_pk_value (row, icol2);
+		      if (var == NULL)
+			  return 0;
+		      icol2++;
+		      switch (var->type)
+			{
+			    /* Input Primary Key Column(s) */
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_out, icol,
+						var->value.intValue);
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_out, icol,
+						 var->value.doubleValue);
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_out, icol,
+					       var->value.textValue,
+					       strlen (var->value.textValue),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_out, icol);
+			    break;
+			};
+		      icol++;
+		  }
+		col = col->next;
+	    }
+	  /* binding n_geom */
+	  sqlite3_bind_int (stmt_out, icol, n_geom);
+	  icol++;
+	  icol2 = 0;
+	  col = tbl->first;
+	  while (col != NULL)
+	    {
+		if (col->role == GAIA_CUTTER_BLADE_PK)
+		  {
+		      /* binding Blade PK values */
+		      var = find_blade_pk_value (row, icol2);
+		      if (var == NULL)
+			  return 0;
+		      icol2++;
+		      switch (var->type)
+			{
+			    /* Blade Primary Key Column(s) */
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_out, icol,
+						var->value.intValue);
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_out, icol,
+						 var->value.doubleValue);
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_out, icol,
+					       var->value.textValue,
+					       strlen (var->value.textValue),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_out, icol);
+			    break;
+			};
+		      icol++;
+		  }
+		col = col->next;
+	    }
+	  /* binding Geometry */
+	  gaiaToSpatiaLiteBlobWkbEx (g, &blob, &size, gpkg_mode);
+	  if (blob == NULL)
+	    {
+		do_update_message (message,
+				   "UNEXPECTED NULL TEMPORARY POLYGON BLOB GEOMETRY");
+		gaiaFreeGeomColl (geom);
+		return 0;
+	    }
+	  sqlite3_bind_blob (stmt_out, icol, blob, size, free);
+	  gaiaFreeGeomColl (g);
+	  ret = sqlite3_step (stmt_out);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      ;
+	  else
+	    {
+		/* some error occurred */
+		do_update_sql_error (message, "INSERT INTO TEMPORARY POLYGONS",
+				     sqlite3_errmsg (handle));
+		return 0;
+	    }
+	  pg = pg->Next;
+      }
+    return 1;
+}
+
+static int
+do_insert_temporary_polygon_intersection (struct output_table *tbl,
+					  sqlite3 * handle,
+					  sqlite3_stmt * stmt_out,
+					  struct temporary_row *row, int n_geom,
+					  char **message)
+{
+/* inserting an Input/Blade intersection into the Polygons Helper Table */
+    int ret;
+    struct output_column *col;
+    struct multivar *var;
+    int icol2 = 0;
+    int icol = 1;
+
+    sqlite3_reset (stmt_out);
+    sqlite3_clear_bindings (stmt_out);
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		/* binding Input PK values */
+		var = find_input_pk_value (row, icol2);
+		if (var == NULL)
+		    return 0;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Input Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_out, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_out, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_out, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_out, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    /* binding n_geom */
+    sqlite3_bind_int (stmt_out, icol, n_geom);
+    icol++;
+    icol2 = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		/* binding Blade PK values */
+		var = find_blade_pk_value (row, icol2);
+		if (var == NULL)
+		    return 0;
+		icol2++;
+		switch (var->type)
+		  {
+		      /* Blade Primary Key Column(s) */
+		  case SQLITE_INTEGER:
+		      sqlite3_bind_int64 (stmt_out, icol, var->value.intValue);
+		      break;
+		  case SQLITE_FLOAT:
+		      sqlite3_bind_double (stmt_out, icol,
+					   var->value.doubleValue);
+		      break;
+		  case SQLITE_TEXT:
+		      sqlite3_bind_text (stmt_out, icol,
+					 var->value.textValue,
+					 strlen (var->value.textValue),
+					 SQLITE_STATIC);
+		      break;
+		  default:
+		      sqlite3_bind_null (stmt_out, icol);
+		      break;
+		  };
+		icol++;
+	    }
+	  col = col->next;
+      }
+    /* binding NULL geometry */
+    sqlite3_bind_null (stmt_out, icol);
+    ret = sqlite3_step (stmt_out);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	return 1;
+
+    /* some error occurred */
+    do_update_sql_error (message, "INSERT INTO TEMPORARY POLYGONS",
+			 sqlite3_errmsg (handle));
+    return 0;
+}
+
+static int
+do_populate_temp_polygons (struct output_table *tbl, sqlite3 * handle,
+			   const void *cache, const char *input_db_prefix,
+			   const char *input_table, const char *input_geom,
+			   const char *blade_db_prefix, const char *blade_table,
+			   const char *blade_geom,
+			   const char *spatial_index_prefix,
+			   const char *spatial_index, const char *tmp_table,
+			   int type, char **message)
+{
+/* populating the temporary helper table - POLYGONs */
+    int ret;
+    sqlite3_stmt *stmt_main = NULL;
+    sqlite3_stmt *stmt_input = NULL;
+    sqlite3_stmt *stmt_blade = NULL;
+    sqlite3_stmt *stmt_tmp = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+    int cast2d = 0;
+    int cast3d = 0;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    switch (type)
+      {
+      case GAIA_POLYGONM:
+      case GAIA_MULTIPOLYGONM:
+	  cast2d = 1;
+	  break;
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGONZM:
+	  cast3d = 1;
+	  break;
+      };
+
+/* composing the SQL statement - main SELECT query */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, i.\"%s\"", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s i.\"%s\"", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		sql = sqlite3_mprintf ("%s, b.\"%s\"", prev, xcolumn);
+		free (xcolumn);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql = sqlite3_mprintf ("%s FROM \"%s\".\"%s\" AS i", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS b ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    sql = sqlite3_mprintf ("%sb.ROWID IN (SELECT pkid FROM ", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (spatial_index_prefix);
+    xtable = gaiaDoubleQuotedSql (spatial_index);
+    sql = sqlite3_mprintf ("%s \"%s\".\"%s\" WHERE", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xcolumn = gaiaDoubleQuotedSql (input_geom);
+    sql =
+	sqlite3_mprintf
+	("%s xmin <= MbrMaxX(i.\"%s\") AND xmax >= MbrMinX(i.\"%s\") ", prev,
+	 xcolumn, xcolumn);
+    sqlite3_free (prev);
+    prev = sql;
+    sql =
+	sqlite3_mprintf
+	("%s AND ymin <= MbrMaxY(i.\"%s\") AND ymax >= MbrMinY(i.\"%s\")))",
+	 prev, xcolumn, xcolumn);
+    free (xcolumn);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - main SELECT query */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_main, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "QUERYING POLYGON INTERSECTIONS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - SELECT geometry FROM Input */
+    xcolumn = gaiaDoubleQuotedSql (input_geom);
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\" WHERE", xcolumn,
+			 xprefix, xtable);
+    free (xcolumn);
+    free (xprefix);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s AND \"%s\" = ?", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" = ?", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT geometry FROM Input */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_input, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT GEOMETRY FROM INPUT",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - SELECT geometry FROM Blade */
+    xcolumn = gaiaDoubleQuotedSql (blade_geom);
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\" WHERE", xcolumn,
+			 xprefix, xtable);
+    free (xcolumn);
+    free (xprefix);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s AND \"%s\" = ?", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\" = ?", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT geometry FROM Blade */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_blade, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT GEOMETRY FROM BLADE",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* creating a Prepared Statement - Inserting into TMP */
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("INSERT INTO TEMP.\"%s\" VALUES (", xtable);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, ?", prev);
+		else
+		    sql = sqlite3_mprintf ("%s?", prev);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the n_geom column */
+    sql = sqlite3_mprintf ("%s, ?", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the geom columns */
+    if (cast2d)
+	sql = sqlite3_mprintf ("%s, CastToXY(?))", prev);
+    else if (cast3d)
+	sql = sqlite3_mprintf ("%s, CastToXYZ(?))", prev);
+    else
+	sql = sqlite3_mprintf ("%s, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - INSERT INTO TMP POLYGONS */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_tmp, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO TMP POLYGONS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - checking matching Input/Blade pairs */
+	  ret = sqlite3_step (stmt_main);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		gaiaGeomCollPtr input_g = NULL;
+		gaiaGeomCollPtr blade_g = NULL;
+		gaiaPolygonPtr pg;
+		int n_geom = 0;
+		unsigned char *input_blob;
+		unsigned char *blade_blob;
+		int input_blob_sz;
+		int blade_blob_sz;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_main, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_main, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_main, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_main, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_main, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_main, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_main, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_main, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+
+		/* reading the Input Geometry */
+		input_g =
+		    do_read_input_geometry (tbl, cache, stmt_input, handle,
+					    &row, message, &input_blob,
+					    &input_blob_sz);
+		if (input_g == NULL)
+		    goto error;
+
+		if (is_null_blade (&row))
+		  {
+		      /* Input doesn't matches any Blade */
+		      if (!do_insert_temporary_polygons
+			  (tbl, handle, cache, stmt_tmp, &row, input_g,
+			   message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    goto error;
+			}
+		      goto skip;
+		  }
+
+		/* reading the Blade Geometry */
+		blade_g =
+		    do_read_blade_geometry (tbl, cache, stmt_blade, handle,
+					    &row, message, &blade_blob,
+					    &blade_blob_sz);
+		if (blade_g == NULL)
+		    goto error;
+
+		if (is_covered_by
+		    (cache, input_g, input_blob, input_blob_sz, blade_g,
+		     blade_blob, blade_blob_sz))
+		  {
+		      /* Input is completely Covered By Blade */
+		      if (!do_insert_temporary_polygons
+			  (tbl, handle, cache, stmt_tmp, &row, input_g,
+			   message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    gaiaFreeGeomColl (blade_g);
+			    goto error;
+			}
+		      goto skip;
+		  }
+
+		if (is_covered_by
+		    (cache, blade_g, blade_blob, blade_blob_sz, input_g,
+		     input_blob, input_blob_sz))
+		  {
+		      /* Blade is completely Covered By Input */
+		      gaiaGeomCollPtr g =
+			  gaiaGeometryIntersection_r (cache, input_g, blade_g);
+		      if (!do_insert_temporary_polygons
+			  (tbl, handle, cache, stmt_tmp, &row, g, message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    gaiaFreeGeomColl (blade_g);
+			    gaiaFreeGeomColl (g);
+			    goto error;
+			}
+		      gaiaFreeGeomColl (g);
+		      goto skip;
+		  }
+
+		pg = input_g->FirstPolygon;
+		while (pg != NULL)
+		  {
+		      unsigned char *pg_blob;
+		      int pg_blob_sz;
+		      gaiaGeomCollPtr pg_geom =
+			  do_prepare_polygon (pg, input_g->Srid);
+		      gaiaToSpatiaLiteBlobWkbEx (pg_geom, &pg_blob, &pg_blob_sz,
+						 gpkg_mode);
+		      n_geom++;
+		      if (gaiaGeomCollPreparedIntersects
+			  (cache, pg_geom, pg_blob, pg_blob_sz, blade_g,
+			   blade_blob, blade_blob_sz))
+			{
+			    /* saving an Input/Blade intersection */
+			    if (!do_insert_temporary_polygon_intersection
+				(tbl, handle, stmt_tmp, &row, n_geom, message))
+			      {
+				  reset_temporary_row (&row);
+				  gaiaFreeGeomColl (input_g);
+				  gaiaFreeGeomColl (blade_g);
+				  gaiaFreeGeomColl (pg_geom);
+				  free (pg_blob);
+				  goto error;
+			      }
+			}
+		      free (pg_blob);
+		      gaiaFreeGeomColl (pg_geom);
+		      pg = pg->Next;
+		  }
+
+	      skip:
+		reset_temporary_row (&row);
+		gaiaFreeGeomColl (input_g);
+		gaiaFreeGeomColl (blade_g);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: MAIN POLYGONS LOOP",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_main);
+    sqlite3_finalize (stmt_input);
+    sqlite3_finalize (stmt_blade);
+    sqlite3_finalize (stmt_tmp);
+    return 1;
+
+  error:
+    if (stmt_main == NULL)
+	sqlite3_finalize (stmt_main);
+    if (stmt_input == NULL)
+	sqlite3_finalize (stmt_input);
+    if (stmt_blade == NULL)
+	sqlite3_finalize (stmt_blade);
+    if (stmt_tmp == NULL)
+	sqlite3_finalize (stmt_tmp);
+    return 0;
+}
+
+static int
+do_update_tmp_cut_polygon (sqlite3 * handle, sqlite3_stmt * stmt_upd,
+			   sqlite3_int64 pk, const unsigned char *blob,
+			   int blob_sz, char **message)
+{
+/* saving an Input Polygon cut against a renoded Blade */
+    int ret;
+
+    sqlite3_reset (stmt_upd);
+    sqlite3_clear_bindings (stmt_upd);
+/* binding the cut Input geometry */
+    sqlite3_bind_blob (stmt_upd, 1, blob, blob_sz, free);
+    sqlite3_bind_int64 (stmt_upd, 2, pk);
+    /* updating the TMP table */
+    ret = sqlite3_step (stmt_upd);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	return 1;
+
+    /* some error occurred */
+    do_update_sql_error (message,
+			 "step: UPDATE TMP SET cut-Polygon",
+			 sqlite3_errmsg (handle));
+    return 0;
+}
+
+static int
+do_cut_tmp_polygons (sqlite3 * handle, const void *cache,
+		     sqlite3_stmt * stmt_in, sqlite3_stmt * stmt_upd,
+		     struct temporary_row *row, char **message,
+		     const unsigned char *blade_blob, int blade_blob_sz)
+{
+/* cutting all Input Polygons intersecting the renoded Blade */
+    int ret;
+    struct multivar *var;
+    int icol = 1;
+    gaiaGeomCollPtr blade_g;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+	  gpkg_mode = pcache->gpkg_mode;
+      }
+
+    blade_g = gaiaFromSpatiaLiteBlobWkbEx (blade_blob, blade_blob_sz,
+					   gpkg_mode, gpkg_amphibious);
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    var = row->first_blade;
+    while (var != NULL)
+      {
+	  /* binding Primary Key values (from Blade) */
+	  switch (var->type)
+	    {
+	    case SQLITE_INTEGER:
+		sqlite3_bind_int64 (stmt_in, icol, var->value.intValue);
+		break;
+	    case SQLITE_FLOAT:
+		sqlite3_bind_double (stmt_in, icol, var->value.doubleValue);
+		break;
+	    case SQLITE_TEXT:
+		sqlite3_bind_text (stmt_in, icol,
+				   var->value.textValue,
+				   strlen (var->value.textValue),
+				   SQLITE_STATIC);
+		break;
+	    default:
+		sqlite3_bind_null (stmt_in, icol);
+		break;
+	    };
+	  icol++;
+	  var = var->next;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - cut Polygons */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		sqlite3_int64 pk = 0;
+		unsigned char *blob = NULL;
+		int blob_sz;
+		gaiaGeomCollPtr input_g;
+		gaiaGeomCollPtr result;
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER
+		    && sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
+		  {
+		      pk = sqlite3_column_int64 (stmt_in, 0);
+		      blob = (unsigned char *) sqlite3_column_blob (stmt_in, 1);
+		      blob_sz = sqlite3_column_bytes (stmt_in, 1);
+		      input_g = gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+							     gpkg_mode,
+							     gpkg_amphibious);
+		      result =
+			  gaiaGeometryIntersection_r (cache, input_g, blade_g);
+		      if (result != NULL)
+			{
+			    gaiaToSpatiaLiteBlobWkbEx (result, &blob, &blob_sz,
+						       gpkg_mode);
+			    gaiaFreeGeomColl (result);
+			}
+		      gaiaFreeGeomColl (input_g);
+		  }
+		if (blob != NULL)
+		  {
+		      if (!do_update_tmp_cut_polygon
+			  (handle, stmt_upd, pk, blob, blob_sz, message))
+			  goto error;
+		  }
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: cut Polygons",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+    gaiaFreeGeomColl (blade_g);
+    return 1;
+
+  error:
+    gaiaFreeGeomColl (blade_g);
+    return 0;
+}
+
+static int
+do_split_polygons (struct output_table *tbl, sqlite3 * handle,
+		   const void *cache, const char *input_db_prefix,
+		   const char *input_table, const char *input_geom,
+		   const char *blade_db_prefix, const char *blade_table,
+		   const char *blade_geom, const char *tmp_table,
+		   char **message)
+{
+/* cutting all Input Polygons intersecting some Blade */
+    int ret;
+    sqlite3_stmt *stmt_blades = NULL;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_upd = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+
+/* composing the SQL statement - SELECT FROM Blades */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, t.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s t.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xcolumn1 = gaiaDoubleQuotedSql (blade_geom);
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql =
+	sqlite3_mprintf
+	("%s, b.\"%s\" FROM TEMP.\"%s\" AS t", prev, xcolumn1, xtable);
+    free (xcolumn1);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (blade_db_prefix);
+    xtable = gaiaDoubleQuotedSql (blade_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS b ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND b.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s b.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("%s) WHERE t.\"%s\" IS NULL GROUP BY", prev, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, t.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s t.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT FROM Blades */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_blades, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM BLADES",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - SELECT Input */
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    xprefix = sqlite3_mprintf ("%s_n_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT t.ROWID, ST_GeometryN(i.\"%s\", t.\"%s\") FROM TEMP.\"%s\" AS t",
+	 xcolumn1, xcolumn2, xtable);
+    free (xcolumn1);
+    free (xcolumn2);
+    free (xtable);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS i ON (", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql = sqlite3_mprintf ("%s) WHERE t.\"%s\" IS NULL", prev, xcolumn1);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s AND t.\"%s\" = ?", prev, xcolumn1);
+		free (xcolumn1);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT Input */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT INPUT FROM TMP",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - UPDATE tmp SET cut-Geom */
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("UPDATE TEMP.\"%s\" SET \"%s\" = ? WHERE ROWID = ?",
+			 xtable, xcolumn1);
+    free (xcolumn1);
+    free (xtable);
+
+/* creating a Prepared Statement - UPDATE tmp SET cut-Geom */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_upd, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "UPDATE TMP cut-Geometries",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - renoded Blades */
+	  ret = sqlite3_step (stmt_blades);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_blades, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_blades, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_blades, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_blades, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the Blade */
+		if (sqlite3_column_type (stmt_blades, icol) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_blades, icol);
+		      int blob_sz = sqlite3_column_bytes (stmt_blades, icol);
+		      /* cutting all Input geoms intersecting the Blade */
+		      if (!do_cut_tmp_polygons
+			  (handle, cache, stmt_in, stmt_upd, &row, message,
+			   blob, blob_sz))
+			{
+			    reset_temporary_row (&row);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      do_update_message (message, "Unexpected NULL Blade\n");
+		      reset_temporary_row (&row);
+		      goto error;
+		  }
+
+		reset_temporary_row (&row);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: BLADES", sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_blades);
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_upd);
+    return 1;
+
+  error:
+    if (stmt_blades != NULL)
+	sqlite3_finalize (stmt_blades);
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_upd != NULL)
+	sqlite3_finalize (stmt_upd);
+    return 0;
+}
+
+static gaiaGeomCollPtr
+do_compute_diff_polygs (const void *cache, sqlite3_stmt * stmt_diff,
+			gaiaPolygonPtr input_pg, int srid,
+			gaiaGeomCollPtr union_g)
+{
+/* computing the difference between two Polygons */
+    int ret;
+    gaiaGeomCollPtr input_g;
+    gaiaGeomCollPtr result = NULL;
+    unsigned char *input_blob = NULL;
+    int input_blob_sz;
+    unsigned char *union_blob = NULL;
+    int union_blob_sz;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    sqlite3_reset (stmt_diff);
+    sqlite3_clear_bindings (stmt_diff);
+    input_g = do_prepare_polygon (input_pg, srid);
+    gaiaToSpatiaLiteBlobWkbEx (input_g, &input_blob, &input_blob_sz, gpkg_mode);
+    gaiaFreeGeomColl (input_g);
+    gaiaToSpatiaLiteBlobWkbEx (union_g, &union_blob, &union_blob_sz, gpkg_mode);
+    sqlite3_bind_blob (stmt_diff, 1, input_blob, input_blob_sz, SQLITE_STATIC);
+    sqlite3_bind_blob (stmt_diff, 2, union_blob, union_blob_sz, SQLITE_STATIC);
+    sqlite3_bind_blob (stmt_diff, 3, union_blob, union_blob_sz, SQLITE_STATIC);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_diff);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		if (sqlite3_column_type (stmt_diff, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_diff, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt_diff, 0);
+		      result =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+	    }
+      }
+
+    free (input_blob);
+    free (union_blob);
+    return result;
+}
+
+static int
+do_get_uncovered_polygons (struct output_table *tbl, sqlite3 * handle,
+			   const void *cache, const char *input_db_prefix,
+			   const char *input_table, const char *input_geom,
+			   const char *tmp_table, int type, char **message)
+{
+/* recovering all Input portions not covered by any Blade */
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    sqlite3_stmt *stmt_diff = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+    int cast2d = 0;
+    int cast3d = 0;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    switch (type)
+      {
+      case GAIA_POLYGONM:
+      case GAIA_MULTIPOLYGONM:
+	  cast2d = 1;
+	  break;
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGONZM:
+	  cast3d = 1;
+	  break;
+      };
+
+/* composing the SQL statement - union of all already assigned portions */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, i.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s i.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("%s, i.\"%s\", ST_UnaryUnion(ST_Collect(t.\"%s\")) ",
+			 prev, xcolumn1, xcolumn2);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    xcolumn1 = gaiaDoubleQuotedSql (tmp_table);
+    sql =
+	sqlite3_mprintf
+	("%s FROM \"%s\".\"%s\" AS i LEFT JOIN TEMP.\"%s\" AS t ON (", prev,
+	 xprefix, xtable, xcolumn1);
+    free (xprefix);
+    free (xtable);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s) GROUP BY", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, i.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s i.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT FROM TMP */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM TMP Union-Geometries",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the Prepared Statement - Inserting into TMP */
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("INSERT INTO TEMP.\"%s\" VALUES (", xtable);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, ?", prev);
+		else
+		    sql = sqlite3_mprintf ("%s?", prev);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the n_geom column */
+    sql = sqlite3_mprintf ("%s, ?", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the geom columns */
+    if (cast2d)
+	sql = sqlite3_mprintf ("%s, CastToXY(?))", prev);
+    else if (cast3d)
+	sql = sqlite3_mprintf ("%s, CastToXYZ(?))", prev);
+    else
+	sql = sqlite3_mprintf ("%s, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - INSERT INTO TMP POLYGONS */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_out, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO TMP POLYGONS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the Prepared Statement - polygons difference */
+    sql =
+	sqlite3_mprintf ("SELECT ST_Difference(ST_Snap(?, ?, 0.000000001), ?)");
+
+/* creating a Prepared Statement - polygons difference */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_diff, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "POLYGONS DIFFERENCE",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - from Temporary Helper */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		gaiaGeomCollPtr input_g = NULL;
+		gaiaGeomCollPtr union_g = NULL;
+		const unsigned char *blob;
+		int blob_sz;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_in, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_in, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_in, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_in, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    add_null_pk_value (&row, 'B', icol2);
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the "geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_BLOB)
+		  {
+		      blob = sqlite3_column_blob (stmt_in, icol);
+		      blob_sz = sqlite3_column_bytes (stmt_in, icol);
+		      input_g =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+		icol++;
+		/* fetching the "union_geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_BLOB)
+		  {
+		      blob = sqlite3_column_blob (stmt_in, icol);
+		      blob_sz = sqlite3_column_bytes (stmt_in, icol);
+		      union_g =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+		if (union_g == NULL)
+		  {
+		      /* fully uncovered Input Geometry */
+		      if (!do_insert_temporary_polygons
+			  (tbl, handle, cache, stmt_out, &row, input_g,
+			   message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      /* partialy uncovered Input Geometry */
+		      int n_geom = 0;
+		      gaiaPolygonPtr pg = input_g->FirstPolygon;
+		      while (pg != NULL)
+			{
+			    gaiaGeomCollPtr diff_g =
+				do_compute_diff_polygs (cache, stmt_diff, pg,
+							input_g->Srid,
+							union_g);
+			    n_geom++;
+			    if (diff_g != NULL)
+			      {
+				  if (!do_insert_temporary_polygons
+				      (tbl, handle, cache, stmt_out, &row,
+				       diff_g, message, n_geom))
+				    {
+					reset_temporary_row (&row);
+					gaiaFreeGeomColl (input_g);
+					gaiaFreeGeomColl (union_g);
+					gaiaFreeGeomColl (diff_g);
+					goto error;
+				    }
+				  gaiaFreeGeomColl (diff_g);
+			      }
+			    pg = pg->Next;
+			}
+		  }
+
+		reset_temporary_row (&row);
+		gaiaFreeGeomColl (input_g);
+		gaiaFreeGeomColl (union_g);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT FROM TEMPORARY POLIGONS",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    sqlite3_finalize (stmt_diff);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    if (stmt_diff != NULL)
+	sqlite3_finalize (stmt_diff);
+    return 0;
+}
+
+static int
+do_insert_output_polygons (struct output_table *tbl, sqlite3 * handle,
+			   const void *cache, const char *out_table,
+			   const char *tmp_table, char **message)
+{
+/* populating the output table */
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+    struct temporary_row prev_row;
+    int prev_ngeom;
+    int prog_res;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    prev_row.first_input = NULL;
+    prev_row.last_input = NULL;
+    prev_row.first_blade = NULL;
+    prev_row.last_blade = NULL;
+
+/* composing the SQL statement - SELECT FROM TMP */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_n_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql =
+	sqlite3_mprintf ("%s, \"%s\", \"%s\" FROM TEMP.\"%s\" ORDER BY", prev,
+			 xcolumn1, xcolumn2, xtable);
+    free (xtable);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_n_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("%s, \"%s\", MbrMinY(\"%s\") DESC, MbrMinX(\"%s\")",
+			 prev, xcolumn1, xcolumn2, xcolumn2);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+
+/* creating a Prepared Statement - SELECT FROM TMP */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM TMP cut-Geometries",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - INSERT INTO Output */
+    xtable = gaiaDoubleQuotedSql (out_table);
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" VALUES(NULL", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		free (xcolumn1);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s, ?, ?, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - INSERT INTO OUTPUT */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_out, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO OUTPUT POLYGONS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - from Temporary Helper */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		int n_geom = 0;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_in, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_in, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_in, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_in, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_in, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_in, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_in, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_in, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the "n_geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_INTEGER)
+		    n_geom = sqlite3_column_int (stmt_in, icol);
+		icol++;
+		if (check_same_input (&prev_row, &row) && n_geom == prev_ngeom)
+		    ;
+		else
+		    prog_res = 1;
+		prev_ngeom = n_geom;
+		copy_input_values (&row, &prev_row);
+		/* fetching the "geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_BLOB)
+		  {
+		      gaiaGeomCollPtr geom;
+		      gaiaPolygonPtr pg;
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_in, icol);
+		      int blob_sz = sqlite3_column_bytes (stmt_in, icol);
+		      geom =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+
+		      pg = geom->FirstPolygon;
+		      while (pg)
+			{
+			    do_insert_output_row
+				(tbl, cache, stmt_out, handle, &row, n_geom,
+				 prog_res++, GAIA_CUTTER_POLYGON, pg,
+				 geom->Srid, message);
+			    pg = pg->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+		reset_temporary_row (&row);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT FROM TEMPORARY POLYGONS",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    reset_temporary_row (&prev_row);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    reset_temporary_row (&prev_row);
+    return 0;
+}
+
+static gaiaGeomCollPtr
+do_compute_diff_lines (const void *cache, sqlite3_stmt * stmt_diff,
+		       gaiaLinestringPtr input_ln, int srid,
+		       gaiaGeomCollPtr union_g)
+{
+/* computing the difference between two Linestrings */
+    int ret;
+    gaiaGeomCollPtr input_g;
+    gaiaGeomCollPtr result = NULL;
+    unsigned char *input_blob = NULL;
+    int input_blob_sz;
+    unsigned char *union_blob = NULL;
+    int union_blob_sz;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    sqlite3_reset (stmt_diff);
+    sqlite3_clear_bindings (stmt_diff);
+    input_g = do_prepare_linestring (input_ln, srid);
+    gaiaToSpatiaLiteBlobWkbEx (input_g, &input_blob, &input_blob_sz, gpkg_mode);
+    gaiaFreeGeomColl (input_g);
+    gaiaToSpatiaLiteBlobWkbEx (union_g, &union_blob, &union_blob_sz, gpkg_mode);
+    sqlite3_bind_blob (stmt_diff, 1, input_blob, input_blob_sz, SQLITE_STATIC);
+    sqlite3_bind_blob (stmt_diff, 2, union_blob, union_blob_sz, SQLITE_STATIC);
+    sqlite3_bind_blob (stmt_diff, 3, union_blob, union_blob_sz, SQLITE_STATIC);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_diff);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		if (sqlite3_column_type (stmt_diff, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_diff, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt_diff, 0);
+		      result =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+	    }
+      }
+
+    free (input_blob);
+    free (union_blob);
+    return result;
+}
+
+static int
+do_get_uncovered_linestrings (struct output_table *tbl, sqlite3 * handle,
+			      const void *cache, const char *input_db_prefix,
+			      const char *input_table, const char *input_geom,
+			      const char *tmp_table, int type, char **message)
+{
+/* recovering all Input portions not covered by any Blade */
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    sqlite3_stmt *stmt_diff = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+    int cast2d = 0;
+    int cast3d = 0;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    switch (type)
+      {
+      case GAIA_LINESTRINGM:
+      case GAIA_MULTILINESTRINGM:
+	  cast2d = 1;
+	  break;
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRINGZM:
+	  cast3d = 1;
+	  break;
+      };
+
+/* composing the SQL statement - union of all already assigned portions */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, i.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s i.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xcolumn1 = gaiaDoubleQuotedSql (input_geom);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    sql =
+	sqlite3_mprintf ("%s, i.\"%s\", ST_UnaryUnion(ST_Collect(t.\"%s\")) ",
+			 prev, xcolumn1, xcolumn2);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    xcolumn1 = gaiaDoubleQuotedSql (tmp_table);
+    sql =
+	sqlite3_mprintf
+	("%s FROM \"%s\".\"%s\" AS i LEFT JOIN TEMP.\"%s\" AS t ON (", prev,
+	 xprefix, xtable, xcolumn1);
+    free (xprefix);
+    free (xtable);
+    free (xcolumn1);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s i.\"%s\" = t.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s) GROUP BY", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, i.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s i.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+
+/* creating a Prepared Statement - SELECT FROM TMP */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM TMP Union-Geometries",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the Prepared Statement - Inserting into TMP */
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("INSERT INTO TEMP.\"%s\" VALUES (", xtable);
+    free (xtable);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, ?", prev);
+		else
+		    sql = sqlite3_mprintf ("%s?", prev);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the n_geom column */
+    sql = sqlite3_mprintf ("%s, ?", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+/* adding the geom columns */
+    if (cast2d)
+	sql = sqlite3_mprintf ("%s, ?, CastToXY(?))", prev);
+    else if (cast3d)
+	sql = sqlite3_mprintf ("%s, ?, CastToXYZ(?))", prev);
+    else
+	sql = sqlite3_mprintf ("%s, ?, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - INSERT INTO TMP LINESTRINGS */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_out, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO TMP LINESTRINGS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the Prepared Statement - linestrings difference */
+    sql =
+	sqlite3_mprintf ("SELECT ST_Difference(ST_Snap(?, ?, 0.000000001), ?)");
+
+/* creating a Prepared Statement - linestrings difference */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_diff, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "LINESTRINGS DIFFERENCE",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - from Temporary Helper */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		gaiaGeomCollPtr input_g = NULL;
+		gaiaGeomCollPtr union_g = NULL;
+		const unsigned char *blob;
+		int blob_sz;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_in, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_in, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_in, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_in, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    add_null_pk_value (&row, 'B', icol2);
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the "geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_BLOB)
+		  {
+		      blob = sqlite3_column_blob (stmt_in, icol);
+		      blob_sz = sqlite3_column_bytes (stmt_in, icol);
+		      input_g =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+		icol++;
+		/* fetching the "union_geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_BLOB)
+		  {
+		      blob = sqlite3_column_blob (stmt_in, icol);
+		      blob_sz = sqlite3_column_bytes (stmt_in, icol);
+		      union_g =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+		  }
+		if (union_g == NULL)
+		  {
+		      /* fully uncovered Input Geometry */
+		      if (!do_insert_temporary_linestrings
+			  (tbl, handle, cache, stmt_out, &row, input_g,
+			   message, -1))
+			{
+			    reset_temporary_row (&row);
+			    gaiaFreeGeomColl (input_g);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      /* partialy uncovered Input Geometry */
+		      int n_geom = 0;
+		      gaiaLinestringPtr ln = input_g->FirstLinestring;
+		      while (ln != NULL)
+			{
+			    gaiaGeomCollPtr diff_g =
+				do_compute_diff_lines (cache, stmt_diff, ln,
+						       input_g->Srid,
+						       union_g);
+			    n_geom++;
+			    if (diff_g != NULL)
+			      {
+				  if (!do_insert_temporary_linestrings
+				      (tbl, handle, cache, stmt_out, &row,
+				       diff_g, message, n_geom))
+				    {
+					reset_temporary_row (&row);
+					gaiaFreeGeomColl (input_g);
+					gaiaFreeGeomColl (union_g);
+					gaiaFreeGeomColl (diff_g);
+					goto error;
+				    }
+				  gaiaFreeGeomColl (diff_g);
+			      }
+			    ln = ln->Next;
+			}
+		  }
+
+		reset_temporary_row (&row);
+		gaiaFreeGeomColl (input_g);
+		gaiaFreeGeomColl (union_g);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT FROM TEMPORARY LINESTRINGS",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    sqlite3_finalize (stmt_diff);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    if (stmt_diff != NULL)
+	sqlite3_finalize (stmt_diff);
+    return 0;
+}
+
+static int
+do_insert_output_linestrings (struct output_table *tbl, sqlite3 * handle,
+			      const void *cache, const char *input_db_prefix,
+			      const char *input_table, const char *input_geom,
+			      const char *out_table, const char *tmp_table,
+			      char **message)
+{
+/* populating the output table */
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn1;
+    char *xcolumn2;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+    int gpkg_mode = 0;
+    int gpkg_amphibious = 0;
+    struct temporary_row prev_row;
+    int prev_ngeom;
+    int prog_res;
+
+    if (cache != NULL)
+      {
+	  struct splite_internal_cache *pcache =
+	      (struct splite_internal_cache *) cache;
+	  gpkg_mode = pcache->gpkg_mode;
+	  gpkg_amphibious = pcache->gpkg_amphibious_mode;
+      }
+
+    prev_row.first_input = NULL;
+    prev_row.last_input = NULL;
+    prev_row.first_blade = NULL;
+    prev_row.last_blade = NULL;
+
+/* composing the SQL statement - SELECT FROM TMP */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, t.\"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s t.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s, t.\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_n_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql =
+	sqlite3_mprintf ("%s, t.\"%s\", t.\"%s\" FROM TEMP.\"%s\" AS t", prev,
+			 xcolumn1, xcolumn2, xtable);
+    free (xtable);
+    free (xcolumn1);
+    free (xcolumn2);
+    sqlite3_free (prev);
+    prev = sql;
+    xprefix = gaiaDoubleQuotedSql (input_db_prefix);
+    xtable = gaiaDoubleQuotedSql (input_table);
+    sql =
+	sqlite3_mprintf ("%s JOIN \"%s\".\"%s\" AS i ON(", prev, xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		xcolumn2 = gaiaDoubleQuotedSql (col->base_name);
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s AND t.\"%s\" = i.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		else
+		    sql =
+			sqlite3_mprintf ("%s t.\"%s\" = i.\"%s\"", prev,
+					 xcolumn1, xcolumn2);
+		free (xcolumn1);
+		free (xcolumn2);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s) ORDER BY", prev);
+    sqlite3_free (prev);
+    prev = sql;
+    comma = 0;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn1);
+		else
+		    sql = sqlite3_mprintf ("%s\"%s\"", prev, xcolumn1);
+		free (xcolumn1);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xprefix = sqlite3_mprintf ("%s_n_geom", tmp_table);
+    xcolumn1 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xprefix = sqlite3_mprintf ("%s_geom", tmp_table);
+    xcolumn2 = gaiaDoubleQuotedSql (xprefix);
+    sqlite3_free (xprefix);
+    xprefix = gaiaDoubleQuotedSql (input_geom);
+    sql =
+	sqlite3_mprintf
+	("%s, \"%s\", ST_Line_Locate_Point(i.\"%s\", ST_StartPoint(ST_GeometryN(t.\"%s\", t.\"%s\")))",
+	 prev, xcolumn1, xprefix, xcolumn2, xcolumn1);
+    free (xcolumn1);
+    free (xcolumn2);
+    free (xprefix);
+    sqlite3_free (prev);
+    prev = sql;
+
+/* creating a Prepared Statement - SELECT FROM TMP */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM TMP cut-Geometries",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* composing the SQL statement - INSERT INTO Output */
+    xtable = gaiaDoubleQuotedSql (out_table);
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" VALUES(NULL", xtable);
+    free (xtable);
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn1 = gaiaDoubleQuotedSql (col->real_name);
+		sql = sqlite3_mprintf ("%s, ?", prev);
+		free (xcolumn1);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    sql = sqlite3_mprintf ("%s, ?, ?, ?)", prev);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - INSERT INTO OUTPUT */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_out, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "INSERT INTO OUTPUT LINESTRINGS",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows - from Temporary Helper */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		int n_geom = 0;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_in, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_in, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_in, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_in, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_in, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_in, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_in, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_in, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the "n_geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_INTEGER)
+		    n_geom = sqlite3_column_int (stmt_in, icol);
+		icol++;
+		if (check_same_input (&prev_row, &row) && n_geom == prev_ngeom)
+		    ;
+		else
+		    prog_res = 1;
+		prev_ngeom = n_geom;
+		copy_input_values (&row, &prev_row);
+		/* fetching the "geom" column value */
+		if (sqlite3_column_type (stmt_in, icol) == SQLITE_BLOB)
+		  {
+		      gaiaGeomCollPtr geom;
+		      gaiaLinestringPtr ln;
+		      const unsigned char *blob =
+			  sqlite3_column_blob (stmt_in, icol);
+		      int blob_sz = sqlite3_column_bytes (stmt_in, icol);
+		      geom =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz,
+						       gpkg_mode,
+						       gpkg_amphibious);
+
+		      ln = geom->FirstLinestring;
+		      while (ln)
+			{
+			    do_insert_output_row
+				(tbl, cache, stmt_out, handle, &row, n_geom,
+				 prog_res++, GAIA_CUTTER_LINESTRING, ln,
+				 geom->Srid, message);
+			    ln = ln->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+		reset_temporary_row (&row);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT FROM TEMPORARY LINESTRINGS",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    reset_temporary_row (&prev_row);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    reset_temporary_row (&prev_row);
+    return 0;
+}
+
+static int
+do_insert_output_points (struct output_table *tbl, sqlite3 * handle,
+			 const void *cache, const char *input_db_prefix,
+			 const char *input_table, const char *input_geom,
+			 const char *out_table, const char *tmp_table,
+			 char **message)
+{
+/* populating the Output table - POINTs */
+    sqlite3_stmt *stmt_tmp = NULL;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    int ret;
+    char *xtable;
+    char *xcolumn;
+    char *sql;
+    char *prev;
+    struct output_column *col;
+    int comma = 0;
+
+/* composing the SQL statement - SELECT FROM Tempory Helper */
+    sql = sqlite3_mprintf ("SELECT");
+    prev = sql;
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Input Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_INPUT_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\"", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    col = tbl->first;
+    while (col != NULL)
+      {
+	  /* Blade Primary Key Column(s) */
+	  if (col->role == GAIA_CUTTER_BLADE_PK)
+	    {
+		xcolumn = gaiaDoubleQuotedSql (col->real_name);
+		if (comma)
+		    sql = sqlite3_mprintf ("%s, \"%s\"", prev, xcolumn);
+		else
+		    sql = sqlite3_mprintf ("%s \"%s\"", prev, xcolumn);
+		free (xcolumn);
+		comma = 1;
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+	  col = col->next;
+      }
+    xtable = gaiaDoubleQuotedSql (tmp_table);
+    sql = sqlite3_mprintf ("%s, touches FROM TEMP.\"%s\"", prev, xtable);
+    free (xtable);
+    sqlite3_free (prev);
+
+/* creating a Prepared Statement - SELECT FROM Temporary Table */
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt_tmp, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "SELECT FROM TMP POINTs",
+			       sqlite3_errmsg (handle));
+	  goto error;
+      }
+
+/* creating a Prepared Statement - SELECT Geometry FROM Input */
+    if (!do_create_input_statement
+	(tbl, handle, input_db_prefix, input_table, input_geom, &stmt_in,
+	 message))
+	goto error;
+
+/* creating a Prepared Statement - INSERT INTO Output */
+    if (!do_create_output_statement
+	(tbl, handle, out_table, &stmt_out, message))
+	goto error;
+
+    while (1)
+      {
+	  /* scrolling the result set rows - from Temporary Helper */
+	  ret = sqlite3_step (stmt_tmp);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		/* fetched one row from the resultset */
+		struct temporary_row row;
+		int icol = 0;
+		int icol2 = 0;
+		int n_geom = 0;
+		int ok_touches = -1;
+		gaiaGeomCollPtr geom = NULL;
+		gaiaPointPtr pt;
+		unsigned char *input_blob;
+		int input_blob_sz;
+
+		row.first_input = NULL;
+		row.last_input = NULL;
+		row.first_blade = NULL;
+		row.last_blade = NULL;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Input Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_INPUT_PK)
+			{
+			    switch (sqlite3_column_type (stmt_tmp, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'I', icol2,
+						    sqlite3_column_int64
+						    (stmt_tmp, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'I', icol2,
+						       sqlite3_column_double
+						       (stmt_tmp, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'I', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_tmp, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'I', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		icol2 = 0;
+		col = tbl->first;
+		while (col != NULL)
+		  {
+		      /* Blade Primary Key Column(s) */
+		      if (col->role == GAIA_CUTTER_BLADE_PK)
+			{
+			    switch (sqlite3_column_type (stmt_tmp, icol))
+			      {
+			      case SQLITE_INTEGER:
+				  add_int_pk_value (&row, 'B', icol2,
+						    sqlite3_column_int64
+						    (stmt_tmp, icol));
+				  break;
+			      case SQLITE_FLOAT:
+				  add_double_pk_value (&row, 'B', icol2,
+						       sqlite3_column_double
+						       (stmt_tmp, icol));
+				  break;
+			      case SQLITE_TEXT:
+				  add_text_pk_value (&row, 'B', icol2,
+						     (const char *)
+						     sqlite3_column_text
+						     (stmt_tmp, icol));
+				  break;
+			      default:
+				  add_null_pk_value (&row, 'B', icol2);
+			      };
+			    icol++;
+			    icol2++;
+			}
+		      col = col->next;
+		  }
+		/* fetching the "Touches" column value */
+		if (sqlite3_column_type (stmt_tmp, icol) == SQLITE_INTEGER)
+		    ok_touches = sqlite3_column_int (stmt_tmp, icol);
+		if (ok_touches == 1)
+		    do_set_null_blade_columns (&row);
+
+		/* reading the Input Geometry */
+		geom =
+		    do_read_input_geometry (tbl, cache, stmt_in, handle, &row,
+					    message, &input_blob,
+					    &input_blob_sz);
+		if (geom == NULL)
+		    goto error;
+
+		n_geom = 0;
+		pt = geom->FirstPoint;
+		while (pt != NULL)
+		  {
+		      /* inserting the Output row(s) */
+		      n_geom++;
+		      if (!do_insert_output_row
+			  (tbl, cache, stmt_out, handle, &row, n_geom, 1,
+			   GAIA_CUTTER_POINT, pt, geom->Srid, message))
+			  goto error;
+		      pt = pt->Next;
+		  }
+		gaiaFreeGeomColl (geom);
+		reset_temporary_row (&row);
+	    }
+	  else
+	    {
+		do_update_sql_error (message,
+				     "step: SELECT FROM TEMPORARY POINTS",
+				     sqlite3_errmsg (handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_tmp);
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  error:
+    if (stmt_tmp != NULL)
+	sqlite3_finalize (stmt_tmp);
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+do_cut_points (struct output_table *tbl, sqlite3 * handle, const void *cache,
+	       const char *input_db_prefix, const char *input_table,
+	       const char *input_geom, const char *blade_db_prefix,
+	       const char *blade_table, const char *blade_geom,
+	       const char *spatial_index_prefix, const char *spatial_index,
+	       const char *out_table, char **tmp_table, int *drop_tmp_table,
+	       char **message)
+{
+/* cutting Input POINTs */
+    if (!do_prepare_temp_points
+	(tbl, handle, input_db_prefix, input_table, input_geom, blade_db_prefix,
+	 blade_table, blade_geom, spatial_index_prefix, spatial_index,
+	 tmp_table, message))
+	return 0;
+    if (!do_insert_output_points
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 out_table, *tmp_table, message))
+	return 0;
+
+    *drop_tmp_table = 1;
+    return 1;
+}
+
+static int
+do_cut_linestrings (struct output_table *tbl, sqlite3 * handle,
+		    const void *cache, const char *input_db_prefix,
+		    const char *input_table, const char *input_geom,
+		    const char *blade_db_prefix, const char *blade_table,
+		    const char *blade_geom, const char *spatial_index_prefix,
+		    const char *spatial_index, const char *out_table,
+		    char **tmp_table, int *drop_tmp_table, int type,
+		    char **message)
+{
+/* cutting Input LINESTRINGs */
+    if (!do_create_temp_linestrings (tbl, handle, tmp_table, message))
+	return 0;
+    if (!do_populate_temp_linestrings
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 blade_db_prefix, blade_table, blade_geom, spatial_index_prefix,
+	 spatial_index, *tmp_table, type, message))
+	return 0;
+    if (!do_split_linestrings
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 blade_db_prefix, blade_table, blade_geom, *tmp_table, message))
+	return 0;
+    if (!do_get_uncovered_linestrings
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 *tmp_table, type, message))
+	return 0;
+    if (!do_insert_output_linestrings
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 out_table, *tmp_table, message))
+	return 0;
+
+    *drop_tmp_table = 1;
+    return 1;
+}
+
+static int
+do_cut_polygons (struct output_table *tbl, sqlite3 * handle, const void *cache,
+		 const char *input_db_prefix, const char *input_table,
+		 const char *input_geom, const char *blade_db_prefix,
+		 const char *blade_table, const char *blade_geom,
+		 const char *spatial_index_prefix, const char *spatial_index,
+		 const char *out_table, char **tmp_table, int *drop_tmp_table,
+		 int type, char **message)
+{
+/* cutting Input POLYGONs */
+    if (!do_create_temp_polygons (tbl, handle, tmp_table, message))
+	return 0;
+    if (!do_populate_temp_polygons
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 blade_db_prefix, blade_table, blade_geom, spatial_index_prefix,
+	 spatial_index, *tmp_table, type, message))
+	return 0;
+    if (!do_split_polygons
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 blade_db_prefix, blade_table, blade_geom, *tmp_table, message))
+	return 0;
+    if (!do_get_uncovered_polygons
+	(tbl, handle, cache, input_db_prefix, input_table, input_geom,
+	 *tmp_table, type, message))
+	return 0;
+    if (!do_insert_output_polygons
+	(tbl, handle, cache, out_table, *tmp_table, message))
+	return 0;
+
+    *drop_tmp_table = 1;
+    return 1;
+}
+
+SPATIALITE_DECLARE int
+gaiaCutter (sqlite3 * handle, const void *cache, const char *xin_db_prefix,
+	    const char *input_table, const char *xinput_geom,
+	    const char *xblade_db_prefix, const char *blade_table,
+	    const char *xblade_geom, const char *out_table, int transaction,
+	    int ram_tmp_store, char **message)
+{
+/* main Cutter tool implementation */
+    const char *in_db_prefix = "MAIN";
+    const char *blade_db_prefix = "MAIN";
+    char *input_geom = NULL;
+    char *blade_geom = NULL;
+    char *spatial_index_prefix = NULL;
+    char *spatial_index = NULL;
+    char *tmp_table = NULL;
+    int input_type;
+    int input_srid;
+    int blade_srid;
+    int retcode = 0;
+    int ret;
+    char *errMsg = NULL;
+    int pending = 0;
+    int drop_spatial_index = 0;
+    int drop_tmp_table = 0;
+    struct output_table *tbl = NULL;
+    const char *sql;
+    int pt_type = 0;
+    int ln_type = 0;
+    int pg_type = 0;
+
+/* testing and validating the arguments */
+    do_reset_message (message);
+    if (xin_db_prefix != NULL)
+	in_db_prefix = xin_db_prefix;
+    if (xblade_db_prefix != NULL)
+	blade_db_prefix = xblade_db_prefix;
+    if (input_table == NULL)
+      {
+	  do_update_message (message, "ERROR: input table name can't be NULL");
+	  goto end;
+      }
+    if (blade_table == NULL)
+      {
+	  do_update_message (message, "ERROR: blade table name can't be NULL");
+	  goto end;
+      }
+    if (out_table == NULL)
+      {
+	  do_update_message (message, "ERROR: output table name can't be NULL");
+	  goto end;
+      }
+    if (!do_check_input
+	(handle, in_db_prefix, input_table, xinput_geom, &input_geom,
+	 &input_srid, &input_type, message))
+	goto end;
+    if (!do_check_blade
+	(handle, blade_db_prefix, blade_table, xblade_geom, &blade_geom,
+	 &blade_srid, message))
+	goto end;
+    if (!do_check_output (handle, "MAIN", out_table, input_geom, message))
+	goto end;
+    if (input_srid != blade_srid)
+      {
+	  do_update_message (message,
+			     "ERROR: both input and blade tables must share the same SRID");
+	  goto end;
+      }
+    if (!do_check_nulls
+	(handle, in_db_prefix, input_table, input_geom, "INPUT", message))
+	goto end;
+    if (!do_check_nulls
+	(handle, blade_db_prefix, blade_table, blade_geom, "BLADE", message))
+	goto end;
+
+/* determining the Output Table layout */
+    tbl = alloc_output_table ();
+    if (tbl == NULL)
+      {
+	  do_update_message (message,
+			     "ERROR: insufficient memory (OutputTable wrapper)");
+	  goto end;
+      }
+    if (add_column_to_output_table
+	(tbl, "PK_UID", "INTEGER", 0, GAIA_CUTTER_OUTPUT_PK, 0) == NULL)
+      {
+	  do_update_message (message,
+			     "ERROR: insufficient memory (OutputTable wrapper)");
+	  goto end;
+      }
+    if (!do_get_input_pk (tbl, handle, in_db_prefix, input_table, message))
+	goto end;
+    if (!do_get_blade_pk (tbl, handle, blade_db_prefix, blade_table, message))
+	goto end;
+    if (add_column_to_output_table
+	(tbl, "n_geom", "INTEGER", 1, GAIA_CUTTER_NORMAL, 0) == NULL)
+      {
+	  do_update_message (message,
+			     "ERROR: insufficient memory (OutputTable wrapper)");
+	  goto end;
+      }
+    if (add_column_to_output_table
+	(tbl, "res_prog", "INTEGER", 1, GAIA_CUTTER_NORMAL, 0) == NULL)
+      {
+	  do_update_message (message,
+			     "ERROR: insufficient memory (OutputTable wrapper)");
+	  goto end;
+      }
+
+/* setting the Temp Store */
+    if (ram_tmp_store)
+	sql = "PRAGMA temp_store=2";
+    else
+	sql = "PRAGMA temp_store=1";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA temp_store", errMsg);
+	  sqlite3_free (errMsg);
+	  goto end;
+      }
+
+    if (transaction)
+      {
+	  /* starting a Transaction */
+	  ret = sqlite3_exec (handle, "BEGIN", NULL, NULL, &errMsg);
+	  if (ret != SQLITE_OK)
+	    {
+		do_update_sql_error (message, "BEGIN", errMsg);
+		sqlite3_free (errMsg);
+		goto end;
+	    }
+	  pending = 1;
+      }
+
+/* creating the Output Table */
+    if (!do_create_output_table
+	(tbl, handle, out_table, input_table, blade_table, message))
+	goto end;
+/* adding the Output Geometry */
+    if (!do_create_output_geometry
+	(handle, out_table, input_geom, input_srid, input_type, message))
+	goto end;
+/* verifying the Blade Spatial Index */
+    if (!do_verify_blade_spatial_index
+	(handle, blade_db_prefix, blade_table, blade_geom,
+	 &spatial_index_prefix, &spatial_index, &drop_spatial_index, message))
+	goto end;
+
+    switch (input_type)
+      {
+      case GAIA_POINT:
+      case GAIA_POINTZ:
+      case GAIA_POINTM:
+      case GAIA_POINTZM:
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTIPOINTZM:
+	  pt_type = 1;
+	  break;
+      case GAIA_LINESTRING:
+      case GAIA_LINESTRINGZ:
+      case GAIA_LINESTRINGM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTILINESTRINGZM:
+	  ln_type = 1;
+	  break;
+      case GAIA_POLYGON:
+      case GAIA_POLYGONZ:
+      case GAIA_POLYGONM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_MULTIPOLYGONM:
+      case GAIA_MULTIPOLYGONZM:
+	  pg_type = 1;
+	  break;
+      };
+
+    if (pt_type)
+      {
+	  /* processing Input of (multi)POINT type */
+	  if (!do_cut_points
+	      (tbl, handle, cache, in_db_prefix, input_table, input_geom,
+	       blade_db_prefix, blade_table, blade_geom, spatial_index_prefix,
+	       spatial_index, out_table, &tmp_table, &drop_tmp_table, message))
+	      goto end;
+      }
+    if (ln_type)
+      {
+	  /* processing Input of (multi)LINESTRING type */
+	  if (!do_cut_linestrings
+	      (tbl, handle, cache, in_db_prefix, input_table, input_geom,
+	       blade_db_prefix, blade_table, blade_geom, spatial_index_prefix,
+	       spatial_index, out_table, &tmp_table, &drop_tmp_table,
+	       input_type, message))
+	      goto end;
+      }
+    if (pg_type)
+      {
+	  /* processing Input of (multi)POLYGON type */
+	  if (!do_cut_polygons
+	      (tbl, handle, cache, in_db_prefix, input_table, input_geom,
+	       blade_db_prefix, blade_table, blade_geom, spatial_index_prefix,
+	       spatial_index, out_table, &tmp_table, &drop_tmp_table,
+	       input_type, message))
+	      goto end;
+      }
+
+    if (drop_tmp_table)
+      {
+	  /* dropping the Temporary Table */
+	  drop_tmp_table = 0;
+	  if (!do_drop_tmp_table (handle, tmp_table, message))
+	      goto end;
+      }
+
+    if (transaction)
+      {
+	  /* committing the Transaction */
+	  ret = sqlite3_exec (handle, "COMMIT", NULL, NULL, &errMsg);
+	  if (ret != SQLITE_OK)
+	    {
+		do_update_sql_error (message, "COMMIT", errMsg);
+		sqlite3_free (errMsg);
+		goto end;
+	    }
+	  pending = 0;
+      }
+    retcode = 1;
+
+/* testing for invalid Output Geoms */
+    if (!do_check_valid (handle, out_table, input_geom, message))
+	retcode = 2;
+
+  end:
+    if (drop_spatial_index)
+      {
+	  /* dropping the transient Blade Spatial Index */
+	  do_drop_blade_spatial_index (handle, spatial_index, message);
+      }
+    if (drop_tmp_table)
+      {
+	  /* dropping the Temporary Table */
+	  do_drop_tmp_table (handle, tmp_table, message);
+      }
+
+/* resetting the Temp Store */
+    sql = "PRAGMA temp_store=0";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &errMsg);
+    if (ret != SQLITE_OK)
+      {
+	  do_update_sql_error (message, "PRAGMA temp_store", errMsg);
+	  sqlite3_free (errMsg);
+      }
+
+    if (input_geom != NULL)
+	free (input_geom);
+    if (blade_geom != NULL)
+	free (blade_geom);
+    if (spatial_index_prefix != NULL)
+	free (spatial_index_prefix);
+    if (spatial_index != NULL)
+	sqlite3_free (spatial_index);
+    if (tmp_table != NULL)
+	sqlite3_free (tmp_table);
+    if (tbl != NULL)
+	destroy_output_table (tbl);
+    if (transaction && pending)
+      {
+	  /* rolling back the Transaction */
+	  ret = sqlite3_exec (handle, "ROLLBACK", NULL, NULL, &errMsg);
+	  if (ret != SQLITE_OK)
+	    {
+		do_update_sql_error (message, "ROLLBACK", errMsg);
+		sqlite3_free (errMsg);
+	    }
+      }
+    return retcode;
+}
+
+#endif /* end GEOS conditionals */
diff --git a/src/gaiageo/gg_geodesic.c b/src/gaiageo/gg_geodesic.c
index 6753492..dc031ad 100644
--- a/src/gaiageo/gg_geodesic.c
+++ b/src/gaiageo/gg_geodesic.c
@@ -28,6 +28,7 @@ Portions created by the Initial Developer are Copyright (C) 2008-2015
 the Initial Developer. All Rights Reserved.
 
 Contributor(s):
+Charles Karney <charles at karney.com>
 
 Alternatively, the contents of this file may be used under the terms of
 either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -60,6 +61,20 @@ the terms of any one of the MPL, the GPL or the LGPL.
 
 #include <spatialite/gaiageo.h>
 
+#ifndef OMIT_PROJ
+#include <proj_api.h>
+#if defined(PJ_VERSION) && PJ_VERSION >= 490
+/* Enable new proj.4's geodesic distance */
+#define PROJ_GEODESIC 1
+#include <geodesic.h>
+#else
+/* Use the old (Vincenty) geodesic distance */
+#define PROJ_GEODESIC 0
+#endif
+#else
+#define PROJ_GEODESIC 0
+#endif
+
 #define DEG2RAD	0.0174532925199432958
 #define PI	3.14159265358979323846
 
@@ -187,7 +202,27 @@ gaiaGeodesicDistance (double a, double b, double rf, double lat1, double lon1,
 /*
 / Calculate geodesic distance (in m) 
 / between two points specified by latitude/longitude 
-/ (in decimal degrees) using Vincenty inverse formula for ellipsoids
+/ (in decimal degrees) 
+*/
+
+#if PROJ_GEODESIC
+/*
+/ using the PROJ.4 own implementation
+/
+/ requires PROJ.4 >= 4.9.0
+/
+/ (accepting a patch suggested by Charles Karney <charles at karney.com>
+*/
+    double s12;
+    struct geod_geodesic gd;
+    if (b == a)
+	b = a;			/* silencing stupid compiler warnings */
+    geod_init (&gd, a, 1 / rf);
+    geod_inverse (&gd, lat1, lon1, lat2, lon2, &s12, 0, 0);
+    return s12;
+#else
+/*
+/ using Vincenty inverse formula for ellipsoids
 /
 / based on original JavaScript by (c) Chris Veness 2002-2008 
 / http://www.movable-type.co.uk/scripts/latlong-vincenty.html
@@ -267,6 +302,7 @@ gaiaGeodesicDistance (double a, double b, double rf, double lat1, double lon1,
 									cos2SigmaM)));
     s = b * A * (sigma - deltaSigma);
     return s;
+#endif /* end Vincenty formula */
 }
 
 GAIAGEO_DECLARE void
diff --git a/src/gaiageo/gg_geometries.c b/src/gaiageo/gg_geometries.c
index b863f10..7c953a6 100644
--- a/src/gaiageo/gg_geometries.c
+++ b/src/gaiageo/gg_geometries.c
@@ -3635,8 +3635,7 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
 		       gaiaGeomCollPtr geom2)
 {
-/* mergine two generic Geometries into a single one */
-    gaiaGeomCollPtr result;
+/* mergine a second generic Geometries into the first one */
     gaiaPointPtr pt;
     gaiaLinestringPtr ln;
     gaiaLinestringPtr new_ln;
@@ -3644,9 +3643,6 @@ gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
     gaiaPolygonPtr new_pg;
     gaiaRingPtr rng;
     gaiaRingPtr new_rng;
-    int dims1;
-    int dims2;
-    int dims;
     double x;
     double y;
     double z;
@@ -3657,97 +3653,7 @@ gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
     if (geom1 == NULL || geom2 == NULL)
 	return NULL;
     if (cache != NULL)
-      {
-	  if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
-	      return NULL;
-      }
-    else
-      {
-	  if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
-	      return NULL;
-      }
-    dims1 = geom1->DimensionModel;
-    dims2 = geom2->DimensionModel;
-/* building a new Geometry */
-    if (dims1 == dims2)
-	dims = dims1;
-    else
-      {
-	  if (dims1 == GAIA_XY_Z_M || dims2 == GAIA_XY_Z_M)
-	      dims = GAIA_XY_Z_M;
-	  else if (dims1 == GAIA_XY_Z && dims2 == GAIA_XY_M)
-	      dims = GAIA_XY_Z_M;
-	  else if (dims1 == GAIA_XY_M && dims2 == GAIA_XY_Z)
-	      dims = GAIA_XY_Z_M;
-	  else if (dims1 == GAIA_XY_Z)
-	      dims = GAIA_XY_Z;
-	  else if (dims2 == GAIA_XY_Z)
-	      dims = GAIA_XY_Z;
-	  else if (dims1 == GAIA_XY_M)
-	      dims = GAIA_XY_M;
-	  else if (dims2 == GAIA_XY_M)
-	      dims = GAIA_XY_M;
-	  else
-	      dims = GAIA_XY;
-      }
-    if (dims == GAIA_XY_Z_M)
-	result = gaiaAllocGeomCollXYZM ();
-    else if (dims == GAIA_XY_Z)
-	result = gaiaAllocGeomCollXYZ ();
-    else if (dims == GAIA_XY_M)
-	result = gaiaAllocGeomCollXYM ();
-    else
-	result = gaiaAllocGeomColl ();
-    result->Srid = geom1->Srid;
-
-    pt = geom1->FirstPoint;
-    while (pt)
-      {
-	  /* copying POINTs from GEOM-1 */
-	  z = 0.0;
-	  m = 0.0;
-	  if (pt->DimensionModel == GAIA_XY_Z_M)
-	    {
-		x = pt->X;
-		y = pt->Y;
-		z = pt->Z;
-		m = pt->M;
-	    }
-	  else if (pt->DimensionModel == GAIA_XY_Z)
-	    {
-		x = pt->X;
-		y = pt->Y;
-		z = pt->Z;
-	    }
-	  else if (pt->DimensionModel == GAIA_XY_M)
-	    {
-		x = pt->X;
-		y = pt->Y;
-		m = pt->M;
-	    }
-	  else
-	    {
-		x = pt->X;
-		y = pt->Y;
-	    }
-	  if (result->DimensionModel == GAIA_XY_Z_M)
-	    {
-		gaiaAddPointToGeomCollXYZM (result, x, y, z, m);
-	    }
-	  else if (result->DimensionModel == GAIA_XY_Z)
-	    {
-		gaiaAddPointToGeomCollXYZ (result, x, y, z);
-	    }
-	  else if (result->DimensionModel == GAIA_XY_M)
-	    {
-		gaiaAddPointToGeomCollXYM (result, x, y, m);
-	    }
-	  else
-	    {
-		gaiaAddPointToGeomColl (result, x, y);
-	    }
-	  pt = pt->Next;
-      }
+	cache = NULL;
 
     pt = geom2->FirstPoint;
     while (pt)
@@ -3779,75 +3685,30 @@ gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
 		x = pt->X;
 		y = pt->Y;
 	    }
-	  if (result->DimensionModel == GAIA_XY_Z_M)
+	  if (geom1->DimensionModel == GAIA_XY_Z_M)
 	    {
-		gaiaAddPointToGeomCollXYZM (result, x, y, z, m);
+		gaiaAddPointToGeomCollXYZM (geom1, x, y, z, m);
 	    }
-	  else if (result->DimensionModel == GAIA_XY_Z)
+	  else if (geom1->DimensionModel == GAIA_XY_Z)
 	    {
-		gaiaAddPointToGeomCollXYZ (result, x, y, z);
+		gaiaAddPointToGeomCollXYZ (geom1, x, y, z);
 	    }
-	  else if (result->DimensionModel == GAIA_XY_M)
+	  else if (geom1->DimensionModel == GAIA_XY_M)
 	    {
-		gaiaAddPointToGeomCollXYM (result, x, y, m);
+		gaiaAddPointToGeomCollXYM (geom1, x, y, m);
 	    }
 	  else
 	    {
-		gaiaAddPointToGeomColl (result, x, y);
+		gaiaAddPointToGeomColl (geom1, x, y);
 	    }
 	  pt = pt->Next;
       }
 
-    ln = geom1->FirstLinestring;
-    while (ln)
-      {
-	  /* copying LINESTRINGs from GEOM-1 */
-	  new_ln = gaiaAddLinestringToGeomColl (result, ln->Points);
-	  for (iv = 0; iv < ln->Points; iv++)
-	    {
-		z = 0.0;
-		m = 0.0;
-		if (ln->DimensionModel == GAIA_XY_Z_M)
-		  {
-		      gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
-		  }
-		else if (ln->DimensionModel == GAIA_XY_Z)
-		  {
-		      gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
-		  }
-		else if (ln->DimensionModel == GAIA_XY_M)
-		  {
-		      gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
-		  }
-		else
-		  {
-		      gaiaGetPoint (ln->Coords, iv, &x, &y);
-		  }
-		if (new_ln->DimensionModel == GAIA_XY_Z_M)
-		  {
-		      gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
-		  }
-		else if (new_ln->DimensionModel == GAIA_XY_Z)
-		  {
-		      gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
-		  }
-		else if (new_ln->DimensionModel == GAIA_XY_M)
-		  {
-		      gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
-		  }
-		else
-		  {
-		      gaiaSetPoint (new_ln->Coords, iv, x, y);
-		  }
-	    }
-	  ln = ln->Next;
-      }
-
     ln = geom2->FirstLinestring;
     while (ln)
       {
 	  /* copying LINESTRINGs from GEOM-2 */
-	  new_ln = gaiaAddLinestringToGeomColl (result, ln->Points);
+	  new_ln = gaiaAddLinestringToGeomColl (geom1, ln->Points);
 	  for (iv = 0; iv < ln->Points; iv++)
 	    {
 		z = 0.0;
@@ -3888,105 +3749,13 @@ gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
 	  ln = ln->Next;
       }
 
-    pg = geom1->FirstPolygon;
-    while (pg)
-      {
-	  /* copying POLYGONs from GEOM-1 */
-	  rng = pg->Exterior;
-	  new_pg =
-	      gaiaAddPolygonToGeomColl (result, rng->Points, pg->NumInteriors);
-	  new_rng = new_pg->Exterior;
-	  for (iv = 0; iv < rng->Points; iv++)
-	    {
-		/* Exterior Ring */
-		z = 0.0;
-		m = 0.0;
-		if (rng->DimensionModel == GAIA_XY_Z_M)
-		  {
-		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
-		  }
-		else if (rng->DimensionModel == GAIA_XY_Z)
-		  {
-		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
-		  }
-		else if (rng->DimensionModel == GAIA_XY_M)
-		  {
-		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
-		  }
-		else
-		  {
-		      gaiaGetPoint (rng->Coords, iv, &x, &y);
-		  }
-		if (new_rng->DimensionModel == GAIA_XY_Z_M)
-		  {
-		      gaiaSetPointXYZM (new_rng->Coords, iv, x, y, z, m);
-		  }
-		else if (new_rng->DimensionModel == GAIA_XY_Z)
-		  {
-		      gaiaSetPointXYZ (new_rng->Coords, iv, x, y, z);
-		  }
-		else if (new_rng->DimensionModel == GAIA_XY_M)
-		  {
-		      gaiaSetPointXYM (new_rng->Coords, iv, x, y, m);
-		  }
-		else
-		  {
-		      gaiaSetPoint (new_rng->Coords, iv, x, y);
-		  }
-	    }
-	  for (ib = 0; ib < pg->NumInteriors; ib++)
-	    {
-		/* Interior Rings */
-		rng = pg->Interiors + ib;
-		new_rng = gaiaAddInteriorRing (new_pg, ib, rng->Points);
-		for (iv = 0; iv < rng->Points; iv++)
-		  {
-		      z = 0.0;
-		      m = 0.0;
-		      if (rng->DimensionModel == GAIA_XY_Z_M)
-			{
-			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
-			}
-		      else if (rng->DimensionModel == GAIA_XY_Z)
-			{
-			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
-			}
-		      else if (rng->DimensionModel == GAIA_XY_M)
-			{
-			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
-			}
-		      else
-			{
-			    gaiaGetPoint (rng->Coords, iv, &x, &y);
-			}
-		      if (new_rng->DimensionModel == GAIA_XY_Z_M)
-			{
-			    gaiaSetPointXYZM (new_rng->Coords, iv, x, y, z, m);
-			}
-		      else if (new_rng->DimensionModel == GAIA_XY_Z)
-			{
-			    gaiaSetPointXYZ (new_rng->Coords, iv, x, y, z);
-			}
-		      else if (new_rng->DimensionModel == GAIA_XY_M)
-			{
-			    gaiaSetPointXYM (new_rng->Coords, iv, x, y, m);
-			}
-		      else
-			{
-			    gaiaSetPoint (new_rng->Coords, iv, x, y);
-			}
-		  }
-	    }
-	  pg = pg->Next;
-      }
-
     pg = geom2->FirstPolygon;
     while (pg)
       {
 	  /* copying POLYGONs from GEOM-2 */
 	  rng = pg->Exterior;
 	  new_pg =
-	      gaiaAddPolygonToGeomColl (result, rng->Points, pg->NumInteriors);
+	      gaiaAddPolygonToGeomColl (geom1, rng->Points, pg->NumInteriors);
 	  new_rng = new_pg->Exterior;
 	  for (iv = 0; iv < rng->Points; iv++)
 	    {
@@ -4072,7 +3841,7 @@ gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
 	  pg = pg->Next;
       }
 
-    return result;
+    return geom1;
 }
 
 GAIAGEO_DECLARE void
diff --git a/src/gaiageo/gg_geoscvt.c b/src/gaiageo/gg_geoscvt.c
index e55f9fc..0013049 100644
--- a/src/gaiageo/gg_geoscvt.c
+++ b/src/gaiageo/gg_geoscvt.c
@@ -54,6 +54,11 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #endif
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -98,8 +103,15 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
     GEOSCoordSequence *cs;
     int ring_points;
     int n_items;
+
+#ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!gaia)
 	return NULL;
+
+
     pt = gaia->FirstPoint;
     while (pt)
       {
@@ -215,6 +227,7 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      cs = GEOSCoordSeq_create (1, dims);
 		      switch (gaia->DimensionModel)
 			{
@@ -230,6 +243,7 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			    break;
 			};
 		      geos = GEOSGeom_createPoint (cs);
+#endif
 		  }
 	    }
 	  break;
@@ -239,8 +253,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 		ln = gaia->FirstLinestring;
 		if (handle != NULL)
 		    cs = GEOSCoordSeq_create_r (handle, ln->Points, dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    cs = GEOSCoordSeq_create (ln->Points, dims);
+#endif
 		for (iv = 0; iv < ln->Points; iv++)
 		  {
 		      switch (ln->DimensionModel)
@@ -255,9 +271,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
 				  GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 			      }
 			    break;
 			case GAIA_XY_M:
@@ -269,8 +287,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
+#endif
 			      }
 			    break;
 			case GAIA_XY_Z_M:
@@ -283,9 +303,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
 				  GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 			      }
 			    break;
 			default:
@@ -297,16 +319,20 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
+#endif
 			      }
 			    break;
 			};
 		  }
 		if (handle != NULL)
 		    geos = GEOSGeom_createLineString_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    geos = GEOSGeom_createLineString (cs);
+#endif
 	    }
 	  break;
       case GAIA_POLYGON:
@@ -321,15 +347,19 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 		      if (gaiaIsNotClosedRing_r (cache, rng))
 			  ring_points++;
 		  }
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		  {
 		      if (gaiaIsNotClosedRing (rng))
 			  ring_points++;
 		  }
+#endif
 		if (handle != NULL)
 		    cs = GEOSCoordSeq_create_r (handle, ring_points, dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    cs = GEOSCoordSeq_create (ring_points, dims);
+#endif
 		for (iv = 0; iv < rng->Points; iv++)
 		  {
 		      switch (rng->DimensionModel)
@@ -351,9 +381,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
 				  GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 			      }
 			    break;
 			case GAIA_XY_M:
@@ -371,8 +403,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
+#endif
 			      }
 			    break;
 			case GAIA_XY_Z_M:
@@ -392,9 +426,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
 				  GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 			      }
 			    break;
 			default:
@@ -412,8 +448,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x);
 				  GEOSCoordSeq_setY (cs, iv, y);
+#endif
 			      }
 			    break;
 			};
@@ -434,9 +472,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x0);
 				  GEOSCoordSeq_setY (cs, iv, y0);
 				  GEOSCoordSeq_setZ (cs, iv, z0);
+#endif
 			      }
 			    break;
 			default:
@@ -447,16 +487,20 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, iv, x0);
 				  GEOSCoordSeq_setY (cs, iv, y0);
+#endif
 			      }
 			    break;
 			};
 		  }
 		if (handle != NULL)
 		    geos_ext = GEOSGeom_createLinearRing_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    geos_ext = GEOSGeom_createLinearRing (cs);
+#endif
 		geos_holes = NULL;
 		if (pg->NumInteriors > 0)
 		  {
@@ -472,16 +516,20 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				  if (gaiaIsNotClosedRing_r (cache, rng))
 				      ring_points++;
 			      }
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    else
 			      {
 				  if (gaiaIsNotClosedRing (rng))
 				      ring_points++;
 			      }
+#endif
 			    if (handle != NULL)
 				cs = GEOSCoordSeq_create_r (handle, ring_points,
 							    dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    else
 				cs = GEOSCoordSeq_create (ring_points, dims);
+#endif
 			    for (iv = 0; iv < rng->Points; iv++)
 			      {
 				  switch (rng->DimensionModel)
@@ -507,9 +555,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_setX (cs, iv, x);
 					      GEOSCoordSeq_setY (cs, iv, y);
 					      GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 					  }
 					break;
 				    case GAIA_XY_M:
@@ -530,8 +580,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_setX (cs, iv, x);
 					      GEOSCoordSeq_setY (cs, iv, y);
+#endif
 					  }
 					break;
 				    case GAIA_XY_Z_M:
@@ -555,9 +607,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_setX (cs, iv, x);
 					      GEOSCoordSeq_setY (cs, iv, y);
 					      GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 					  }
 					break;
 				    default:
@@ -577,8 +631,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_setX (cs, iv, x);
 					      GEOSCoordSeq_setY (cs, iv, y);
+#endif
 					  }
 					break;
 				    };
@@ -602,9 +658,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_setX (cs, iv, x0);
 					      GEOSCoordSeq_setY (cs, iv, y0);
 					      GEOSCoordSeq_setZ (cs, iv, z0);
+#endif
 					  }
 					break;
 				    default:
@@ -617,8 +675,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_setX (cs, iv, x0);
 					      GEOSCoordSeq_setY (cs, iv, y0);
+#endif
 					  }
 					break;
 				    };
@@ -626,8 +686,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			    if (handle != NULL)
 				geos_int =
 				    GEOSGeom_createLinearRing_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    else
 				geos_int = GEOSGeom_createLinearRing (cs);
+#endif
 			    *(geos_holes + ib) = geos_int;
 			}
 		  }
@@ -635,10 +697,12 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 		    geos =
 			GEOSGeom_createPolygon_r (handle, geos_ext, geos_holes,
 						  pg->NumInteriors);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    geos =
 			GEOSGeom_createPolygon (geos_ext, geos_holes,
 						pg->NumInteriors);
+#endif
 		if (geos_holes)
 		    free (geos_holes);
 	    }
@@ -676,8 +740,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 		  {
 		      if (handle != NULL)
 			  cs = GEOSCoordSeq_create_r (handle, 1, dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  cs = GEOSCoordSeq_create (1, dims);
+#endif
 		      switch (pt->DimensionModel)
 			{
 			case GAIA_XY_Z:
@@ -690,9 +756,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, 0, pt->X);
 				  GEOSCoordSeq_setY (cs, 0, pt->Y);
 				  GEOSCoordSeq_setZ (cs, 0, pt->Z);
+#endif
 			      }
 			    break;
 			default:
@@ -703,15 +771,19 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_setX (cs, 0, pt->X);
 				  GEOSCoordSeq_setY (cs, 0, pt->Y);
+#endif
 			      }
 			    break;
 			};
 		      if (handle != NULL)
 			  geos_item = GEOSGeom_createPoint_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  geos_item = GEOSGeom_createPoint (cs);
+#endif
 		      *(geos_coll + nItem++) = geos_item;
 		      pt = pt->Next;
 		  }
@@ -723,8 +795,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 		  {
 		      if (handle != NULL)
 			  cs = GEOSCoordSeq_create_r (handle, ln->Points, dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  cs = GEOSCoordSeq_create (ln->Points, dims);
+#endif
 		      for (iv = 0; iv < ln->Points; iv++)
 			{
 			    switch (ln->DimensionModel)
@@ -739,9 +813,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
 					GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 				    }
 				  break;
 			      case GAIA_XY_M:
@@ -753,8 +829,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
+#endif
 				    }
 				  break;
 			      case GAIA_XY_Z_M:
@@ -768,9 +846,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
 					GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 				    }
 				  break;
 			      default:
@@ -782,16 +862,20 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
+#endif
 				    }
 				  break;
 			      };
 			}
 		      if (handle != NULL)
 			  geos_item = GEOSGeom_createLineString_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  geos_item = GEOSGeom_createLineString (cs);
+#endif
 		      *(geos_coll + nItem++) = geos_item;
 		      ln = ln->Next;
 		  }
@@ -809,16 +893,20 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			    if (gaiaIsNotClosedRing_r (handle, rng))
 				ring_points++;
 			}
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			{
 			    if (gaiaIsNotClosedRing (rng))
 				ring_points++;
 			}
+#endif
 		      if (handle != NULL)
 			  cs = GEOSCoordSeq_create_r (handle, ring_points,
 						      dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  cs = GEOSCoordSeq_create (ring_points, dims);
+#endif
 		      for (iv = 0; iv < rng->Points; iv++)
 			{
 			    switch (rng->DimensionModel)
@@ -840,9 +928,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
 					GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 				    }
 				  break;
 			      case GAIA_XY_M:
@@ -860,8 +950,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
+#endif
 				    }
 				  break;
 			      case GAIA_XY_Z_M:
@@ -882,9 +974,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
 					GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 				    }
 				  break;
 			      default:
@@ -902,8 +996,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x);
 					GEOSCoordSeq_setY (cs, iv, y);
+#endif
 				    }
 				  break;
 			      };
@@ -927,9 +1023,11 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x0);
 					GEOSCoordSeq_setY (cs, iv, y0);
 					GEOSCoordSeq_setZ (cs, iv, z0);
+#endif
 				    }
 				  break;
 			      default:
@@ -942,16 +1040,20 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_setX (cs, iv, x0);
 					GEOSCoordSeq_setY (cs, iv, y0);
+#endif
 				    }
 				  break;
 			      };
 			}
 		      if (handle != NULL)
 			  geos_ext = GEOSGeom_createLinearRing_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  geos_ext = GEOSGeom_createLinearRing (cs);
+#endif
 		      geos_holes = NULL;
 		      if (pg->NumInteriors > 0)
 			{
@@ -968,18 +1070,22 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 					if (gaiaIsNotClosedRing_r (cache, rng))
 					    ring_points++;
 				    }
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  else
 				    {
 					if (gaiaIsNotClosedRing (rng))
 					    ring_points++;
 				    }
+#endif
 				  if (handle != NULL)
 				      cs = GEOSCoordSeq_create_r (handle,
 								  ring_points,
 								  dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  else
 				      cs = GEOSCoordSeq_create (ring_points,
 								dims);
+#endif
 				  for (iv = 0; iv < rng->Points; iv++)
 				    {
 					switch (rng->DimensionModel)
@@ -1008,12 +1114,14 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 						}
 					      else
 						{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 						    GEOSCoordSeq_setX (cs, iv,
 								       x);
 						    GEOSCoordSeq_setY (cs, iv,
 								       y);
 						    GEOSCoordSeq_setZ (cs, iv,
 								       z);
+#endif
 						}
 					      break;
 					  case GAIA_XY_M:
@@ -1036,10 +1144,12 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 						}
 					      else
 						{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 						    GEOSCoordSeq_setX (cs, iv,
 								       x);
 						    GEOSCoordSeq_setY (cs, iv,
 								       y);
+#endif
 						}
 					      break;
 					  case GAIA_XY_Z_M:
@@ -1066,12 +1176,14 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 						}
 					      else
 						{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 						    GEOSCoordSeq_setX (cs, iv,
 								       x);
 						    GEOSCoordSeq_setY (cs, iv,
 								       y);
 						    GEOSCoordSeq_setZ (cs, iv,
 								       z);
+#endif
 						}
 					      break;
 					  default:
@@ -1094,10 +1206,12 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 						}
 					      else
 						{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 						    GEOSCoordSeq_setX (cs, iv,
 								       x);
 						    GEOSCoordSeq_setY (cs, iv,
 								       y);
+#endif
 						}
 					      break;
 					  };
@@ -1124,12 +1238,14 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 						}
 					      else
 						{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 						    GEOSCoordSeq_setX (cs, iv,
 								       x0);
 						    GEOSCoordSeq_setY (cs, iv,
 								       y0);
 						    GEOSCoordSeq_setZ (cs, iv,
 								       z0);
+#endif
 						}
 					      break;
 					  default:
@@ -1144,10 +1260,12 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 						}
 					      else
 						{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 						    GEOSCoordSeq_setX (cs, iv,
 								       x0);
 						    GEOSCoordSeq_setY (cs, iv,
 								       y0);
+#endif
 						}
 					      break;
 					  };
@@ -1156,8 +1274,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 				      geos_int =
 					  GEOSGeom_createLinearRing_r (handle,
 								       cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  else
 				      geos_int = GEOSGeom_createLinearRing (cs);
+#endif
 				  *(geos_holes + ib) = geos_int;
 			      }
 			}
@@ -1166,10 +1286,12 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 			      GEOSGeom_createPolygon_r (handle, geos_ext,
 							geos_holes,
 							pg->NumInteriors);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  geos_item =
 			      GEOSGeom_createPolygon (geos_ext, geos_holes,
 						      pg->NumInteriors);
+#endif
 		      if (geos_holes)
 			  free (geos_holes);
 		      *(geos_coll + nItem++) = geos_item;
@@ -1187,8 +1309,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
 	      geos =
 		  GEOSGeom_createCollection_r (handle, geos_type, geos_coll,
 					       n_items);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      geos = GEOSGeom_createCollection (geos_type, geos_coll, n_items);
+#endif
 	  if (geos_coll)
 	      free (geos_coll);
 	  break;
@@ -1199,8 +1323,10 @@ toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
       {
 	  if (handle != NULL)
 	      GEOSSetSRID_r (handle, geos, gaia->Srid);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      GEOSSetSRID (geos, gaia->Srid);
+#endif
       }
     return geos;
 }
@@ -1232,12 +1358,20 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
     gaiaLinestringPtr ln;
     gaiaPolygonPtr pg;
     gaiaRingPtr rng;
+
+#ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!geos)
 	return NULL;
+
     if (handle != NULL)
 	type = GEOSGeomTypeId_r (handle, geos);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
 	type = GEOSGeomTypeId (geos);
+#endif
     switch (type)
       {
       case GEOS_POINT:
@@ -1258,9 +1392,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		gaia->Srid = GEOSGetSRID (geos);
 		cs = GEOSGeom_getCoordSeq (geos);
 		GEOSCoordSeq_getDimensions (cs, &dims);
+#endif
 	    }
 	  if (dims == 3)
 	    {
@@ -1272,9 +1408,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      GEOSCoordSeq_getX (cs, 0, &x);
 		      GEOSCoordSeq_getY (cs, 0, &y);
 		      GEOSCoordSeq_getZ (cs, 0, &z);
+#endif
 		  }
 	    }
 	  else
@@ -1286,8 +1424,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      GEOSCoordSeq_getX (cs, 0, &x);
 		      GEOSCoordSeq_getY (cs, 0, &y);
+#endif
 		  }
 		z = 0.0;
 	    }
@@ -1319,10 +1459,12 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		gaia->Srid = GEOSGetSRID (geos);
 		cs = GEOSGeom_getCoordSeq (geos);
 		GEOSCoordSeq_getDimensions (cs, &dims);
 		GEOSCoordSeq_getSize (cs, &points);
+#endif
 	    }
 	  ln = gaiaAddLinestringToGeomColl (gaia, points);
 	  for (iv = 0; iv < (int) points; iv++)
@@ -1337,9 +1479,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_getX (cs, iv, &x);
 			    GEOSCoordSeq_getY (cs, iv, &y);
 			    GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 			}
 		  }
 		else
@@ -1351,8 +1495,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_getX (cs, iv, &x);
 			    GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 			}
 		      z = 0.0;
 		  }
@@ -1386,8 +1532,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 	  gaia->DeclaredType = GAIA_POLYGON;
 	  if (handle != NULL)
 	      gaia->Srid = GEOSGetSRID_r (handle, geos);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      gaia->Srid = GEOSGetSRID (geos);
+#endif
 	  /* exterior ring */
 	  if (handle != NULL)
 	    {
@@ -1399,11 +1547,13 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		holes = GEOSGetNumInteriorRings (geos);
 		geos_ring = GEOSGetExteriorRing (geos);
 		cs = GEOSGeom_getCoordSeq (geos_ring);
 		GEOSCoordSeq_getDimensions (cs, &dims);
 		GEOSCoordSeq_getSize (cs, &points);
+#endif
 	    }
 	  pg = gaiaAddPolygonToGeomColl (gaia, points, holes);
 	  rng = pg->Exterior;
@@ -1419,9 +1569,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_getX (cs, iv, &x);
 			    GEOSCoordSeq_getY (cs, iv, &y);
 			    GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 			}
 		  }
 		else
@@ -1433,8 +1585,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_getX (cs, iv, &x);
 			    GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 			}
 		      z = 0.0;
 		  }
@@ -1467,10 +1621,12 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      geos_ring = GEOSGetInteriorRingN (geos, ib);
 		      cs = GEOSGeom_getCoordSeq (geos_ring);
 		      GEOSCoordSeq_getDimensions (cs, &dims);
 		      GEOSCoordSeq_getSize (cs, &points);
+#endif
 		  }
 		rng = gaiaAddInteriorRing (pg, ib, points);
 		for (iv = 0; iv < (int) points; iv++)
@@ -1485,9 +1641,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_getX (cs, iv, &x);
 				  GEOSCoordSeq_getY (cs, iv, &y);
 				  GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 			      }
 			}
 		      else
@@ -1499,8 +1657,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_getX (cs, iv, &x);
 				  GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 			      }
 			    z = 0.0;
 			}
@@ -1550,8 +1710,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		gaia->Srid = GEOSGetSRID (geos);
 		nItems = GEOSGetNumGeometries (geos);
+#endif
 	    }
 	  for (it = 0; it < nItems; it++)
 	    {
@@ -1563,8 +1725,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      geos_item = GEOSGetGeometryN (geos, it);
 		      itemType = GEOSGeomTypeId (geos_item);
+#endif
 		  }
 		switch (itemType)
 		  {
@@ -1576,8 +1740,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    cs = GEOSGeom_getCoordSeq (geos_item);
 			    GEOSCoordSeq_getDimensions (cs, &dims);
+#endif
 			}
 		      if (dims == 3)
 			{
@@ -1589,9 +1755,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_getX (cs, 0, &x);
 				  GEOSCoordSeq_getY (cs, 0, &y);
 				  GEOSCoordSeq_getZ (cs, 0, &z);
+#endif
 			      }
 			}
 		      else
@@ -1603,8 +1771,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  GEOSCoordSeq_getX (cs, 0, &x);
 				  GEOSCoordSeq_getY (cs, 0, &y);
+#endif
 			      }
 			    z = 0.0;
 			}
@@ -1626,9 +1796,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    cs = GEOSGeom_getCoordSeq (geos_item);
 			    GEOSCoordSeq_getDimensions (cs, &dims);
 			    GEOSCoordSeq_getSize (cs, &points);
+#endif
 			}
 		      ln = gaiaAddLinestringToGeomColl (gaia, points);
 		      for (iv = 0; iv < (int) points; iv++)
@@ -1646,9 +1818,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_getX (cs, iv, &x);
 					GEOSCoordSeq_getY (cs, iv, &y);
 					GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 				    }
 			      }
 			    else
@@ -1662,8 +1836,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_getX (cs, iv, &x);
 					GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 				    }
 				  z = 0.0;
 			      }
@@ -1690,8 +1866,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		      if (handle != NULL)
 			  nSubItems =
 			      GEOSGetNumGeometries_r (handle, geos_item);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  nSubItems = GEOSGetNumGeometries (geos_item);
+#endif
 		      for (sub_it = 0; sub_it < nSubItems; sub_it++)
 			{
 			    /* looping on elementaty geometries */
@@ -1708,11 +1886,13 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  geos_sub_item =
 				      GEOSGetGeometryN (geos_item, sub_it);
 				  cs = GEOSGeom_getCoordSeq (geos_sub_item);
 				  GEOSCoordSeq_getDimensions (cs, &dims);
 				  GEOSCoordSeq_getSize (cs, &points);
+#endif
 			      }
 			    ln = gaiaAddLinestringToGeomColl (gaia, points);
 			    for (iv = 0; iv < (int) points; iv++)
@@ -1730,9 +1910,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_getX (cs, iv, &x);
 					      GEOSCoordSeq_getY (cs, iv, &y);
 					      GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 					  }
 				    }
 				  else
@@ -1746,8 +1928,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_getX (cs, iv, &x);
 					      GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 					  }
 					z = 0.0;
 				    }
@@ -1787,11 +1971,13 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    holes = GEOSGetNumInteriorRings (geos_item);
 			    geos_ring = GEOSGetExteriorRing (geos_item);
 			    cs = GEOSGeom_getCoordSeq (geos_ring);
 			    GEOSCoordSeq_getDimensions (cs, &dims);
 			    GEOSCoordSeq_getSize (cs, &points);
+#endif
 			}
 		      pg = gaiaAddPolygonToGeomColl (gaia, points, holes);
 		      rng = pg->Exterior;
@@ -1810,9 +1996,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_getX (cs, iv, &x);
 					GEOSCoordSeq_getY (cs, iv, &y);
 					GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 				    }
 			      }
 			    else
@@ -1826,8 +2014,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					GEOSCoordSeq_getX (cs, iv, &x);
 					GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 				    }
 				  z = 0.0;
 			      }
@@ -1865,11 +2055,13 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  geos_ring =
 				      GEOSGetInteriorRingN (geos_item, ib);
 				  cs = GEOSGeom_getCoordSeq (geos_ring);
 				  GEOSCoordSeq_getDimensions (cs, &dims);
 				  GEOSCoordSeq_getSize (cs, &points);
+#endif
 			      }
 			    rng = gaiaAddInteriorRing (pg, ib, points);
 			    for (iv = 0; iv < (int) points; iv++)
@@ -1887,9 +2079,11 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_getX (cs, iv, &x);
 					      GEOSCoordSeq_getY (cs, iv, &y);
 					      GEOSCoordSeq_getZ (cs, iv, &z);
+#endif
 					  }
 				    }
 				  else
@@ -1903,8 +2097,10 @@ fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 					  }
 					else
 					  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					      GEOSCoordSeq_getX (cs, iv, &x);
 					      GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 					  }
 					z = 0.0;
 				    }
diff --git a/src/gaiageo/gg_lwgeom.c b/src/gaiageo/gg_lwgeom.c
index 0ae8e71..08d2d69 100644
--- a/src/gaiageo/gg_lwgeom.c
+++ b/src/gaiageo/gg_lwgeom.c
@@ -90,29 +90,60 @@ splite_lwgeom_version (void)
 static void
 lwgaia_noticereporter (const char *fmt, va_list ap)
 {
-    char *msg;
-    if (!lw_vasprintf (&msg, fmt, ap))
+    char *msg = sqlite3_vmprintf (fmt, ap);
+    if (msg == NULL)
+      {
+	  va_end (ap);
+	  return;
+      }
+    if (strlen (msg) > 1)
+	spatialite_e ("LWGEOM notice: %s\n", msg);
+    gaiaSetLwGeomWarningMsg (msg);
+    sqlite3_free (msg);
+}
+
+static void
+lwgaiatopo_noticereporter (const char *fmt, va_list ap)
+{
+    char *msg = sqlite3_vmprintf (fmt, ap);
+    if (msg == NULL)
       {
 	  va_end (ap);
 	  return;
       }
-    spatialite_e ("LWGEOM notice: %s\n", msg);
+    if (strlen (msg) > 1)
+	spatialite_e ("LWGEOM notice: %s\n", msg);
     gaiaSetLwGeomWarningMsg (msg);
-    free (msg);
+    sqlite3_free (msg);
 }
 
 static void
 lwgaia_errorreporter (const char *fmt, va_list ap)
 {
-    char *msg;
-    if (!lw_vasprintf (&msg, fmt, ap))
+    char *msg = sqlite3_vmprintf (fmt, ap);
+    if (msg == NULL)
       {
 	  va_end (ap);
 	  return;
       }
-    spatialite_e ("LWGEOM error: %s\n", msg);
+    if (strlen (msg) > 1)
+	spatialite_e ("LWGEOM error: %s\n", msg);
     gaiaSetLwGeomErrorMsg (msg);
-    free (msg);
+    sqlite3_free (msg);
+}
+
+static void
+lwgaiatopo_errorreporter (const char *fmt, va_list ap)
+{
+    char *msg = sqlite3_vmprintf (fmt, ap);
+    if (msg == NULL)
+      {
+	  va_end (ap);
+	  return;
+      }
+    if (strlen (msg) > 1)
+	gaiaSetLwGeomErrorMsg (msg);
+    sqlite3_free (msg);
 }
 
 #ifndef POSTGIS_2_1
@@ -136,6 +167,13 @@ splite_lwgeom_init (void)
     lwgeom_set_handlers (NULL, NULL, NULL, lwgaia_errorreporter,
 			 lwgaia_noticereporter);
 }
+
+SPATIALITE_PRIVATE void
+splite_lwgeomtopo_init (void)
+{
+    lwgeom_set_handlers (NULL, NULL, NULL, lwgaiatopo_errorreporter,
+			 lwgaiatopo_noticereporter);
+}
 #endif
 
 GAIAGEO_DECLARE void
@@ -738,8 +776,8 @@ toLWGeom (const gaiaGeomCollPtr gaia)
 			      }
 			    else if (gaia->DimensionModel == GAIA_XY_Z_M)
 			      {
-				  gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z,
-						    &m);
+				  gaiaGetPointXYZM (rng->Coords, 0, &x, &y,
+						    &z, &m);
 			      }
 			    else
 			      {
@@ -1543,11 +1581,6 @@ check_split_args (gaiaGeomCollPtr input, gaiaGeomCollPtr blade)
 	  b_pts++;
 	  pt = pt->Next;
       }
-    if (b_pts > 1)
-      {
-	  /* MultiPoint on Blade is forbidden !!!! */
-	  return 0;
-      }
     ln = blade->FirstLinestring;
     while (ln)
       {
@@ -1555,11 +1588,6 @@ check_split_args (gaiaGeomCollPtr input, gaiaGeomCollPtr blade)
 	  b_lns++;
 	  ln = ln->Next;
       }
-    if (b_lns > 1)
-      {
-	  /* MultiLinestring on Blade is forbidden !!!! */
-	  return 0;
-      }
     if (blade->FirstPolygon != NULL)
       {
 	  /* Polygon(s) on Blade is forbidden !!!! */
@@ -1570,19 +1598,19 @@ check_split_args (gaiaGeomCollPtr input, gaiaGeomCollPtr blade)
 	  /* empty Blade */
 	  return 0;
       }
-    if (b_pts + b_lns > 1)
+    if (b_pts >= 1 && b_lns >= 1)
       {
 	  /* invalid Blade [point + linestring] */
 	  return 0;
       }
 
 /* compatibility check */
-    if (b_lns == 1)
+    if (b_lns >= 1)
       {
 	  /* Linestring blade is always valid */
 	  return 1;
       }
-    if (i_lns >= 1 && b_pts == 1)
+    if (i_lns >= 1 && b_pts >= 1)
       {
 	  /* Linestring or MultiLinestring input and Point blade is allowed */
 	  return 1;
@@ -2387,6 +2415,82 @@ gaia3DMaxDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, double *dist)
     return ret;
 }
 
+static LWLINE *
+linestring2lwline (gaiaLinestringPtr ln, int srid)
+{
+/* converting a Linestring into an LWLINE */
+    POINTARRAY *pa;
+    POINT4D point;
+    int iv;
+    double x;
+    double y;
+    double z;
+    double m;
+    int has_z = 0;
+
+    if (ln->DimensionModel == GAIA_XY_Z || ln->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+
+    pa = ptarray_construct (has_z, 0, ln->Points);
+    for (iv = 0; iv < ln->Points; iv++)
+      {
+	  /* copying vertices */
+	  if (ln->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (ln->Coords, iv, &x, &y);
+	    }
+	  point.x = x;
+	  point.y = y;
+	  if (has_z)
+	      point.z = z;
+	  else
+	      point.z = 0.0;
+	  point.m = 0.0;
+	  ptarray_set_point4d (pa, iv, &point);
+      }
+    return lwline_construct (srid, NULL, pa);
+}
+
+GAIAGEO_DECLARE int
+gaia3dLength (gaiaGeomCollPtr geom, double *length)
+{
+/* wrapping LWGEOM lwline_length */
+    LWLINE *line;
+    gaiaLinestringPtr ln;
+    double l = 0.0;
+    int ret = 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    ln = geom->FirstLinestring;
+    while (ln != NULL)
+      {
+	  ret = 1;
+	  line = linestring2lwline (ln, geom->Srid);
+	  l += lwgeom_length ((LWGEOM *) line);
+	  lwline_free (line);
+	  ln = ln->Next;
+      }
+    *length = l;
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+    return ret;
+}
+
 GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaNodeLines (gaiaGeomCollPtr geom)
 {
diff --git a/src/gaiageo/gg_relations.c b/src/gaiageo/gg_relations.c
index dcd1261..81370c0 100644
--- a/src/gaiageo/gg_relations.c
+++ b/src/gaiageo/gg_relations.c
@@ -56,6 +56,11 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #endif
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -73,11 +78,13 @@ SPATIALITE_PRIVATE void
 splite_free_geos_cache_item (struct splite_geos_cache_item *p)
 {
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     if (p->preparedGeosGeom)
 	GEOSPreparedGeom_destroy (p->preparedGeosGeom);
     if (p->geosGeom)
 	GEOSGeom_destroy (p->geosGeom);
 #endif
+#endif
     p->geosGeom = NULL;
     p->preparedGeosGeom = NULL;
 }
@@ -482,7 +489,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollEquals (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if two Geometries are "spatially equal" */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -500,6 +508,10 @@ gaiaGeomCollEquals (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSEquals (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -544,7 +556,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollIntersects (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if two Geometries do "spatially intersects" */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -562,6 +575,10 @@ gaiaGeomCollIntersects (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSIntersects (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -656,7 +673,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollDisjoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if two Geometries are "spatially disjoint" */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -674,6 +692,10 @@ gaiaGeomCollDisjoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSDisjoint (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -769,7 +791,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollOverlaps (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if two Geometries do "spatially overlaps" */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -787,6 +810,10 @@ gaiaGeomCollOverlaps (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSOverlaps (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -882,7 +909,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollCrosses (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if two Geometries do "spatially crosses" */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -900,6 +928,10 @@ gaiaGeomCollCrosses (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSCrosses (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -995,7 +1027,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollTouches (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if two Geometries do "spatially touches" */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -1013,6 +1046,10 @@ gaiaGeomCollTouches (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSTouches (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1108,7 +1145,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollWithin (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if GEOM-1 is completely contained within GEOM-2 */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -1126,6 +1164,10 @@ gaiaGeomCollWithin (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSWithin (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1224,7 +1266,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollContains (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if GEOM-1 completely contains GEOM-2 */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -1242,6 +1285,10 @@ gaiaGeomCollContains (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     ret = GEOSContains (g1, g2);
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1341,7 +1388,8 @@ gaiaGeomCollRelate (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
 		    const char *pattern)
 {
 /* checks if if GEOM-1 and GEOM-2 have a spatial relationship as specified by the pattern Matrix */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -1356,6 +1404,10 @@ gaiaGeomCollRelate (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
     GEOSGeom_destroy (g2);
     if (ret == 2)
 	return -1;
+#else
+    if (geom1 == NULL || geom2 == NULL || pattern == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1397,8 +1449,9 @@ GAIAGEO_DECLARE int
 gaiaGeomCollLength (gaiaGeomCollPtr geom, double *xlength)
 {
 /* computes the total length for this Geometry */
+    int ret = 0;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     double length;
-    int ret;
     GEOSGeometry *g;
     gaiaResetGeosMsg ();
     if (!geom)
@@ -1410,6 +1463,10 @@ gaiaGeomCollLength (gaiaGeomCollPtr geom, double *xlength)
     GEOSGeom_destroy (g);
     if (ret)
 	*xlength = length;
+#else
+    if (geom == NULL || xlength == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1450,8 +1507,9 @@ gaiaGeomCollLengthOrPerimeter (gaiaGeomCollPtr geom, int perimeter,
 			       double *xlength)
 {
 /* computes the total length or perimeter for this Geometry */
+    int ret = 0;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     double length;
-    int ret;
     GEOSGeometry *g;
     int mode = GAIA2GEOS_ONLY_LINESTRINGS;
     if (perimeter)
@@ -1471,6 +1529,10 @@ gaiaGeomCollLengthOrPerimeter (gaiaGeomCollPtr geom, int perimeter,
     GEOSGeom_destroy (g);
     if (ret)
 	*xlength = length;
+#else
+    if (geom == NULL || perimeter == 0 || xlength == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1518,8 +1580,9 @@ GAIAGEO_DECLARE int
 gaiaGeomCollArea (gaiaGeomCollPtr geom, double *xarea)
 {
 /* computes the total area for this Geometry */
+    int ret = 0;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     double area;
-    int ret;
     GEOSGeometry *g;
     gaiaResetGeosMsg ();
     if (!geom)
@@ -1531,6 +1594,10 @@ gaiaGeomCollArea (gaiaGeomCollPtr geom, double *xarea)
     GEOSGeom_destroy (g);
     if (ret)
 	*xarea = area;
+#else
+    if (geom == NULL || xarea == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1570,8 +1637,9 @@ gaiaGeomCollDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
 		      double *xdist)
 {
 /* computes the minimum distance intercurring between GEOM-1 and GEOM-2 */
+    int ret = 0;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     double dist;
-    int ret;
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -1586,6 +1654,10 @@ gaiaGeomCollDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
     GEOSGeom_destroy (g2);
     if (ret)
 	*xdist = dist;
+#else
+    if (geom1 == NULL || geom2 == NULL || xdist == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1628,7 +1700,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeometryIntersection (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* builds a new geometry representing the "spatial intersection" of GEOM-1 and GEOM-2 */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     GEOSGeometry *g3;
@@ -1661,6 +1734,10 @@ gaiaGeometryIntersection (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom1->Srid;
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -1720,7 +1797,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeometryUnion (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* builds a new geometry representing the "spatial union" of GEOM-1 and GEOM-2 */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     GEOSGeometry *g3;
@@ -1755,6 +1833,10 @@ gaiaGeometryUnion (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     if (geo->DeclaredType == GAIA_POLYGON &&
 	geom1->DeclaredType == GAIA_MULTIPOLYGON)
 	geo->DeclaredType = GAIA_MULTIPOLYGON;
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -1816,9 +1898,10 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaUnionCascaded (gaiaGeomCollPtr geom)
 {
 /* UnionCascaded (single Collection of polygons) */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
-    gaiaGeomCollPtr result;
     int pts = 0;
     int lns = 0;
     int pgs = 0;
@@ -1872,6 +1955,10 @@ gaiaUnionCascaded (gaiaGeomCollPtr geom)
     if (result == NULL)
 	return NULL;
     result->Srid = geom->Srid;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -1953,7 +2040,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeometryDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* builds a new geometry representing the "spatial difference" of GEOM-1 and GEOM-2 */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     GEOSGeometry *g3;
@@ -1981,6 +2069,10 @@ gaiaGeometryDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom1->Srid;
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -2035,7 +2127,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeometrySymDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* builds a new geometry representing the "spatial symmetric difference" of GEOM-1 and GEOM-2 */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     GEOSGeometry *g3;
@@ -2063,6 +2156,10 @@ gaiaGeometrySymDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom1->Srid;
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -2117,7 +2214,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaBoundary (gaiaGeomCollPtr geom)
 {
 /* builds a new geometry representing the combinatorial boundary of GEOM */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -2142,6 +2240,10 @@ gaiaBoundary (gaiaGeomCollPtr geom)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -2192,6 +2294,7 @@ GAIAGEO_DECLARE int
 gaiaGeomCollCentroid (gaiaGeomCollPtr geom, double *x, double *y)
 {
 /* returns a Point representing the centroid for this Geometry */
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     gaiaGeomCollPtr geo;
     GEOSGeometry *g1;
     GEOSGeometry *g2;
@@ -2226,6 +2329,10 @@ gaiaGeomCollCentroid (gaiaGeomCollPtr geom, double *x, double *y)
 	  return 1;
       }
     gaiaFreeGeomColl (geo);
+#else
+    if (geom == NULL || x == NULL || y == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return 0;
 }
 
@@ -2286,6 +2393,7 @@ GAIAGEO_DECLARE int
 gaiaGetPointOnSurface (gaiaGeomCollPtr geom, double *x, double *y)
 {
 /* returns a Point guaranteed to lie on the Surface */
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     gaiaGeomCollPtr geo;
     GEOSGeometry *g1;
     GEOSGeometry *g2;
@@ -2320,6 +2428,10 @@ gaiaGetPointOnSurface (gaiaGeomCollPtr geom, double *x, double *y)
 	  return 1;
       }
     gaiaFreeGeomColl (geo);
+#else
+    if (geom == NULL || x == NULL || y == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return 0;
 }
 
@@ -2361,7 +2473,7 @@ gaiaGetPointOnSurface_r (const void *p_cache, gaiaGeomCollPtr geom, double *x,
     else if (geom->DimensionModel == GAIA_XY_Z_M)
 	geo = gaiaFromGeos_XYZM_r (cache, g2);
     else
-	geo = gaiaFromGeos_XY_r (cache, g2);
+	geo = gaiaFromGeos_XYZ_r (cache, g2);
     GEOSGeom_destroy_r (handle, g2);
     if (geo == NULL)
 	return 0;
@@ -2380,7 +2492,8 @@ GAIAGEO_DECLARE int
 gaiaIsSimple (gaiaGeomCollPtr geom)
 {
 /* checks if this GEOMETRYCOLLECTION is a simple one */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g;
     gaiaResetGeosMsg ();
     if (!geom)
@@ -2392,6 +2505,10 @@ gaiaIsSimple (gaiaGeomCollPtr geom)
     GEOSGeom_destroy (g);
     if (ret == 2)
 	return -1;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -2429,9 +2546,10 @@ GAIAGEO_DECLARE int
 gaiaIsRing (gaiaLinestringPtr line)
 {
 /* checks if this LINESTRING can be a valid RING */
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     gaiaGeomCollPtr geo;
     gaiaLinestringPtr line2;
-    int ret;
     int iv;
     double x;
     double y;
@@ -2498,6 +2616,10 @@ gaiaIsRing (gaiaLinestringPtr line)
     GEOSGeom_destroy (g);
     if (ret == 2)
 	return -1;
+#else
+    if (line == NULL)
+	line = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -2592,7 +2714,8 @@ GAIAGEO_DECLARE int
 gaiaIsValid (gaiaGeomCollPtr geom)
 {
 /* checks if this GEOMETRYCOLLECTION is a valid one */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g;
     gaiaResetGeosMsg ();
     if (!geom)
@@ -2606,6 +2729,10 @@ gaiaIsValid (gaiaGeomCollPtr geom)
     GEOSGeom_destroy (g);
     if (ret == 2)
 	return -1;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -2646,7 +2773,8 @@ gaiaIsValidReason (gaiaGeomCollPtr geom)
 {
 /* return a TEXT string stating if a Geometry is valid
 / and if not valid, a reason why */
-    char *text;
+    char *text = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     int len;
     const char *str;
     char *gstr;
@@ -2685,6 +2813,10 @@ gaiaIsValidReason (gaiaGeomCollPtr geom)
     text = malloc (len + 1);
     strcpy (text, gstr);
     GEOSFree (gstr);
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return text;
 }
 
@@ -2726,7 +2858,7 @@ gaiaIsValidReason_r (const void *p_cache, gaiaGeomCollPtr geom)
 	  strcpy (text, str);
 	  return text;
       }
-    if (gaiaIsNotClosedGeomColl (geom))
+    if (gaiaIsNotClosedGeomColl_r (cache, geom))
       {
 	  str = "Invalid: Unclosed Rings were detected";
 	  len = strlen (str);
@@ -2750,10 +2882,11 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaIsValidDetail (gaiaGeomCollPtr geom)
 {
 /* return a Geometry detail causing a Geometry to be invalid */
+    gaiaGeomCollPtr detail = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     char *reason = NULL;
     GEOSGeometry *g;
     GEOSGeometry *d = NULL;
-    gaiaGeomCollPtr detail;
     gaiaResetGeosMsg ();
     if (!geom)
 	return NULL;
@@ -2770,6 +2903,10 @@ gaiaIsValidDetail (gaiaGeomCollPtr geom)
 	return NULL;
     detail = gaiaFromGeos_XY (d);
     GEOSGeom_destroy (d);
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return detail;
 }
 
@@ -2797,7 +2934,7 @@ gaiaIsValidDetail_r (const void *p_cache, gaiaGeomCollPtr geom)
 	return NULL;
     if (gaiaIsToxic (geom))
 	return NULL;
-    if (gaiaIsNotClosedGeomColl (geom))
+    if (gaiaIsNotClosedGeomColl_r (cache, geom))
 	return NULL;
     g = gaiaToGeos_r (cache, geom);
     GEOSisValidDetail_r (handle, g, 0, &reason, &d);
@@ -2880,7 +3017,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeomCollSimplify (gaiaGeomCollPtr geom, double tolerance)
 {
 /* builds a simplified geometry using the Douglas-Peuker algorihtm */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -2905,6 +3043,10 @@ gaiaGeomCollSimplify (gaiaGeomCollPtr geom, double tolerance)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL || tolerance == 0.0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -2956,7 +3098,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeomCollSimplifyPreserveTopology (gaiaGeomCollPtr geom, double tolerance)
 {
 /* builds a simplified geometry using the Douglas-Peuker algorihtm [preserving topology] */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -2981,6 +3124,10 @@ gaiaGeomCollSimplifyPreserveTopology (gaiaGeomCollPtr geom, double tolerance)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL || tolerance == 0.0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -3032,7 +3179,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaConvexHull (gaiaGeomCollPtr geom)
 {
 /* builds a geometry that is the convex hull of GEOM */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -3057,6 +3205,10 @@ gaiaConvexHull (gaiaGeomCollPtr geom)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -3107,7 +3259,8 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaGeomCollBuffer (gaiaGeomCollPtr geom, double radius, int points)
 {
 /* builds a geometry that is the GIS buffer of GEOM */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -3132,6 +3285,10 @@ gaiaGeomCollBuffer (gaiaGeomCollPtr geom, double radius, int points)
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL || radius == 0.0 || points == 0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -3197,6 +3354,11 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
     gaiaPolygonPtr pg;
     gaiaRingPtr rng;
 
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return;
+#endif
+
     if (handle != NULL)
       {
 	  geos_ring = GEOSGetExteriorRing_r (handle, geos);
@@ -3207,11 +3369,13 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  geos_ring = GEOSGetExteriorRing (geos);
 	  interiors = GEOSGetNumInteriorRings (geos);
 	  coords = GEOSGeom_getCoordSeq (geos_ring);
 	  GEOSCoordSeq_getDimensions (coords, &geos_dims);
 	  GEOSCoordSeq_getSize (coords, &pts);
+#endif
       }
 
     pg = gaiaAddPolygonToGeomColl (result, pts, interiors);
@@ -3229,9 +3393,11 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      GEOSCoordSeq_getX (coords, iv, &x);
 		      GEOSCoordSeq_getY (coords, iv, &y);
 		      GEOSCoordSeq_getZ (coords, iv, &z);
+#endif
 		  }
 	    }
 	  else
@@ -3243,8 +3409,10 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      GEOSCoordSeq_getX (coords, iv, &x);
 		      GEOSCoordSeq_getY (coords, iv, &y);
+#endif
 		  }
 		z = 0.0;
 	    }
@@ -3278,10 +3446,12 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		geos_ring = GEOSGetInteriorRingN (geos, ib);
 		coords = GEOSGeom_getCoordSeq (geos_ring);
 		GEOSCoordSeq_getDimensions (coords, &geos_dims);
 		GEOSCoordSeq_getSize (coords, &pts);
+#endif
 	    }
 	  rng = gaiaAddInteriorRing (pg, ib, pts);
 	  for (iv = 0; iv < (int) pts; iv++)
@@ -3296,9 +3466,11 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_getX (coords, iv, &x);
 			    GEOSCoordSeq_getY (coords, iv, &y);
 			    GEOSCoordSeq_getZ (coords, iv, &z);
+#endif
 			}
 		  }
 		else
@@ -3310,8 +3482,10 @@ auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_getX (coords, iv, &x);
 			    GEOSCoordSeq_getY (coords, iv, &y);
+#endif
 			}
 		      z = 0.0;
 		  }
@@ -3357,8 +3531,10 @@ auxGeosMbr (GEOSContextHandle_t handle, const GEOSCoordSequence * cs,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		GEOSCoordSeq_getX (cs, iv, &x);
 		GEOSCoordSeq_getY (cs, iv, &y);
+#endif
 	    }
 	  if (x < *min_x)
 	      *min_x = x;
@@ -3415,14 +3591,22 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
     double max_y2;
     int ret;
 
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!geom)
 	return NULL;
+
     if (cache != NULL)
 	ret = gaiaIsToxic_r (cache, geom);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
 	ret = gaiaIsToxic (geom);
+#endif
     if (ret)
 	return NULL;
+
     pt = geom->FirstPoint;
     while (pt)
       {
@@ -3465,8 +3649,10 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
       {
 	  if (handle != NULL)
 	      cs = GEOSCoordSeq_create_r (handle, ln->Points, geos_dims);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      cs = GEOSCoordSeq_create (ln->Points, geos_dims);
+#endif
 	  for (iv = 0; iv < ln->Points; iv++)
 	    {
 		/* exterior ring segments */
@@ -3497,9 +3683,11 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_setX (cs, iv, x);
 			    GEOSCoordSeq_setY (cs, iv, y);
 			    GEOSCoordSeq_setZ (cs, iv, z);
+#endif
 			}
 		  }
 		else
@@ -3511,23 +3699,29 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    GEOSCoordSeq_setX (cs, iv, x);
 			    GEOSCoordSeq_setY (cs, iv, y);
+#endif
 			}
 		  }
 	    }
 	  if (handle != NULL)
 	      *p_item++ = GEOSGeom_createLineString_r (handle, cs);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      *p_item++ = GEOSGeom_createLineString (cs);
+#endif
 	  ln = ln->Next;
       }
 
 /* calling GEOSPolygonize */
     if (handle != NULL)
 	geos = GEOSPolygonize_r (handle, geos_list, lns);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
 	geos = GEOSPolygonize (geos_list, lns);
+#endif
     if (geos == NULL)
 	goto cleanup;
 
@@ -3544,8 +3738,10 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
     error = 0;
     if (handle != NULL)
 	items = GEOSGetNumGeometries_r (handle, geos);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
 	items = GEOSGetNumGeometries (geos);
+#endif
     for (ig = 0; ig < items; ig++)
       {
 	  /* looping on elementaty GEOS geometries */
@@ -3561,6 +3757,7 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		geos_item = GEOSGetGeometryN (geos, ig);
 		if (GEOSGeomTypeId (geos_item) != GEOS_POLYGON)
 		  {
@@ -3568,6 +3765,7 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 		      error = 1;
 		      goto cleanup;
 		  }
+#endif
 	    }
       }
 
@@ -3585,8 +3783,10 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		geos_item = GEOSGetGeometryN (geos, ig);
 		interiors = GEOSGetNumInteriorRings (geos_item);
+#endif
 	    }
 	  for (ib = 0; ib < interiors; ib++)
 	    {
@@ -3600,9 +3800,11 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      geos_ring = GEOSGetInteriorRingN (geos_item, ib);
 		      coords = GEOSGeom_getCoordSeq (geos_ring);
 		      GEOSCoordSeq_getSize (coords, &pts1);
+#endif
 		  }
 		auxGeosMbr (handle, coords, pts1, &min_x1, &min_y1, &max_x1,
 			    &max_y1);
@@ -3634,6 +3836,7 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    geos_item2 = GEOSGetGeometryN (geos, iv);
 			    if (GEOSGetNumInteriorRings (geos_item2) > 0)
 			      {
@@ -3643,6 +3846,7 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 			    geos_ring = GEOSGetExteriorRing (geos_item2);
 			    coords = GEOSGeom_getCoordSeq (geos_ring);
 			    GEOSCoordSeq_getSize (coords, &pts2);
+#endif
 			}
 		      if (pts1 == pts2)
 			{
@@ -3679,8 +3883,10 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 	  /* looping on GEOS Polygons */
 	  if (handle != NULL)
 	      geos_item = GEOSGetGeometryN_r (handle, geos, ig);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      geos_item = GEOSGetGeometryN (geos, ig);
+#endif
 	  if (valid_polygons[ig] == 'Y')
 	      auxFromGeosPolygon (handle, geos_item, result);
       }
@@ -3698,8 +3904,10 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
 		  {
 		      if (handle != NULL)
 			  GEOSGeom_destroy_r (handle, *p_item);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      else
 			  GEOSGeom_destroy (*p_item);
+#endif
 		  }
 		p_item++;
 	    }
@@ -3710,8 +3918,10 @@ gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
       {
 	  if (handle != NULL)
 	      GEOSGeom_destroy_r (handle, geos);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      GEOSGeom_destroy (geos);
+#endif
       }
     if (error || result->FirstPolygon == NULL)
       {
@@ -3752,7 +3962,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollCovers (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if geom1 "spatially covers" geom2 */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -3770,6 +3981,10 @@ gaiaGeomCollCovers (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     GEOSGeom_destroy (g2);
     if (ret == 2)
 	return -1;
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -3870,7 +4085,8 @@ GAIAGEO_DECLARE int
 gaiaGeomCollCoveredBy (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
 /* checks if geom1 is "spatially covered by" geom2 */
-    int ret;
+    int ret = -1;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -3888,6 +4104,10 @@ gaiaGeomCollCoveredBy (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     GEOSGeom_destroy (g2);
     if (ret == 2)
 	return -1;
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
diff --git a/src/gaiageo/gg_relations_ext.c b/src/gaiageo/gg_relations_ext.c
index 5303c9b..b802643 100644
--- a/src/gaiageo/gg_relations_ext.c
+++ b/src/gaiageo/gg_relations_ext.c
@@ -56,6 +56,11 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #endif
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -75,7 +80,8 @@ gaiaOffsetCurve (gaiaGeomCollPtr geom, double radius, int points,
 // (which is expected to be of the LINESTRING type)
 //
 */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaPointPtr pt;
@@ -139,6 +145,10 @@ gaiaOffsetCurve (gaiaGeomCollPtr geom, double radius, int points,
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL || radius == 0.0 || points == 0 || left_right == 0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -239,7 +249,8 @@ gaiaSingleSidedBuffer (gaiaGeomCollPtr geom, double radius, int points,
 // (which is expected to be of the LINESTRING type)
 //
 */
-    gaiaGeomCollPtr geo;
+    gaiaGeomCollPtr geo = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     GEOSBufferParams *params = NULL;
@@ -315,6 +326,10 @@ gaiaSingleSidedBuffer (gaiaGeomCollPtr geom, double radius, int points,
     if (geo == NULL)
 	return NULL;
     geo->Srid = geom->Srid;
+#else
+    if (geom == NULL || radius == 0.0 || points == 0 || left_right == 0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return geo;
 }
 
@@ -425,8 +440,9 @@ gaiaHausdorffDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
 / computes the (discrete) Hausdorff distance intercurring 
 / between GEOM-1 and GEOM-2 
 */
+    int ret = 0;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     double dist;
-    int ret;
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaResetGeosMsg ();
@@ -439,6 +455,10 @@ gaiaHausdorffDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
     GEOSGeom_destroy (g2);
     if (ret)
 	*xdist = dist;
+#else
+    if (geom1 == NULL || geom2 == NULL || xdist == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return ret;
 }
 
@@ -1057,8 +1077,9 @@ gaiaSharedPaths (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 // (which are expected to be of the LINESTRING/MULTILINESTRING type)
 //
 */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     gaiaGeomCollPtr geo;
-    gaiaGeomCollPtr result;
     gaiaGeomCollPtr line1;
     gaiaGeomCollPtr line2;
     GEOSGeometry *g1;
@@ -1104,6 +1125,10 @@ gaiaSharedPaths (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     geo->Srid = geom1->Srid;
     result = arrange_shared_paths (geo);
     gaiaFreeGeomColl (geo);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -1185,10 +1210,11 @@ gaiaLineInterpolatePoint (gaiaGeomCollPtr geom, double fraction)
  *
  * the fraction is expressed into the range from 0.0 to 1.0
  */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     int pts = 0;
     int lns = 0;
     int pgs = 0;
-    gaiaGeomCollPtr result;
     gaiaPointPtr pt;
     gaiaLinestringPtr ln;
     gaiaPolygonPtr pg;
@@ -1255,6 +1281,10 @@ gaiaLineInterpolatePoint (gaiaGeomCollPtr geom, double fraction)
     if (result == NULL)
 	return NULL;
     result->Srid = geom->Srid;
+#else
+    if (geom == NULL || fraction == 0.0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -1372,6 +1402,7 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
     double length;
     double current_length = 0.0;
     GEOSContextHandle_t handle = NULL;
+
     if (cache != NULL)
       {
 	  if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
@@ -1381,6 +1412,10 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
 	  if (handle == NULL)
 	      return NULL;
       }
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!geom)
 	return NULL;
     if (distance <= 0.0)
@@ -1430,6 +1465,7 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  g = gaiaToGeos (geom);
 	  if (GEOSLength (g, &length))
 	    {
@@ -1445,6 +1481,7 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
 		GEOSGeom_destroy (g);
 		return NULL;
 	    }
+#endif
       }
 
 /* creating the MultiPoint [always supporting M] */
@@ -1455,8 +1492,18 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
 	result = gaiaAllocGeomCollXYM ();
     if (result == NULL)
       {
-	  GEOSGeom_destroy (g);
-	  return NULL;
+	  if (cache != NULL)
+	    {
+		GEOSGeom_destroy_r (handle, g);
+		return NULL;
+	    }
+	  else
+	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+		GEOSGeom_destroy (g);
+		return NULL;
+#endif
+	    }
       }
 
     while (1)
@@ -1468,8 +1515,10 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
 	  /* interpolating a point */
 	  if (handle != NULL)
 	      g_pt = GEOSInterpolate_r (handle, g, current_length);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      g_pt = GEOSInterpolate (g, current_length);
+#endif
 	  if (!g_pt)
 	      goto error;
 	  if (geom->DimensionModel == GAIA_XY_Z)
@@ -1530,14 +1579,18 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
 	    }
 	  if (handle != NULL)
 	      GEOSGeom_destroy_r (handle, g_pt);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  else
 	      GEOSGeom_destroy (g_pt);
+#endif
 	  gaiaFreeGeomColl (xpt);
       }
     if (handle != NULL)
 	GEOSGeom_destroy_r (handle, g);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
 	GEOSGeom_destroy (g);
+#endif
     result->Srid = geom->Srid;
     result->DeclaredType = GAIA_MULTIPOINT;
     return result;
@@ -1551,9 +1604,11 @@ gaiaLineInterpolateEquidistantPointsCommon (struct splite_internal_cache *cache,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  if (g_pt)
 	      GEOSGeom_destroy (g_pt);
 	  GEOSGeom_destroy (g);
+#endif
       }
     gaiaFreeGeomColl (result);
     return NULL;
@@ -1594,6 +1649,8 @@ gaiaLineLocatePoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
  *
  * the fraction is expressed into the range from 0.0 to 1.0
  */
+    double result = -1.0;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     int pts1 = 0;
     int lns1 = 0;
     int pgs1 = 0;
@@ -1602,7 +1659,6 @@ gaiaLineLocatePoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
     int pgs2 = 0;
     double length;
     double projection;
-    double result;
     gaiaPointPtr pt;
     gaiaLinestringPtr ln;
     gaiaPolygonPtr pg;
@@ -1672,6 +1728,10 @@ gaiaLineLocatePoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 	result = -1.0;
     GEOSGeom_destroy (g1);
     GEOSGeom_destroy (g2);
+#else
+    if (geom1 == NULL || geom2 == NULL)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -1814,6 +1874,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
     double m;
     unsigned int dims;
     GEOSContextHandle_t handle = NULL;
+
     if (cache != NULL)
       {
 	  if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
@@ -1823,6 +1884,10 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
 	  if (handle == NULL)
 	      return NULL;
       }
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!geom)
 	return NULL;
 
@@ -1879,6 +1944,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  g = gaiaToGeos (geom);
 	  if (GEOSLength (g, &length))
 	    {
@@ -1893,6 +1959,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
 	  g_start = GEOSInterpolate (g, start);
 	  g_end = GEOSInterpolate (g, end);
 	  GEOSGeom_destroy (g);
+#endif
       }
     if (!g_start || !g_end)
 	return NULL;
@@ -1936,6 +2003,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      cs = GEOSCoordSeq_create (2, 2);
 		      GEOSCoordSeq_setX (cs, 0, x0);
 		      GEOSCoordSeq_setY (cs, 0, y0);
@@ -1945,6 +2013,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
 		      GEOSLength (segm, &length);
 		      total += length;
 		      GEOSGeom_destroy (segm);
+#endif
 		  }
 		if (total > start && i_start < 0)
 		    i_start = iv;
@@ -2006,6 +2075,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  in_cs = GEOSGeom_getCoordSeq (g_start);
 	  GEOSCoordSeq_getDimensions (in_cs, &dims);
 	  if (dims == 3)
@@ -2023,6 +2093,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
 		m = 0.0;
 	    }
 	  GEOSGeom_destroy (g_start);
+#endif
       }
     switch (out->DimensionModel)
       {
@@ -2106,6 +2177,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  in_cs = GEOSGeom_getCoordSeq (g_end);
 	  GEOSCoordSeq_getDimensions (in_cs, &dims);
 	  if (dims == 3)
@@ -2123,6 +2195,7 @@ gaiaLineSubstringCommon (struct splite_internal_cache *cache,
 		m = 0.0;
 	    }
 	  GEOSGeom_destroy (g_end);
+#endif
       }
     switch (out->DimensionModel)
       {
@@ -2186,12 +2259,18 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
     gaiaLinestringPtr ln;
     gaiaPolygonPtr pg;
     gaiaRingPtr rng;
-    GEOSGeometry *geos;
+    GEOSGeometry *geos = NULL;
     GEOSGeometry *geos_item;
     GEOSGeometry **geos_coll;
     GEOSCoordSequence *cs;
+
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!gaia)
 	return NULL;
+
     pt = gaia->FirstPoint;
     while (pt)
       {
@@ -2257,6 +2336,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		cs = GEOSCoordSeq_create (1, dims);
 		switch (pt->DimensionModel)
 		  {
@@ -2272,6 +2352,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 		      break;
 		  };
 		geos_item = GEOSGeom_createPoint (cs);
+#endif
 	    }
 	  *(geos_coll + nItem++) = geos_item;
 	  pt = pt->Next;
@@ -2316,6 +2397,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      cs = GEOSCoordSeq_create (1, dims);
 		      if (dims == 3)
 			{
@@ -2329,6 +2411,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 			    GEOSCoordSeq_setY (cs, 0, y);
 			}
 		      geos_item = GEOSGeom_createPoint (cs);
+#endif
 		  }
 		*(geos_coll + nItem++) = geos_item;
 	    }
@@ -2376,6 +2459,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 		  }
 		else
 		  {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		      cs = GEOSCoordSeq_create (1, dims);
 		      if (dims == 3)
 			{
@@ -2389,6 +2473,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 			    GEOSCoordSeq_setY (cs, 0, y);
 			}
 		      geos_item = GEOSGeom_createPoint (cs);
+#endif
 		  }
 		*(geos_coll + nItem++) = geos_item;
 	    }
@@ -2434,6 +2519,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    cs = GEOSCoordSeq_create (1, dims);
 			    if (dims == 3)
 			      {
@@ -2447,6 +2533,7 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 				  GEOSCoordSeq_setY (cs, 0, y);
 			      }
 			    geos_item = GEOSGeom_createPoint (cs);
+#endif
 			}
 		      *(geos_coll + nItem++) = geos_item;
 		  }
@@ -2461,12 +2548,14 @@ buildGeosPoints (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 	  free (geos_coll);
 	  GEOSSetSRID_r (handle, geos, gaia->Srid);
       }
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
       {
 	  geos = GEOSGeom_createCollection (GEOS_MULTIPOINT, geos_coll, pts);
 	  free (geos_coll);
 	  GEOSSetSRID (geos, gaia->Srid);
       }
+#endif
     return geos;
 }
 
@@ -2489,12 +2578,18 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
     gaiaLinestringPtr ln;
     gaiaPolygonPtr pg;
     gaiaRingPtr rng;
-    GEOSGeometry *geos;
+    GEOSGeometry *geos = NULL;
     GEOSGeometry *geos_item;
     GEOSGeometry **geos_coll;
     GEOSCoordSequence *cs;
+
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!gaia)
 	return NULL;
+
     ln = gaia->FirstLinestring;
     while (ln)
       {
@@ -2578,6 +2673,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    cs = GEOSCoordSeq_create (2, dims);
 			    if (dims == 3)
 			      {
@@ -2596,6 +2692,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 				  GEOSCoordSeq_setY (cs, 1, y);
 			      }
 			    geos_item = GEOSGeom_createLineString (cs);
+#endif
 			}
 		      *(geos_coll + nItem++) = geos_item;
 		  }
@@ -2655,6 +2752,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    cs = GEOSCoordSeq_create (2, dims);
 			    if (dims == 3)
 			      {
@@ -2673,6 +2771,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 				  GEOSCoordSeq_setY (cs, 1, y);
 			      }
 			    geos_item = GEOSGeom_createLineString (cs);
+#endif
 			}
 		      *(geos_coll + nItem++) = geos_item;
 		  }
@@ -2730,6 +2829,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 			      }
 			    else
 			      {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 				  cs = GEOSCoordSeq_create (2, dims);
 				  if (dims == 3)
 				    {
@@ -2748,6 +2848,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 					GEOSCoordSeq_setY (cs, 1, y);
 				    }
 				  geos_item = GEOSGeom_createLineString (cs);
+#endif
 			      }
 			    *(geos_coll + nItem++) = geos_item;
 			}
@@ -2766,6 +2867,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 	  free (geos_coll);
 	  GEOSSetSRID_r (handle, geos, gaia->Srid);
       }
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     else
       {
 	  geos =
@@ -2774,6 +2876,7 @@ buildGeosSegments (GEOSContextHandle_t handle, const gaiaGeomCollPtr gaia)
 	  free (geos_coll);
 	  GEOSSetSRID (geos, gaia->Srid);
       }
+#endif
     return geos;
 }
 
@@ -2781,7 +2884,7 @@ static gaiaGeomCollPtr
 gaiaShortestLineCommon (struct splite_internal_cache *cache,
 			gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
 {
-/* attempts to compute the the shortest line between two geometries */
+/* attempts to compute the shortest line between two geometries */
     GEOSGeometry *g1_points;
     GEOSGeometry *g1_segments;
     const GEOSGeometry *g1_item;
@@ -2790,7 +2893,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
     const GEOSGeometry *g2_item;
     const GEOSCoordSequence *cs;
     GEOSGeometry *g_pt;
-    gaiaGeomCollPtr result;
+    gaiaGeomCollPtr result = NULL;
     gaiaLinestringPtr ln;
     int nItems1;
     int nItems2;
@@ -2807,6 +2910,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
     double min_dist = DBL_MAX;
     double projection;
     GEOSContextHandle_t handle = NULL;
+
     if (cache != NULL)
       {
 	  if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
@@ -2816,6 +2920,10 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 	  if (handle == NULL)
 	      return NULL;
       }
+#ifdef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
+    if (handle == NULL)
+	return NULL;
+#endif
     if (!geom1 || !geom2)
 	return NULL;
 
@@ -2834,15 +2942,19 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		nItems1 = GEOSGetNumGeometries (g1_points);
 		nItems2 = GEOSGetNumGeometries (g2_points);
+#endif
 	    }
 	  for (it1 = 0; it1 < nItems1; it1++)
 	    {
 		if (handle != NULL)
 		    g1_item = GEOSGetGeometryN_r (handle, g1_points, it1);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    g1_item = GEOSGetGeometryN (g1_points, it1);
+#endif
 		for (it2 = 0; it2 < nItems2; it2++)
 		  {
 		      int distret;
@@ -2856,8 +2968,10 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    g2_item = GEOSGetGeometryN (g2_points, it2);
 			    distret = GEOSDistance (g1_item, g2_item, &dist);
+#endif
 			}
 		      if (distret)
 			{
@@ -2914,6 +3028,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					cs = GEOSGeom_getCoordSeq (g1_item);
 					GEOSCoordSeq_getDimensions (cs, &dims);
 					if (dims == 3)
@@ -2942,6 +3057,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 					      GEOSCoordSeq_getY (cs, 0, &y_fin);
 					      z_fin = 0.0;
 					  }
+#endif
 				    }
 			      }
 			}
@@ -2959,15 +3075,19 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		nItems1 = GEOSGetNumGeometries (g1_points);
 		nItems2 = GEOSGetNumGeometries (g2_segments);
+#endif
 	    }
 	  for (it1 = 0; it1 < nItems1; it1++)
 	    {
 		if (handle != NULL)
 		    g1_item = GEOSGetGeometryN_r (handle, g1_points, it1);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    g1_item = GEOSGetGeometryN (g1_points, it1);
+#endif
 		for (it2 = 0; it2 < nItems2; it2++)
 		  {
 		      int distret;
@@ -2981,8 +3101,10 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    g2_item = GEOSGetGeometryN (g2_segments, it2);
 			    distret = GEOSDistance (g1_item, g2_item, &dist);
+#endif
 			}
 		      if (distret)
 			{
@@ -3057,6 +3179,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					projection =
 					    GEOSProject (g2_item, g1_item);
 					g_pt =
@@ -3108,6 +3231,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 						}
 					      GEOSGeom_destroy (g_pt);
 					  }
+#endif
 				    }
 			      }
 			}
@@ -3125,15 +3249,19 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 	    }
 	  else
 	    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		nItems1 = GEOSGetNumGeometries (g1_segments);
 		nItems2 = GEOSGetNumGeometries (g2_points);
+#endif
 	    }
 	  for (it1 = 0; it1 < nItems1; it1++)
 	    {
 		if (handle != NULL)
 		    g1_item = GEOSGetGeometryN_r (handle, g1_segments, it1);
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 		else
 		    g1_item = GEOSGetGeometryN (g1_segments, it1);
+#endif
 		for (it2 = 0; it2 < nItems2; it2++)
 		  {
 		      int distret;
@@ -3147,8 +3275,10 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 			}
 		      else
 			{
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 			    g2_item = GEOSGetGeometryN (g2_points, it2);
 			    distret = GEOSDistance (g1_item, g2_item, &dist);
+#endif
 			}
 		      if (distret)
 			{
@@ -3223,6 +3353,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 				    }
 				  else
 				    {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 					projection =
 					    GEOSProject (g1_item, g2_item);
 					g_pt =
@@ -3274,6 +3405,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 						}
 					      GEOSGeom_destroy (g_pt);
 					  }
+#endif
 				    }
 			      }
 			}
@@ -3293,6 +3425,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
       }
     else
       {
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
 	  if (g1_points)
 	      GEOSGeom_destroy (g1_points);
 	  if (g1_segments)
@@ -3301,6 +3434,7 @@ gaiaShortestLineCommon (struct splite_internal_cache *cache,
 	      GEOSGeom_destroy (g2_points);
 	  if (g2_segments)
 	      GEOSGeom_destroy (g2_segments);
+#endif
       }
     if (min_dist == DBL_MAX || min_dist <= 0.0)
 	return NULL;
@@ -3375,10 +3509,11 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaSnap (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, double tolerance)
 {
 /* attempts to "snap" geom1 on geom2 using the given tolerance */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     GEOSGeometry *g3;
-    gaiaGeomCollPtr result;
     gaiaResetGeosMsg ();
     if (!geom1 || !geom2)
 	return NULL;
@@ -3402,6 +3537,10 @@ gaiaSnap (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, double tolerance)
     if (result == NULL)
 	return NULL;
     result->Srid = geom1->Srid;
+#else
+    if (geom1 == NULL || geom2 == NULL || tolerance == 0.0)
+	geom1 = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -3455,9 +3594,10 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaLineMerge (gaiaGeomCollPtr geom)
 {
 /* attempts to reassemble lines from a collection of sparse fragments */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
-    gaiaGeomCollPtr result;
     gaiaResetGeosMsg ();
     if (!geom)
 	return NULL;
@@ -3481,6 +3621,10 @@ gaiaLineMerge (gaiaGeomCollPtr geom)
     if (result == NULL)
 	return NULL;
     result->Srid = geom->Srid;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -3532,9 +3676,10 @@ GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaUnaryUnion (gaiaGeomCollPtr geom)
 {
 /* Unary Union (single Collection) */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
-    gaiaGeomCollPtr result;
     gaiaResetGeosMsg ();
     if (!geom)
 	return NULL;
@@ -3557,6 +3702,10 @@ gaiaUnaryUnion (gaiaGeomCollPtr geom)
     if (result == NULL)
 	return NULL;
     result->Srid = geom->Srid;
+#else
+    if (geom == NULL)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -4044,9 +4193,10 @@ gaiaDelaunayTriangulation (gaiaGeomCollPtr geom, double tolerance,
 			   int only_edges)
 {
 /* Delaunay Triangulation */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
-    gaiaGeomCollPtr result;
     gaiaResetGeosMsg ();
     if (!geom)
 	return NULL;
@@ -4071,6 +4221,10 @@ gaiaDelaunayTriangulation (gaiaGeomCollPtr geom, double tolerance,
 	result->DeclaredType = GAIA_MULTILINESTRING;
     else
 	result->DeclaredType = GAIA_MULTIPOLYGON;
+#else
+    if (geom == NULL || tolerance == 0.0 || only_edges == 0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
@@ -4098,7 +4252,7 @@ gaiaDelaunayTriangulation_r (const void *p_cache, gaiaGeomCollPtr geom,
 	return NULL;
     g1 = gaiaToGeos_r (cache, geom);
     g2 = GEOSDelaunayTriangulation_r (handle, g1, tolerance, only_edges);
-    GEOSGeom_destroy (g1);
+    GEOSGeom_destroy_r (handle, g1);
     if (!g2)
 	return NULL;
     if (geom->DimensionModel == GAIA_XY_Z)
@@ -4120,22 +4274,267 @@ gaiaDelaunayTriangulation_r (const void *p_cache, gaiaGeomCollPtr geom,
     return result;
 }
 
+#ifdef GEOS_REENTRANT		/* only if GEOS >= 3.5.0 directly supporting Voronoj */
+static gaiaGeomCollPtr
+voronoj_envelope (gaiaGeomCollPtr geom, double extra_frame_size)
+{
+/* building the extended envelope for Voronoj */
+    gaiaGeomCollPtr bbox;
+    gaiaPolygonPtr pg;
+    gaiaRingPtr rect;
+    double minx;
+    double miny;
+    double maxx;
+    double maxy;
+    double ext_x;
+    double ext_y;
+    double delta;
+    double delta2;
+
+    gaiaMbrGeometry (geom);
+/* setting the frame extent */
+    if (extra_frame_size < 0.0)
+	extra_frame_size = 5.0;
+    ext_x = geom->MaxX - geom->MinX;
+    ext_y = geom->MaxY - geom->MinY;
+    delta = (ext_x * extra_frame_size) / 100.0;
+    delta2 = (ext_y * extra_frame_size) / 100.0;
+    if (delta2 > delta)
+	delta = delta2;
+    minx = geom->MinX - delta;
+    miny = geom->MinY - delta;
+    maxx = geom->MaxX + delta;
+    maxy = geom->MaxY + delta;
+
+/* building the frame */
+    if (geom->DimensionModel == GAIA_XY_Z)
+	bbox = gaiaAllocGeomCollXYZ ();
+    else if (geom->DimensionModel == GAIA_XY_M)
+	bbox = gaiaAllocGeomCollXYM ();
+    else if (geom->DimensionModel == GAIA_XY_Z_M)
+	bbox = gaiaAllocGeomCollXYZM ();
+    else
+	bbox = gaiaAllocGeomColl ();
+    bbox->Srid = geom->Srid;
+    bbox->DeclaredType = GAIA_POLYGON;
+    pg = gaiaAddPolygonToGeomColl (bbox, 5, 0);
+    rect = pg->Exterior;
+    if (geom->DimensionModel == GAIA_XY_Z)
+      {
+	  gaiaSetPointXYZ (rect->Coords, 0, minx, miny, 0.0);
+	  gaiaSetPointXYZ (rect->Coords, 1, maxx, miny, 0.0);
+	  gaiaSetPointXYZ (rect->Coords, 2, maxx, maxy, 0.0);
+	  gaiaSetPointXYZ (rect->Coords, 3, minx, maxy, 0.0);
+	  gaiaSetPointXYZ (rect->Coords, 4, minx, miny, 0.0);
+      }
+    else if (geom->DimensionModel == GAIA_XY_M)
+      {
+	  gaiaSetPointXYM (rect->Coords, 0, minx, miny, 0.0);
+	  gaiaSetPointXYM (rect->Coords, 1, maxx, miny, 0.0);
+	  gaiaSetPointXYM (rect->Coords, 2, maxx, maxy, 0.0);
+	  gaiaSetPointXYM (rect->Coords, 3, minx, maxy, 0.0);
+	  gaiaSetPointXYM (rect->Coords, 4, minx, miny, 0.0);
+      }
+    else if (geom->DimensionModel == GAIA_XY_Z_M)
+      {
+	  gaiaSetPointXYZM (rect->Coords, 0, minx, miny, 0.0, 0.0);
+	  gaiaSetPointXYZM (rect->Coords, 1, maxx, miny, 0.0, 0.0);
+	  gaiaSetPointXYZM (rect->Coords, 2, maxx, maxy, 0.0, 0.0);
+	  gaiaSetPointXYZM (rect->Coords, 3, minx, maxy, 0.0, 0.0);
+	  gaiaSetPointXYZM (rect->Coords, 4, minx, miny, 0.0, 0.0);
+      }
+    else
+      {
+	  gaiaSetPoint (rect->Coords, 0, minx, miny);	/* vertex # 1 */
+	  gaiaSetPoint (rect->Coords, 1, maxx, miny);	/* vertex # 2 */
+	  gaiaSetPoint (rect->Coords, 2, maxx, maxy);	/* vertex # 3 */
+	  gaiaSetPoint (rect->Coords, 3, minx, maxy);	/* vertex # 4 */
+	  gaiaSetPoint (rect->Coords, 4, minx, miny);	/* vertex # 5 [same as vertex # 1 to close the polygon] */
+      }
+
+    return bbox;
+}
+
+static int
+voronoj_mbr_contains (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2)
+{
+/* checks if MBR#1 fully contains MBR#2 */
+    if (g2->MinX < g1->MinX)
+	return 0;
+    if (g2->MaxX > g1->MaxX)
+	return 0;
+    if (g2->MinY < g1->MinY)
+	return 0;
+    if (g2->MaxY > g1->MaxY)
+	return 0;
+    return 1;
+}
+
+static int
+voronoj_mbr_overlaps (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2)
+{
+/* checks if two MBRs do overlap */
+    if (g1->MaxX < g2->MinX)
+	return 0;
+    if (g1->MinX > g2->MaxX)
+	return 0;
+    if (g1->MaxY < g2->MinY)
+	return 0;
+    if (g1->MinY > g2->MaxY)
+	return 0;
+    return 1;
+}
+
+static gaiaGeomCollPtr
+voronoj_postprocess (struct splite_internal_cache *cache, gaiaGeomCollPtr raw,
+		     gaiaGeomCollPtr envelope, int only_edges)
+{
+/* postprocessing the result returned by GEOS Voronoj */
+    gaiaGeomCollPtr candidate;
+    gaiaGeomCollPtr result;
+    gaiaGeomCollPtr framed;
+    gaiaPolygonPtr pg;
+    gaiaPolygonPtr new_pg;
+
+    if (raw->DimensionModel == GAIA_XY_Z)
+	result = gaiaAllocGeomCollXYZ ();
+    else if (raw->DimensionModel == GAIA_XY_M)
+	result = gaiaAllocGeomCollXYM ();
+    else if (raw->DimensionModel == GAIA_XY_Z_M)
+	result = gaiaAllocGeomCollXYZM ();
+    else
+	result = gaiaAllocGeomColl ();
+    result->Srid = raw->Srid;
+    result->DeclaredType = GAIA_MULTIPOLYGON;
+
+    if (raw->DimensionModel == GAIA_XY_Z)
+	candidate = gaiaAllocGeomCollXYZ ();
+    else if (raw->DimensionModel == GAIA_XY_M)
+	candidate = gaiaAllocGeomCollXYM ();
+    else if (raw->DimensionModel == GAIA_XY_Z_M)
+	candidate = gaiaAllocGeomCollXYZM ();
+    else
+	candidate = gaiaAllocGeomColl ();
+    candidate->Srid = raw->Srid;
+    candidate->DeclaredType = GAIA_POLYGON;
+
+    gaiaMbrGeometry (raw);
+    gaiaMbrGeometry (envelope);
+    pg = raw->FirstPolygon;
+    while (pg != NULL)
+      {
+	  candidate->FirstPolygon = pg;
+	  candidate->LastPolygon = pg;
+	  candidate->MinX = pg->MinX;
+	  candidate->MinY = pg->MinY;
+	  candidate->MaxX = pg->MaxX;
+	  candidate->MaxY = pg->MaxY;
+	  if (voronoj_mbr_contains (envelope, candidate))
+	    {
+		/* copying a Polygon fully contained within the frame */
+		new_pg = gaiaClonePolygon (pg);
+		if (result->FirstPolygon == NULL)
+		    result->FirstPolygon = new_pg;
+		if (result->LastPolygon != NULL)
+		    result->LastPolygon->Next = new_pg;
+		result->LastPolygon = new_pg;
+	    }
+	  else if (voronoj_mbr_overlaps (envelope, candidate))
+	    {
+		/* found a polygon only partially contained within the frame */
+		new_pg = gaiaClonePolygon (pg);
+		candidate->FirstPolygon = new_pg;
+		candidate->LastPolygon = new_pg;
+		if (cache == NULL)
+		    framed = gaiaGeometryIntersection (envelope, candidate);
+		else
+		    framed =
+			gaiaGeometryIntersection_r (cache, envelope, candidate);
+		candidate->FirstPolygon = NULL;
+		candidate->LastPolygon = NULL;
+		gaiaFreePolygon (new_pg);
+		if (framed)
+		  {
+		      /* copying all framed polygons into the result */
+		      gaiaPolygonPtr pg2 = framed->FirstPolygon;
+		      while (pg2 != NULL)
+			{
+			    if (result->FirstPolygon == NULL)
+				result->FirstPolygon = pg2;
+			    if (result->LastPolygon != NULL)
+				result->LastPolygon->Next = pg2;
+			    result->LastPolygon = pg2;
+			    pg2 = pg2->Next;
+			}
+		      framed->FirstPolygon = NULL;
+		      framed->LastPolygon = NULL;
+		      gaiaFreeGeomColl (framed);
+		  }
+	    }
+	  pg = pg->Next;
+      }
+
+    candidate->FirstPolygon = NULL;
+    candidate->LastPolygon = NULL;
+    gaiaFreeGeomColl (candidate);
+    gaiaFreeGeomColl (raw);
+    if (only_edges)
+      {
+	  gaiaGeomCollPtr lines = gaiaLinearize (result, 1);
+	  gaiaFreeGeomColl (result);
+	  return lines;
+      }
+    return result;
+}
+#endif
+
 GAIAGEO_DECLARE gaiaGeomCollPtr
 gaiaVoronojDiagram (gaiaGeomCollPtr geom, double extra_frame_size,
 		    double tolerance, int only_edges)
 {
 /* Voronoj Diagram */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
-    gaiaGeomCollPtr result;
+#ifdef GEOS_REENTRANT
+    GEOSGeometry *env;
+    gaiaGeomCollPtr envelope;
+#else
+    void *voronoj;
     gaiaPolygonPtr pg;
     int pgs = 0;
     int errs = 0;
-    void *voronoj;
+#endif
     gaiaResetGeosMsg ();
     if (!geom)
 	return NULL;
     g1 = gaiaToGeos (geom);
+#ifdef GEOS_REENTRANT		/* GEOS >= 3.5.0 directly supports Voronoj */
+    envelope = voronoj_envelope (geom, extra_frame_size);
+    env = gaiaToGeos (envelope);
+    g2 = GEOSVoronoiDiagram (g1, env, tolerance, 0);
+    GEOSGeom_destroy (g1);
+    GEOSGeom_destroy (env);
+    if (!g2)
+      {
+	  gaiaFreeGeomColl (envelope);
+	  return NULL;
+      }
+    if (geom->DimensionModel == GAIA_XY_Z)
+	result = gaiaFromGeos_XYZ (g2);
+    else if (geom->DimensionModel == GAIA_XY_M)
+	result = gaiaFromGeos_XYM (g2);
+    else if (geom->DimensionModel == GAIA_XY_Z_M)
+	result = gaiaFromGeos_XYZM (g2);
+    else
+	result = gaiaFromGeos_XY (g2);
+    GEOSGeom_destroy (g2);
+    result = voronoj_postprocess (NULL, result, envelope, only_edges);
+    gaiaFreeGeomColl (envelope);
+    if (result == NULL)
+	return NULL;
+#else
     g2 = GEOSDelaunayTriangulation (g1, tolerance, 0);
     GEOSGeom_destroy (g1);
     if (!g2)
@@ -4188,6 +4587,12 @@ gaiaVoronojDiagram (gaiaGeomCollPtr geom, double extra_frame_size,
 	result->DeclaredType = GAIA_MULTILINESTRING;
     else
 	result->DeclaredType = GAIA_MULTIPOLYGON;
+#endif /* end GEOS_REENTRANT */
+#else
+    if (geom == NULL || extra_frame_size == 0.0 || tolerance == 0.0
+	|| only_edges == 0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif /* end GEOS_USE_ONLY_R_API */
     return result;
 }
 
@@ -4199,10 +4604,15 @@ gaiaVoronojDiagram_r (const void *p_cache, gaiaGeomCollPtr geom,
     GEOSGeometry *g1;
     GEOSGeometry *g2;
     gaiaGeomCollPtr result;
+#ifdef GEOS_REENTRANT
+    GEOSGeometry *env;
+    gaiaGeomCollPtr envelope;
+#else
     gaiaPolygonPtr pg;
     int pgs = 0;
     int errs = 0;
     void *voronoj;
+#endif
     struct splite_internal_cache *cache =
 	(struct splite_internal_cache *) p_cache;
     GEOSContextHandle_t handle = NULL;
@@ -4218,6 +4628,31 @@ gaiaVoronojDiagram_r (const void *p_cache, gaiaGeomCollPtr geom,
     if (!geom)
 	return NULL;
     g1 = gaiaToGeos_r (cache, geom);
+#ifdef GEOS_REENTRANT		/* GEOS >= 3.5.0 directly supports Voronoj */
+    envelope = voronoj_envelope (geom, extra_frame_size);
+    env = gaiaToGeos_r (cache, envelope);
+    g2 = GEOSVoronoiDiagram_r (handle, g1, env, tolerance, 0);
+    GEOSGeom_destroy_r (handle, g1);
+    GEOSGeom_destroy_r (handle, env);
+    if (!g2)
+      {
+	  gaiaFreeGeomColl (envelope);
+	  return NULL;
+      }
+    if (geom->DimensionModel == GAIA_XY_Z)
+	result = gaiaFromGeos_XYZ_r (cache, g2);
+    else if (geom->DimensionModel == GAIA_XY_M)
+	result = gaiaFromGeos_XYM_r (cache, g2);
+    else if (geom->DimensionModel == GAIA_XY_Z_M)
+	result = gaiaFromGeos_XYZM_r (cache, g2);
+    else
+	result = gaiaFromGeos_XY_r (cache, g2);
+    GEOSGeom_destroy_r (handle, g2);
+    result = voronoj_postprocess (cache, result, envelope, only_edges);
+    gaiaFreeGeomColl (envelope);
+    if (result == NULL)
+	return NULL;
+#else
     g2 = GEOSDelaunayTriangulation_r (handle, g1, tolerance, 0);
     GEOSGeom_destroy_r (handle, g1);
     if (!g2)
@@ -4271,6 +4706,7 @@ gaiaVoronojDiagram_r (const void *p_cache, gaiaGeomCollPtr geom,
 	result->DeclaredType = GAIA_MULTILINESTRING;
     else
 	result->DeclaredType = GAIA_MULTIPOLYGON;
+#endif /* end GEOS_REENTRANT */
     return result;
 }
 
@@ -4279,9 +4715,10 @@ gaiaConcaveHull (gaiaGeomCollPtr geom, double factor, double tolerance,
 		 int allow_holes)
 {
 /* Concave Hull */
+    gaiaGeomCollPtr result = NULL;
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     GEOSGeometry *g1;
     GEOSGeometry *g2;
-    gaiaGeomCollPtr result;
     gaiaGeomCollPtr concave_hull;
     gaiaPolygonPtr pg;
     int pgs = 0;
@@ -4331,6 +4768,10 @@ gaiaConcaveHull (gaiaGeomCollPtr geom, double factor, double tolerance,
     result = concave_hull;
 
     result->Srid = geom->Srid;
+#else
+    if (geom == NULL || factor == 0.0 || tolerance == 0.0 || allow_holes == 0)
+	geom = NULL;		/* silencing stupid compiler warnings */
+#endif
     return result;
 }
 
diff --git a/src/gaiageo/gg_shape.c b/src/gaiageo/gg_shape.c
index a948fbc..0510945 100644
--- a/src/gaiageo/gg_shape.c
+++ b/src/gaiageo/gg_shape.c
@@ -1681,6 +1681,8 @@ gaiaReadShpEntity_ex (gaiaShapefilePtr shp, int current_row, int srid,
 		shp->flDbf);
     if (rd != shp->DbfReclen)
 	goto error;
+    if (*(shp->BufDbf) == '*')
+	goto dbf_deleted;
 /* positioning and reading corresponding SHP entity - geometry */
     offset = off_shp * 2;
     skpos = fseek (shp->flShp, offset, SEEK_SET);
@@ -2532,6 +2534,11 @@ gaiaReadShpEntity_ex (gaiaShapefilePtr shp, int current_row, int srid,
     strcpy (shp->LastError, errMsg);
     shp_free_rings (&ringsColl);
     return 0;
+  dbf_deleted:
+    if (shp->LastError)
+	free (shp->LastError);
+    shp->LastError = NULL;
+    return -1;
   conversion_error:
     if (shp->LastError)
 	free (shp->LastError);
@@ -2747,7 +2754,7 @@ gaiaWriteShpEntity (gaiaShapefilePtr shp, gaiaDbfListPtr entity)
 		      if (fld->Value->Type == GAIA_TEXT_VALUE)
 			{
 			    len = strlen (fld->Value->TxtValue);
-			    dynbuf = malloc (len + 1);
+			    dynbuf = malloc (2048 + len + 1);
 			    strcpy (dynbuf, fld->Value->TxtValue);
 			    if (len > 512)
 			      {
diff --git a/src/gaiageo/gg_voronoj.c b/src/gaiageo/gg_voronoj.c
index f39c7ce..ad02532 100644
--- a/src/gaiageo/gg_voronoj.c
+++ b/src/gaiageo/gg_voronoj.c
@@ -123,6 +123,8 @@ struct concave_hull_str
     double count;
 };
 
+#ifndef GEOS_REENTRANT		/* GEOS >= 3.5.0 directly supports Voronoj */
+
 static double *
 voronoj_sorted_up (struct voronoj_aux *voronoj, int *count)
 {
@@ -655,8 +657,8 @@ voronoj_build_r (const void *p_cache, int count, void *p_first,
     double intercept = 0.0;
     double minx = DBL_MAX;
     double miny = DBL_MAX;
-    double maxx = DBL_MIN;
-    double maxy = DBL_MIN;
+    double maxx = -DBL_MAX;
+    double maxy = -DBL_MAX;
     double ext_x;
     double ext_y;
     double delta;
@@ -1480,6 +1482,8 @@ voronoj_free (void *p_voronoj)
     free (voronoj);
 }
 
+#endif /* END GEOS_REENTRANT - GEOS >= 3.5.0 */
+
 SPATIALITE_PRIVATE int
 delaunay_triangle_check (void *ppg)
 {
diff --git a/src/gaiageo/gg_xml.c b/src/gaiageo/gg_xml.c
index ac8f7d0..af0c88d 100644
--- a/src/gaiageo/gg_xml.c
+++ b/src/gaiageo/gg_xml.c
@@ -438,7 +438,7 @@ sniff_sld_payload (xmlNodePtr node, int *layers, int *point, int *line,
 static void
 sniff_payload (xmlDocPtr xml_doc, int *is_iso_metadata,
 	       int *is_sld_se_vector_style, int *is_sld_se_raster_style,
-	       int *is_sld_style, int *is_svg)
+	       int *is_sld_style, int *is_svg, int *is_gpx)
 {
 /* sniffing the payload type */
     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
@@ -446,6 +446,7 @@ sniff_payload (xmlDocPtr xml_doc, int *is_iso_metadata,
     *is_sld_se_vector_style = 0;
     *is_sld_se_raster_style = 0;
     *is_svg = 0;
+    *is_gpx = 0;
     if (root->name != NULL)
       {
 	  const char *name = (const char *) (root->name);
@@ -487,6 +488,8 @@ sniff_payload (xmlDocPtr xml_doc, int *is_iso_metadata,
 	    }
 	  if (strcmp (name, "svg") == 0)
 	      *is_svg = 1;
+	  if (strcmp (name, "gpx") == 0)
+	      *is_gpx = 1;
       }
 }
 
@@ -1467,6 +1470,7 @@ gaiaXmlToBlob (const void *p_cache, const unsigned char *xml, int xml_len,
     int is_sld_se_raster_style = 0;
     int is_sld_style = 0;
     int is_svg = 0;
+    int is_gpx = 0;
     int len;
     int zip_len;
     short uri_len = 0;
@@ -1607,7 +1611,7 @@ gaiaXmlToBlob (const void *p_cache, const unsigned char *xml, int xml_len,
 
 /* testing for special cases: ISO Metadata, SLD/SE Styles and SVG */
     sniff_payload (xml_doc, &is_iso_metadata, &is_sld_se_vector_style,
-		   &is_sld_se_raster_style, &is_sld_style, &is_svg);
+		   &is_sld_se_raster_style, &is_sld_style, &is_svg, &is_gpx);
     if (is_iso_metadata)
 	retrieve_iso_identifiers (xml_doc, &fileIdentifier,
 				  &parentIdentifier, &title, &abstract,
@@ -1682,6 +1686,8 @@ gaiaXmlToBlob (const void *p_cache, const unsigned char *xml, int xml_len,
 	flags |= GAIA_XML_SLD_STYLE;
     if (is_svg)
 	flags |= GAIA_XML_SVG;
+    if (is_gpx)
+	flags |= GAIA_XML_GPX;
     *(buf + 1) = flags;		/* XmlBLOB flags */
     *(buf + 2) = GAIA_XML_HEADER;	/* HEADER signature */
     gaiaExport32 (buf + 3, xml_len, 1, endian_arch);	/* the uncompressed XMLDocument size */
@@ -1824,6 +1830,7 @@ gaiaXmlBlobCompression (const unsigned char *blob,
     int is_sld_se_raster_style = 0;
     int is_sld_style = 0;
     int is_svg = 0;
+    int is_gpx = 0;
     unsigned char *xml;
     unsigned char *buf;
     unsigned char *ptr;
@@ -1854,6 +1861,8 @@ gaiaXmlBlobCompression (const unsigned char *blob,
 	is_sld_style = 1;
     if ((flag & GAIA_XML_SVG) == GAIA_XML_SVG)
 	is_svg = 1;
+    if ((flag & GAIA_XML_GPX) == GAIA_XML_GPX)
+	is_gpx = 1;
     in_xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
     in_zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
     uri_len = gaiaImport16 (blob + 11, little_endian, endian_arch);
@@ -2015,6 +2024,8 @@ gaiaXmlBlobCompression (const unsigned char *blob,
 	flags |= GAIA_XML_SLD_STYLE;
     if (is_svg)
 	flags |= GAIA_XML_SVG;
+    if (is_gpx)
+	flags |= GAIA_XML_GPX;
     *(buf + 1) = flags;		/* XmlBLOB flags */
     *(buf + 2) = GAIA_XML_HEADER;	/* HEADER signature */
     gaiaExport32 (buf + 3, out_xml_len, 1, endian_arch);	/* the uncompressed XMLDocument size */
@@ -2835,6 +2846,8 @@ gaiaXmlFromBlob (const unsigned char *blob, int blob_size, int indent,
     free (xml);
     xmlFreeDoc (xml_doc);
     *result = out;
+    if (*(out + out_len - 1) == '\0' && out_len > 0)
+	out_len -= 1;
     *res_size = out_len;
     xmlSetGenericErrorFunc ((void *) stderr, NULL);
 }
@@ -3022,7 +3035,7 @@ gaiaIsSldStyleXmlBlob (const unsigned char *blob, int blob_size)
 GAIAGEO_DECLARE int
 gaiaIsSvgXmlBlob (const unsigned char *blob, int blob_size)
 {
-/* Checks if a valid XmlBLOB buffer does actually contains an SLD/SE Style or not */
+/* Checks if a valid XmlBLOB buffer does actually contains an SVG image or not */
     int svg = 0;
     unsigned char flag;
 
@@ -3036,6 +3049,22 @@ gaiaIsSvgXmlBlob (const unsigned char *blob, int blob_size)
 }
 
 GAIAGEO_DECLARE int
+gaiaIsGpxXmlBlob (const unsigned char *blob, int blob_size)
+{
+/* Checks if a valid XmlBLOB buffer does actually contains a GPX document or not */
+    int gpx = 0;
+    unsigned char flag;
+
+/* validity check */
+    if (!gaiaIsValidXmlBlob (blob, blob_size))
+	return -1;		/* cannot be an XmlBLOB */
+    flag = *(blob + 1);
+    if ((flag & GAIA_XML_GPX) == GAIA_XML_GPX)
+	gpx = 1;
+    return gpx;
+}
+
+GAIAGEO_DECLARE int
 gaiaXmlBlobGetDocumentSize (const unsigned char *blob, int blob_size)
 {
 /* Return the XMLDocument size (in bytes) from a valid XmlBLOB buffer */
@@ -4217,6 +4246,331 @@ gaiaXmlBlobGetEncoding (const unsigned char *blob, int blob_size)
     return NULL;
 }
 
+static void
+parse_gpx_trkpt_values (xmlNodePtr node, double *x, double *y)
+{
+/* fetching values from a GPX <trkpt> tag */
+    struct _xmlAttr *attr;
+
+    *x = 0.0;
+    *y = 0.0;
+
+    attr = node->properties;
+    while (attr != NULL)
+      {
+	  /* attributes */
+	  if (attr->type == XML_ATTRIBUTE_NODE)
+	    {
+		const char *name = (const char *) (attr->name);
+		xmlNode *text = attr->children;
+		if (strcmp (name, "lat") == 0 && text != NULL)
+		    *y = atof ((const char *) (text->content));
+		if (strcmp (name, "lon") == 0 && text != NULL)
+		    *x = atof ((const char *) (text->content));
+	    }
+	  attr = attr->next;
+      }
+}
+
+static double
+gpx_time2m (sqlite3_stmt * stmt, const char *timestamp)
+{
+/* transforming a timestamp into an M-value */
+    double m = 0.0;
+    int ret;
+
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_text (stmt, 1, timestamp, strlen (timestamp), SQLITE_STATIC);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_FLOAT)
+		    m = sqlite3_column_double (stmt, 0);
+	    }
+      }
+    return m;
+}
+
+static void
+parse_gpx_trkpt_children (xmlNodePtr node, sqlite3_stmt * stmt, double *z,
+			  double *m)
+{
+/* parsing the children of a GPX <trkpt> tag */
+    xmlNode *text;
+    *z = 0.0;
+    *m = 1721059.500000;		/* 0000-01-01T00:00:00Z */
+
+    while (node)
+      {
+	  if (node->type == XML_ELEMENT_NODE)
+	    {
+		const char *name = (const char *) (node->name);
+		if (strcmp (name, "ele") == 0)
+		  {
+		      text = node->children;
+		      if (text != NULL)
+			  *z = atof ((const char *) (text->content));
+		  }
+		if (strcmp (name, "time") == 0)
+		  {
+		      text = node->children;
+		      if (text != NULL)
+			  *m = gpx_time2m (stmt,
+					   (const char *) (text->content));
+		  }
+	    }
+	  node = node->next;
+      }
+}
+
+static void
+parse_gpx_trkpt_tag (xmlNodePtr node, sqlite3_stmt * stmt,
+		     gaiaDynamicLinePtr dyn)
+{
+/* parsing a GPX <trkpt> tag */
+
+    while (node)
+      {
+	  if (node->type == XML_ELEMENT_NODE)
+	    {
+		const char *name = (const char *) (node->name);
+		if (strcmp (name, "trkpt") == 0)
+		  {
+		      double x;
+		      double y;
+		      double z;
+		      double m;
+		      parse_gpx_trkpt_values (node, &x, &y);
+		      parse_gpx_trkpt_children (node->children, stmt, &z, &m);
+		      gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
+		  }
+	    }
+	  node = node->next;
+      }
+}
+
+static void
+gpx_copy_line (gaiaDynamicLinePtr dyn, gaiaGeomCollPtr geom)
+{
+/* copying a Linestring from a DynamicLine */
+    gaiaPointPtr pt;
+    int pts = 0;
+    gaiaLinestringPtr ln;
+    int iv;
+
+    pt = dyn->First;
+    while (pt != NULL)
+      {
+	  /* counting how many points */
+	  pts++;
+	  pt = pt->Next;
+      }
+    if (pts < 2)
+	return;
+
+    ln = gaiaAddLinestringToGeomColl (geom, pts);
+    iv = 0;
+    pt = dyn->First;
+    while (pt != NULL)
+      {
+	  /* copying points */
+	  gaiaSetPointXYZM (ln->Coords, iv, pt->X, pt->Y, pt->Z, pt->M);
+	  iv++;
+	  pt = pt->Next;
+      }
+}
+
+static void
+parse_gpx_trkseg_tag (xmlNodePtr node, sqlite3_stmt * stmt,
+		      gaiaGeomCollPtr geom)
+{
+/* parsing a GPX <trkseg> tag */
+
+    while (node)
+      {
+	  if (node->type == XML_ELEMENT_NODE)
+	    {
+		const char *name = (const char *) (node->name);
+		if (strcmp (name, "trkseg") == 0)
+		  {
+		      gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
+		      parse_gpx_trkpt_tag (node->children, stmt, dyn);
+		      gpx_copy_line (dyn, geom);
+		      gaiaFreeDynamicLine (dyn);
+		  }
+	    }
+	  node = node->next;
+      }
+}
+
+static void
+parse_gpx_trk_tag (xmlNodePtr node, sqlite3_stmt * stmt, gaiaGeomCollPtr geom)
+{
+/* parsing a GPX <trk> tag */
+
+    while (node)
+      {
+	  if (node->type == XML_ELEMENT_NODE)
+	    {
+		const char *name = (const char *) (node->name);
+		if (strcmp (name, "trk") == 0)
+		    parse_gpx_trkseg_tag (node->children, stmt, geom);
+	    }
+	  node = node->next;
+      }
+}
+
+static void
+parse_gpx_tag (xmlNodePtr node, sqlite3_stmt * stmt, gaiaGeomCollPtr geom)
+{
+/* parsing a GPX document */
+
+    while (node)
+      {
+	  if (node->type == XML_ELEMENT_NODE)
+	    {
+		const char *name = (const char *) (node->name);
+		if (strcmp (name, "gpx") == 0)
+		    parse_gpx_trk_tag (node->children, stmt, geom);
+	    }
+	  node = node->next;
+      }
+}
+
+static void
+parse_gpx (xmlDocPtr xml_doc, sqlite3_stmt * stmt, gaiaGeomCollPtr geom)
+{
+/* attempting to parse a GPX document */
+    xmlNodePtr root = xmlDocGetRootElement (xml_doc);
+    parse_gpx_tag (root, stmt, geom);
+}
+
+GAIAGEO_DECLARE gaiaGeomCollPtr
+gaiaXmlBlobMLineFromGPX (const unsigned char *blob, int blob_size,
+			 sqlite3 * sqlite)
+{
+/* Return a MultiLinestring Geometry from a valid XmlBLOB buffer of the GPX type */
+    int ret;
+    const char *sql;
+    sqlite3_stmt *stmt = NULL;
+    int compressed = 0;
+    int little_endian = 0;
+    unsigned char flag;
+    const unsigned char *ptr;
+    int xml_len;
+    int zip_len;
+    short uri_len;
+    short fileid_len;
+    short parentid_len;
+    short name_len;
+    short title_len;
+    short abstract_len;
+    short geometry_len;
+    unsigned char *xml;
+    xmlDocPtr xml_doc;
+    int legacy_blob = 0;
+    int endian_arch = gaiaEndianArch ();
+    xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
+    gaiaGeomCollPtr geom = NULL;
+
+/* validity check */
+    if (!gaiaIsValidXmlBlob (blob, blob_size))
+	return NULL;		/* cannot be an XmlBLOB */
+    if (!gaiaIsGpxXmlBlob (blob, blob_size))
+	return NULL;		/* not a GPX document */
+    if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
+	legacy_blob = 1;
+    flag = *(blob + 1);
+    if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
+	little_endian = 1;
+    if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
+	compressed = 1;
+    xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
+    zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
+    ptr = blob + 11;
+    uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
+    ptr += 3 + uri_len;
+    fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
+    ptr += 3 + fileid_len;
+    parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
+    ptr += 3 + parentid_len;
+    if (!legacy_blob)
+      {
+	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
+	  ptr += 3 + name_len;
+      }
+    title_len = gaiaImport16 (ptr, little_endian, endian_arch);
+    ptr += 3 + title_len;
+    abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
+    ptr += 3 + abstract_len;
+    geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
+    ptr += 3 + geometry_len;
+    ptr++;
+    if (compressed)
+      {
+	  /* unzipping the XML payload */
+	  uLong refLen = xml_len;
+	  const Bytef *in = ptr;
+	  xml = malloc (xml_len + 1);
+	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
+	    {
+		/* uncompress error */
+		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
+		free (xml);
+		return NULL;
+	    }
+	  *(xml + xml_len) = '\0';
+      }
+    else
+      {
+	  /* just copying the uncompressed XML payload */
+	  xml = malloc (xml_len + 1);
+	  memcpy (xml, ptr, xml_len);
+	  *(xml + xml_len) = '\0';
+      }
+/* attempting to parse the GPX document */
+    xmlSetGenericErrorFunc (NULL, silentError);
+    xml_doc =
+	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
+    if (xml_doc == NULL)
+      {
+	  /* parsing error; not a well-formed XML */
+	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
+	  return NULL;
+      }
+    free (xml);
+
+/* creating a prepared SQL statement transforming timestamps into M-values */
+    sql = "SELECT julianday(?)";
+    ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
+    if (ret != SQLITE_OK)
+	goto end;
+
+    geom = gaiaAllocGeomCollXYZM ();
+    geom->Srid = 4326;
+    geom->DeclaredType = GAIA_MULTILINESTRING;
+    parse_gpx (xml_doc, stmt, geom);
+    sqlite3_finalize (stmt);
+
+    if (geom->FirstLinestring == NULL)
+      {
+	  /* empty geometry: returning NULL */
+	  gaiaFreeGeomColl (geom);
+	  geom = NULL;
+      }
+
+  end:
+    xmlFreeDoc (xml_doc);
+    xmlSetGenericErrorFunc ((void *) stderr, NULL);
+    return geom;
+}
+
 GAIAGEO_DECLARE char *
 gaia_libxml2_version (void)
 {
diff --git a/src/geopackage/gaia_cvt_gpkg.c b/src/geopackage/gaia_cvt_gpkg.c
index 1aad8b3..e8ae6ef 100644
--- a/src/geopackage/gaia_cvt_gpkg.c
+++ b/src/geopackage/gaia_cvt_gpkg.c
@@ -874,7 +874,7 @@ do_insert_content (sqlite3 * handle, const char *table_name,
 
     xtable = gaiaDoubleQuotedSql (table_name);
     xgeom = gaiaDoubleQuotedSql (geometry_column);
-    sql = sqlite3_mprintf ("INSERT INTO gpkg_contents (table_name, data_type, "
+    sql = sqlite3_mprintf ("INSERT OR IGNORE INTO gpkg_contents (table_name, data_type, "
 			   "identifier, description, last_change, min_x, min_y, max_x, max_y, srs_id) "
 			   "SELECT Lower(%Q), 'features', Lower(%Q), ' ', "
 			   "strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), Min(ST_MinX(\"%s\")), "
diff --git a/src/geopackage/gpkgAddGeometryColumn.c b/src/geopackage/gpkgAddGeometryColumn.c
index 5081b71..41d59a5 100644
--- a/src/geopackage/gpkgAddGeometryColumn.c
+++ b/src/geopackage/gpkgAddGeometryColumn.c
@@ -182,6 +182,15 @@ fnct_gpkgAddGeometryColumn (sqlite3_context * context, int argc
                  "VALUES (%Q, 'feature', %i, NULL, NULL, NULL, NULL)",
                  table, srid);
 
+    ret = sqlite3_exec (sqlite, sql_stmt, NULL, NULL, &errMsg);
+    sqlite3_free (sql_stmt);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_result_error (context, errMsg, -1);
+	  sqlite3_free (errMsg);
+	  return;
+      }
+
     /* Add column definition to metadata table */
     sql_stmt = sqlite3_mprintf ("INSERT INTO gpkg_geometry_columns "
 				"(table_name, column_name, geometry_type_name, srs_id, z, m) "
diff --git a/src/geopackage/gpkgCreateBaseTables.c b/src/geopackage/gpkgCreateBaseTables.c
index 5388568..a2d5885 100644
--- a/src/geopackage/gpkgCreateBaseTables.c
+++ b/src/geopackage/gpkgCreateBaseTables.c
@@ -119,7 +119,6 @@ fnct_gpkgCreateBaseTables (sqlite3_context * context, int argc
 	    "CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id))",
 
 	/* Geopackage specification Table 9 / Table 27 */
-	/* TODO: figure out if the defaults are required - https://github.com/opengis/geopackage/issues/67 */
 	"CREATE TABLE gpkg_tile_matrix (\n"
 	    "table_name TEXT NOT NULL,\n"
 	    "zoom_level INTEGER NOT NULL,\n"
@@ -150,9 +149,9 @@ fnct_gpkgCreateBaseTables (sqlite3_context * context, int argc
 	    "constraint_type TEXT NOT NULL,\n"
 	    "value TEXT,\n"
 	    "min NUMERIC,\n"
-	    "minIsInclusive BOOLEAN,\n"
+	    "min_is_inclusive BOOLEAN,\n"
 	    "max NUMERIC,\n"
-	    "maxIsInclusive BOOLEAN,\n"
+	    "max_is_inclusive BOOLEAN,\n"
 	    "description TEXT,\n"
 	    "CONSTRAINT gdcc_ntv UNIQUE (constraint_name, constraint_type, value))",
 
diff --git a/src/headers/Makefile.am b/src/headers/Makefile.am
index d14f53c..1fddd49 100644
--- a/src/headers/Makefile.am
+++ b/src/headers/Makefile.am
@@ -1,4 +1,8 @@
 
+if MODULE_ONLY
+noinst_HEADERS = 
+nobase_include_HEADERS = 
+else
 noinst_HEADERS = spatialite_private.h
 nobase_include_HEADERS = spatialite.h \
 	spatialite/gaiaexif.h \
@@ -19,4 +23,7 @@ nobase_include_HEADERS = spatialite.h \
 	spatialite/sqlite.h \
 	spatialite/debug.h \
 	spatialite/geopackage.h \
-	spatialite/control_points.h
+	spatialite/control_points.h \
+	spatialite/gaia_topology.h \
+	spatialite/gaia_network.h
+endif
diff --git a/src/headers/Makefile.in b/src/headers/Makefile.in
index f5c5164..17bb260 100644
--- a/src/headers/Makefile.in
+++ b/src/headers/Makefile.in
@@ -96,8 +96,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(nobase_include_HEADERS) \
-	$(noinst_HEADERS) $(am__DIST_COMMON)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__nobase_include_HEADERS_DIST) \
+	$(am__noinst_HEADERS_DIST) $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -121,6 +121,16 @@ am__can_run_installinfo = \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
+am__nobase_include_HEADERS_DIST = spatialite.h spatialite/gaiaexif.h \
+	spatialite/gaiaaux.h spatialite/gaiamatrix.h \
+	spatialite/gaiageo.h spatialite/gg_const.h \
+	spatialite/gg_structs.h spatialite/gg_core.h \
+	spatialite/gg_mbr.h spatialite/gg_formats.h \
+	spatialite/gg_dynamic.h spatialite/gg_advanced.h \
+	spatialite/gg_xml.h spatialite/gg_wfs.h spatialite/gg_dxf.h \
+	spatialite/spatialite.h spatialite/sqlite.h spatialite/debug.h \
+	spatialite/geopackage.h spatialite/control_points.h \
+	spatialite/gaia_topology.h spatialite/gaia_network.h
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -149,6 +159,7 @@ am__uninstall_files_from_dir = { \
          $(am__cd) "$$dir" && rm -f $$files; }; \
   }
 am__installdirs = "$(DESTDIR)$(includedir)"
+am__noinst_HEADERS_DIST = spatialite_private.h
 HEADERS = $(nobase_include_HEADERS) $(noinst_HEADERS)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
 # Read a list of newline-separated strings from the standard input,
@@ -300,28 +311,32 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-noinst_HEADERS = spatialite_private.h
-nobase_include_HEADERS = spatialite.h \
-	spatialite/gaiaexif.h \
-	spatialite/gaiaaux.h \
-	spatialite/gaiamatrix.h \
-	spatialite/gaiageo.h \
-	spatialite/gg_const.h \
-	spatialite/gg_structs.h \
-	spatialite/gg_core.h \
-	spatialite/gg_mbr.h \
-	spatialite/gg_formats.h \
-	spatialite/gg_dynamic.h \
-	spatialite/gg_advanced.h \
-	spatialite/gg_xml.h \
-	spatialite/gg_wfs.h \
-	spatialite/gg_dxf.h \
-	spatialite/spatialite.h \
-	spatialite/sqlite.h \
-	spatialite/debug.h \
-	spatialite/geopackage.h \
-	spatialite/control_points.h
-
+ at MODULE_ONLY_FALSE@noinst_HEADERS = spatialite_private.h
+ at MODULE_ONLY_TRUE@noinst_HEADERS = 
+ at MODULE_ONLY_FALSE@nobase_include_HEADERS = spatialite.h \
+ at MODULE_ONLY_FALSE@	spatialite/gaiaexif.h \
+ at MODULE_ONLY_FALSE@	spatialite/gaiaaux.h \
+ at MODULE_ONLY_FALSE@	spatialite/gaiamatrix.h \
+ at MODULE_ONLY_FALSE@	spatialite/gaiageo.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_const.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_structs.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_core.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_mbr.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_formats.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_dynamic.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_advanced.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_xml.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_wfs.h \
+ at MODULE_ONLY_FALSE@	spatialite/gg_dxf.h \
+ at MODULE_ONLY_FALSE@	spatialite/spatialite.h \
+ at MODULE_ONLY_FALSE@	spatialite/sqlite.h \
+ at MODULE_ONLY_FALSE@	spatialite/debug.h \
+ at MODULE_ONLY_FALSE@	spatialite/geopackage.h \
+ at MODULE_ONLY_FALSE@	spatialite/control_points.h \
+ at MODULE_ONLY_FALSE@	spatialite/gaia_topology.h \
+ at MODULE_ONLY_FALSE@	spatialite/gaia_network.h
+
+ at MODULE_ONLY_TRUE@nobase_include_HEADERS = 
 all: all-am
 
 .SUFFIXES:
diff --git a/src/headers/spatialite.h b/src/headers/spatialite.h
index 13ac90a..9a572c1 100644
--- a/src/headers/spatialite.h
+++ b/src/headers/spatialite.h
@@ -188,6 +188,18 @@ extern "C"
     SPATIALITE_DECLARE void spatialite_cleanup_ex (const void *ptr);
 
 /**
+ Partially Cleaning-up a SpatiaLite connection
+
+ This function will destroy all TopoGeo and TopoNet objects from within a local cache.
+
+ \param ptr the same memory pointer passed to the corresponding call to
+ spatialite_init_ex() and returned by spatialite_alloc_connection()
+
+ \sa spatialite_init_ex, spatialite_alloc_connection
+*/
+    SPATIALITE_DECLARE void spatialite_finalize_topologies (const void *ptr);
+
+/**
  Dumps a full geometry-table into an external Shapefile
 
  \param sqlite handle to current DB connection
@@ -711,7 +723,7 @@ extern "C"
 
  \sa check_duplicated_rows, remove_duplicated_rows_ex
 
- \note when two (or more) duplicated rows exist, only the first occurence
+ \note when two (or more) duplicated rows exist, only the first occurrence
  will be preserved, then deleting any further occurrence.
  */
     SPATIALITE_DECLARE void remove_duplicated_rows (sqlite3 * sqlite,
@@ -727,7 +739,7 @@ extern "C"
 
  \sa check_duplicated_rows, remove_duplicated_rows_ex2
 
- \note when two (or more) duplicated rows exist, only the first occurence
+ \note when two (or more) duplicated rows exist, only the first occurrence
  will be preserved, then deleting any further occurrence.
  */
     SPATIALITE_DECLARE void remove_duplicated_rows_ex (sqlite3 * sqlite,
@@ -746,7 +758,7 @@ extern "C"
 
  \sa check_duplicated_rows, remove_duplicated_rows
 
- \note when two (or more) duplicated rows exist, only the first occurence
+ \note when two (or more) duplicated rows exist, only the first occurrence
  will be preserved, then deleting any further occurrence.
  */
     SPATIALITE_DECLARE void remove_duplicated_rows_ex2 (sqlite3 * sqlite,
@@ -1404,6 +1416,54 @@ extern "C"
 							    int *not_repaired,
 							    char **err_msg);
 
+/**
+  Will precisely cut the input dataset against polygonal blade(s)
+  and will consequently create and populate an output dataset
+  
+ \param db_handle handle to the current SQLite connection
+ \param cache a memory pointer returned by spatialite_alloc_connection()
+ \param in_db_prefix prefix of the database where the input table
+ is expected to be found. if NULL then "MAIN" will be assumed.
+ \param input_table name of the input table to be processed.
+ \param input_geometry name of the input table Geometry column;
+ it could be NULL and in this case the appropriate column name will
+ be automatically determind. anyway if the input table do contains
+ two or more Geometries passing a NULL geometry name will raise a
+ fatal error.
+ \param blade_db_prefix prefix of the database where the "blade" table
+ is expected to be found. if NULL then "MAIN" will be assumed.
+ \param blade_table name of the table expected to contain Polygons
+ or MultiPolygon Geometries acting as blades.
+ \param blade_geometry name of the "blade" table Geometry column;
+ it could be NULL and in this case the appropriate column name will
+ be automatically determind. anyway if the input table do contains
+ two or more Geometries passing a NULL geometry name will raise a
+ fatal error.
+ \param output_table name to assinged to the destination table intended
+ to permanently store all results. this table must non exists.
+ \param transaction boolean; if set to TRUE will internally handle
+ a SQL Transaction.
+ \param ram_tmp_store boolean: if set to TRUE all TEMPORARY tables
+ and indices will be created in RAM, otherwise in a file.
+ \param message pointer to a string buffer; if not NULL it will point
+ on completion an eventual error message.
+ 
+ \return 0 on failure, any other value on success
+ 
+ \note the message buffer if not NULL will point to a dymanic memory
+ allocation and is expected to be released by calling sqlite3_free()
+ */
+    SPATIALITE_DECLARE int gaiaCutter (sqlite3 * db_handle, const void *cache,
+				       const char *in_db_prefix,
+				       const char *input_table,
+				       const char *input_geom,
+				       const char *blade_db_prefix,
+				       const char *blade_table,
+				       const char *blade_geom,
+				       const char *output_table,
+				       int transaction, int ram_tmp_store,
+				       char **message);
+
     SPATIALITE_DECLARE int gaiaGPKG2Spatialite (sqlite3 * handle_in,
 						const char *gpkg_in_path,
 						sqlite3 * handle_out,
diff --git a/src/headers/spatialite/gaia_network.h b/src/headers/spatialite/gaia_network.h
new file mode 100644
index 0000000..20526e1
--- /dev/null
+++ b/src/headers/spatialite/gaia_network.h
@@ -0,0 +1,587 @@
+/*
+ gaia_network.h -- Gaia common support for Topology-Network
+  
+ version 4.3, 2015 August 11
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+
+/**
+ \file gaia_network.h
+
+ Topology-Network handling functions and constants 
+ */
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+/* stdio.h included for FILE objects. */
+#include <stdio.h>
+#ifdef DLL_EXPORT
+#define GAIANET_DECLARE __declspec(dllexport)
+#else
+#define GAIANET_DECLARE extern
+#endif
+#endif
+
+#ifndef _GAIANET_H
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+#define _GAIANET_H
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ Typedef for Topology-Network Accessor Object (opaque, hidden)
+
+ \sa GaiaNetworkAccessorPtr
+ */
+    typedef struct gaia_network_accessor GaiaNetworkAccessor;
+/**
+ Typedef for Network Accessor Object pointer (opaque, hidden)
+
+ \sa GaiaNetworkAccessor
+ */
+    typedef struct gaia_network_accessor *GaiaNetworkAccessorPtr;
+
+/**
+ returns the last Topology-Network exception (if any)
+
+ \param network_name unique name identifying the Topology-Network.
+ 
+ \return pointer to the last Topology-Network error message: may be NULL if
+ no Topology error is currently pending.
+ */
+    GAIANET_DECLARE const char *gaiaNetworkGetLastException (const char
+							     *network_name);
+
+/**
+ creates a new Topology-Network and all related DB objects
+
+ \param handle pointer to the current DB connection.
+ \param network_name unique name identifying the Topology-Network.
+ \param spatial boolean: if TRUE this Topology-Network will be assumed
+ to be of the Spatial type, otherwise a Logical Network will be assumed.
+ \param srid a spatial reference identifier (only applies to Spatial
+ Networks).
+ \param has_z boolean: if TRUE this Topology-Network supports 3D (XYZ) 
+ (only applies to Spatial Networks).
+ \param allow_coincident boolean: if TRUE coincident Nodes will be
+ tolerated, otherwise a coincident Node condition will raise an exception.
+ This argument only applies to Spatial Networks and is meaningless for
+ Logical Networks.
+
+ \return 0 on failure: any other value on success.
+
+ \sa gaiaNetworkDrop
+ */
+    GAIANET_DECLARE int gaiaNetworkCreate (sqlite3 * handle,
+					   const char *network_name,
+					   int spatial, int srid, int has_z,
+					   int allow_coincident);
+
+/**
+ completely drops an already existing Topology-Network and removes all related DB objects
+
+ \param handle pointer to the current DB connection.
+ \param network_name unique name identifying the Topology-Network.
+
+ \return 0 on failure: any other value on success.
+
+ \sa gaiaNetworkCreate
+ */
+    GAIANET_DECLARE int gaiaNetworkDrop (sqlite3 * handle,
+					 const char *network_name);
+
+/**
+ creates an opaque Topology-Network Accessor object starting from its DB configuration
+
+ \param handle pointer to the current DB connection.
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param network_name unique name identifying the Topology-Network.
+
+ \return the pointer to newly created Topology-Network Accessor Object: 
+ NULL on failure.
+
+ \sa gaiaNetworkCreate, gaiaNetworkDestroy, gaiaNetworkFromCache, 
+ gaiaGetNetwork
+ 
+ \note you are responsible to destroy (before or after) any allocated 
+ Topology-Network Accessor Object. The Topology-Network Accessor once 
+ created will be preserved within the internal connection cache for 
+ future references.
+ */
+    GAIANET_DECLARE GaiaNetworkAccessorPtr gaiaNetworkFromDBMS (sqlite3 *
+								handle,
+								const void
+								*cache,
+								const char
+								*network_name);
+
+/**
+ retrieves a Topology configuration from DB
+
+ \param handle pointer to the current DB connection.
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param net_name unique name identifying the Topology-Network.
+ \param network_name on completion will point to the real Topology-Network name.
+ \param spatial on completion will report if the Topology-Network is of
+ the Spatial or Logical type.
+ \param srid on completion will contain the Topology-Network SRID.
+ \param has_z on completion will report if the Topology-Network is of the 3D type. 
+ \param allow_coincident on completion will report if the Topology-Network
+ tolerates a Coindident Nodes condition without raising an exception. 
+
+ \return 1 on success: NULL on failure.
+
+ \sa gaiaNetworkCreate, gaiaNetworkDestroy, gaiaNetworkFromCache, 
+ gaiaGetNetwork
+ */
+    GAIANET_DECLARE int gaiaReadNetworkFromDBMS (sqlite3 *
+						 handle,
+						 const char
+						 *net_name,
+						 char **network_name,
+						 int *spatial, int *srid,
+						 int *has_z,
+						 int *allow_coincident);
+
+/**
+ retrieves an already defined opaque Topology-Network Accessor object from the
+ internal connection cache
+
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param network_name unique name identifying the Topology-Network.
+
+ \return pointer to an already existing Topology-Network Accessor Object: NULL on failure.
+
+ \sa gaiaNetworkCreate, gaiaNetworkDestroy, gaiaNetworkFromDBMS, 
+ gaiaGetNetwork
+ */
+    GAIANET_DECLARE GaiaNetworkAccessorPtr gaiaNetworkFromCache (const void
+								 *cache,
+								 const char
+								 *network_name);
+
+/**
+ will attempt to return a reference to a Topology-Network Accessor object
+
+ \param handle pointer to the current DB connection.
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param network_name unique name identifying the Topology-Network.
+
+ \return pointer to Topology-Network Accessor Object: NULL on failure.
+
+ \sa gaiaNetworkCreate, gaiaNetworkDestroy, gaiaNetworkFromCache,
+ gaiaNetworkFromDBMS
+ 
+ \note if a corresponding Topology-Network Accessor Object is already defined
+ will return a pointer to such Objet. Otherwise an attempt will be made
+ in order to create a new Topology-Network Accessor object starting from 
+ its DB configuration.
+ */
+    GAIANET_DECLARE GaiaNetworkAccessorPtr gaiaGetNetwork (sqlite3 *
+							   handle,
+							   const void
+							   *cache,
+							   const char
+							   *network_name);
+
+/**
+ destroys a Topology-Network Accessor object and any related memory allocation
+
+ \param ptr pointer to the Topology-Network Accessor Object to be destroyed.
+
+ \sa gaiaNetworkFromDBMS
+ */
+    GAIANET_DECLARE void gaiaNetworkDestroy (GaiaNetworkAccessorPtr ptr);
+
+/**
+ Adds an isolated node into the Topology-Network
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param pt pointer to the Node Geometry.
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaMoveIsoNetNode, gaiaRemIsoNetNode,
+ gaiaAddLink
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaAddIsoNetNode (GaiaNetworkAccessorPtr ptr,
+						     gaiaPointPtr pt);
+
+/**
+ Moves an isolated node in a Topology-Network from one point to another
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param node the unique identifier of node.
+ \param pt pointer to the Node Geometry.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddIsoNetNode, gaiaRemIsoNetNode
+ */
+    GAIANET_DECLARE int gaiaMoveIsoNetNode (GaiaNetworkAccessorPtr ptr,
+					    sqlite3_int64 node,
+					    gaiaPointPtr pt);
+
+/**
+ Removes an isolated node from a Topology-Network
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param node the unique identifier of node.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddIsoNetNode, gaiaMoveIsoNetNode
+ */
+    GAIANET_DECLARE int gaiaRemIsoNetNode (GaiaNetworkAccessorPtr ptr,
+					   sqlite3_int64 node);
+
+/**
+ Adds a link into the Topology-Network
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param start_node the Start Node's unique identifier.
+ \param end_node the End Node unique identifier.
+ \param ln pointer to the Link Geometry.
+
+ \return the ID of the inserted Link; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddIsoNetNode, gaiaChangeLinkGeom,
+ gaiaRemoveLink, gaiaNewLogLinkSplit, gaiaModLogLinkSplit, 
+ gaiaNewGeoLinkSplit, gaiaModGeoLinkSplit, gaiaNewLinkHeal,
+ gaiaModLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaAddLink (GaiaNetworkAccessorPtr ptr,
+					       sqlite3_int64 start_node,
+					       sqlite3_int64 end_node,
+					       gaiaLinestringPtr ln);
+
+/**
+ Changes the shape of a Link without affecting the Topology-Network structure
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link_id the Link unique identifier.
+ \param ln pointer to the Link Geometry.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaRemoveLink
+ */
+    GAIANET_DECLARE int gaiaChangeLinkGeom (GaiaNetworkAccessorPtr ptr,
+					    sqlite3_int64 link_id,
+					    gaiaLinestringPtr ln);
+
+/**
+ Removes a Link from a Topology-Network
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of link.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink
+ */
+    GAIANET_DECLARE int gaiaRemoveLink (GaiaNetworkAccessorPtr ptr,
+					sqlite3_int64 link);
+
+/**
+ Split a logical link, replacing it with two new links.
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of the link to be split.
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaModLogLinkSplit, 
+ gaiaNewGeoLinkSplit, gaiaModGeoLinkSplit, gaiaNewLinkHeal,
+ gaiaModLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaNewLogLinkSplit (GaiaNetworkAccessorPtr
+						       ptr, sqlite3_int64 link);
+
+/**
+ Split a logical link, modifying the original link and adding a new one.
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of the link to be split.
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaNewLogLinkSplit, 
+ gaiaNewGeoLinkSplit, gaiaModGeoLinkSplit, gaiaNewLinkHeal,
+ gaiaModLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaModLogLinkSplit (GaiaNetworkAccessorPtr
+						       ptr, sqlite3_int64 link);
+
+/**
+ Split a spatial link by a node, replacing it with two new links.
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of the link to be split.
+ \param pt pointer to the Node Geometry.
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaNewLogLinkSplit, 
+ gaiaModLogLinkSplit, gaiaModGeoLinkSplit, gaiaNewLinkHeal,
+ gaiaModLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaNewGeoLinkSplit (GaiaNetworkAccessorPtr
+						       ptr, sqlite3_int64 link,
+						       gaiaPointPtr pt);
+
+/**
+ Split a spatial link by a node, modifying the original link and adding
+ a new one.
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of the link to be split.
+ \param pt pointer to the Node Geometry.
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaNewLogLinkSplit, 
+ gaiaModLogLinkSplit, gaiaNewGeoLinkSplit, gaiaNewLinkHeal,
+ gaiaModLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaModGeoLinkSplit (GaiaNetworkAccessorPtr
+						       ptr, sqlite3_int64 link,
+						       gaiaPointPtr pt);
+
+/**
+ Heal two links by deleting the node connecting them, deleting both links,
+ and replacing them with a new link whose direction is the same as the
+ first link provided.
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of the first link to be healed.
+ \param anotherlink the unique identifier of the second link to be healed.
+
+ \return the ID of the removed Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaNewLogLinkSplit, 
+ gaiaModLogLinkSplit, gaiaNewGeoLinkSplit, gaiaModGeoLinkSplit,
+ gaiaModLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaNewLinkHeal (GaiaNetworkAccessorPtr
+						   ptr, sqlite3_int64 link,
+						   sqlite3_int64 anotherlink);
+
+/**
+ Heal two links by deleting the node connecting them, modfying the first
+ link provided, and deleting the second link.
+ * 
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param link the unique identifier of the first link to be healed.
+ \param anotherlink the unique identifier of the second link to be healed.
+
+ \return the ID of the removed Node; a negative number on failure.
+
+ \sa gaiaNetworkFromDBMS, gaiaAddLink, gaiaNewLogLinkSplit, 
+ gaiaModLogLinkSplit, gaiaNewGeoLinkSplit, gaiaModGeoLinkSplit,
+ gaiaNewLinkHeal
+ */
+    GAIANET_DECLARE sqlite3_int64 gaiaModLinkHeal (GaiaNetworkAccessorPtr
+						   ptr, sqlite3_int64 link,
+						   sqlite3_int64 anotherlink);
+
+/**
+ Creates a temporary table containing a validation report for a given 
+ Logical TopoNet.
+
+ \param ptr pointer to the Topology Accessor Object.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIANET_DECLARE int gaiaValidLogicalNet (GaiaNetworkAccessorPtr ptr);
+
+/**
+ Creates a temporary table containing a validation report for a given 
+ Spatial TopoNet.
+
+ \param ptr pointer to the Topology Accessor Object.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIANET_DECLARE int gaiaValidSpatialNet (GaiaNetworkAccessorPtr ptr);
+
+/**
+ Find the ID of a NetNode at a Point location
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param pt pointer to the Point Geometry.
+ \param tolerance approximation factor.
+
+ \return the ID of a NetNode; -1 on failure.
+
+ \sa gaiaNetworkFromDBMS
+ */
+    GAIANET_DECLARE sqlite3_int64
+	gaiaGetNetNodeByPoint (GaiaNetworkAccessorPtr ptr, gaiaPointPtr pt,
+			       double tolerance);
+
+/**
+ Find the ID of a Link at a Point location
+
+ \param ptr pointer to the Topology-Network Accessor Object.
+ \param pt pointer to the Point Geometry.
+ \param tolerance approximation factor.
+
+ \return the ID of a Link; -1 on failure.
+
+ \sa gaiaNetworkFromDBMS
+ */
+    GAIANET_DECLARE sqlite3_int64
+	gaiaGetLinkByPoint (GaiaNetworkAccessorPtr ptr, gaiaPointPtr pt,
+			    double tolerance);
+
+/**
+ Populates a Network by importing a whole GeoTable
+
+ \param ptr pointer to the Network Accessor Object.
+ \param db-prefix prefix of the DB containing the input GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param table name of the input GeoTable.
+ \param column name of the input Geometry Column.
+ Could be NULL is the input table has just a single Geometry Column.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaNetworkFromDBMS
+ */
+    GAIANET_DECLARE int
+	gaiaTopoNet_FromGeoTable (GaiaNetworkAccessorPtr ptr,
+				  const char *db_prefix, const char *table,
+				  const char *column);
+
+/**
+ Return a Point geometry (seed) identifying a Network Link
+
+ \param ptr pointer to the Network Accessor Object.
+ \param link the unique identifier of the link.
+
+ \return pointer to Geomtry (point); NULL on failure.
+
+ \sa gaiaNetworkFromDBMS
+ */
+    GAIANET_DECLARE gaiaGeomCollPtr
+	gaiaGetLinkSeed (GaiaNetworkAccessorPtr ptr, sqlite3_int64 link);
+
+/**
+ Will update all Seeds for a Topology-Network
+
+ \param ptr pointer to the Network Accessor Object.
+ \param mode if set to 0 a full update of all Seeds will be performed,
+ otherwise an incremental update will happen.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaNetworkFromDBMS
+ */
+    GAIANET_DECLARE int
+	gaiaTopoNetUpdateSeeds (GaiaNetworkAccessorPtr ptr, int mode);
+
+/**
+ Extracts a Simple Features Table out from a Network by matching
+ Network Seeds to a given reference Table.
+
+ \param ptr pointer to the Network Accessor Object.
+ \param db-prefix prefix of the DB containing the reference GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param ref_table name of the reference GeoTable.
+ \param ref_column name of the reference Geometry Column.
+ Could be NULL is the reference table has just a single Geometry Column.
+ \param out_table name of the output table to be created and populated.
+ \param with_spatial_index boolean flag: if set to TRUE (non ZERO) a Spatial
+ Index supporting the output table will be created.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIANET_DECLARE int
+	gaiaTopoNet_ToGeoTable (GaiaNetworkAccessorPtr ptr,
+				const char *db_prefix, const char *ref_table,
+				const char *ref_column, const char *out_table,
+				int with_spatial_index);
+
+/**
+ Extracts a simplified/generalized Simple Features Table out from a Network 
+ by matching Network Seeds to a given reference Table.
+
+ \param ptr pointer to the Network Accessor Object.
+ \param db-prefix prefix of the DB containing the reference GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param ref_table name of the reference GeoTable.
+ \param ref_column name of the reference Geometry Column.
+ Could be NULL is the reference table has just a single Geometry Column.
+ \param out_table name of the output table to be created and populated.
+ \param tolerance approximation radius required by the Douglar-Peucker
+ simplification algorithm.
+ \param with_spatial_index boolean flag: if set to TRUE (non ZERO) a Spatial
+ Index supporting the output table will be created.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIANET_DECLARE int
+	gaiaTopoNet_ToGeoTableGeneralize (GaiaNetworkAccessorPtr ptr,
+					  const char *db_prefix,
+					  const char *ref_table,
+					  const char *ref_column,
+					  const char *out_table,
+					  double tolerance,
+					  int with_spatial_index);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif				/* _GAIANET_H */
diff --git a/src/headers/spatialite/gaia_topology.h b/src/headers/spatialite/gaia_topology.h
new file mode 100644
index 0000000..ecee683
--- /dev/null
+++ b/src/headers/spatialite/gaia_topology.h
@@ -0,0 +1,846 @@
+/*
+ gaia_topology.h -- Gaia common support for Topology
+  
+ version 4.3, 2015 July 15
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+
+/**
+ \file gaia_topology.h
+
+ Topology handling functions and constants 
+ */
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+/* stdio.h included for FILE objects. */
+#include <stdio.h>
+#ifdef DLL_EXPORT
+#define GAIATOPO_DECLARE __declspec(dllexport)
+#else
+#define GAIATOPO_DECLARE extern
+#endif
+#endif
+
+#ifndef _GAIATOPO_H
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+#define _GAIATOPO_H
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ Typedef for Topology Accessor Object (opaque, hidden)
+
+ \sa GaiaTopologyAccessorPtr
+ */
+    typedef struct gaia_topology_accessor GaiaTopologyAccessor;
+/**
+ Typedef for Topology Accessor Object pointer (opaque, hidden)
+
+ \sa GaiaTopologyAccessor
+ */
+    typedef struct gaia_topology_accessor *GaiaTopologyAccessorPtr;
+
+/**
+ returns the last Topology exception (if any)
+
+ \param topo_name unique name identifying the Topology.
+ 
+ \return pointer to the last Topology error message: may be NULL if
+ no Topology error is currently pending.
+ */
+    GAIATOPO_DECLARE const char *gaiaTopologyGetLastException (const char
+							       *topo_name);
+
+/**
+ creates a new Topology and all related DB objects
+
+ \param handle pointer to the current DB connection.
+ \param topo_name unique name identifying the Topology.
+ \param srid a spatial reference identifier.
+ \param tolerance a tolerance factor measuren in the same units defined
+        by the associated SRID.
+ \param has_z boolean: if TRUE this Topology supports 3D (XYZ).
+
+ \return 0 on failure: any other value on success.
+
+ \sa gaiaTopologyDrop
+ */
+    GAIATOPO_DECLARE int gaiaTopologyCreate (sqlite3 * handle,
+					     const char *topo_name, int srid,
+					     double tolerance, int has_z);
+
+/**
+ completely drops an already existing Topology and removes all related DB objects
+
+ \param handle pointer to the current DB connection.
+ \param topo_name unique name identifying the Topology.
+
+ \return 0 on failure: any other value on success.
+
+ \sa gaiaTopologyCreate
+ */
+    GAIATOPO_DECLARE int gaiaTopologyDrop (sqlite3 * handle,
+					   const char *topo_name);
+
+/**
+ creates an opaque Topology Accessor object starting from its DB configuration
+
+ \param handle pointer to the current DB connection.
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param topo_name unique name identifying the Topology.
+
+ \return the pointer to newly created Topology Accessor Object: NULL on failure.
+
+ \sa gaiaTopologyCreate, gaiaTopologyDestroy, gaiaTopologyFromCache, 
+ gaiaGetTopology
+ 
+ \note you are responsible to destroy (before or after) any allocated 
+ Topology Accessor Object. The Topology Accessor once created will be
+ preserved within the internal connection cache for future references.
+ */
+    GAIATOPO_DECLARE GaiaTopologyAccessorPtr gaiaTopologyFromDBMS (sqlite3 *
+								   handle,
+								   const void
+								   *cache,
+								   const char
+								   *topo_name);
+
+/**
+ retrieves a Topology configuration from DB
+
+ \param handle pointer to the current DB connection.
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param topo_name unique name identifying the Topology.
+ \param topology_name on completion will point to the real Topology name.
+ \param srid on completion will contain the Topology SRID.
+ \param tolerance on completion will contain the tolerance argument.
+ \param has_z on completion will report if the Topology is of the 3D type. 
+
+ \return 1 on success: NULL on failure.
+
+ \sa gaiaTopologyCreate, gaiaTopologyDestroy, gaiaTopologyFromCache, 
+ gaiaGetTopology
+ */
+    GAIATOPO_DECLARE int gaiaReadTopologyFromDBMS (sqlite3 *
+						   handle,
+						   const char
+						   *topo_name,
+						   char **topology_name,
+						   int *srid, double *tolerance,
+						   int *has_z);
+
+/**
+ retrieves an already defined opaque Topology Accessor object from the
+ internal connection cache
+
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param topo_name unique name identifying the Topology.
+
+ \return pointer to an already existing Topology Accessor Object: NULL on failure.
+
+ \sa gaiaTopologyCreate, gaiaTopologyDestroy, gaiaTopologyFromDBMS, 
+ gaiaGetTopology
+ */
+    GAIATOPO_DECLARE GaiaTopologyAccessorPtr gaiaTopologyFromCache (const void
+								    *cache,
+								    const char
+								    *topo_name);
+
+/**
+ will attempt to return a reference to a Topology Accessor object
+
+ \param handle pointer to the current DB connection.
+ \param cache pointer to the opaque Cache Object supporting the DB connection
+ \param topo_name unique name identifying the Topology.
+
+ \return pointer to Topology Accessor Object: NULL on failure.
+
+ \sa gaiaTopologyCreate, gaiaTopologyDestroy, gaiaTopologyFromCache,
+ gaiaTopologyFromDBMS
+ 
+ \note if a corresponding Topology Accessor Object is already defined
+ will return a pointer to such Objet. Otherwise an attempt will be made
+ in order to create a new Topology Accessor object starting from its DB 
+ configuration.
+ */
+    GAIATOPO_DECLARE GaiaTopologyAccessorPtr gaiaGetTopology (sqlite3 *
+							      handle,
+							      const void
+							      *cache,
+							      const char
+							      *topo_name);
+
+/**
+ destroys a Topology Accessor object and any related memory allocation
+
+ \param ptr pointer to the Topology Accessor Object to be destroyed.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE void gaiaTopologyDestroy (GaiaTopologyAccessorPtr ptr);
+
+/**
+ Adds an isolated node into the Topology
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param face the unique identifier of containing face or -1 for "unknown".
+ \param pt pointer to the Node Geometry.
+ \param skip_checks boolean: if TRUE skips consistency checks
+ (coincident nodes, crossing edges, actual face containement)
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaAddIsoNode (GaiaTopologyAccessorPtr ptr,
+						   sqlite3_int64 face,
+						   gaiaPointPtr pt,
+						   int skip_checks);
+
+/**
+ Moves an isolated node in a Topology from one point to another
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param node the unique identifier of node.
+ \param pt pointer to the Node Geometry.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int gaiaMoveIsoNode (GaiaTopologyAccessorPtr ptr,
+					  sqlite3_int64 node, gaiaPointPtr pt);
+
+/**
+ Removes an isolated node from a Topology
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param node the unique identifier of node.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int gaiaRemIsoNode (GaiaTopologyAccessorPtr ptr,
+					 sqlite3_int64 node);
+
+/**
+ Adds an isolated edge into the Topology
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param start_node the Start Node's unique identifier.
+ \param end_node the End Node unique identifier.
+ \param ln pointer to the Edge Geometry.
+
+ \return the ID of the inserted Edge; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaAddIsoEdge (GaiaTopologyAccessorPtr ptr,
+						   sqlite3_int64 start_node,
+						   sqlite3_int64 end_node,
+						   gaiaLinestringPtr ln);
+
+/**
+ Removes an isolated edge from a Topology
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge the unique identifier of edge.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int gaiaRemIsoEdge (GaiaTopologyAccessorPtr ptr,
+					 sqlite3_int64 edge);
+
+/**
+ Changes the shape of an Edge without affecting the Topology structure
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge_id the Edge unique identifier.
+ \param ln pointer to the Edge Geometry.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int gaiaChangeEdgeGeom (GaiaTopologyAccessorPtr ptr,
+					     sqlite3_int64 edge_id,
+					     gaiaLinestringPtr ln);
+
+/**
+ Split an edge by a node, modifying the original edge and adding a new one.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge the unique identifier of the edge to be split.
+ \param pt pointer to the Node Geometry.
+ \param skip_checks boolean: if TRUE skips consistency checks
+ (coincident node, point not on edge...)
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaModEdgeSplit (GaiaTopologyAccessorPtr
+						     ptr, sqlite3_int64 edge,
+						     gaiaPointPtr pt,
+						     int skip_checks);
+
+/**
+ Split an edge by a node, replacing it with two new edges.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge the unique identifier of the edge to be split.
+ \param pt pointer to the Node Geometry.
+ \param skip_checks boolean: if TRUE skips consistency checks
+ (coincident node, point not on edge...)
+
+ \return the ID of the inserted Node; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaNewEdgesSplit (GaiaTopologyAccessorPtr
+						      ptr, sqlite3_int64 edge,
+						      gaiaPointPtr pt,
+						      int skip_checks);
+
+/**
+ Adds a new edge possibly splitting and modifying a face.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param start_node the unique identifier of the starting node.
+ \param end_node the unique identifier of the ending node.
+ \param ln pointer to the Edge Geometry.
+ \param skip_checks boolean: if TRUE skips consistency checks
+ (curve being simple and valid, start/end nodes, consistency 
+ actual face containement)
+
+ \return the ID of the inserted Edge; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaAddEdgeModFace (GaiaTopologyAccessorPtr
+						       ptr,
+						       sqlite3_int64 start_node,
+						       sqlite3_int64 end_node,
+						       gaiaLinestringPtr ln,
+						       int skip_checks);
+
+/**
+ Adds a new edge possibly splitting a face (replacing with two new faces).
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param start_node the unique identifier of the starting node.
+ \param end_node the unique identifier of the ending node.
+ \param ln pointer to the Edge Geometry.
+ \param skip_checks boolean: if TRUE skips consistency checks
+ (curve being simple and valid, start/end nodes, consistency 
+ actual face containement)
+
+ \return the ID of the inserted Edge; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaAddEdgeNewFaces (GaiaTopologyAccessorPtr
+							ptr,
+							sqlite3_int64
+							start_node,
+							sqlite3_int64 end_node,
+							gaiaLinestringPtr ln,
+							int skip_checks);
+
+/**
+ Removes an edge, and if the removed edge separated two faces, delete one
+ of them and modify the other to take the space of both.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge_id the unique identifier of the edge to be removed.
+
+ \return the ID of face that takes up the space previously occupied 
+ by the removed edge; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaRemEdgeModFace (GaiaTopologyAccessorPtr
+						       ptr,
+						       sqlite3_int64 edge_id);
+
+/**
+ Removes an edge, and if the removed edge separated two faces, delete the
+ original faces and replace them with a new face.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge_id the unique identifier of the edge to be removed.
+
+ \return the ID of the created face; a negative number on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaRemEdgeNewFace (GaiaTopologyAccessorPtr
+						       ptr,
+						       sqlite3_int64 edge_id);
+
+/**
+ Heal two edges by removing the node connecting them, modifying the
+ first edge and removing the second edge
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge_id1 the unique identifier of the first edge to be healed.
+ \param edge_id2 the unique identifier of the second edge to be healed.
+
+ \return the ID of the removed node.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaModEdgeHeal (GaiaTopologyAccessorPtr
+						    ptr,
+						    sqlite3_int64 edge_id1,
+						    sqlite3_int64 edge_id2);
+
+/**
+ Heal two edges by removing the node connecting them, deleting both edges
+ and replacing them with an edge whose orientation is the same of the
+ first edge provided
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge_id1 the unique identifier of the first edge to be healed.
+ \param edge_id2 the unique identifier of the second edge to be healed.
+
+ \return the ID of the removed node.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64 gaiaNewEdgeHeal (GaiaTopologyAccessorPtr
+						    ptr,
+						    sqlite3_int64 edge_id1,
+						    sqlite3_int64 edge_id2);
+
+/**
+ Return the geometry of a Topology Face
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param face the unique identifier of the face.
+
+ \return pointer to Geomtry (polygon); NULL on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE gaiaGeomCollPtr
+	gaiaGetFaceGeometry (GaiaTopologyAccessorPtr ptr, sqlite3_int64 face);
+
+/**
+ Updates a temporary table containing the ordered list of Edges
+ (in counterclockwise order) for every Face.
+ EdgeIDs are signed value; a negative ID intends reverse direction.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param face the unique identifier of the face.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaGetFaceEdges (GaiaTopologyAccessorPtr ptr, sqlite3_int64 face);
+
+/**
+ Find the ID of a Node at a Point location
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param pt pointer to the Point Geometry.
+ \param tolerance approximation factor.
+
+ \return the ID of a Node; -1 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64
+	gaiaGetNodeByPoint (GaiaTopologyAccessorPtr ptr, gaiaPointPtr pt,
+			    double tolerance);
+
+/**
+ Find the ID of an Edge at a Point location
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param pt pointer to the Point Geometry.
+ \param tolerance approximation factor.
+
+ \return the ID of an Edge; -1 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64
+	gaiaGetEdgeByPoint (GaiaTopologyAccessorPtr ptr, gaiaPointPtr pt,
+			    double tolerance);
+
+/**
+ Find the ID of a Face at a Point location
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param pt pointer to the Point Geometry.
+ \param tolerance approximation factor.
+
+ \return the ID of a Face; -1 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64
+	gaiaGetFaceByPoint (GaiaTopologyAccessorPtr ptr, gaiaPointPtr pt,
+			    double tolerance);
+
+/**
+ Transforms a (multi)Linestring or (multi)Polygon into an new MultiLinestring.
+
+ \param geom pointer to the input Geometry (Linestring, MultiLinestring,
+ Polygon or MultiPolygon).
+ \param line_max_points if set to a positive number all input Linestrings 
+ and/or Polygon Rings will be split into simpler Lines having no more than
+ this maximum number of points. 
+ \param max_length if set to a positive value all input Linestrings 
+ and/or Polygon Rings will be split into simpler Lines having a length
+ not exceeding this threshold. If both line_max_points and max_legth
+ are set as the same time the first condition occurring will cause
+ a new Line to be started.
+
+ \return a MultiLinestring Geometry; NULL on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE gaiaGeomCollPtr
+	gaiaTopoGeo_SubdivideLines (gaiaGeomCollPtr geom, int line_max_points,
+				    double max_length);
+
+/**
+ Adds a Point to an existing Topology and possibly splitting an Edge.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param pt pointer to the Point Geometry.
+ \param tolerance approximation factor.
+
+ \return the ID of the Node; -1 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE sqlite3_int64
+	gaiaTopoGeo_AddPoint (GaiaTopologyAccessorPtr ptr, gaiaPointPtr pt,
+			      double tolerance);
+
+/**
+ Adds a Linestring to an existing Topology and possibly splitting Edges/Faces.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param ln pointer to the Linestring Geometry.
+ \param tolerance approximation factor.
+ \param edge_ids on success will point to an array of Edge IDs
+ \param ids_count on success will report the number of Edge IDs in the
+ above array
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_AddLineString (GaiaTopologyAccessorPtr ptr,
+				   gaiaLinestringPtr pt, double tolerance,
+				   sqlite3_int64 ** edge_ids, int *ids_count);
+
+/**
+ Adds a Polygon to an existing Topology and possibly splitting Edges/Faces.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param pg pointer to the Polygon Geometry.
+ \param tolerance approximation factor.
+ \param face_ids on success will point to an array of Face IDs
+ \param ids_count on success will report the number of Face IDs in the
+ above array
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_AddPolygon (GaiaTopologyAccessorPtr ptr, gaiaPolygonPtr pg,
+				double tolerance, sqlite3_int64 ** face_ids,
+				int *ids_count);
+
+/**
+ Populates a Topology by importing a whole GeoTable
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param db-prefix prefix of the DB containing the input GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param table name of the input GeoTable.
+ \param column name of the input Geometry Column.
+ Could be NULL is the input table has just a single Geometry Column.
+ \param tolerance approximation factor.
+ \param line_max_points if set to a positive number all input Linestrings
+ and/or Polygon Rings will be split into simpler Linestrings having no more 
+ than this maximum number of points. 
+ \param max_length if set to a positive value all input Linestrings 
+ and/or Polygon Rings will be split into simpler Lines having a length
+ not exceeding this threshold. If both line_max_points and max_legth
+ are set as the same time the first condition occurring will cause
+ a new Line to be started. 
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_FromGeoTable (GaiaTopologyAccessorPtr ptr,
+				  const char *db_prefix, const char *table,
+				  const char *column, double tolerance,
+				  int line_max_points, double max_length);
+
+/**
+ Creates a temporary table containing a validation report for a given TopoGeo.
+
+ \param ptr pointer to the Topology Accessor Object.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int gaiaValidateTopoGeo (GaiaTopologyAccessorPtr ptr);
+
+/**
+ Return a Point geometry (seed) identifying a Topology Edge
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param edge the unique identifier of the edge.
+
+ \return pointer to Geomtry (point); NULL on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE gaiaGeomCollPtr
+	gaiaGetEdgeSeed (GaiaTopologyAccessorPtr ptr, sqlite3_int64 edge);
+
+/**
+ Return a Point geometry (seed) identifying a Topology Face
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param face the unique identifier of the face.
+
+ \return pointer to Geomtry (point); NULL on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE gaiaGeomCollPtr
+	gaiaGetFaceSeed (GaiaTopologyAccessorPtr ptr, sqlite3_int64 face);
+
+/**
+ Will update all Seeds for a Topology-Geometry
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param mode if set to 0 a full update of all Seeds will be performed,
+ otherwise an incremental update will happen.
+
+ \return 1 on success; 0 on failure.
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeoUpdateSeeds (GaiaTopologyAccessorPtr ptr, int mode);
+
+/**
+ Extracts a Simple Features Table out from a Topology by matching
+ Topology Seeds to a given reference Table.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param db-prefix prefix of the DB containing the reference GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param ref_table name of the reference GeoTable.
+ \param ref_column name of the reference Geometry Column.
+ Could be NULL is the reference table has just a single Geometry Column.
+ \param out_table name of the output output table to be created and populated.
+ \param with_spatial_index boolean flag: if set to TRUE (non ZERO) a Spatial
+ Index supporting the output table will be created.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_ToGeoTable (GaiaTopologyAccessorPtr ptr,
+				const char *db_prefix, const char *ref_table,
+				const char *ref_column, const char *out_table,
+				int with_spatial_index);
+
+/**
+ Extracts a simplified/generalized Simple Features Table out from a Topology 
+ by matching Topology Seeds to a given reference Table.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param db-prefix prefix of the DB containing the reference GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param ref_table name of the reference GeoTable.
+ \param ref_column name of the reference Geometry Column.
+ Could be NULL is the reference table has just a single Geometry Column.
+ \param out_table name of the output output table to be created and populated.
+ \param tolerance approximation radius required by the Douglar-Peucker
+ simplification algorithm.
+ \param with_spatial_index boolean flag: if set to TRUE (non ZERO) a Spatial
+ Index supporting the output table will be created.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_ToGeoTableGeneralize (GaiaTopologyAccessorPtr ptr,
+					  const char *db_prefix,
+					  const char *ref_table,
+					  const char *ref_column,
+					  const char *out_table,
+					  double tolerance,
+					  int with_spatial_index);
+
+/**
+ creates a TopoLayer and its corresponding Feature relations for a given 
+ Topology by matching Topology Seeds to a given reference Table.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param db-prefix prefix of the DB containing the reference GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param ref_table name of the reference GeoTable.
+ \param ref_column name of the reference Geometry Column.
+ Could be NULL is the reference table has just a single Geometry Column.
+ \param topolayer_name name of the TopoLayer to be created.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_CreateTopoLayer (GaiaTopologyAccessorPtr ptr,
+				     const char *db_prefix,
+				     const char *ref_table,
+				     const char *ref_column,
+				     const char *topolayer_name);
+
+/**
+ initializes a TopoLayer (laking all corresponding Feature relations) for a given 
+ Topology from a given reference Table.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param db-prefix prefix of the DB containing the reference GeoTable.
+ If NULL the "main" DB will be intended by default.
+ \param ref_table name of the reference GeoTable.
+ \param topolayer_name name of the TopoLayer to be created.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_InitTopoLayer (GaiaTopologyAccessorPtr ptr,
+				   const char *db_prefix,
+				   const char *ref_table,
+				   const char *topolayer_name);
+
+/**
+ completely removes a TopoLayer from a Topology.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param topolayer_name name of the TopoLayer to be removed.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_RemoveTopoLayer (GaiaTopologyAccessorPtr ptr,
+				     const char *topolayer_name);
+
+/**
+ creates a GeoTable by exporting Features out from a given TopoLayer.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param topolayer_name name of an existing TopoLayer.
+ \param out_table name of the output GeoTable to be created.
+ \param with_spatial_index boolean flag: if set to TRUE (non ZERO) a Spatial
+ Index supporting the output table will be created.
+ \param create_only boolean flag; is set to any value != 0 (TRUE)
+ just the output table will be creayed but no TopoFeature will
+ be actually inserted.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_ExportTopoLayer (GaiaTopologyAccessorPtr ptr,
+				     const char *topolayer_name,
+				     const char *out_table,
+				     int with_spatial_index, int create_only);
+
+/**
+ inserts into the output GeoTable a single Features extracted out 
+ from a given TopoLayer.
+
+ \param ptr pointer to the Topology Accessor Object.
+ \param topolayer_name name of an existing TopoLayer.
+ \param out_table name of the target GeoTable.
+ \param fid unique identifier of the TopoLayer's Feature to
+ be inserted.
+
+ \return 1 on success; -1 on failure (will raise an exception).
+
+ \sa gaiaTopologyFromDBMS
+ */
+    GAIATOPO_DECLARE int
+	gaiaTopoGeo_InsertFeatureFromTopoLayer (GaiaTopologyAccessorPtr ptr,
+						const char *topolayer_name,
+						const char *out_table,
+						sqlite3_int64 fid);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif				/* _GAIATOPO_H */
diff --git a/src/headers/spatialite/gg_advanced.h b/src/headers/spatialite/gg_advanced.h
index de6fbc9..aba496f 100644
--- a/src/headers/spatialite/gg_advanced.h
+++ b/src/headers/spatialite/gg_advanced.h
@@ -3546,6 +3546,21 @@ extern "C"
 					   gaiaGeomCollPtr geom2, double *dist);
 
 /**
+ Calculates the 2D or 3D Length for a Linestring or Multilinestring
+ accordingly to the dimensions of Geometry
+
+ \param geom the Geometry object 
+ \param length on completion this variable will contain the calculated length
+
+ \return 0 on failure: any other value on success.
+
+ \sa gaiaGeomCollDistance
+
+ \remark \b LWGEOM support required.
+ */
+    GAIAGEO_DECLARE int gaia3dLength (gaiaGeomCollPtr geom, double *length);
+
+/**
  Utility function: Split
 
  \param input the input Geometry object.
diff --git a/src/headers/spatialite/gg_formats.h b/src/headers/spatialite/gg_formats.h
index 90fc5df..a35b204 100644
--- a/src/headers/spatialite/gg_formats.h
+++ b/src/headers/spatialite/gg_formats.h
@@ -1415,6 +1415,7 @@ extern "C"
  \param srid feature's SRID 
 
  \return 0 on failure: any other value on success.
+ -1 when the corresponding DBF record is marked as DELETED.
 
  \sa gaiaAllocShapefile, gaiaFreeShapefile, gaiaOpenShpRead, gaiaOpenShpWrite,
  gaiaShpAnalyze, gaiaWriteShpEntity, gaiaFlushShpHeaders
diff --git a/src/headers/spatialite/gg_xml.h b/src/headers/spatialite/gg_xml.h
index f37f9bd..007542b 100644
--- a/src/headers/spatialite/gg_xml.h
+++ b/src/headers/spatialite/gg_xml.h
@@ -106,6 +106,8 @@ extern "C"
 #define GAIA_XML_SLD_STYLE		0x48
 /** XmlBLOB FLAG - SVG bitmask */
 #define GAIA_XML_SVG			0x20
+/** XmlBLOB FLAG - GPX bitmask */
+#define GAIA_XML_GPX			0x08
 
 
 /* function prototypes */
@@ -218,7 +220,7 @@ extern "C"
  \sa gaiaIsCompressedXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsIsoMetadataXmlBlob, gaiaIsSldSeVectorStyleXmlBlob, 
  gaiaIsSldSeRasterStyleXmlBlob, gaiaIsSldStyleXmlBlob,
- gaiaIsSvgXmlBlob
+ gaiaIsSvgXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsValidXmlBlob (const unsigned char *blob,
 					    int size);
@@ -234,7 +236,7 @@ extern "C"
  \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsIsoMetadataXmlBlob, gaiaIsSldSeVectorStyleXmlBlob, 
  gaiaIsSldSeRasterStyleXmlBlob, gaiaIsSldStyleXmlBlob,
- gaiaIsSvgXmlBlob
+ gaiaIsSvgXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsCompressedXmlBlob (const unsigned char *blob,
 						 int size);
@@ -250,7 +252,7 @@ extern "C"
  \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsCompressedXmlBlob, gaiaIsSldSeVectorStyleXmlBlob, 
  gaiaIsSldSeRasterStyleXmlBlob, gaiaIsSldStyleXmlBlob,
- gaiaIsSvgXmlBlob
+ gaiaIsSvgXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsIsoMetadataXmlBlob (const unsigned char *blob,
 						  int size);
@@ -266,7 +268,7 @@ extern "C"
 
  \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsCompressedXmlBlob, gaiaIsIsoMetadataXmlBlob, 
- gaiaIsSldSeRasterStyleXmlBlob, gaiaIsSvgXmlBlob
+ gaiaIsSldSeRasterStyleXmlBlob, gaiaIsSvgXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsSldSeVectorStyleXmlBlob (const unsigned char
 						       *blob, int size);
@@ -283,7 +285,7 @@ extern "C"
  \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsCompressedXmlBlob, gaiaIsIsoMetadataXmlBlob, 
  gaiaIsSldSeVectorStyleXmlBlob, gaiaIsSldStyleXmlBlob,
- gaiaIsSvgXmlBlob
+ gaiaIsSvgXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsSldSeRasterStyleXmlBlob (const unsigned char
 						       *blob, int size);
@@ -300,7 +302,7 @@ extern "C"
  \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsCompressedXmlBlob, gaiaIsIsoMetadataXmlBlob, 
  gaiaIsSldSeVectorStyleXmlBlob, gaiaIsSldSeRasterXmlBlob,
- gaiaIsSvgXmlBlob
+ gaiaIsSvgXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsSldStyleXmlBlob (const unsigned char
 					       *blob, int size);
@@ -316,11 +318,26 @@ extern "C"
  \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
  gaiaIsCompressedXmlBlob, gaiaIsIsoMetadataXmlBlob, 
  gaiaIsSldSeVectorStyleXmlBlob, gaiaIsSldStyleXmlBlob,
- gaiaIsSldSeRasterStyleXmlBlob
+ gaiaIsSldSeRasterStyleXmlBlob, gaiaIsGpxXmlBlob
  */
     GAIAGEO_DECLARE int gaiaIsSvgXmlBlob (const unsigned char *blob, int size);
 
 /**
+ Checks if a valid XmlBLOB buffer does contain a GPX document or not
+
+ \param blob pointer to the XmlBLOB buffer.
+ \param size XmlBLOB's size (in bytes).
+
+ \return TRUE or FALSE if the BLOB actually is a valid XmlBLOB; -1 in any other case.
+
+ \sa gaiaIsValidXmlBlob, gaiaIsSchemaValidatedXmlBlob, 
+ gaiaIsCompressedXmlBlob, gaiaIsIsoMetadataXmlBlob, 
+ gaiaIsSldSeVectorStyleXmlBlob, gaiaIsSldStyleXmlBlob,
+ gaiaIsSldSeRasterStyleXmlBlob, gaiaIsSvgXmlBlob
+ */
+    GAIAGEO_DECLARE int gaiaIsGpxXmlBlob (const unsigned char *blob, int size);
+
+/**
  Return another XmlBLOB buffer compressed / uncompressed
 
  \param blob pointer to the input XmlBLOB buffer.
@@ -605,19 +622,19 @@ extern "C"
 						  *blob, int size);
 
 /**
- Return the Geometry Buffer from a valid XmlBLOB buffer
+ Return the Geometry buffer from a valid XmlBLOB buffer
 
  \param blob pointer to the XmlBLOB buffer.
  \param size XmlBLOB's size (in bytes).
  \param blob_geom on completion this variable will contain
- a pointer to the returned Geometry Buffer (NULL if no Geometry
+ a pointer to the returned Geometry buffer (NULL if no Geometry
  was defined within the XmlBLOB)
  \param blob_size on completion this variable will contain
- the size (in bytes) of the returned Geometry Buffer
+ the size (in bytes) of the returned Geometry buffer
 
  \sa gaiaIsIsoMetadataXmlBlob
 
- \note the returned Geometry Buffer corresponds to dynamically allocated memory:
+ \note the returned Geometry buffer corresponds to dynamically allocated memory:
  so you are responsible to free() it before or after.
  */
     GAIAGEO_DECLARE void gaiaXmlBlobGetGeometry (const unsigned char
@@ -626,6 +643,25 @@ extern "C"
 						 int *blob_size);
 
 /**
+ Return a MultiLinestring Geometry from a valid GPX XmlBLOB buffer
+
+ \param blob pointer to the XmlBLOB buffer.
+ \param size XmlBLOB's size (in bytes).
+ \param db_handle handle to the current SQLite connection
+ 
+ \return a Geometry of the MultiLinestring type, or NULL
+
+ \sa gaiaIsIsoMetadataXmlBlob
+
+ \note the returned Geometry corresponds to dynamically allocated memory:
+ so you are responsible to free() it before or after.
+ */
+    GAIAGEO_DECLARE gaiaGeomCollPtr gaiaXmlBlobMLineFromGPX (const unsigned char
+							     *blob, int size,
+							     sqlite3 *
+							     db_handle);
+
+/**
  Return the Charset Encoding from a valid XmlBLOB buffer
 
  \param blob pointer to the XmlBLOB buffer.
diff --git a/src/headers/spatialite/spatialite.h b/src/headers/spatialite/spatialite.h
index 67b784f..d549c5f 100644
--- a/src/headers/spatialite/spatialite.h
+++ b/src/headers/spatialite/spatialite.h
@@ -55,6 +55,7 @@ SPATIALITE_PRIVATE int virtualbbox_extension_init (void *db,
 SPATIALITE_PRIVATE int mbrcache_extension_init (void *db);
 SPATIALITE_PRIVATE int virtual_spatialindex_extension_init (void *db);
 SPATIALITE_PRIVATE int virtual_elementary_extension_init (void *db);
+SPATIALITE_PRIVATE int virtual_knn_extension_init (void *db);
 SPATIALITE_PRIVATE int virtual_xpath_extension_init (void *db,
 						     const void *p_cache);
 SPATIALITE_PRIVATE int virtualgpkg_extension_init (void *db);
diff --git a/src/headers/spatialite_private.h b/src/headers/spatialite_private.h
index 2101e77..9230028 100644
--- a/src/headers/spatialite_private.h
+++ b/src/headers/spatialite_private.h
@@ -138,12 +138,24 @@ extern "C"
 	void *xmlParsingErrors;
 	void *xmlSchemaValidationErrors;
 	void *xmlXPathErrors;
+	char *cutterMessage;
 	struct splite_geos_cache_item cacheItem1;
 	struct splite_geos_cache_item cacheItem2;
 	struct splite_xmlSchema_cache_item xmlSchemaCache[MAX_XMLSCHEMA_CACHE];
 	int pool_index;
 	void (*geos_warning) (const char *fmt, ...);
 	void (*geos_error) (const char *fmt, ...);
+	char *gaia_geos_error_msg;
+	char *gaia_geos_warning_msg;
+	char *gaia_geosaux_error_msg;
+	void *firstTopology;
+	void *lastTopology;
+	void *firstNetwork;
+	void *lastNetwork;
+	unsigned int next_topo_savepoint;
+	char *topo_savepoint_name;
+	unsigned int next_network_savepoint;
+	char *network_savepoint_name;
 	unsigned char magic2;
     };
 
@@ -205,6 +217,10 @@ extern "C"
     SPATIALITE_PRIVATE void free_internal_cache (struct splite_internal_cache
 						 *cache);
 
+    SPATIALITE_PRIVATE void free_internal_cache_topologies (void *first);
+
+    SPATIALITE_PRIVATE void free_internal_cache_networks (void *first);
+
     SPATIALITE_PRIVATE struct epsg_defs *add_epsg_def (int filter_srid,
 						       struct epsg_defs **first,
 						       struct epsg_defs **last,
@@ -329,10 +345,6 @@ extern "C"
     SPATIALITE_PRIVATE void getProjParams (void *p_sqlite, int srid,
 					   char **params);
 
-    SPATIALITE_PRIVATE void getProjParamsEx (void *p_sqlite, int srid,
-					     char **params,
-					     int gpkg_amphibious_mode);
-
     SPATIALITE_PRIVATE int getEllipsoidParams (void *p_sqlite, int srid,
 					       double *a, double *b,
 					       double *rf);
@@ -629,6 +641,8 @@ extern "C"
 
     SPATIALITE_PRIVATE void splite_lwgeom_init (void);
 
+    SPATIALITE_PRIVATE void splite_lwgeomtopo_init (void);
+
     SPATIALITE_PRIVATE void splite_free_geos_cache_item (struct
 							 splite_geos_cache_item
 							 *p);
@@ -679,6 +693,12 @@ extern "C"
 							const char *in_table,
 							const char *out_table);
 
+    SPATIALITE_PRIVATE const void *gaiaAuxClonerCreateEx (const void *sqlite,
+							  const char *db_prefix,
+							  const char *in_table,
+							  const char *out_table,
+							  int create_only);
+
     SPATIALITE_PRIVATE void gaiaAuxClonerDestroy (const void *cloner);
 
     SPATIALITE_PRIVATE void gaiaAuxClonerAddOption (const void *cloner,
@@ -692,6 +712,282 @@ extern "C"
 						  int blob_sz, double *E,
 						  double *N, double *Z);
 
+/* Topology SQL functions */
+    SPATIALITE_PRIVATE void fnctaux_GetLastTopologyException (const void
+							      *context,
+							      int argc,
+							      const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_CreateTopology (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_DropTopology (const void *context, int argc,
+						  const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddIsoNode (const void *context, int argc,
+						const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_MoveIsoNode (const void *context, int argc,
+						 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_RemIsoNode (const void *context,
+						int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddIsoEdge (const void *context, int argc,
+						const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddEdgeModFace (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddEdgeNewFaces (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_RemEdgeNewFace (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_RemEdgeModFace (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ChangeEdgeGeom (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_RemIsoEdge (const void *context,
+						int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddIsoEdge (const void *context, int argc,
+						const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ModEdgeSplit (const void *context, int argc,
+						  const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_NewEdgesSplit (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ModEdgeHeal (const void *context, int argc,
+						 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_NewEdgeHeal (const void *context, int argc,
+						 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetFaceEdges (const void *context, int argc,
+						  const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetFaceGeometry (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ValidateTopoGeo (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_CreateTopoGeo (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetNodeByPoint (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetEdgeByPoint (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetFaceByPoint (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_AddPoint (const void *context,
+						      int argc,
+						      const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_AddLineString (const void *context,
+							   int argc,
+							   const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_FromGeoTable (const void *context,
+							  int argc,
+							  const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_ToGeoTable (const void *context,
+							int argc,
+							const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_ToGeoTableGeneralize (const void
+								  *context,
+								  int argc,
+								  const void
+								  *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_CreateTopoLayer (const void
+							     *context, int argc,
+							     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_InitTopoLayer (const void
+							   *context, int argc,
+							   const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_RemoveTopoLayer (const void
+							     *context, int argc,
+							     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_ExportTopoLayer (const void
+							     *context, int argc,
+							     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_InsertFeatureFromTopoLayer (const
+									void
+									*context,
+									int
+									argc,
+									const
+									void
+									*argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_Clone (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_SubdivideLines (const void *context,
+							    int argc,
+							    const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_GetEdgeSeed (const void *context,
+							 int argc,
+							 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_GetFaceSeed (const void *context,
+							 int argc,
+							 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoGeo_UpdateSeeds (const void *context,
+							 int argc,
+							 const void *argv);
+
+    SPATIALITE_PRIVATE void start_topo_savepoint (const void *handle,
+						  const void *cache);
+
+    SPATIALITE_PRIVATE void release_topo_savepoint (const void *handle,
+						    const void *cache);
+
+    SPATIALITE_PRIVATE void rollback_topo_savepoint (const void *handle,
+						     const void *cache);
+
+/* Topology-Network SQL functions */
+    SPATIALITE_PRIVATE void fnctaux_GetLastNetworkException (const void
+							     *context,
+							     int argc,
+							     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_CreateNetwork (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_DropNetwork (const void *context, int argc,
+						 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddIsoNetNode (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_MoveIsoNetNode (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_RemIsoNetNode (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_AddLink (const void *context, int argc,
+					     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ChangeLinkGeom (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_RemoveLink (const void *context, int argc,
+						const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_NewLogLinkSplit (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ModLogLinkSplit (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_NewGeoLinkSplit (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ModGeoLinkSplit (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_NewLinkHeal (const void *context, int argc,
+						 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ModLinkHeal (const void *context, int argc,
+						 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_LogiNetFromTGeo (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_SpatNetFromTGeo (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_SpatNetFromGeom (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ValidLogicalNet (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_ValidSpatialNet (const void *context,
+						     int argc,
+						     const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetNetNodeByPoint (const void *context,
+						       int argc,
+						       const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_GetLinkByPoint (const void *context,
+						    int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_FromGeoTable (const void *context,
+							  int argc,
+							  const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_ToGeoTable (const void *context,
+							int argc,
+							const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_ToGeoTableGeneralize (const void
+								  *context,
+								  int argc,
+								  const void
+								  *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_ToGeoTableGeneralize (const void
+								  *context,
+								  int argc,
+								  const void
+								  *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_Clone (const void *context,
+						   int argc, const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_GetLinkSeed (const void *context,
+							 int argc,
+							 const void *argv);
+
+    SPATIALITE_PRIVATE void fnctaux_TopoNet_UpdateSeeds (const void *context,
+							 int argc,
+							 const void *argv);
+
+    SPATIALITE_PRIVATE void start_net_savepoint (const void *handle,
+						 const void *cache);
+
+    SPATIALITE_PRIVATE void release_net_savepoint (const void *handle,
+						   const void *cache);
+
+    SPATIALITE_PRIVATE void rollback_net_savepoint (const void *handle,
+						    const void *cache);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/shapefiles/shapefiles.c b/src/shapefiles/shapefiles.c
index 4fe3420..b15fff9 100644
--- a/src/shapefiles/shapefiles.c
+++ b/src/shapefiles/shapefiles.c
@@ -419,6 +419,7 @@ load_shapefile_ex2 (sqlite3 * sqlite, char *shp_path, char *table,
     int dup;
     int idup;
     int current_row;
+    int deleted = 0;
     char **col_name = NULL;
     unsigned char *blob;
     int blob_size;
@@ -684,7 +685,7 @@ load_shapefile_ex2 (sqlite3 * sqlite, char *shp_path, char *table,
 		xdummy = sqlite3_mprintf ("COL_%d", seed++);
 		spatialite_e
 		    ("Warning: duplicated fieldName \"%s\" in shapefile \"%s\": "
-		     "renaming the second occurence in table \"%s\" as \"%s\".\n",
+		     "renaming the second occurrence in table \"%s\" as \"%s\".\n",
 		     dummy, shp_path, table, xdummy);
 		dummy = xdummy;
 	    }
@@ -1100,6 +1101,13 @@ load_shapefile_ex2 (sqlite3 * sqlite, char *shp_path, char *table,
       {
 	  /* inserting rows from shapefile */
 	  ret = gaiaReadShpEntity_ex (shp, current_row, srid, text_dates);
+	  if (ret < 0)
+	    {
+		/* found a DBF deleted record */
+		current_row++;
+		deleted++;
+		continue;
+	    }
 	  if (!ret)
 	    {
 		if (!(shp->LastError))	/* normal SHP EOF */
@@ -1256,14 +1264,14 @@ load_shapefile_ex2 (sqlite3 * sqlite, char *shp_path, char *table,
 		return 0;
 	    }
 	  if (rows)
-	      *rows = current_row;
+	      *rows = current_row - deleted;
 	  if (verbose)
 	      spatialite_e
 		  ("\nInserted %d rows into '%s' from SHAPEFILE\n========\n",
-		   current_row, table);
+		   current_row - deleted, table);
 	  if (err_msg)
 	      sprintf (err_msg, "Inserted %d rows into '%s' from SHAPEFILE",
-		       current_row, table);
+		       current_row - deleted, table);
 	  return 1;
       }
 }
diff --git a/src/shapefiles/validator.c b/src/shapefiles/validator.c
index 7252a51..ace9ee9 100644
--- a/src/shapefiles/validator.c
+++ b/src/shapefiles/validator.c
@@ -2409,9 +2409,9 @@ sanitize_geometry_column_common (const void *p_cache, sqlite3 * sqlite,
     free_sanitize_report (report);
     if (out)
 	fclose (out);
-	
+
 #endif /* end LWGEOM conditional */
-    
+
     return 0;
 }
 
diff --git a/src/spatialite/Makefile.am b/src/spatialite/Makefile.am
index 66ad19e..c5cedc2 100644
--- a/src/spatialite/Makefile.am
+++ b/src/spatialite/Makefile.am
@@ -22,7 +22,8 @@ SPATIALITE_COMMON_SOURCES = mbrcache.c \
 	virtualnetwork.c \
 	virtualshape.c \
 	virtualxpath.c \
-	virtualelementary.c
+	virtualelementary.c \
+	virtualknn.c
 
 libsplite_la_SOURCES = $(SPATIALITE_COMMON_SOURCES)
 
diff --git a/src/spatialite/Makefile.in b/src/spatialite/Makefile.in
index 259be7b..296d058 100644
--- a/src/spatialite/Makefile.in
+++ b/src/spatialite/Makefile.in
@@ -112,7 +112,8 @@ am__objects_1 = libsplite_la-mbrcache.lo libsplite_la-spatialite.lo \
 	libsplite_la-virtualgpkg.lo libsplite_la-virtualbbox.lo \
 	libsplite_la-virtualspatialindex.lo \
 	libsplite_la-virtualnetwork.lo libsplite_la-virtualshape.lo \
-	libsplite_la-virtualxpath.lo libsplite_la-virtualelementary.lo
+	libsplite_la-virtualxpath.lo libsplite_la-virtualelementary.lo \
+	libsplite_la-virtualknn.lo
 am_libsplite_la_OBJECTS = $(am__objects_1)
 libsplite_la_OBJECTS = $(am_libsplite_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
@@ -132,7 +133,7 @@ am__objects_2 = splite_la-mbrcache.lo splite_la-spatialite.lo \
 	splite_la-virtualgpkg.lo splite_la-virtualbbox.lo \
 	splite_la-virtualspatialindex.lo splite_la-virtualnetwork.lo \
 	splite_la-virtualshape.lo splite_la-virtualxpath.lo \
-	splite_la-virtualelementary.lo
+	splite_la-virtualelementary.lo splite_la-virtualknn.lo
 am_splite_la_OBJECTS = $(am__objects_2)
 splite_la_OBJECTS = $(am_splite_la_OBJECTS)
 splite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
@@ -350,7 +351,8 @@ SPATIALITE_COMMON_SOURCES = mbrcache.c \
 	virtualnetwork.c \
 	virtualshape.c \
 	virtualxpath.c \
-	virtualelementary.c
+	virtualelementary.c \
+	virtualknn.c
 
 libsplite_la_SOURCES = $(SPATIALITE_COMMON_SOURCES)
 libsplite_la_CFLAGS = -fvisibility=hidden
@@ -433,6 +435,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualelementary.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualfdo.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualgpkg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualknn.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualnetwork.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualshape.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libsplite_la-virtualspatialindex.Plo at am__quote@
@@ -452,6 +455,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualelementary.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualfdo.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualgpkg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualknn.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualnetwork.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualshape.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/splite_la-virtualspatialindex.Plo at am__quote@
@@ -611,6 +615,13 @@ libsplite_la-virtualelementary.lo: virtualelementary.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsplite_la_CFLAGS) $(CFLAGS) -c -o libsplite_la-virtualelementary.lo `test -f 'virtualelementary.c' || echo '$(srcdir)/'`virtualelementary.c
 
+libsplite_la-virtualknn.lo: virtualknn.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsplite_la_CFLAGS) $(CFLAGS) -MT libsplite_la-virtualknn.lo -MD -MP -MF $(DEPDIR)/libsplite_la-virtualknn.Tpo -c -o libsplite_la-virtualknn.lo `test -f 'virtualknn.c' || echo '$(srcdir)/'`virtualknn.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsplite_la-virtualknn.Tpo $(DEPDIR)/libsplite_la-virtualknn.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='virtualknn.c' object='libsplite_la-virtualknn.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsplite_la_CFLAGS) $(CFLAGS) -c -o libsplite_la-virtualknn.lo `test -f 'virtualknn.c' || echo '$(srcdir)/'`virtualknn.c
+
 splite_la-mbrcache.lo: mbrcache.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(splite_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(splite_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT splite_la-mbrcache.lo -MD -MP -MF $(DEPDIR)/splite_la-mbrcache.Tpo -c -o splite_la-mbrcache.lo `test -f 'mbrcache.c' || echo '$(srcdir)/'`mbrcache.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/splite_la-mbrcache.Tpo $(DEPDIR)/splite_la-mbrcache.Plo
@@ -744,6 +755,13 @@ splite_la-virtualelementary.lo: virtualelementary.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(splite_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(splite_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o splite_la-virtualelementary.lo `test -f 'virtualelementary.c' || echo '$(srcdir)/'`virtualelementary.c
 
+splite_la-virtualknn.lo: virtualknn.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(splite_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(splite_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT splite_la-virtualknn.lo -MD -MP -MF $(DEPDIR)/splite_la-virtualknn.Tpo -c -o splite_la-virtualknn.lo `test -f 'virtualknn.c' || echo '$(srcdir)/'`virtualknn.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/splite_la-virtualknn.Tpo $(DEPDIR)/splite_la-virtualknn.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='virtualknn.c' object='splite_la-virtualknn.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(splite_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(splite_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o splite_la-virtualknn.lo `test -f 'virtualknn.c' || echo '$(srcdir)/'`virtualknn.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
diff --git a/src/spatialite/spatialite.c b/src/spatialite/spatialite.c
index 2e9dcdb..977896c 100644
--- a/src/spatialite/spatialite.c
+++ b/src/spatialite/spatialite.c
@@ -109,6 +109,11 @@ Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
 #endif
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -454,7 +459,20 @@ fnct_has_geos_trunk (sqlite3_context * context, int argc, sqlite3_value ** argv)
 / return 1 if built including GEOS-TRUNK; otherwise 0
 */
     GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
-#ifdef GEOS_TRUNK		/* GEOS-TRUNK is supported */
+    sqlite3_result_int (context, 0);
+}
+
+static void
+fnct_has_geos_reentrant (sqlite3_context * context, int argc,
+			 sqlite3_value ** argv)
+{
+/* SQL function:
+/ HasGeosReentrant()
+/
+/ return 1 if built including GEOS-REENTRANT; otherwise 0
+*/
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+#ifdef GEOS_REENTRANT		/* GEOS-REENTRANT is supported */
     sqlite3_result_int (context, 1);
 #else
     sqlite3_result_int (context, 0);
@@ -462,6 +480,27 @@ fnct_has_geos_trunk (sqlite3_context * context, int argc, sqlite3_value ** argv)
 }
 
 static void
+fnct_has_geos_only_reentrant (sqlite3_context * context, int argc,
+			      sqlite3_value ** argv)
+{
+/* SQL function:
+/ HasGeosOnlyReentrant()
+/
+/ return 1 if built including GEOS-ONLY_REENTRANT; otherwise 0
+*/
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+#ifdef GEOS_REENTRANT		/* GEOS-REENTRANT is supported */
+#ifdef GEOS_ONLY_REENTRANT	/* GEOS-ONLY-REENTRANT is supported */
+    sqlite3_result_int (context, 1);
+#else
+    sqlite3_result_int (context, 0);
+#endif
+#else
+    sqlite3_result_int (context, 0);
+#endif
+}
+
+static void
 fnct_lwgeom_version (sqlite3_context * context, int argc, sqlite3_value ** argv)
 {
 /* SQL function:
@@ -636,6 +675,39 @@ fnct_has_geopackage (sqlite3_context * context, int argc, sqlite3_value ** argv)
 }
 
 static void
+fnct_has_gcp (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+/* SQL function:
+/ HasGCP()
+/ HasGroundControlPoints()
+/
+/ return 1 if built including GroundControlPoints support (GGP); otherwise 0
+*/
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+#ifdef ENABLE_GCP		/* GCP are supported */
+    sqlite3_result_int (context, 1);
+#else
+    sqlite3_result_int (context, 0);
+#endif
+}
+
+static void
+fnct_has_topology (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+/* SQL function:
+/ HasTopology()
+/
+/ return 1 if built including GroundControlPoints support (GGP); otherwise 0
+*/
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+#ifdef POSTGIS_2_2		/* POSTGIS_2_2 is supported */
+    sqlite3_result_int (context, 1);
+#else
+    sqlite3_result_int (context, 0);
+#endif
+}
+
+static void
 fnct_GeometryConstraints (sqlite3_context * context, int argc,
 			  sqlite3_value ** argv)
 {
@@ -2036,6 +2108,12 @@ fnct_InitSpatialMetaData (sqlite3_context * context, int argc,
     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
     if (ret != SQLITE_OK)
 	goto error;
+/* creating the KNN VIRTUAL TABLE */
+    strcpy (sql, "CREATE VIRTUAL TABLE KNN ");
+    strcat (sql, "USING VirtualKNN()");
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
+    if (ret != SQLITE_OK)
+	goto error;
 
     if (transaction)
       {
@@ -2283,6 +2361,225 @@ fnct_CloneTable (sqlite3_context * context, int argc, sqlite3_value ** argv)
 }
 
 static void
+fnct_CreateClonedTable (sqlite3_context * context, int argc,
+			sqlite3_value ** argv)
+{
+/* SQL function:
+/ CreateClonedTable(text db_prefix, text in_table, text out_table, integer transaction)
+/ CreateClonedTable(text db_prefix, text in_table, text out_table, integer transaction,
+/            ... text option1 ..., ... text option2 ..., text option10)
+/
+/ creating a cloned table [CREATE only without COPYing]
+/ returns 1 on success
+/ 0 on failure (NULL on invalid arguments)
+*/
+    int ret;
+    char *errMsg = NULL;
+    const char *db_prefix;
+    const char *in_table;
+    const char *out_table;
+    int transaction = 0;
+    int active = 0;
+    const void *cloner = NULL;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 1 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	in_table = (const char *) sqlite3_value_text (argv[1]);
+    else
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 2 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 3 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (sqlite3_value_type (argv[3]) == SQLITE_INTEGER)
+	transaction = sqlite3_value_int (argv[3]);
+    else
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 4 is not of the Integer type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+
+/* additional options */
+    if (argc > 4 && sqlite3_value_type (argv[4]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 5 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 5 && sqlite3_value_type (argv[5]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 6 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 6 && sqlite3_value_type (argv[6]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 7 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 7 && sqlite3_value_type (argv[7]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 8 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 8 && sqlite3_value_type (argv[8]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 9 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 9 && sqlite3_value_type (argv[9]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 10 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 10 && sqlite3_value_type (argv[10]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 11 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 11 && sqlite3_value_type (argv[11]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 12 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 12 && sqlite3_value_type (argv[12]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 13 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+    if (argc > 13 && sqlite3_value_type (argv[13]) != SQLITE_TEXT)
+      {
+	  spatialite_e
+	      ("CreateClonedTable() error: argument 14 is not of the String or TEXT type\n");
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+    cloner = gaiaAuxClonerCreateEx (sqlite, db_prefix, in_table, out_table, 1);
+    if (cloner == NULL)
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+/* additional options */
+    if (argc > 4)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[4]));
+    if (argc > 5)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[5]));
+    if (argc > 6)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[6]));
+    if (argc > 7)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[7]));
+    if (argc > 8)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[8]));
+    if (argc > 9)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[9]));
+    if (argc > 10)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[10]));
+    if (argc > 11)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[11]));
+    if (argc > 12)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[12]));
+    if (argc > 13)
+	gaiaAuxClonerAddOption (cloner,
+				(const char *) sqlite3_value_text (argv[13]));
+
+    if (!gaiaAuxClonerCheckValidTarget (cloner))
+	goto error;
+
+    if (transaction)
+      {
+	  /* starting a Transaction */
+	  ret = sqlite3_exec (sqlite, "BEGIN", NULL, NULL, &errMsg);
+	  if (ret != SQLITE_OK)
+	      goto error;
+      }
+    active = 1;
+
+    if (!gaiaAuxClonerExecute (cloner))
+	goto error;
+    gaiaAuxClonerDestroy (cloner);
+    updateSpatiaLiteHistory (sqlite, out_table, NULL,
+			     "table successfully cloned");
+
+    if (transaction)
+      {
+	  /* confirming the still pending Transaction */
+	  ret = sqlite3_exec (sqlite, "COMMIT", NULL, NULL, &errMsg);
+	  if (ret != SQLITE_OK)
+	      goto error;
+      }
+
+    sqlite3_result_int (context, 1);
+    return;
+  error:
+    if (cloner != NULL)
+	gaiaAuxClonerDestroy (cloner);
+    spatialite_e ("CreateClonedTable() error:\"%s\"\n", errMsg);
+    sqlite3_free (errMsg);
+    if (transaction && active)
+      {
+	  /* performing a Rollback */
+	  ret = sqlite3_exec (sqlite, "ROLLBACK", NULL, NULL, &errMsg);
+	  if (ret != SQLITE_OK)
+	    {
+		spatialite_e ("CreateClonedTable() error:\"%s\"\n", errMsg);
+		sqlite3_free (errMsg);
+	    }
+      }
+    sqlite3_result_int (context, 0);
+    return;
+}
+
+static void
 fnct_CheckGeoPackageMetaData (sqlite3_context * context, int argc,
 			      sqlite3_value ** argv)
 {
@@ -10418,7 +10715,6 @@ fnct_Collect_step (sqlite3_context * context, int argc, sqlite3_value ** argv)
 	      result = gaiaMergeGeometries_r (data, *p, geom);
 	  else
 	      result = gaiaMergeGeometries (*p, geom);
-	  gaiaFreeGeomColl (*p);
 	  *p = result;
 	  gaiaFreeGeomColl (geom);
       }
@@ -10507,7 +10803,15 @@ fnct_Collect (sqlite3_context * context, int argc, sqlite3_value ** argv)
 	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
 				     gpkg_amphibious);
     if (!geo1 || !geo2)
-	sqlite3_result_null (context);
+      {
+	  if (geo1 != NULL)
+	      gaiaFreeGeomColl (geo1);
+	  if (geo2 != NULL)
+	      gaiaFreeGeomColl (geo2);
+	  geo1 = NULL;
+	  geo2 = NULL;
+	  sqlite3_result_null (context);
+      }
     else
       {
 	  void *data = sqlite3_user_data (context);
@@ -10532,7 +10836,6 @@ fnct_Collect (sqlite3_context * context, int argc, sqlite3_value ** argv)
 		gaiaFreeGeomColl (result);
 	    }
       }
-    gaiaFreeGeomColl (geo1);
     gaiaFreeGeomColl (geo2);
 }
 
@@ -18208,7 +18511,6 @@ fnct_Polygonize_step (sqlite3_context * context, int argc,
 	      result = gaiaMergeGeometries_r (data, *p, geom);
 	  else
 	      result = gaiaMergeGeometries (*p, geom);
-	  gaiaFreeGeomColl (*p);
 	  *p = result;
 	  gaiaFreeGeomColl (geom);
       }
@@ -18591,8 +18893,8 @@ fnct_Transform (sqlite3_context * context, int argc, sqlite3_value ** argv)
     else
       {
 	  srid_from = geo->Srid;
-	  getProjParamsEx (sqlite, srid_from, &proj_from, gpkg_amphibious);
-	  getProjParamsEx (sqlite, srid_to, &proj_to, gpkg_amphibious);
+	  getProjParams (sqlite, srid_from, &proj_from);
+	  getProjParams (sqlite, srid_to, &proj_to);
 	  if (proj_to == NULL || proj_from == NULL)
 	    {
 		if (proj_from)
@@ -19178,11 +19480,10 @@ length_common (const void *p_cache, sqlite3_context * context, int argc,
 					l = gaiaGeodesicTotalLength (a,
 								     b,
 								     rf,
-								     line->DimensionModel,
-								     line->
-								     Coords,
 								     line->
-								     Points);
+								     DimensionModel,
+								     line->Coords,
+								     line->Points);
 					if (l < 0.0)
 					  {
 					      length = -1.0;
@@ -19204,12 +19505,9 @@ length_common (const void *p_cache, sqlite3_context * context, int argc,
 					      ring = polyg->Exterior;
 					      l = gaiaGeodesicTotalLength (a, b,
 									   rf,
-									   ring->
-									   DimensionModel,
-									   ring->
-									   Coords,
-									   ring->
-									   Points);
+									   ring->DimensionModel,
+									   ring->Coords,
+									   ring->Points);
 					      if (l < 0.0)
 						{
 						    length = -1.0;
@@ -19355,6 +19653,61 @@ fnct_Perimeter (sqlite3_context * context, int argc, sqlite3_value ** argv)
     length_common (data, context, argc, argv, 1);
 }
 
+#ifdef ENABLE_LWGEOM		/* only if LWGEOM is enabled */
+
+static void
+fnct_3dLength (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+/* SQL function:
+/ ST_3dLength(BLOB encoded GEOMETRYCOLLECTION)
+/
+/ returns  the total 2D or 3D length for current geometry
+/ accordingly to the Geometry dimensions 
+/ returns NULL if any error is encountered
+/
+/ Please note: this function will ignore
+/ any Polygon (only Linestrings will be considered)
+/
+*/
+    unsigned char *p_blob;
+    int n_bytes;
+    double length = 0.0;
+    int ret;
+    gaiaGeomCollPtr geo = NULL;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) != SQLITE_BLOB)
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+    p_blob = (unsigned char *) sqlite3_value_blob (argv[0]);
+    n_bytes = sqlite3_value_bytes (argv[0]);
+    geo =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!geo)
+	sqlite3_result_null (context);
+    else
+      {
+	  ret = gaia3dLength (geo, &length);
+	  if (!ret)
+	      sqlite3_result_null (context);
+	  else
+	      sqlite3_result_double (context, length);
+      }
+    gaiaFreeGeomColl (geo);
+}
+
+#endif /* end LWGEOM conditional */
+
 static void
 fnct_Area (sqlite3_context * context, int argc, sqlite3_value ** argv)
 {
@@ -19555,8 +19908,26 @@ fnct_PointOnSurface (sqlite3_context * context, int argc, sqlite3_value ** argv)
 	      sqlite3_result_null (context);
 	  else
 	    {
-		result = gaiaAllocGeomColl ();
-		gaiaAddPointToGeomColl (result, x, y);
+		if (geo->DimensionModel == GAIA_XY_Z)
+		  {
+		      result = gaiaAllocGeomCollXYZ ();
+		      gaiaAddPointToGeomCollXYZ (result, x, y, 0.0);
+		  }
+		else if (geo->DimensionModel == GAIA_XY_M)
+		  {
+		      result = gaiaAllocGeomCollXYM ();
+		      gaiaAddPointToGeomCollXYM (result, x, y, 0.0);
+		  }
+		else if (geo->DimensionModel == GAIA_XY_Z_M)
+		  {
+		      result = gaiaAllocGeomCollXYZM ();
+		      gaiaAddPointToGeomCollXYZM (result, x, y, 0.0, 0.0);
+		  }
+		else
+		  {
+		      result = gaiaAllocGeomColl ();
+		      gaiaAddPointToGeomColl (result, x, y);
+		  }
 		result->Srid = geo->Srid;
 		gaiaToSpatiaLiteBlobWkbEx (result, &p_result, &len, gpkg_mode);
 		gaiaFreeGeomColl (result);
@@ -20078,7 +20449,6 @@ fnct_Union_final (sqlite3_context * context)
 	      tmp = gaiaMergeGeometries_r (data, aggregate, geom);
 	  else
 	      tmp = gaiaMergeGeometries (aggregate, geom);
-	  gaiaFreeGeomColl (aggregate);
 	  gaiaFreeGeomColl (geom);
 	  item->geom = NULL;
 	  aggregate = tmp;
@@ -21683,1260 +22053,6 @@ fnct_BdMPolyFromWKB2 (sqlite3_context * context, int argc,
     return;
 }
 
-static int
-check_topo_table (sqlite3 * sqlite, const char *table, int is_view)
-{
-/* checking if some Topology-related table/view already exists */
-    int exists = 0;
-    char *sql_statement;
-    char *errMsg = NULL;
-    int ret;
-    char **results;
-    int rows;
-    int columns;
-    int i;
-    sql_statement =
-	sqlite3_mprintf ("SELECT name FROM sqlite_master WHERE type = '%s'"
-			 "AND Upper(name) = Upper(%Q)",
-			 (!is_view) ? "table" : "view", table);
-    ret = sqlite3_get_table (sqlite, sql_statement, &results, &rows, &columns,
-			     &errMsg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  sqlite3_free (errMsg);
-	  return 0;
-      }
-    for (i = 1; i <= rows; i++)
-	exists = 1;
-    sqlite3_free_table (results);
-    return exists;
-}
-
-static int
-create_topo_nodes (sqlite3 * sqlite, const char *table, int srid, int dims)
-{
-/* creating the topo_nodes table */
-    char *sql_statement;
-    char *sqltable;
-    char *idx_name;
-    char *xidx_name;
-    int ret;
-    char *err_msg = NULL;
-    sqltable = gaiaDoubleQuotedSql (table);
-    sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
-				     "node_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
-				     "node_code TEXT)", sqltable);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE '%s' error: %s\n", table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sql_statement =
-	sqlite3_mprintf
-	("SELECT AddGeometryColumn(%Q, 'Geometry', %d, 'POINT', '%s', 1)",
-	 table, srid, (dims == GAIA_XY_Z) ? "XYZ" : "XY");
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("AddGeometryColumn '%s'.'Geometry' error: %s\n",
-			table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sql_statement =
-	sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'Geometry')", table);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CreateSpatialIndex '%s'.'Geometry' error: %s\n",
-			table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_code", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (node_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('node_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_topo_edges (sqlite3 * sqlite, const char *table, int srid, int dims)
-{
-/* creating the topo_edges table */
-    char *sql_statement;
-    char *sqltable;
-    char *idx_name;
-    char *xidx_name;
-    int ret;
-    char *err_msg = NULL;
-    sqltable = gaiaDoubleQuotedSql (table);
-    sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
-				     "edge_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
-				     "node_from_code TEXT,\n"
-				     "node_to_code TEXT,\n"
-				     "edge_code TEXT)", sqltable);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE '%s' error: %s\n", table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sql_statement =
-	sqlite3_mprintf
-	("SELECT AddGeometryColumn(%Q, 'Geometry', %d, 'LINESTRING', '%s', 1)",
-	 table, srid, (dims == GAIA_XY_Z) ? "XYZ" : "XY");
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("AddGeometryColumn '%s'.'Geometry' error: %s\n",
-			table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sql_statement =
-	sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'Geometry')", table);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CreateSpatialIndex '%s'.'Geometry' error: %s\n",
-			table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_code", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('edge_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_from", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (node_from_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('node_from_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_to", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (node_to_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('node_to_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_topo_faces (sqlite3 * sqlite, const char *table)
-{
-/* creating the topo_faces table */
-    char *sql_statement;
-    char *sqltable;
-    char *idx_name;
-    char *xidx_name;
-    int ret;
-    char *err_msg = NULL;
-    sqltable = gaiaDoubleQuotedSql (table);
-    sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
-				     "face_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
-				     "face_code TEXT)", sqltable);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE '%s' error: %s\n", table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_code", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (face_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('face_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_topo_faces_edges (sqlite3 * sqlite, const char *table,
-			 const char *table2)
-{
-/* creating the topo_faces_edges table */
-    char *sql_statement;
-    char *sqltable;
-    char *sqltable2;
-    char *idx_name;
-    char *xidx_name;
-    int ret;
-    char *err_msg = NULL;
-    sqltable = gaiaDoubleQuotedSql (table);
-    sqltable2 = gaiaDoubleQuotedSql (table2);
-    sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
-				     "face_id INTEGER NOT NULL,\n"
-				     "edge_code TEXT NOT NULL,\n"
-				     "orientation TEXT,\n"
-				     "CONSTRAINT pk_faces_edges PRIMARY KEY "
-				     "(face_id, edge_code),\n"
-				     "CONSTRAINT fk_faces_edges FOREIGN KEY "
-				     "(face_id) REFERENCES \"%s\" (face_id))\n",
-				     sqltable, sqltable2);
-    free (sqltable);
-    free (sqltable2);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE '%s' error: %s\n", table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_edge", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('edge_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_topo_curves (sqlite3 * sqlite, const char *table)
-{
-/* creating the topo_curves table */
-    char *sql_statement;
-    char *sqltable;
-    char *idx_name;
-    char *xidx_name;
-    int ret;
-    char *err_msg = NULL;
-    sqltable = gaiaDoubleQuotedSql (table);
-    sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
-				     "curve_id INTEGER NOT NULL,\n"
-				     "edge_code TEXT NOT NULL,\n"
-				     "orientation TEXT,\n"
-				     "CONSTRAINT pk_curves PRIMARY KEY "
-				     "(curve_id, edge_code))\n", sqltable);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE '%s' error: %s\n", table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_edge", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('edge_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_topo_surfaces (sqlite3 * sqlite, const char *table)
-{
-/* creating the topo_surfaces table */
-    char *sql_statement;
-    char *sqltable;
-    char *idx_name;
-    char *xidx_name;
-    int ret;
-    char *err_msg = NULL;
-    sqltable = gaiaDoubleQuotedSql (table);
-    sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
-				     "surface_id INTEGER NOT NULL,\n"
-				     "face_code TEXT NOT NULL,\n"
-				     "orientation TEXT,\n"
-				     "CONSTRAINT pk_surfaces PRIMARY KEY "
-				     "(surface_id, face_code))", sqltable);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE '%s' error: %s\n", table, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    sqltable = gaiaDoubleQuotedSql (table);
-    idx_name = sqlite3_mprintf ("idx_%s_face", table);
-    xidx_name = gaiaDoubleQuotedSql (idx_name);
-    sqlite3_free (idx_name);
-    sql_statement =
-	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (face_code)",
-			 xidx_name, sqltable);
-    free (sqltable);
-    free (xidx_name);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("Create Index '%s'('face_code') error: %s\n",
-			sqltable, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_node_codes (sqlite3 * sqlite, const char *view,
-			 const char *table_nodes)
-{
-/* creating the check node codes VIEW */
-    char *sql_statement;
-    char *sqltable;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sqltable = gaiaDoubleQuotedSql (table_nodes);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT node_code AS node_code, Count(node_id) AS count\n"
-				     "FROM \"%s\"\nGROUP BY node_code\nHAVING count > 1\n",
-				     sqlview, sqltable);
-    free (sqlview);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_node_geoms (sqlite3 * sqlite, const char *view,
-			 const char *table_nodes)
-{
-/* creating the check node geoms VIEW */
-    char *sql_statement;
-    char *sqltable;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sqltable = gaiaDoubleQuotedSql (table_nodes);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT n1.node_id AS node1_id, n1.node_code AS node1_code, "
-				     "n2.node_id AS node2_id, n2.node_code AS node2_code\n"
-				     "FROM \"%s\" AS n1\nJOIN \"%s\" AS n2 ON (\n"
-				     "  n1.node_id <> n2.node_id AND\n"
-				     "  ST_Equals(n1.Geometry, n2.Geometry) = 1 AND\n"
-				     "  n2.node_id IN (\n	SELECT ROWID FROM SpatialIndex\n"
-				     "  WHERE f_table_name = %Q AND\n  search_frame = n1.Geometry))\n",
-				     sqlview, sqltable, sqltable, table_nodes);
-    free (sqlview);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_edge_codes (sqlite3 * sqlite, const char *view,
-			 const char *table_edges)
-{
-/* creating the check edge codes VIEW */
-    char *sql_statement;
-    char *sqltable;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sqltable = gaiaDoubleQuotedSql (table_edges);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT edge_code AS edge_code, Count(edge_id) AS count\n"
-				     "FROM \"%s\"\nGROUP BY edge_code\nHAVING count > 1\n",
-				     sqlview, sqltable);
-    free (sqlview);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_edge_geoms (sqlite3 * sqlite, const char *view,
-			 const char *table_edges)
-{
-/* creating the check edge geoms VIEW */
-    char *sql_statement;
-    char *sqltable;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sqltable = gaiaDoubleQuotedSql (table_edges);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT e1.edge_id AS edge1_id, e1.edge_code AS edge1_code, "
-				     "e2.edge_id AS edge2_id, e2.edge_code AS edge2_code\n"
-				     "FROM \"%s\" AS e1\nJOIN \"%s\" AS e2 ON (\n  e1.edge_id <> e2.edge_id AND\n"
-				     "NOT (e1.node_from_code = e2.node_from_code "
-				     "AND e1.node_to_code = e2.node_to_code) AND\n"
-				     "  ST_Crosses(e1.Geometry, e2.Geometry) = 1 AND\n"
-				     "  e2.edge_id IN (\n"
-				     "    SELECT ROWID FROM SpatialIndex\n"
-				     "	   WHERE f_table_name = %Q AND\n        search_frame = e1.Geometry))\n",
-				     sqlview, sqltable, sqltable, table_edges);
-    free (sqlview);
-    free (sqltable);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_edge_node_geoms (sqlite3 * sqlite, const char *view,
-			      const char *table_edges, const char *table_nodes)
-{
-/* creating the check edge/node geoms VIEW */
-    char *sql_statement;
-    char *sql_edges;
-    char *sql_nodes;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_edges = gaiaDoubleQuotedSql (table_edges);
-    sql_nodes = gaiaDoubleQuotedSql (table_nodes);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT e.edge_id AS edge_id, n.node_id AS node_id\n"
-				     "FROM \"%s\" AS e,\n\"%s\" AS n\n"
-				     "WHERE ST_Intersects(e.Geometry, n.Geometry)\n"
-				     "  AND ST_Equals(ST_StartPoint(e.Geometry), n.Geometry) = 0\n"
-				     "  AND ST_Equals(ST_EndPoint(e.Geometry), n.Geometry) = 0\n"
-				     "  AND n.ROWID IN (\n    SELECT ROWID FROM SpatialIndex\n"
-				     "  WHERE f_table_name = %Q\n      AND search_frame = e.Geometry);",
-				     sqlview, sql_edges, sql_nodes,
-				     table_nodes);
-    free (sqlview);
-    free (sql_nodes);
-    free (sql_edges);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_face_codes (sqlite3 * sqlite, const char *view,
-			 const char *table_faces)
-{
-/* creating the check face codes VIEW */
-    char *sql_statement;
-    char *sqltable;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sqltable = gaiaDoubleQuotedSql (table_faces);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT face_code AS face_code, Count(face_id) AS count\n"
-				     "FROM \"%s\"\nGROUP BY face_code\nHAVING count > 1\n",
-				     sqlview, sqltable);
-    free (sqltable);
-    free (sqlview);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_faces_resolved (sqlite3 * sqlite, const char *view, const char *faces,
-		       const char *faces_edges, const char *edges)
-{
-/* creating the Faces Resolved VIEW */
-    char *sql_statement;
-    char *sql_faces;
-    char *sql_faces_edges;
-    char *sql_edges;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_faces = gaiaDoubleQuotedSql (faces);
-    sql_faces_edges = gaiaDoubleQuotedSql (faces_edges);
-    sql_edges = gaiaDoubleQuotedSql (edges);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT f.face_id AS face_id, f.face_code AS face_code, "
-				     "ST_Polygonize(e.Geometry) AS Geometry\n"
-				     "FROM \"%s\" AS f\nLEFT JOIN \"%s\" AS fe ON (fe.face_id = f.face_id)\n"
-				     "LEFT JOIN \"%s\" AS e ON (e.edge_code = fe.edge_code)\n"
-				     "GROUP BY f.face_id\n", sqlview,
-				     sql_faces, sql_faces_edges, sql_edges);
-    free (sqlview);
-    free (sql_faces);
-    free (sql_faces_edges);
-    free (sql_edges);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_curves_resolved (sqlite3 * sqlite, const char *view,
-			const char *curves, char *edges)
-{
-/* creating the Curves Resolved VIEW */
-    char *sql_statement;
-    char *sql_curves;
-    char *sql_edges;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_curves = gaiaDoubleQuotedSql (curves);
-    sql_edges = gaiaDoubleQuotedSql (edges);
-    sql_statement =
-	sqlite3_mprintf
-	("CREATE VIEW \"%s\" AS\nSELECT c.curve_id AS curve_id, "
-	 "CastToMultiLinestring(ST_Collect(e.Geometry)) AS Geometry\n"
-	 "FROM \"%s\" AS c\nLEFT JOIN \"%s\" AS e ON (e.edge_code = c.edge_code)\n"
-	 "GROUP BY c.curve_id\n", sqlview, sql_curves, sql_edges);
-    free (sqlview);
-    free (sql_edges);
-    free (sql_curves);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_surfaces_resolved (sqlite3 * sqlite, const char *view,
-			  const char *surfaces, const char *faces)
-{
-/* creating the Surfaces Resolved VIEW */
-    char *sql_statement;
-    char *sql_surfaces;
-    char *sql_faces;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_surfaces = gaiaDoubleQuotedSql (surfaces);
-    sql_faces = gaiaDoubleQuotedSql (faces);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT s.surface_id AS surface_id,\n"
-				     "  CastToMultipolygon(ST_UnaryUnion(ST_Collect(f.Geometry))) AS Geometry\n"
-				     "FROM \"%s\" AS s\n"
-				     "LEFT JOIN \"%s\" AS f ON (f.face_code = s.face_code)\n"
-				     "GROUP BY s.surface_id\n", sqlview,
-				     sql_surfaces, sql_faces);
-    free (sqlview);
-    free (sql_surfaces);
-    free (sql_faces);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_dangling_nodes (sqlite3 * sqlite, const char *view,
-		       const char *nodes, const char *edges)
-{
-/* creating the Dangling Nodes VIEW */
-    char *sql_statement;
-    char *sql_nodes;
-    char *sql_edges;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_nodes = gaiaDoubleQuotedSql (nodes);
-    sql_edges = gaiaDoubleQuotedSql (edges);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT n.node_id AS node_id\nFROM \"%s\" AS n\n"
-				     "LEFT JOIN \"%s\" AS e ON (n.node_code = e.node_from_code)\n"
-				     "WHERE e.edge_id IS NULL\nINTERSECT\nSELECT n.node_id AS node_id\n"
-				     "FROM \"%s\" AS n\nLEFT JOIN \"%s\" AS e ON (n.node_code = e.node_to_code)\n"
-				     "WHERE e.edge_id IS NULL\n", sqlview,
-				     sql_nodes, sql_edges, sql_nodes,
-				     sql_edges);
-    free (sqlview);
-    free (sql_nodes);
-    free (sql_edges);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_dangling_edges (sqlite3 * sqlite, const char *view,
-		       const char *edges, const char *faces_edges,
-		       const char *curves)
-{
-/* creating the Dangling Edges VIEW */
-    char *sql_statement;
-    char *sql_edges;
-    char *sql_faces_edges;
-    char *sql_curves;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_edges = gaiaDoubleQuotedSql (edges);
-    sql_faces_edges = gaiaDoubleQuotedSql (faces_edges);
-    sql_curves = gaiaDoubleQuotedSql (curves);
-    sql_statement = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
-				     "SELECT e.edge_id AS edge_id\nFROM \"%s\" AS e\n"
-				     "LEFT JOIN \"%s\" AS f ON (e.edge_code = f.edge_code)\n"
-				     "WHERE f.edge_code IS NULL\nINTERSECT\nSELECT e.edge_id AS edge_id\n"
-				     "FROM \"%s\" AS e\nLEFT JOIN \"%s\" AS c ON (e.edge_code = c.edge_code)\n"
-				     "WHERE c.edge_code IS NULL\n", sqlview,
-				     sql_edges, sql_faces_edges, sql_edges,
-				     sql_curves);
-    free (sqlview);
-    free (sql_edges);
-    free (sql_faces_edges);
-    free (sql_curves);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_check_edges_from_to (sqlite3 * sqlite, const char *view,
-			    const char *edges, const char *nodes)
-{
-/* creating the Edges/Nodes [from/to] VIEW */
-    char skeleton[2048];
-    char *sql_statement;
-    char *sql_edges;
-    char *sql_nodes;
-    char *sqlview;
-    int ret;
-    char *err_msg = NULL;
-    sqlview = gaiaDoubleQuotedSql (view);
-    sql_edges = gaiaDoubleQuotedSql (edges);
-    sql_nodes = gaiaDoubleQuotedSql (nodes);
-    strcpy (skeleton, "CREATE VIEW \"%s\" AS\n");
-    strcat (skeleton, "SELECT e.edge_id AS edge_id, n.node_id AS node_id,\n");
-    strcat (skeleton, "  n.node_code AS node_code,\n");
-    strcat (skeleton, "'Mismatching coords' AS error_cause\n");
-    strcat (skeleton, "FROM \"%s\" AS e\n");
-    strcat (skeleton, "JOIN \"%s\" AS n ON ");
-    strcat (skeleton, "(e.node_from_code = n.node_code)\n");
-    strcat (skeleton,
-	    "WHERE ST_Equals(ST_StartPoint(e.Geometry), n.Geometry) = 0\n");
-    strcat (skeleton, "UNION\n");
-    strcat (skeleton, "SELECT e.edge_id AS edge_id, n.node_id AS node_id,\n");
-    strcat (skeleton, "  n.node_code AS node_code,\n");
-    strcat (skeleton, " 'Mismatching coords' AS error_cause\n");
-    strcat (skeleton, "FROM \"%s\" AS e\n");
-    strcat (skeleton, "JOIN \"%s\" AS n ON ");
-    strcat (skeleton, "(e.node_to_code = n.node_code)\n");
-    strcat (skeleton,
-	    "WHERE ST_Equals(ST_EndPoint(e.Geometry), n.Geometry) = 0\n");
-    strcat (skeleton, "UNION\n");
-    strcat (skeleton, "SELECT e.edge_id AS edge_id, n.node_id AS node_id,\n");
-    strcat (skeleton, "  n.node_code AS node_code,\n");
-    strcat (skeleton, "  'Unresolved Node reference' AS error_cause\n");
-    strcat (skeleton, "FROM \"%s\" AS e\n");
-    strcat (skeleton, "LEFT JOIN \"%s\" AS n ON ");
-    strcat (skeleton, "(e.node_from_code = n.node_code)\n");
-    strcat (skeleton, "WHERE n.node_id IS NULL\n");
-    strcat (skeleton, "UNION\n");
-    strcat (skeleton, "SELECT e.edge_id AS edge_id, n.node_id AS node_id,\n");
-    strcat (skeleton, "  n.node_code AS node_code,\n");
-    strcat (skeleton, "  'Unresolved Node reference' AS error_cause\n");
-    strcat (skeleton, "FROM \"%s\" AS e\n");
-    strcat (skeleton, "LEFT JOIN \"%s\" AS n ON ");
-    strcat (skeleton, "(e.node_to_code = n.node_code)\n");
-    strcat (skeleton, "WHERE n.node_id IS NULL\n");
-    sql_statement = sqlite3_mprintf (skeleton, sqlview,
-				     sql_edges, sql_nodes, sql_edges,
-				     sql_nodes, sql_edges, sql_nodes,
-				     sql_edges, sql_nodes);
-    free (sqlview);
-    free (sql_edges);
-    free (sql_nodes);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE VIEW '%s' error: %s\n", view, err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-create_topo_master (sqlite3 * sqlite)
-{
-/* creating the topo_master table */
-    char sql[2048];
-    int ret;
-    char *err_msg = NULL;
-
-/* creating the table */
-    strcpy (sql, "CREATE TABLE topology_master (\n");
-    strcat (sql, "nodes TEXT NOT NULL,\n");
-    strcat (sql, "edges TEXT NOT NULL,\n");
-    strcat (sql, "faces TEXT NOT NULL,\n");
-    strcat (sql, "faces_edges TEXT NOT NULL,\n");
-    strcat (sql, "curves TEXT NOT NULL,\n");
-    strcat (sql, "surfaces TEXT NOT NULL,\n");
-    strcat (sql, "check_node_ids TEXT NOT NULL,\n");
-    strcat (sql, "check_node_geoms TEXT NOT NULL,\n");
-    strcat (sql, "check_edge_ids TEXT NOT NULL,\n");
-    strcat (sql, "check_edge_geoms TEXT NOT NULL,\n");
-    strcat (sql, "check_edge_node_geoms TEXT NOT NULL,\n");
-    strcat (sql, "check_face_ids TEXT NOT NULL,\n");
-    strcat (sql, "faces_resolved TEXT NOT NULL,\n");
-    strcat (sql, "curves_resolved TEXT NOT NULL,\n");
-    strcat (sql, "surfaces_resolved TEXT NOT NULL,\n");
-    strcat (sql, "dangling_nodes TEXT NOT NULL,\n");
-    strcat (sql, "dangling_edges TEXT NOT NULL,\n");
-    strcat (sql, "check_edges_from_to TEXT NOT NULL,\n");
-    strcat (sql, "coord_dimension TEXT NOT NULL,\n");
-    strcat (sql, "srid INTEGER NOT NULL,\n");
-    strcat (sql, "CONSTRAINT fk_topo_master FOREIGN KEY \n");
-    strcat (sql, "(srid) REFERENCES spatial_ref_sys (srid))");
-    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("CREATE TABLE 'topology_master' error: %s\n", err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static int
-update_topo_master (sqlite3 * sqlite, const char *nodes, const char *edges,
-		    const char *faces, const char *faces_edges,
-		    const char *curves, const char *surfaces,
-		    const char *check_nodes, const char *check_node_geoms,
-		    const char *check_edges, const char *check_edge_geoms,
-		    const char *check_edge_node_geoms,
-		    const char *check_faces, const char *faces_res,
-		    const char *curves_res, const char *surfaces_res,
-		    const char *dangling_nodes, const char *dangling_edges,
-		    const char *check_edges_from_to, int srid, int dims)
-{
-/* updating the topo_master table */
-    char *sql_statement;
-    int ret;
-    char *err_msg = NULL;
-
-/* inserting Topology data into MASTER */
-    sql_statement = sqlite3_mprintf ("INSERT INTO topology_master "
-				     "(nodes, edges, faces, faces_edges, curves, surfaces, check_node_ids, "
-				     "check_node_geoms, check_edge_ids, check_edge_geoms, check_edge_node_geoms, "
-				     "check_face_ids, faces_resolved, curves_resolved, surfaces_resolved, "
-				     "dangling_nodes, dangling_edges, check_edges_from_to, coord_dimension, srid) "
-				     "VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d)",
-				     nodes, edges, faces, faces_edges, curves,
-				     surfaces, check_nodes, check_node_geoms,
-				     check_edges, check_edge_geoms,
-				     check_edge_node_geoms, check_faces,
-				     faces_res, curves_res, surfaces_res,
-				     dangling_nodes, dangling_edges,
-				     check_edges_from_to,
-				     (dims == GAIA_XY_Z) ? "XYZ" : "XY", srid);
-    ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &err_msg);
-    sqlite3_free (sql_statement);
-    if (ret != SQLITE_OK)
-      {
-	  spatialite_e ("INSERT INTO 'topology_master' error: %s\n", err_msg);
-	  sqlite3_free (err_msg);
-	  return 0;
-      }
-    return 1;
-}
-
-static void
-fnct_CreateTopologyTables (sqlite3_context * context, int argc,
-			   sqlite3_value ** argv)
-{
-/* SQL function:
-/ CreateTopologyTables(srid, coord_dims)
-/  or
-/ CreateTopologyTables(prefix, srid, coord_dims)
-/
-/ creates any Topology related table 
-/ returns 1 on success
-/ 0 on failure
-*/
-    const char *prefix = "topo_";
-    const unsigned char *txt_dims;
-    int srid = -1;
-    int dimension;
-    int dims = -1;
-    char *table_curves;
-    char *table_surfaces;
-    char *table_nodes;
-    char *table_edges;
-    char *table_faces;
-    char *table_faces_edges;
-    char *view_check_node_codes;
-    char *view_check_node_geoms;
-    char *view_check_edge_codes;
-    char *view_check_edge_geoms;
-    char *view_check_edge_node_geoms;
-    char *view_check_face_codes;
-    char *view_faces_resolved;
-    char *view_curves_resolved;
-    char *view_surfaces_resolved;
-    char *view_dangling_nodes;
-    char *view_dangling_edges;
-    char *view_edges_check_from_to;
-    const char *tables[20];
-    int views[20];
-    int *p_view;
-    const char **p_tbl;
-    int ok_table;
-    int create_master = 1;
-    sqlite3 *sqlite = sqlite3_context_db_handle (context);
-    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
-    if (argc == 3)
-      {
-	  if (sqlite3_value_type (argv[0]) != SQLITE_TEXT)
-	    {
-		spatialite_e
-		    ("CreateTopologyTables() error: argument 1 [table_prefix] is not of the String type\n");
-		sqlite3_result_int (context, 0);
-		return;
-	    }
-	  prefix = (char *) sqlite3_value_text (argv[0]);
-	  if (sqlite3_value_type (argv[1]) != SQLITE_INTEGER)
-	    {
-		spatialite_e
-		    ("CreateTopologyTables() error: argument 2 [SRID] is not of the Integer type\n");
-		sqlite3_result_int (context, 0);
-		return;
-	    }
-	  srid = sqlite3_value_int (argv[1]);
-	  if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
-	    {
-		dimension = sqlite3_value_int (argv[2]);
-		if (dimension == 2)
-		    dims = GAIA_XY;
-		if (dimension == 3)
-		    dims = GAIA_XY_Z;
-	    }
-	  else if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
-	    {
-		txt_dims = sqlite3_value_text (argv[2]);
-		if (strcasecmp ((char *) txt_dims, "XY") == 0)
-		    dims = GAIA_XY;
-		if (strcasecmp ((char *) txt_dims, "XYZ") == 0)
-		    dims = GAIA_XY_Z;
-	    }
-	  else
-	    {
-		spatialite_e
-		    ("CreateTopologyTables() error: argument 3 [dimension] is not of the Integer or Text type\n");
-		sqlite3_result_int (context, 0);
-		return;
-	    }
-      }
-    else
-      {
-	  if (sqlite3_value_type (argv[0]) != SQLITE_INTEGER)
-	    {
-		spatialite_e
-		    ("CreateTopologyTables() error: argument 1 [SRID] is not of the Integer type\n");
-		sqlite3_result_int (context, 0);
-		return;
-	    }
-	  srid = sqlite3_value_int (argv[0]);
-	  if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
-	    {
-		dimension = sqlite3_value_int (argv[1]);
-		if (dimension == 2)
-		    dims = GAIA_XY;
-		if (dimension == 3)
-		    dims = GAIA_XY_Z;
-	    }
-	  else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
-	    {
-		txt_dims = sqlite3_value_text (argv[1]);
-		if (strcasecmp ((char *) txt_dims, "XY") == 0)
-		    dims = GAIA_XY;
-		if (strcasecmp ((char *) txt_dims, "XYZ") == 0)
-		    dims = GAIA_XY_Z;
-	    }
-	  else
-	    {
-		spatialite_e
-		    ("CreateTopologyTables() error: argument 2 [dimension] is not of the Integer or Text type\n");
-		sqlite3_result_int (context, 0);
-		return;
-	    }
-      }
-    if (dims == GAIA_XY || dims == GAIA_XY_Z)
-	;
-    else
-      {
-	  spatialite_e
-	      ("CreateTopologyTables() error: [dimension] ILLEGAL VALUE\n");
-	  sqlite3_result_int (context, 0);
-	  return;
-      }
-    if (srid <= 0)
-      {
-	  spatialite_e ("CreateTopologyTables() error: [SRID] ILLEGAL VALUE\n");
-	  sqlite3_result_int (context, 0);
-	  return;
-      }
-
-/* checking Topology tables */
-    tables[0] = "topology_master";
-    views[0] = 0;
-    table_curves = sqlite3_mprintf ("%scurves", prefix);
-    tables[1] = table_curves;
-    views[1] = 0;
-    table_surfaces = sqlite3_mprintf ("%ssurfaces", prefix);
-    tables[2] = table_surfaces;
-    views[2] = 0;
-    table_nodes = sqlite3_mprintf ("%snodes", prefix);
-    tables[3] = table_nodes;
-    views[3] = 0;
-    table_edges = sqlite3_mprintf ("%sedges", prefix);
-    tables[4] = table_edges;
-    views[4] = 0;
-    table_faces = sqlite3_mprintf ("%sfaces", prefix);
-    tables[5] = table_faces;
-    views[5] = 0;
-    table_faces_edges = sqlite3_mprintf ("%sfaces_edges", prefix);
-    tables[6] = table_faces_edges;
-    views[6] = 0;
-    view_check_node_codes =
-	sqlite3_mprintf ("%snodes_check_dupl_codes", prefix);
-    tables[7] = view_check_node_codes;
-    views[7] = 1;
-    view_check_node_geoms =
-	sqlite3_mprintf ("%snodes_check_dupl_geoms", prefix);
-    tables[8] = view_check_node_geoms;
-    views[8] = 1;
-    view_check_edge_codes =
-	sqlite3_mprintf ("%sedges_check_dupl_codes", prefix);
-    tables[9] = view_check_edge_codes;
-    views[9] = 1;
-    view_check_edge_geoms =
-	sqlite3_mprintf ("%sedges_check_intersections", prefix);
-    tables[10] = view_check_edge_geoms;
-    views[10] = 1;
-    view_check_edge_node_geoms =
-	sqlite3_mprintf ("%sedges_check_nodes", prefix);
-    tables[11] = view_check_edge_node_geoms;
-    views[11] = 1;
-    view_check_face_codes =
-	sqlite3_mprintf ("%sfaces_check_dupl_codes", prefix);
-    tables[12] = view_check_face_codes;
-    views[12] = 1;
-    view_faces_resolved = sqlite3_mprintf ("%sfaces_resolved", prefix);
-    tables[13] = view_faces_resolved;
-    views[13] = 1;
-    view_curves_resolved = sqlite3_mprintf ("%scurves_resolved", prefix);
-    tables[14] = view_curves_resolved;
-    views[14] = 1;
-    view_surfaces_resolved = sqlite3_mprintf ("%ssurfaces_resolved", prefix);
-    tables[15] = view_surfaces_resolved;
-    views[15] = 1;
-    view_dangling_nodes = sqlite3_mprintf ("%sdangling_nodes", prefix);
-    tables[16] = view_dangling_nodes;
-    views[16] = 1;
-    view_dangling_edges = sqlite3_mprintf ("%sdangling_edges", prefix);
-    tables[17] = view_dangling_edges;
-    views[17] = 1;
-    view_edges_check_from_to =
-	sqlite3_mprintf ("%sedges_check_from_to", prefix);
-    tables[18] = view_edges_check_from_to;
-    views[18] = 1;
-    tables[19] = NULL;
-    p_view = views;
-    p_tbl = tables;
-    while (*p_tbl != NULL)
-      {
-	  ok_table = check_topo_table (sqlite, *p_tbl, *p_view);
-	  if (ok_table)
-	    {
-		if (strcmp (*p_tbl, "topology_master") == 0)
-		    create_master = 0;
-		else
-		  {
-		      spatialite_e
-			  ("CreateTopologyTables() error: table '%s' already exists\n",
-			   *p_tbl);
-		      goto error;
-		  }
-	    }
-	  p_tbl++;
-	  p_view++;
-      }
-
-/* creating Topology tables */
-    if (create_master)
-      {
-	  if (!create_topo_master (sqlite))
-	      goto error;
-      }
-    if (!create_topo_nodes (sqlite, table_nodes, srid, dims))
-	goto error;
-    if (!create_topo_edges (sqlite, table_edges, srid, dims))
-	goto error;
-    if (!create_topo_faces (sqlite, table_faces))
-	goto error;
-    if (!create_topo_faces_edges (sqlite, table_faces_edges, table_faces))
-	goto error;
-    if (!create_topo_curves (sqlite, table_curves))
-	goto error;
-    if (!create_topo_surfaces (sqlite, table_surfaces))
-	goto error;
-    if (!create_check_node_codes (sqlite, view_check_node_codes, table_nodes))
-	goto error;
-    if (!create_check_node_geoms (sqlite, view_check_node_geoms, table_nodes))
-	goto error;
-    if (!create_check_edge_codes (sqlite, view_check_edge_codes, table_edges))
-	goto error;
-    if (!create_check_edge_geoms (sqlite, view_check_edge_geoms, table_edges))
-	goto error;
-    if (!create_check_edge_node_geoms
-	(sqlite, view_check_edge_node_geoms, table_edges, table_nodes))
-	goto error;
-    if (!create_check_face_codes (sqlite, view_check_face_codes, table_faces))
-	goto error;
-    if (!create_faces_resolved
-	(sqlite, view_faces_resolved, table_faces, table_faces_edges,
-	 table_edges))
-	goto error;
-    if (!create_curves_resolved
-	(sqlite, view_curves_resolved, table_curves, table_edges))
-	goto error;
-    if (!create_surfaces_resolved
-	(sqlite, view_surfaces_resolved, table_surfaces, view_faces_resolved))
-	goto error;
-    if (!create_dangling_nodes
-	(sqlite, view_dangling_nodes, table_nodes, table_edges))
-	goto error;
-    if (!create_dangling_edges
-	(sqlite, view_dangling_edges, table_edges, table_faces_edges,
-	 table_curves))
-	goto error;
-    if (!create_check_edges_from_to
-	(sqlite, view_edges_check_from_to, table_edges, table_nodes))
-	goto error;
-    if (!update_topo_master
-	(sqlite, table_nodes, table_edges, table_faces, table_faces_edges,
-	 table_curves, table_surfaces, view_check_node_codes,
-	 view_check_node_geoms, view_check_edge_codes, view_check_edge_geoms,
-	 view_check_edge_node_geoms, view_check_face_codes,
-	 view_faces_resolved, view_curves_resolved, view_surfaces_resolved,
-	 view_dangling_nodes, view_dangling_edges, view_edges_check_from_to,
-	 srid, dims))
-	goto error;
-    updateSpatiaLiteHistory (sqlite, "*** TOPOLOGY ***", NULL,
-			     "Topology tables successfully created");
-    sqlite3_result_int (context, 1);
-    sqlite3_free (table_curves);
-    sqlite3_free (table_surfaces);
-    sqlite3_free (table_nodes);
-    sqlite3_free (table_edges);
-    sqlite3_free (table_faces);
-    sqlite3_free (table_faces_edges);
-    sqlite3_free (view_check_node_codes);
-    sqlite3_free (view_check_node_geoms);
-    sqlite3_free (view_check_edge_codes);
-    sqlite3_free (view_check_edge_geoms);
-    sqlite3_free (view_check_edge_node_geoms);
-    sqlite3_free (view_check_face_codes);
-    sqlite3_free (view_faces_resolved);
-    sqlite3_free (view_curves_resolved);
-    sqlite3_free (view_surfaces_resolved);
-    sqlite3_free (view_dangling_nodes);
-    sqlite3_free (view_dangling_edges);
-    sqlite3_free (view_edges_check_from_to);
-    return;
-
-  error:
-    sqlite3_result_int (context, 0);
-    sqlite3_free (table_curves);
-    sqlite3_free (table_surfaces);
-    sqlite3_free (table_nodes);
-    sqlite3_free (table_edges);
-    sqlite3_free (table_faces);
-    sqlite3_free (table_faces_edges);
-    sqlite3_free (view_check_node_codes);
-    sqlite3_free (view_check_node_geoms);
-    sqlite3_free (view_check_edge_codes);
-    sqlite3_free (view_check_edge_geoms);
-    sqlite3_free (view_check_edge_node_geoms);
-    sqlite3_free (view_check_face_codes);
-    sqlite3_free (view_faces_resolved);
-    sqlite3_free (view_curves_resolved);
-    sqlite3_free (view_surfaces_resolved);
-    sqlite3_free (view_dangling_nodes);
-    sqlite3_free (view_dangling_edges);
-    sqlite3_free (view_edges_check_from_to);
-    return;
-}
-
 static void
 fnct_OffsetCurve (sqlite3_context * context, int argc, sqlite3_value ** argv)
 {
@@ -26545,6 +25661,174 @@ fnct_SelfIntersections (sqlite3_context * context, int argc,
 
 #endif /* end LWGEOM support */
 
+
+static void
+fnct_Cutter (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+/* SQL function:
+/ ST_Cutter(TEXT in_db_prefix, TEXT input_table, TEXT input_geom,
+/              TEXT blade_db_prefix, TEXT blade_table, TEXT blade_geom,
+/              TEXT output_table)
+/ ST_Cutter(TEXT in_db_prefix, TEXT input_table, TEXT input_geom,
+/              TEXT blade_db_prefix, TEXT blade_table, TEXT blade_geom,
+/              TEXT output_table, INT transaction)
+/ ST_Cutter(TEXT in_db_prefix, TEXT input_table, TEXT input_geom,
+/              TEXT blade_db_prefix, TEXT blade_table, TEXT blade_geom,
+/              TEXT output_table, INT transaction, INT ram_temp_store)
+/
+/ the "input" table-geometry is expected to be declared as POINT,
+/ LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING or MULTIPOLYGON
+/ and can be of any 2D or 3D dimension
+/
+/ the "blade" table-geometry is expected to be declared as POLYGON
+/ or MULTIPOLYGON, and will always be casted to a pure(X,Y) dimension
+/
+/ the "output" table *must* not exists, and will be automatically
+/ created within the MAIN database.
+/ 
+/ in_db_prefix and/or blade_db_prefix can eventually be NULL, and
+/ in this case the MAIN db will be assumed
+/
+/ input_geom and/or blade_geom can eventually be NULL, and in this
+/ case the geometry column name will be automatically determined.
+/ anyway when a table defines two or more Geometries declaring a
+/ NULL geometry name will cause a failure.
+/
+///////////////////////////////////////////////////////////////////
+/
+/ will precisely cut the input dataset against polygonal blade(s)
+/ and will consequently create and populate an output dataset
+/
+/
+/ returns 1 on success
+/ 0 on failure, -1 on invalid arguments
+*/
+    sqlite3 *sqlite;
+    int ret = 0;
+    const char *in_db_prefix = NULL;
+    const char *input_table = NULL;
+    const char *input_geom = NULL;
+    const char *blade_db_prefix = NULL;
+    const char *blade_table = NULL;
+    const char *blade_geom = NULL;
+    const char *output_table = NULL;
+    int transaction = 0;
+    int ram_tmp_store = 0;
+    char **message = NULL;
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	message = &(cache->cutterMessage);
+
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	in_db_prefix = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	input_table = (const char *) sqlite3_value_text (argv[1]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	input_geom = (const char *) sqlite3_value_text (argv[2]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	blade_db_prefix = (const char *) sqlite3_value_text (argv[3]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (sqlite3_value_type (argv[4]) == SQLITE_TEXT)
+	blade_table = (const char *) sqlite3_value_text (argv[4]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (sqlite3_value_type (argv[5]) == SQLITE_NULL)
+	;
+    else if (sqlite3_value_type (argv[5]) == SQLITE_TEXT)
+	blade_geom = (const char *) sqlite3_value_text (argv[5]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (sqlite3_value_type (argv[6]) == SQLITE_TEXT)
+	output_table = (const char *) sqlite3_value_text (argv[6]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (argc >= 8)
+      {
+	  if (sqlite3_value_type (argv[7]) == SQLITE_INTEGER)
+	      transaction = sqlite3_value_int (argv[7]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+    if (argc == 9)
+      {
+	  if (sqlite3_value_type (argv[8]) == SQLITE_INTEGER)
+	      ram_tmp_store = sqlite3_value_int (argv[8]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+
+    sqlite = sqlite3_context_db_handle (context);
+    ret =
+	gaiaCutter (sqlite, cache, in_db_prefix, input_table, input_geom,
+		    blade_db_prefix, blade_table, blade_geom, output_table,
+		    transaction, ram_tmp_store, message);
+
+    sqlite3_result_int (context, ret);
+}
+
+static void
+fnct_GetCutterMessage (sqlite3_context * context, int argc,
+		       sqlite3_value ** argv)
+{
+/* SQL function:
+/ GetCutterMessage( void )
+/
+/ will return the last diagnostic message from Cutter
+/ NULL if there is no pending message
+*/
+    char *message = NULL;
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	message = cache->cutterMessage;
+
+    if (message == NULL)
+	sqlite3_result_null (context);
+    else
+	sqlite3_result_text (context, message, strlen (message), SQLITE_STATIC);
+}
+
 #endif /* end including GEOS */
 
 static int
@@ -28673,6 +27957,8 @@ fnct_BlobToFile (sqlite3_context * context, int argc, sqlite3_value ** argv)
     sqlite3_result_int (context, ret);
 }
 
+#ifndef OMIT_GEOS		/* only if GEOS is enabled */
+
 static int
 load_dxf (sqlite3 * db_handle, struct splite_internal_cache *cache,
 	  char *filename, int srid, int append, int force_dims, int mode,
@@ -29035,6 +28321,8 @@ fnct_ImportDXFfromDir (sqlite3_context * context, int argc,
     sqlite3_result_int (context, ret);
 }
 
+#endif /* end GEOS conditional */
+
 static void
 fnct_ExportDXF (sqlite3_context * context, int argc, sqlite3_value ** argv)
 {
@@ -30181,8 +29469,7 @@ fnct_GeodesicLength (sqlite3_context * context, int argc, sqlite3_value ** argv)
 				  /* interior Rings */
 				  ring = polyg->Interiors + ib;
 				  l = gaiaGeodesicTotalLength (a, b, rf,
-							       ring->
-							       DimensionModel,
+							       ring->DimensionModel,
 							       ring->Coords,
 							       ring->Points);
 				  if (l < 0.0)
@@ -30276,8 +29563,7 @@ fnct_GreatCircleLength (sqlite3_context * context, int argc,
 			    ring = polyg->Exterior;
 			    length +=
 				gaiaGreatCircleTotalLength (a, b,
-							    ring->
-							    DimensionModel,
+							    ring->DimensionModel,
 							    ring->Coords,
 							    ring->Points);
 			    for (ib = 0; ib < polyg->NumInteriors; ib++)
@@ -30286,8 +29572,7 @@ fnct_GreatCircleLength (sqlite3_context * context, int argc,
 				  ring = polyg->Interiors + ib;
 				  length +=
 				      gaiaGreatCircleTotalLength (a, b,
-								  ring->
-								  DimensionModel,
+								  ring->DimensionModel,
 								  ring->Coords,
 								  ring->Points);
 			      }
@@ -32894,6 +32179,31 @@ fnct_XB_IsSvg (sqlite3_context * context, int argc, sqlite3_value ** argv)
 }
 
 static void
+fnct_XB_IsGpx (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+/* SQL function:
+/ XB_IsGpx(XmlBLOB)
+/
+/ returns TRUE if the current BLOB is a GPX document XmlBLOB,
+/ FALSE if it's a valid XmlBLOB but not a GPX document
+/ or -1 if any error is encountered
+*/
+    unsigned char *p_blob;
+    int n_bytes;
+    int ret;
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) != SQLITE_BLOB)
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    p_blob = (unsigned char *) sqlite3_value_blob (argv[0]);
+    n_bytes = sqlite3_value_bytes (argv[0]);
+    ret = gaiaIsGpxXmlBlob (p_blob, n_bytes);
+    sqlite3_result_int (context, ret);
+}
+
+static void
 fnct_XB_GetDocumentSize (sqlite3_context * context, int argc,
 			 sqlite3_value ** argv)
 {
@@ -33362,6 +32672,47 @@ fnct_XB_GetGeometry (sqlite3_context * context, int argc, sqlite3_value ** argv)
 }
 
 static void
+fnct_XB_MLineFromGPX (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+/* SQL function:
+/ XB_MLineFromGPX(XmlBLOB)
+/
+/ if the BLOB is a valid XmlBLOB of the GPX type then
+/ a MultiLinestring will be returned
+/ return NULL on any other case
+*/
+    const unsigned char *p_blob;
+    int n_bytes;
+    int blob_len;
+    unsigned char *blob = NULL;
+    gaiaGeomCollPtr geom;
+    int gpkg_mode = 0;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	gpkg_mode = cache->gpkg_mode;
+    if (sqlite3_value_type (argv[0]) != SQLITE_BLOB)
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+    p_blob = sqlite3_value_blob (argv[0]);
+    n_bytes = sqlite3_value_bytes (argv[0]);
+    geom = gaiaXmlBlobMLineFromGPX (p_blob, n_bytes, sqlite);
+    if (geom != NULL)
+      {
+	  /* builds the BLOB geometry to be returned */
+	  gaiaToSpatiaLiteBlobWkbEx (geom, &blob, &blob_len, gpkg_mode);
+	  sqlite3_result_blob (context, blob, blob_len, free);
+	  gaiaFreeGeomColl (geom);
+      }
+    else
+	sqlite3_result_null (context);
+}
+
+static void
 fnct_XB_GetEncoding (sqlite3_context * context, int argc, sqlite3_value ** argv)
 {
 /* SQL function:
@@ -35533,6 +34884,446 @@ fnct_getDecimalPrecision (sqlite3_context * context, int argc,
     sqlite3_result_int (context, cache->decimal_precision);
 }
 
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+static void
+fnct_CreateTopology (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_CreateTopology (context, argc, argv);
+}
+
+static void
+fnct_DropTopology (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_DropTopology (context, argc, argv);
+}
+
+static void
+fnct_GetLastTopologyException (sqlite3_context * context, int argc,
+			       sqlite3_value ** argv)
+{
+    fnctaux_GetLastTopologyException (context, argc, argv);
+}
+
+static void
+fnct_AddIsoNode (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_AddIsoNode (context, argc, argv);
+}
+
+static void
+fnct_MoveIsoNode (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_MoveIsoNode (context, argc, argv);
+}
+
+static void
+fnct_RemIsoNode (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_RemIsoNode (context, argc, argv);
+}
+
+static void
+fnct_AddIsoEdge (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_AddIsoEdge (context, argc, argv);
+}
+
+static void
+fnct_RemIsoEdge (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_RemIsoEdge (context, argc, argv);
+}
+
+static void
+fnct_ModEdgeSplit (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_ModEdgeSplit (context, argc, argv);
+}
+
+static void
+fnct_NewEdgesSplit (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_NewEdgesSplit (context, argc, argv);
+}
+
+static void
+fnct_AddEdgeModFace (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_AddEdgeModFace (context, argc, argv);
+}
+
+static void
+fnct_AddEdgeNewFaces (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_AddEdgeNewFaces (context, argc, argv);
+}
+
+static void
+fnct_ChangeEdgeGeom (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_ChangeEdgeGeom (context, argc, argv);
+}
+
+static void
+fnct_RemEdgeModFace (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_RemEdgeModFace (context, argc, argv);
+}
+
+static void
+fnct_RemEdgeNewFace (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_RemEdgeNewFace (context, argc, argv);
+}
+
+static void
+fnct_ModEdgeHeal (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_ModEdgeHeal (context, argc, argv);
+}
+
+static void
+fnct_NewEdgeHeal (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_NewEdgeHeal (context, argc, argv);
+}
+
+static void
+fnct_GetFaceGeometry (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_GetFaceGeometry (context, argc, argv);
+}
+
+static void
+fnct_GetFaceEdges (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_GetFaceEdges (context, argc, argv);
+}
+
+static void
+fnct_ValidateTopoGeo (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_ValidateTopoGeo (context, argc, argv);
+}
+
+static void
+fnct_CreateTopoGeo (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_CreateTopoGeo (context, argc, argv);
+}
+
+static void
+fnct_GetNodeByPoint (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_GetNodeByPoint (context, argc, argv);
+}
+
+static void
+fnct_GetEdgeByPoint (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_GetEdgeByPoint (context, argc, argv);
+}
+
+static void
+fnct_GetFaceByPoint (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_GetFaceByPoint (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_AddPoint (sqlite3_context * context, int argc,
+		       sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_AddPoint (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_AddLineString (sqlite3_context * context, int argc,
+			    sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_AddLineString (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_FromGeoTable (sqlite3_context * context, int argc,
+			   sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_FromGeoTable (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_ToGeoTable (sqlite3_context * context, int argc,
+			 sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_ToGeoTable (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_ToGeoTableGeneralize (sqlite3_context * context, int argc,
+				   sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_ToGeoTableGeneralize (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_CreateTopoLayer (sqlite3_context * context, int argc,
+			      sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_CreateTopoLayer (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_InitTopoLayer (sqlite3_context * context, int argc,
+			    sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_InitTopoLayer (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_RemoveTopoLayer (sqlite3_context * context, int argc,
+			      sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_RemoveTopoLayer (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_ExportTopoLayer (sqlite3_context * context, int argc,
+			      sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_ExportTopoLayer (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_InsertFeatureFromTopoLayer (sqlite3_context * context, int argc,
+					 sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_InsertFeatureFromTopoLayer (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_Clone (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_Clone (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_SubdivideLines (sqlite3_context * context, int argc,
+			     sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_SubdivideLines (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_GetEdgeSeed (sqlite3_context * context, int argc,
+			  sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_GetEdgeSeed (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_GetFaceSeed (sqlite3_context * context, int argc,
+			  sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_GetFaceSeed (context, argc, argv);
+}
+
+static void
+fnct_TopoGeo_UpdateSeeds (sqlite3_context * context, int argc,
+			  sqlite3_value ** argv)
+{
+    fnctaux_TopoGeo_UpdateSeeds (context, argc, argv);
+}
+
+static void
+fnct_CreateNetwork (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_CreateNetwork (context, argc, argv);
+}
+
+static void
+fnct_DropNetwork (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_DropNetwork (context, argc, argv);
+}
+
+static void
+fnct_GetLastNetworkException (sqlite3_context * context, int argc,
+			      sqlite3_value ** argv)
+{
+    fnctaux_GetLastNetworkException (context, argc, argv);
+}
+
+static void
+fnct_AddIsoNetNode (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_AddIsoNetNode (context, argc, argv);
+}
+
+static void
+fnct_MoveIsoNetNode (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_MoveIsoNetNode (context, argc, argv);
+}
+
+static void
+fnct_RemIsoNetNode (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_RemIsoNetNode (context, argc, argv);
+}
+
+static void
+fnct_AddLink (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_AddLink (context, argc, argv);
+}
+
+static void
+fnct_ChangeLinkGeom (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_ChangeLinkGeom (context, argc, argv);
+}
+
+static void
+fnct_RemoveLink (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_RemoveLink (context, argc, argv);
+}
+
+static void
+fnct_NewLogLinkSplit (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_NewLogLinkSplit (context, argc, argv);
+}
+
+static void
+fnct_ModLogLinkSplit (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_ModLogLinkSplit (context, argc, argv);
+}
+
+static void
+fnct_NewGeoLinkSplit (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_NewGeoLinkSplit (context, argc, argv);
+}
+
+static void
+fnct_ModGeoLinkSplit (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_ModGeoLinkSplit (context, argc, argv);
+}
+
+static void
+fnct_ModLinkHeal (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_ModLinkHeal (context, argc, argv);
+}
+
+static void
+fnct_NewLinkHeal (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_NewLinkHeal (context, argc, argv);
+}
+
+static void
+fnct_LogiNetFromTGeo (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_LogiNetFromTGeo (context, argc, argv);
+}
+
+static void
+fnct_SpatNetFromTGeo (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_SpatNetFromTGeo (context, argc, argv);
+}
+
+static void
+fnct_SpatNetFromGeom (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_SpatNetFromGeom (context, argc, argv);
+}
+
+static void
+fnct_ValidLogicalNet (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_ValidLogicalNet (context, argc, argv);
+}
+
+static void
+fnct_ValidSpatialNet (sqlite3_context * context, int argc,
+		      sqlite3_value ** argv)
+{
+    fnctaux_ValidSpatialNet (context, argc, argv);
+}
+
+static void
+fnct_GetNetNodeByPoint (sqlite3_context * context, int argc,
+			sqlite3_value ** argv)
+{
+    fnctaux_GetNetNodeByPoint (context, argc, argv);
+}
+
+static void
+fnct_GetLinkByPoint (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_GetLinkByPoint (context, argc, argv);
+}
+
+static void
+fnct_TopoNet_FromGeoTable (sqlite3_context * context, int argc,
+			   sqlite3_value ** argv)
+{
+    fnctaux_TopoNet_FromGeoTable (context, argc, argv);
+}
+
+static void
+fnct_TopoNet_ToGeoTable (sqlite3_context * context, int argc,
+			 sqlite3_value ** argv)
+{
+    fnctaux_TopoNet_ToGeoTable (context, argc, argv);
+}
+
+static void
+fnct_TopoNet_ToGeoTableGeneralize (sqlite3_context * context, int argc,
+				   sqlite3_value ** argv)
+{
+    fnctaux_TopoNet_ToGeoTableGeneralize (context, argc, argv);
+}
+
+static void
+fnct_TopoNet_Clone (sqlite3_context * context, int argc, sqlite3_value ** argv)
+{
+    fnctaux_TopoNet_Clone (context, argc, argv);
+}
+
+static void
+fnct_TopoNet_GetLinkSeed (sqlite3_context * context, int argc,
+			  sqlite3_value ** argv)
+{
+    fnctaux_TopoNet_GetLinkSeed (context, argc, argv);
+}
+
+static void
+fnct_TopoNet_UpdateSeeds (sqlite3_context * context, int argc,
+			  sqlite3_value ** argv)
+{
+    fnctaux_TopoNet_UpdateSeeds (context, argc, argv);
+}
+
+#endif /* end TOPOLOGY conditionals */
+
 #ifdef LOADABLE_EXTENSION
 static void
 splite_close_callback (void *p_cache)
@@ -35612,6 +35403,12 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "HasGeosTrunk", 0,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_has_geos_trunk, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "HasGeosReentrant", 0,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_has_geos_reentrant, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "HasGeosOnlyReentrant", 0,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_has_geos_only_reentrant, 0, 0, 0);
     sqlite3_create_function_v2 (db, "HasLwGeom", 0,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_has_lwgeom, 0, 0, 0);
@@ -35636,6 +35433,15 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "HasGeoPackage", 0,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_has_geopackage, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "HasGCP", 0,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_has_gcp, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "HasGroundControlPoints", 0,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_has_gcp, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "HasTopology", 0,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_has_topology, 0, 0, 0);
     sqlite3_create_function_v2 (db, "GeometryConstraints", 3,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_GeometryConstraints, 0, 0, 0);
@@ -35912,6 +35718,39 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "CloneTable", 14,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_CloneTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 4,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 5,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 6,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 7,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 8,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 9,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 10,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 11,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 12,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 13,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateClonedTable", 14,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_CreateClonedTable, 0, 0, 0);
 
 #ifndef OMIT_PROJ		/* PROJ.4 is strictly required to support KML */
     sqlite3_create_function_v2 (db, "AsKml", 1,
@@ -37218,6 +37057,9 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
 	  sqlite3_create_function_v2 (db, "BlobToFile", 2,
 				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				      fnct_BlobToFile, 0, 0, 0);
+
+#ifndef OMIT_GEOS		/* only if GEOS is enabled */
+
 	  sqlite3_create_function_v2 (db, "ImportDXF", 1,
 				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
 				      fnct_ImportDXF, 0, 0, 0);
@@ -37230,6 +37072,9 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
 	  sqlite3_create_function_v2 (db, "ImportDXFfromDir", 8,
 				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
 				      fnct_ImportDXFfromDir, 0, 0, 0);
+
+#endif /* GEOS enabled */
+
 	  sqlite3_create_function_v2 (db, "ExportDXF", 9,
 				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
 				      fnct_ExportDXF, 0, 0, 0);
@@ -37904,12 +37749,6 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "ST_BdMPolyFromWKB", 2,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
 				fnct_BdMPolyFromWKB2, 0, 0, 0);
-    sqlite3_create_function_v2 (db, "CreateTopologyTables", 2,
-				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
-				fnct_CreateTopologyTables, 0, 0, 0);
-    sqlite3_create_function_v2 (db, "CreateTopologyTables", 3,
-				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
-				fnct_CreateTopologyTables, 0, 0, 0);
     sqlite3_create_function_v2 (db, "OffsetCurve", 2,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
 				fnct_OffsetCurve, 0, 0, 0);
@@ -38256,9 +38095,25 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "ST_SelfIntersections", 1,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
 				fnct_SelfIntersections, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_3dLength", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_3dLength, 0, 0, 0);
 
 #endif /* end LWGEOM support */
 
+    sqlite3_create_function_v2 (db, "ST_Cutter", 7,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_Cutter, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_Cutter", 8,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_Cutter, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_Cutter", 9,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_Cutter, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "GetCutterMessage", 0,
+				SQLITE_UTF8, cache,
+				fnct_GetCutterMessage, 0, 0, 0);
+
 #endif /* end including GEOS */
 
 #ifdef ENABLE_LIBXML2		/* including LIBXML2 */
@@ -38476,6 +38331,9 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "XB_IsSvg", 1,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_XB_IsSvg, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "XB_IsGpx", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+				fnct_XB_IsGpx, 0, 0, 0);
     sqlite3_create_function_v2 (db, "XB_GetSchemaURI", 1,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_XB_GetSchemaURI, 0, 0, 0);
@@ -38512,6 +38370,9 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
     sqlite3_create_function_v2 (db, "XB_GetGeometry", 1,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_XB_GetGeometry, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "XB_MLineFromGPX", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_XB_MLineFromGPX, 0, 0, 0);
     sqlite3_create_function_v2 (db, "XB_GetDocumentSize", 1,
 				SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
 				fnct_XB_GetDocumentSize, 0, 0, 0);
@@ -38617,6 +38478,276 @@ register_spatialite_sql_functions (void *p_db, const void *p_cache)
 
 #endif /* end enabling GeoPackage extensions */
 
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    if (sqlite3_libversion_number () >= 3008003)
+      {
+	  /* only SQLite >= 3.8.3 can suppoty WITH RECURSIVE */
+	  sqlite3_create_function_v2 (db, "CreateTopology", 1,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_CreateTopology, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "CreateTopology", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_CreateTopology, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "CreateTopology", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_CreateTopology, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "CreateTopology", 4,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_CreateTopology, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_InitTopoGeo", 1,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_CreateTopology, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "DropTopology", 1,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_DropTopology, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "GetLastTopologyException", 1,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_GetLastTopologyException, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_AddIsoNode", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_AddIsoNode, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_MoveIsoNode", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_MoveIsoNode, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_RemIsoNode", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_RemIsoNode, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_AddIsoEdge", 4,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_AddIsoEdge, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_RemIsoEdge", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_RemIsoEdge, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_ModEdgeSplit", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_ModEdgeSplit, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_NewEdgesSplit", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_NewEdgesSplit, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_AddEdgeModFace", 4,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_AddEdgeModFace, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_AddEdgeNewFaces", 4,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_AddEdgeNewFaces, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_ChangeEdgeGeom", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_ChangeEdgeGeom, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_RemEdgeNewFace", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_RemEdgeNewFace, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_RemEdgeModFace", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_RemEdgeModFace, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_ModEdgeHeal", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_ModEdgeHeal, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_NewEdgeHeal", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_NewEdgeHeal, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_GetFaceGeometry", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_GetFaceGeometry, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_GetFaceEdges", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_GetFaceEdges, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_ValidateTopoGeo", 1,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_ValidateTopoGeo, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "ST_CreateTopoGeo", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_CreateTopoGeo, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "GetNodeByPoint", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_GetNodeByPoint, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "GetEdgeByPoint", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_GetEdgeByPoint, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "GetFaceByPoint", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_GetFaceByPoint, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_AddPoint", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_AddPoint, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_AddLineString", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_AddLineString, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_FromGeoTable", 5,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_FromGeoTable, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_FromGeoTable", 7,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_FromGeoTable, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ToGeoTable", 5,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ToGeoTable, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ToGeoTable", 6,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ToGeoTable, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ToGeoTableGeneralize", 6,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ToGeoTableGeneralize, 0, 0,
+				      0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ToGeoTableGeneralize", 7,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ToGeoTableGeneralize, 0, 0,
+				      0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_Clone", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_Clone, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_SubdivideLines", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_SubdivideLines, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_GetEdgeSeed", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_GetEdgeSeed, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_GetFaceSeed", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_GetFaceSeed, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_UpdateSeeds", 1,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_UpdateSeeds, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_UpdateSeeds", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_UpdateSeeds, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_CreateTopoLayer", 5,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_CreateTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_CreateTopoLayer", 6,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_CreateTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_InitTopoLayer", 4,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_InitTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_RemoveTopoLayer", 2,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_RemoveTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ExportTopoLayer", 3,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ExportTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ExportTopoLayer", 4,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ExportTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_ExportTopoLayer", 5,
+				      SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				      fnct_TopoGeo_ExportTopoLayer, 0, 0, 0);
+	  sqlite3_create_function_v2 (db, "TopoGeo_InsertFeatureFromTopoLayer",
+				      4, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+				      cache,
+				      fnct_TopoGeo_InsertFeatureFromTopoLayer,
+				      0, 0, 0);
+      }
+
+    sqlite3_create_function_v2 (db, "CreateNetwork", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_CreateNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateNetwork", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_CreateNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateNetwork", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_CreateNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateNetwork", 4,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_CreateNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "CreateNetwork", 5,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_CreateNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_InitTopoNet", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_CreateNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "DropNetwork", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_DropNetwork, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "GetLastNetworkException", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_GetLastNetworkException, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_AddIsoNetNode", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_AddIsoNetNode, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_MoveIsoNetNode", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_MoveIsoNetNode, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_RemIsoNetNode", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_RemIsoNetNode, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_AddLink", 4,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_AddLink, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_ChangeLinkGeom", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_ChangeLinkGeom, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_RemoveLink", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_RemoveLink, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_NewLogLinkSplit", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_NewLogLinkSplit, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_ModLogLinkSplit", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_ModLogLinkSplit, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_NewGeoLinkSplit", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_NewGeoLinkSplit, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_ModGeoLinkSplit", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_ModGeoLinkSplit, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_NewLinkHeal", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_NewLinkHeal, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_ModLinkHeal", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_ModLinkHeal, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_LogiNetFromTGeo", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_LogiNetFromTGeo, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_SpatNetFromTGeo", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_SpatNetFromTGeo, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_SpatNetFromGeom", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_SpatNetFromGeom, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_ValidLogicalNet", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_ValidLogicalNet, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "ST_ValidSpatialNet", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_ValidSpatialNet, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "GetNetNodeByPoint", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_GetNetNodeByPoint, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "GetLinkByPoint", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_GetLinkByPoint, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_FromGeoTable", 4,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_FromGeoTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_ToGeoTable", 5,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_ToGeoTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_ToGeoTable", 6,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_ToGeoTable, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_ToGeoTableGeneralize", 6,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_ToGeoTableGeneralize, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_ToGeoTableGeneralize", 7,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_ToGeoTableGeneralize, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_Clone", 3,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_Clone, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_GetLinkSeed", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_GetLinkSeed, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_UpdateSeeds", 1,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_UpdateSeeds, 0, 0, 0);
+    sqlite3_create_function_v2 (db, "TopoNet_UpdateSeeds", 2,
+				SQLITE_UTF8 | SQLITE_DETERMINISTIC, cache,
+				fnct_TopoNet_UpdateSeeds, 0, 0, 0);
+#endif /* end TOPOLOGY conditionals */
+
     return cache;
 }
 
@@ -38651,6 +38782,8 @@ init_spatialite_virtualtables (void *p_db, const void *p_cache)
     virtual_spatialindex_extension_init (db);
 /* initializing the VirtualElementary  extension */
     virtual_elementary_extension_init (db);
+/* initializing the VirtualKNN  extension */
+    virtual_knn_extension_init (db);
 
 #ifdef ENABLE_GEOPACKAGE	/* only if GeoPackage support is enabled */
 /* initializing the VirtualFDO  extension */
@@ -38697,7 +38830,9 @@ spatialite_init_geos (void)
 {
 /* initializes GEOS (or resets to initial state - as required by LWGEOM) */
 #ifndef OMIT_GEOS		/* initializing GEOS */
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     initGEOS (geos_warning, geos_error);
+#endif
 #endif /* end GEOS  */
 }
 
@@ -38730,6 +38865,8 @@ spatialite_splash_screen (int verbose)
 		    ("\t- 'VirtualSpatialIndex'\t[R*Tree metahandler]\n");
 		spatialite_i
 		    ("\t- 'VirtualElementary'\t[ElemGeoms metahandler]\n");
+		spatialite_i
+		    ("\t- 'VirtualKNN'\t[K-Nearest Neighbors metahandler]\n");
 
 #ifdef ENABLE_LIBXML2		/* VirtualXPath is supported */
 		spatialite_i
diff --git a/src/spatialite/spatialite_init.c b/src/spatialite/spatialite_init.c
index 19dcc96..30fdfbd 100644
--- a/src/spatialite/spatialite_init.c
+++ b/src/spatialite/spatialite_init.c
@@ -72,6 +72,11 @@ Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
 #include <spatialite_private.h>
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -109,7 +114,9 @@ spatialite_init (int verbose)
     spatialite_initialize ();
 
 #ifndef OMIT_GEOS		/* initializing GEOS */
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     initGEOS (geos_warning, geos_error);
+#endif
 #endif /* end GEOS  */
 
 #ifdef POSTGIS_2_1		/* initializing liblwgeom from PostGIS 2.1.x (or later) */
@@ -129,8 +136,10 @@ spatialite_cleanup ()
 */
 
 #ifndef OMIT_GEOS
+#ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
     finishGEOS ();
 #endif
+#endif
 
 #ifdef ENABLE_LWGEOM
     gaiaResetLwGeomMsg ();
diff --git a/src/spatialite/srid_aux.c b/src/spatialite/srid_aux.c
index 79523a9..5b60e8e 100644
--- a/src/spatialite/srid_aux.c
+++ b/src/spatialite/srid_aux.c
@@ -1888,10 +1888,10 @@ getProjParamsFromGeopackageTable (sqlite3 * sqlite, int srid,
 }
 
 SPATIALITE_PRIVATE void
-getProjParamsEx (void *p_sqlite, int srid, char **proj_params,
-		 int gpkg_amphibious_mode)
+getProjParams (void *p_sqlite, int srid, char **proj_params)
 {
-/* retrives the PROJ params - generic interface */sqlite3 *sqlite = (sqlite3 *) p_sqlite;
+/* retrives the PROJ params from SPATIAL_SYS_REF table */
+    sqlite3 *sqlite = (sqlite3 *) p_sqlite;
     *proj_params = NULL;
 
 /* searching within "vanilla" spatial_reference_sys */
@@ -1902,13 +1902,3 @@ getProjParamsEx (void *p_sqlite, int srid, char **proj_params,
 /* last opportunity: search within GPKG srs */
     getProjParamsFromGeopackageTable (sqlite, srid, proj_params);
 }
-
-SPATIALITE_PRIVATE void
-getProjParams (void *p_sqlite, int srid, char **proj_params)
-{
-/* 
-* retrives the PROJ params from SPATIAL_SYS_REF table, if possible 
-* convenience method - disabling GPKG amphibious mode
-*/
-    getProjParamsEx (p_sqlite, srid, proj_params, 0);
-}
diff --git a/src/spatialite/statistics.c b/src/spatialite/statistics.c
index 7c51cf8..759bb55 100644
--- a/src/spatialite/statistics.c
+++ b/src/spatialite/statistics.c
@@ -74,14 +74,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include <spatialite_private.h>
 #include <spatialite/gaiaaux.h>
 
-#ifndef OMIT_GEOS		/* including GEOS */
-#include <geos_c.h>
-#endif
-
-#ifndef OMIT_PROJ		/* including PROJ.4 */
-#include <proj_api.h>
-#endif
-
 #ifdef _WIN32
 #define strcasecmp	_stricmp
 #endif /* not WIN32 */
@@ -2063,6 +2055,12 @@ check_drop_layout (sqlite3 * sqlite, const char *prefix, const char *table,
     int ret;
     char *sql;
     char *q_prefix = gaiaDoubleQuotedSql (prefix);
+
+    if (strcasecmp (prefix, "TEMP") == 0)
+      {
+	  /* TEMPORARY object; unconditioanally returning TRUE */
+	  return 1;
+      }
     sql =
 	sqlite3_mprintf
 	("SELECT type, name FROM \"%s\".sqlite_master WHERE type = 'table' or type = 'view'",
@@ -2174,6 +2172,96 @@ check_drop_layout (sqlite3 * sqlite, const char *prefix, const char *table,
     return 1;
 }
 
+static int
+check_topology_table (sqlite3 * sqlite, const char *prefix, const char *table)
+{
+/* avoiding to Drop GeoTables belonging to some TopoGeo or TopoNet */
+    char *xprefix;
+    char *sql;
+    char *table_name;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    int found = 0;
+
+    if (prefix == NULL)
+	prefix = "main";
+
+/* testing within Topologies */
+    xprefix = gaiaDoubleQuotedSql (prefix);
+    sql =
+	sqlite3_mprintf ("SELECT topology_name FROM \"%s\".topologies",
+			 xprefix);
+    free (xprefix);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto networks;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		const char *name = results[(i * columns) + 0];
+		table_name = sqlite3_mprintf ("%s_node", name);
+		if (strcasecmp (table, table_name) == 0)
+		    found = 1;
+		sqlite3_free (table_name);
+		table_name = sqlite3_mprintf ("%s_edge", name);
+		if (strcasecmp (table, table_name) == 0)
+		    found = 1;
+		sqlite3_free (table_name);
+	    }
+      }
+    sqlite3_free_table (results);
+    if (found)
+      {
+	  spatialite_e ("DropTable: can't drop TopoGeo table \"%s\".\"%s\"",
+			prefix, table);
+	  return 1;
+      }
+
+  networks:
+/* testing within Networks */
+    xprefix = gaiaDoubleQuotedSql (prefix);
+    sql = sqlite3_mprintf ("SELECT network_name FROM \"%s\".netowrks", xprefix);
+    free (xprefix);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto end;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		const char *name = results[(i * columns) + 0];
+		table_name = sqlite3_mprintf ("%s_node", name);
+		if (strcasecmp (table, table_name) == 0)
+		    found = 1;
+		sqlite3_free (table_name);
+		table_name = sqlite3_mprintf ("%s_link", name);
+		if (strcasecmp (table, table_name) == 0)
+		    found = 1;
+		sqlite3_free (table_name);
+	    }
+      }
+    sqlite3_free_table (results);
+    if (found)
+      {
+	  spatialite_e ("DropTable: can't drop TopoNet table \"%s\".\"%s\"",
+			prefix, table);
+	  return 1;
+      }
+
+  end:
+    return 0;
+}
+
 SPATIALITE_DECLARE int
 gaiaDropTable (sqlite3 * sqlite, const char *table)
 {
@@ -2232,6 +2320,9 @@ gaiaDropTableEx2 (sqlite3 * sqlite, const char *prefix, const char *table,
 /* checking the actual DB configuration */
     if (!check_drop_layout (sqlite, prefix, table, &aux))
 	goto rollback;
+/* avoiding to drop TopoGeo and TopoNet tables */
+    if (check_topology_table (sqlite, prefix, table))
+	goto rollback;
 /* recursively dropping any depending View */
     if (!do_drop_sub_view (sqlite, prefix, table, &aux))
 	goto rollback;
diff --git a/src/spatialite/table_cloner.c b/src/spatialite/table_cloner.c
index e5f133b..a7dbd71 100644
--- a/src/spatialite/table_cloner.c
+++ b/src/spatialite/table_cloner.c
@@ -173,6 +173,7 @@ struct aux_cloner
     int with_triggers;
     int append;
     int already_existing;
+    int create_only;
 };
 
 static int
@@ -2092,8 +2093,9 @@ already_existing_table (sqlite3 * sqlite, const char *table)
 }
 
 SPATIALITE_PRIVATE const void *
-gaiaAuxClonerCreate (const void *sqlite, const char *db_prefix,
-		     const char *in_table, const char *out_table)
+gaiaAuxClonerCreateEx (const void *sqlite, const char *db_prefix,
+		       const char *in_table, const char *out_table,
+		       int create_only)
 {
 /* creating a Cloner object */
     int len;
@@ -2138,6 +2140,7 @@ gaiaAuxClonerCreate (const void *sqlite, const char *db_prefix,
     cloner->with_triggers = 0;
     cloner->append = 0;
     cloner->already_existing = 0;
+    cloner->create_only = create_only;
 
 /* exploring the input table - Columns */
     if (!check_input_table_columns (cloner))
@@ -2161,6 +2164,14 @@ gaiaAuxClonerCreate (const void *sqlite, const char *db_prefix,
     return NULL;
 }
 
+SPATIALITE_PRIVATE const void *
+gaiaAuxClonerCreate (const void *sqlite, const char *db_prefix,
+		     const char *in_table, const char *out_table)
+{
+/* creating a Cloner object */
+    return gaiaAuxClonerCreateEx (sqlite, db_prefix, in_table, out_table, 0);
+}
+
 SPATIALITE_PRIVATE void
 gaiaAuxClonerDestroy (const void *handle)
 {
@@ -2310,10 +2321,13 @@ gaiaAuxClonerExecute (const void *handle)
 		return 0;
 	    }
       }
-    if (!copy_rows (cloner))
+    if (cloner->create_only == 0)
       {
-	  spatialite_e ("CloneTable: unable to copy Table rows\n");
-	  return 0;
+	  if (!copy_rows (cloner))
+	    {
+		spatialite_e ("CloneTable: unable to copy Table rows\n");
+		return 0;
+	    }
       }
     return 1;
 }
diff --git a/src/spatialite/virtualknn.c b/src/spatialite/virtualknn.c
new file mode 100644
index 0000000..7e9e790
--- /dev/null
+++ b/src/spatialite/virtualknn.c
@@ -0,0 +1,1587 @@
+/*
+
+ virtualknn.c -- SQLite3 extension [VIRTUAL TABLE RTree metahandler]
+
+ version 4.4, 2015 November 27
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/*
+ 
+CREDITS:
+
+this module has been completely funded by:
+Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
+(K-Nearest Neighbors [KNN] module) 
+
+CIG: 644544015A
+
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#include <spatialite/sqlite.h>
+
+#include <spatialite/spatialite.h>
+#include <spatialite/gaiaaux.h>
+#include <spatialite/gaiageo.h>
+
+static struct sqlite3_module my_knn_module;
+
+#define MAX_MBR	8
+
+/******************************************************************************
+/
+/ VirtualTable structs
+/
+******************************************************************************/
+
+typedef struct VKnnRectStruct
+{
+/* a Rectangle (MBR) item into the R*Tree hierarchy */
+    double minx;
+    double maxx;
+    double miny;
+    double maxy;
+    double dist;
+    int has_children;
+} VKnnRect;
+typedef VKnnRect *VKnnRectPtr;
+
+typedef struct VKnnTreeStruct
+{
+/* an R*Tree level */
+    VKnnRect mbr_array[MAX_MBR];
+    double max_dist;
+    int curr_items;
+} VKnnTree;
+typedef VKnnTree *VKnnTreePtr;
+
+typedef struct VKnnItemStruct
+{
+/* a Feature item into the KNN sorted array */
+    sqlite3_int64 rowid;
+    double dist;
+} VKnnItem;
+typedef VKnnItem *VKnnItemPtr;
+
+typedef struct VKnnContextStruct
+{
+/* current KNN context */
+    char *table_name;
+    char *column_name;
+    double minx;
+    double maxx;
+    double miny;
+    double maxy;
+    unsigned char *blob;
+    int blob_size;
+    sqlite3_stmt *stmt_dist;
+    sqlite3_stmt *stmt_rect;
+    VKnnItemPtr knn_array;
+    int max_items;
+    VKnnTreePtr tree;
+    int levels;
+    int curr_level;
+    double max_dist;
+    int curr_items;
+} VKnnContext;
+typedef VKnnContext *VKnnContextPtr;
+
+typedef struct VirtualKnnStruct
+{
+/* extends the sqlite3_vtab struct */
+    const sqlite3_module *pModule;	/* ptr to sqlite module: USED INTERNALLY BY SQLITE */
+    int nRef;			/* # references: USED INTERNALLY BY SQLITE */
+    char *zErrMsg;		/* error message: USE INTERNALLY BY SQLITE */
+    sqlite3 *db;		/* the sqlite db holding the virtual table */
+    VKnnContextPtr knn_ctx;	/* KNN context */
+} VirtualKnn;
+typedef VirtualKnn *VirtualKnnPtr;
+
+typedef struct VirtualKnnCursorStruct
+{
+/* extends the sqlite3_vtab_cursor struct */
+    VirtualKnnPtr pVtab;	/* Virtual table of this cursor */
+    int eof;			/* the EOF marker */
+    int CurrentIndex;		/* index of the current KNN item */
+} VirtualKnnCursor;
+typedef VirtualKnnCursor *VirtualKnnCursorPtr;
+
+static void
+vknn_empty_context (VKnnContextPtr ctx)
+{
+/* setting an empty KNN context */
+    if (ctx == NULL)
+	return;
+    ctx->table_name = NULL;
+    ctx->column_name = NULL;
+    ctx->minx = DBL_MAX;
+    ctx->maxx = -DBL_MAX;
+    ctx->miny = DBL_MAX;
+    ctx->maxy = -DBL_MAX;
+    ctx->blob = NULL;
+    ctx->blob_size = 0;
+    ctx->max_items = 0;
+    ctx->stmt_dist = NULL;
+    ctx->stmt_rect = NULL;
+    ctx->knn_array = NULL;
+    ctx->max_dist = -DBL_MAX;
+    ctx->tree = NULL;
+    ctx->levels = 0;
+    ctx->curr_level = -1;
+    ctx->curr_items = 0;
+}
+
+static VKnnContextPtr
+vknn_create_context (void)
+{
+/* creating an empty KNN context */
+    VKnnContextPtr ctx = malloc (sizeof (VKnnContext));
+    vknn_empty_context (ctx);
+    return ctx;
+}
+
+static void
+vknn_reset_context (VKnnContextPtr ctx)
+{
+/* freeing a KNN context */
+    if (ctx == NULL)
+	return;
+    if (ctx->table_name != NULL)
+	free (ctx->table_name);
+    if (ctx->column_name != NULL)
+	free (ctx->column_name);
+    if (ctx->blob != NULL)
+	free (ctx->blob);
+    if (ctx->stmt_dist != NULL)
+	sqlite3_finalize (ctx->stmt_dist);
+    if (ctx->stmt_rect != NULL)
+	sqlite3_finalize (ctx->stmt_rect);
+    if (ctx->knn_array != NULL)
+	free (ctx->knn_array);
+    if (ctx->tree != NULL)
+	free (ctx->tree);
+    vknn_empty_context (ctx);
+}
+
+static void
+vknn_init_context (VKnnContextPtr ctx, const char *table, const char *column,
+		   gaiaGeomCollPtr geom, int max_items,
+		   sqlite3_stmt * stmt_dist, sqlite3_stmt * stmt_rect)
+{
+/* initializing a KNN context */
+    int i;
+    if (ctx == NULL)
+	return;
+    vknn_reset_context (ctx);
+    i = strlen (table);
+    ctx->table_name = malloc (i + 1);
+    strcpy (ctx->table_name, table);
+    i = strlen (column);
+    ctx->column_name = malloc (i + 1);
+    strcpy (ctx->column_name, column);
+    ctx->minx = geom->MinX;
+    ctx->maxx = geom->MaxX;
+    ctx->miny = geom->MinY;
+    ctx->maxy = geom->MaxY;
+    gaiaToSpatiaLiteBlobWkb (geom, &(ctx->blob), &(ctx->blob_size));
+    ctx->max_items = max_items;
+    ctx->stmt_dist = stmt_dist;
+    ctx->stmt_rect = stmt_rect;
+    ctx->knn_array = malloc (sizeof (VKnnItem) * max_items);
+    for (i = 0; i < max_items; i++)
+      {
+	  /* initializing the KNN sorted array */
+	  VKnnItemPtr item = ctx->knn_array + i;
+	  item->rowid = 0;
+	  item->dist = DBL_MAX;
+      }
+    ctx->max_dist = -DBL_MAX;
+    ctx->curr_items = 0;
+    ctx->tree = NULL;
+    ctx->levels = 0;
+    ctx->curr_level = -1;
+}
+
+static void
+vknn_free_context (void *p)
+{
+/* freeing a KNN context */
+    VKnnContextPtr ctx = (VKnnContextPtr) p;
+    vknn_reset_context (ctx);
+    free (ctx);
+}
+
+static void
+vknn_shift_items (VKnnContextPtr ctx, int index)
+{
+/* shifting down the Features sorted array */
+    int i;
+    for (i = ctx->max_items - 1; i > index; i--)
+      {
+	  VKnnItemPtr item1 = ctx->knn_array + i - 1;
+	  VKnnItemPtr item2 = ctx->knn_array + i;
+	  item2->rowid = item1->rowid;
+	  item2->dist = item1->dist;
+	  if ((i == ctx->max_items - 1) && item2->dist != DBL_MAX)
+	      ctx->max_dist = item2->dist;
+      }
+}
+
+static void
+vknn_update_items (VKnnContextPtr ctx, sqlite3_int64 rowid, double dist)
+{
+/* updating the Features sorted array */
+    int i;
+    if (ctx->curr_items == ctx->max_items)
+      {
+	  if (dist >= ctx->max_dist)
+	      return;
+      }
+    for (i = 0; i < ctx->max_items; i++)
+      {
+	  VKnnItemPtr item = ctx->knn_array + i;
+	  if (rowid == item->rowid)
+	      return;
+	  if (dist < item->dist)
+	    {
+		vknn_shift_items (ctx, i);
+		item->rowid = rowid;
+		item->dist = dist;
+		break;
+	    }
+      }
+    if (dist > ctx->max_dist)
+	ctx->max_dist = dist;
+    if (ctx->curr_items < ctx->max_items)
+	ctx->curr_items += 1;
+}
+
+static void
+vknn_shift_rects (VKnnTreePtr tree_level, int index)
+{
+/* shifting down the RTree MBRs sorted array */
+    int i;
+    for (i = MAX_MBR - 1; i > index; i--)
+      {
+	  VKnnRectPtr rect1 = &(tree_level->mbr_array[i - 1]);
+	  VKnnRectPtr rect2 = &(tree_level->mbr_array[i]);
+	  rect2->minx = rect1->minx;
+	  rect2->miny = rect1->miny;
+	  rect2->maxx = rect1->maxx;
+	  rect2->maxy = rect1->maxy;
+	  rect2->dist = rect1->dist;
+	  rect2->has_children = rect1->has_children;
+	  if ((i == MAX_MBR - 1) && rect2->dist != DBL_MAX)
+	      tree_level->max_dist = rect2->dist;
+      }
+}
+
+static void
+vknn_update_tree (VKnnContextPtr ctx, int level, double minx, double miny,
+		  double maxx, double maxy, double dist)
+{
+/* updating the Tree levels sorted array */
+    VKnnTreePtr tree_level;
+    int i;
+
+    if (ctx == NULL)
+	return;
+    if (ctx->tree == NULL)
+	return;
+    if (level < 0 || level >= ctx->levels)
+	return;
+    tree_level = ctx->tree + level;
+    if (tree_level->curr_items == MAX_MBR)
+      {
+	  if (dist >= tree_level->max_dist)
+	      return;
+      }
+    for (i = 0; i < MAX_MBR; i++)
+      {
+	  VKnnRectPtr rect = &(tree_level->mbr_array[i]);
+	  if (dist < rect->dist)
+	    {
+		vknn_shift_rects (tree_level, i);
+		rect->minx = minx;
+		rect->miny = miny;
+		rect->maxx = maxx;
+		rect->maxy = maxy;
+		rect->dist = dist;
+		rect->has_children = 0;
+		break;
+	    }
+      }
+    if (dist > tree_level->max_dist)
+	tree_level->max_dist = dist;
+    if (tree_level->curr_items < MAX_MBR)
+	tree_level->curr_items += 1;
+}
+
+static int
+vknn_check_mbr (VKnnContextPtr ctx, double rtree_minx, double rtree_miny,
+		double rtree_maxx, double rtree_maxy)
+{
+/* comparing two MBRs */
+    if (rtree_minx >= ctx->minx && rtree_maxx <= ctx->maxx
+	&& rtree_miny >= ctx->miny && rtree_maxy <= ctx->maxy)
+	return FULLY_WITHIN;
+    if (rtree_maxx < ctx->minx)
+	return NOT_WITHIN;
+    if (rtree_minx > ctx->maxx)
+	return NOT_WITHIN;
+    if (rtree_maxy < ctx->miny)
+	return NOT_WITHIN;
+    if (rtree_miny > ctx->maxy)
+	return NOT_WITHIN;
+    return PARTLY_WITHIN;
+}
+
+static double
+vknn_compute_distance (VKnnContextPtr ctx, sqlite3_int64 rowid)
+{
+/* computing the distance between two geometries (in meters) */
+    double dist = DBL_MAX;
+    int ret;
+    sqlite3_stmt *stmt;
+    if (ctx == NULL)
+	return DBL_MAX;
+    if (ctx->blob == NULL)
+	return DBL_MAX;
+    if (ctx->stmt_dist == NULL)
+	return DBL_MAX;
+    stmt = ctx->stmt_dist;
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_blob (stmt, 1, ctx->blob, ctx->blob_size, SQLITE_STATIC);
+    sqlite3_bind_int64 (stmt, 2, rowid);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_FLOAT)
+		    dist = sqlite3_column_double (stmt, 0);
+	    }
+	  else
+	    {
+		dist = DBL_MAX;
+		break;
+	    }
+      }
+    return dist;
+}
+
+static double
+vknn_rect_distance (VKnnContextPtr ctx, double minx, double miny, double maxx,
+		    double maxy)
+{
+/* computing the distance between the geometry and an R*Tree MBR */
+    double dist = DBL_MAX;
+    int ret;
+    sqlite3_stmt *stmt;
+    if (ctx == NULL)
+	return DBL_MAX;
+    if (ctx->blob == NULL)
+	return DBL_MAX;
+    if (ctx->stmt_rect == NULL)
+	return DBL_MAX;
+    stmt = ctx->stmt_rect;
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_blob (stmt, 1, ctx->blob, ctx->blob_size, SQLITE_STATIC);
+    sqlite3_bind_double (stmt, 2, minx);
+    sqlite3_bind_double (stmt, 3, miny);
+    sqlite3_bind_double (stmt, 4, maxx);
+    sqlite3_bind_double (stmt, 5, maxy);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_FLOAT)
+		    dist = sqlite3_column_double (stmt, 0);
+	    }
+	  else
+	    {
+		dist = DBL_MAX;
+		break;
+	    }
+      }
+    return dist;
+}
+
+int
+vknn_query_callback (sqlite3_rtree_query_info * info)
+{
+/* R*Tree Query Callback function */
+    int lev;
+    int i;
+    VKnnContextPtr ctx = (VKnnContextPtr) (info->pContext);
+
+    if (ctx->curr_level == -1 && ctx->tree == NULL)
+      {
+	  /* first MBR: allocating the RTree structure */
+	  ctx->levels = info->mxLevel - 1;
+	  ctx->tree = malloc (sizeof (VKnnTree) * (ctx->levels));
+	  for (lev = 0; lev < ctx->levels; lev++)
+	    {
+		/* initializing all Tree levels */
+		VKnnTreePtr tree_level = ctx->tree + lev;
+		for (i = 0; i < MAX_MBR; i++)
+		  {
+		      tree_level->mbr_array[i].minx = DBL_MAX;
+		      tree_level->mbr_array[i].maxx = -DBL_MAX;
+		      tree_level->mbr_array[i].miny = DBL_MAX;
+		      tree_level->mbr_array[i].maxy = -DBL_MAX;
+		      tree_level->mbr_array[i].dist = DBL_MAX;
+		  }
+		tree_level->max_dist = -DBL_MAX;
+		tree_level->curr_items = 0;
+	    }
+	  ctx->curr_level = info->iLevel;
+      }
+
+    if (info->iLevel > ctx->curr_level)
+      {
+	  /* previous R*Tree level; testing */
+	  int lvl = info->mxLevel - info->iLevel - 1;
+	  VKnnTreePtr tree_level = ctx->tree + lvl;
+	  if (info->nCoord == 4)
+	    {
+		double rtree_minx = info->aCoord[0];
+		double rtree_maxx = info->aCoord[1];
+		double rtree_miny = info->aCoord[2];
+		double rtree_maxy = info->aCoord[3];
+		for (i = 0; i < tree_level->curr_items; i++)
+		  {
+		      VKnnRectPtr rect = &(tree_level->mbr_array[i]);
+		      if (rect->minx == rtree_minx && rect->miny == rtree_miny
+			  && rect->maxx == rtree_maxx
+			  && rect->maxy == rtree_maxy)
+			{
+			    info->eWithin = FULLY_WITHIN;
+			    return SQLITE_OK;
+			}
+		  }
+		info->eWithin = NOT_WITHIN;
+		return SQLITE_OK;
+	    }
+
+      }
+    if (info->iLevel < ctx->curr_level)
+      {
+	  /* next R*Tree level; giving up */
+	  info->eWithin = NOT_WITHIN;
+	  return SQLITE_OK;
+      }
+
+    if (info->nCoord == 4)
+      {
+	  double rtree_minx = info->aCoord[0];
+	  double rtree_maxx = info->aCoord[1];
+	  double rtree_miny = info->aCoord[2];
+	  double rtree_maxy = info->aCoord[3];
+	  info->eWithin =
+	      vknn_check_mbr (ctx, rtree_minx, rtree_miny, rtree_maxx,
+			      rtree_maxy);
+	  if (info->iRowid == 0)
+	    {
+		double dist =
+		    vknn_rect_distance (ctx, rtree_minx, rtree_miny, rtree_maxx,
+					rtree_maxy);
+		vknn_update_tree (ctx, info->mxLevel - info->iLevel - 1,
+				  rtree_minx, rtree_miny, rtree_maxx,
+				  rtree_maxy, dist);
+		info->eWithin = NOT_WITHIN;
+	    }
+	  else if (info->iLevel == 0 && info->iRowid > 0)
+	    {
+		double dist = vknn_compute_distance (ctx, info->iRowid);
+		vknn_update_items (ctx, info->iRowid, dist);
+		info->eWithin = NOT_WITHIN;
+	    }
+      }
+    else
+	info->eWithin = NOT_WITHIN;
+    return SQLITE_OK;
+}
+
+static int
+vknn_check_view_rtree (sqlite3 * sqlite, const char *table_name,
+		       const char *geom_column, char **real_table,
+		       char **real_geom, int *is_geographic)
+{
+/* checks if the required RTree is actually defined - SpatialView */
+    sqlite3_stmt *stmt;
+    char *sql_statement;
+    int ret;
+    int count = 0;
+    char *rt = NULL;
+    char *rg = NULL;
+    int is_longlat = 0;
+
+/* testing if views_geometry_columns exists */
+    sql_statement = sqlite3_mprintf ("SELECT tbl_name FROM sqlite_master "
+				     "WHERE type = 'table' AND tbl_name = 'views_geometry_columns'");
+    ret =
+	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	return 0;
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	      count++;
+      }
+    sqlite3_finalize (stmt);
+    if (count != 1)
+	return 0;
+    count = 0;
+
+/* attempting to find the RTree Geometry Column */
+    sql_statement =
+	sqlite3_mprintf
+	("SELECT a.f_table_name, a.f_geometry_column, SridIsGeographic(b.srid) "
+	 "FROM views_geometry_columns AS a " "JOIN geometry_columns AS b ON ("
+	 "Upper(a.f_table_name) = Upper(b.f_table_name) AND "
+	 "Upper(a.f_geometry_column) = Upper(b.f_geometry_column)) "
+	 "WHERE Upper(a.view_name) = Upper(%Q) "
+	 "AND Upper(a.view_geometry) = Upper(%Q) AND b.spatial_index_enabled = 1",
+	 table_name, geom_column);
+    ret =
+	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	return 0;
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const char *v = (const char *) sqlite3_column_text (stmt, 0);
+		int len = sqlite3_column_bytes (stmt, 0);
+		if (rt)
+		    free (rt);
+		rt = malloc (len + 1);
+		strcpy (rt, v);
+		v = (const char *) sqlite3_column_text (stmt, 1);
+		len = sqlite3_column_bytes (stmt, 1);
+		if (rg)
+		    free (rg);
+		rg = malloc (len + 1);
+		strcpy (rg, v);
+		is_longlat = sqlite3_column_int (stmt, 2);
+		count++;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    if (count != 1)
+	return 0;
+    if (!validateRowid (sqlite, rt))
+      {
+	  free (rt);
+	  free (rg);
+	  return 0;
+      }
+    *real_table = rt;
+    *real_geom = rg;
+    *is_geographic = is_longlat;
+    return 1;
+}
+
+static int
+vknn_check_rtree (sqlite3 * sqlite, const char *db_prefix,
+		  const char *table_name, const char *geom_column,
+		  char **real_table, char **real_geom, int *is_geographic)
+{
+/* checks if the required RTree is actually defined */
+    sqlite3_stmt *stmt;
+    char *sql_statement;
+    int ret;
+    int count = 0;
+    char *rt = NULL;
+    char *rg = NULL;
+    int is_longlat = 0;
+
+    if (db_prefix == NULL)
+      {
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT f_table_name, f_geometry_column, SridIsGeographic(srid) "
+	       "FROM geometry_columns WHERE Upper(f_table_name) = Upper(%Q) AND "
+	       "Upper(f_geometry_column) = Upper(%Q) AND spatial_index_enabled = 1",
+	       table_name, geom_column);
+      }
+    else
+      {
+	  char *quoted_db = gaiaDoubleQuotedSql (db_prefix);
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT f_table_name, f_geometry_column, SridIsGeographic(srid) "
+	       "FROM \"%s\".geometry_columns WHERE Upper(f_table_name) = Upper(%Q) AND "
+	       "Upper(f_geometry_column) = Upper(%Q) AND spatial_index_enabled = 1",
+	       quoted_db, table_name, geom_column);
+	  free (quoted_db);
+      }
+    ret =
+	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	return 0;
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const char *v = (const char *) sqlite3_column_text (stmt, 0);
+		int len = sqlite3_column_bytes (stmt, 0);
+		if (rt)
+		    free (rt);
+		rt = malloc (len + 1);
+		strcpy (rt, v);
+		v = (const char *) sqlite3_column_text (stmt, 1);
+		len = sqlite3_column_bytes (stmt, 1);
+		if (rg)
+		    free (rg);
+		rg = malloc (len + 1);
+		strcpy (rg, v);
+		is_longlat = sqlite3_column_int (stmt, 2);
+		count++;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    if (count != 1)
+	return vknn_check_view_rtree (sqlite, table_name, geom_column,
+				      real_table, real_geom, is_geographic);
+    else
+      {
+	  *real_table = rt;
+	  *real_geom = rg;
+	  *is_geographic = is_longlat;
+      }
+    return 1;
+}
+
+static int
+vknn_find_view_rtree (sqlite3 * sqlite, const char *db_prefix,
+		      const char *table_name, char **real_table,
+		      char **real_geom, int *is_geographic)
+{
+/* attempts to find the corresponding RTree Geometry Column - SpatialView */
+    sqlite3_stmt *stmt;
+    char *sql_statement;
+    int ret;
+    int count = 0;
+    char *rt = NULL;
+    char *rg = NULL;
+    int is_longlat = 0;
+
+/* testing if views_geometry_columns exists */
+    if (db_prefix == NULL)
+      {
+	  sql_statement = sqlite3_mprintf ("SELECT tbl_name FROM sqlite_master "
+					   "WHERE type = 'table' AND tbl_name = 'views_geometry_columns'");
+      }
+    else
+      {
+	  char *quoted_db = gaiaDoubleQuotedSql (db_prefix);
+	  sql_statement =
+	      sqlite3_mprintf ("SELECT tbl_name FROM \"%s\".sqlite_master "
+			       "WHERE type = 'table' AND tbl_name = 'views_geometry_columns'",
+			       quoted_db);
+	  free (quoted_db);
+      }
+    ret =
+	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	return 0;
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	      count++;
+      }
+    sqlite3_finalize (stmt);
+    if (count != 1)
+	return 0;
+    count = 0;
+
+/* attempting to find the RTree Geometry Column */
+    if (db_prefix == NULL)
+      {
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT a.f_table_name, a.f_geometry_column, SridIsGeographic(b.srid) "
+	       "FROM views_geometry_columns AS a "
+	       "JOIN geometry_columns AS b ON ("
+	       "Upper(a.f_table_name) = Upper(b.f_table_name) AND "
+	       "Upper(a.f_geometry_column) = Upper(b.f_geometry_column)) "
+	       "WHERE Upper(a.view_name) = Upper(%Q) AND b.spatial_index_enabled = 1",
+	       table_name);
+      }
+    else
+      {
+	  char *quoted_db = gaiaDoubleQuotedSql (db_prefix);
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT a.f_table_name, a.f_geometry_column, SridIsGeographic(b.srid) "
+	       "FROM \"%s\".views_geometry_columns AS a "
+	       "JOIN \"%s\".geometry_columns AS b ON ("
+	       "Upper(a.f_table_name) = Upper(b.f_table_name) AND "
+	       "Upper(a.f_geometry_column) = Upper(b.f_geometry_column)) "
+	       "WHERE Upper(a.view_name) = Upper(%Q) AND b.spatial_index_enabled = 1",
+	       quoted_db, quoted_db, table_name);
+	  free (quoted_db);
+      }
+    ret =
+	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	return 0;
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const char *v = (const char *) sqlite3_column_text (stmt, 0);
+		int len = sqlite3_column_bytes (stmt, 0);
+		if (rt)
+		    free (rt);
+		rt = malloc (len + 1);
+		strcpy (rt, v);
+		v = (const char *) sqlite3_column_text (stmt, 1);
+		len = sqlite3_column_bytes (stmt, 1);
+		if (rg)
+		    free (rg);
+		rg = malloc (len + 1);
+		strcpy (rg, v);
+		is_longlat = sqlite3_column_int (stmt, 2);
+		count++;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    if (count != 1)
+	return 0;
+    *real_table = rt;
+    *real_geom = rg;
+    *is_geographic = is_longlat;
+    return 1;
+}
+
+static int
+vknn_find_rtree (sqlite3 * sqlite, const char *db_prefix,
+		 const char *table_name, char **real_table, char **real_geom,
+		 int *is_geographic)
+{
+/* attempts to find the corresponding RTree Geometry Column */
+    sqlite3_stmt *stmt;
+    char *sql_statement;
+    int ret;
+    int count = 0;
+    char *rt = NULL;
+    char *rg = NULL;
+    int is_longlat = 0;
+
+    if (db_prefix == NULL)
+      {
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT f_table_name, f_geometry_column, SridIsGeographic(srid) "
+	       " FROM geometry_columns WHERE Upper(f_table_name) = Upper(%Q) "
+	       "AND spatial_index_enabled = 1", table_name);
+      }
+    else
+      {
+	  char *quoted_db = gaiaDoubleQuotedSql (db_prefix);
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT f_table_name, f_geometry_column, SridIsGeographic(srid) "
+	       " FROM \"%s\".geometry_columns WHERE Upper(f_table_name) = Upper(%Q) "
+	       "AND spatial_index_enabled = 1", quoted_db, table_name);
+	  free (quoted_db);
+      }
+    ret =
+	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	return 0;
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const char *v = (const char *) sqlite3_column_text (stmt, 0);
+		int len = sqlite3_column_bytes (stmt, 0);
+		if (rt)
+		    free (rt);
+		rt = malloc (len + 1);
+		strcpy (rt, v);
+		v = (const char *) sqlite3_column_text (stmt, 1);
+		len = sqlite3_column_bytes (stmt, 1);
+		if (rg)
+		    free (rg);
+		rg = malloc (len + 1);
+		strcpy (rg, v);
+		is_longlat = sqlite3_column_int (stmt, 2);
+		count++;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    if (count != 1)
+	return vknn_find_view_rtree (sqlite, db_prefix, table_name,
+				     real_table, real_geom, is_geographic);
+    else
+      {
+	  *real_table = rt;
+	  *real_geom = rg;
+	  *is_geographic = is_longlat;
+      }
+    return 1;
+}
+
+static void
+vknn_parse_table_name (const char *tn, char **db_prefix, char **table_name)
+{
+/* attempting to extract an eventual DB prefix */
+    int i;
+    int len = strlen (tn);
+    int i_dot = -1;
+    if (strncasecmp (tn, "DB=", 3) == 0)
+      {
+	  int l_db;
+	  int l_tbl;
+	  for (i = 3; i < len; i++)
+	    {
+		if (tn[i] == '.')
+		  {
+		      i_dot = i;
+		      break;
+		  }
+	    }
+	  if (i_dot > 1)
+	    {
+		l_db = i_dot - 3;
+		l_tbl = len - (i_dot + 1);
+		*db_prefix = malloc (l_db + 1);
+		memset (*db_prefix, '\0', l_db + 1);
+		memcpy (*db_prefix, tn + 3, l_db);
+		*table_name = malloc (l_tbl + 1);
+		strcpy (*table_name, tn + i_dot + 1);
+		return;
+	    }
+      }
+    *table_name = malloc (len + 1);
+    strcpy (*table_name, tn);
+}
+
+static int
+vknn_create (sqlite3 * db, void *pAux, int argc, const char *const *argv,
+	     sqlite3_vtab ** ppVTab, char **pzErr)
+{
+/* creates the virtual table for R*Tree KNN metahandling */
+    VirtualKnnPtr p_vt;
+    char *buf;
+    char *vtable;
+    char *xname;
+    if (pAux)
+	pAux = pAux;		/* unused arg warning suppression */
+    if (argc == 3)
+      {
+	  vtable = gaiaDequotedSql ((char *) argv[2]);
+      }
+    else
+      {
+	  *pzErr =
+	      sqlite3_mprintf
+	      ("[VirtualKNN module] CREATE VIRTUAL: illegal arg list {void}\n");
+	  return SQLITE_ERROR;
+      }
+    p_vt = (VirtualKnnPtr) sqlite3_malloc (sizeof (VirtualKnn));
+    if (!p_vt)
+	return SQLITE_NOMEM;
+    p_vt->db = db;
+    p_vt->pModule = &my_knn_module;
+    p_vt->nRef = 0;
+    p_vt->zErrMsg = NULL;
+    p_vt->knn_ctx = vknn_create_context ();
+/* preparing the COLUMNs for this VIRTUAL TABLE */
+    xname = gaiaDoubleQuotedSql (vtable);
+    buf = sqlite3_mprintf ("CREATE TABLE \"%s\" (f_table_name TEXT, "
+			   "f_geometry_column TEXT, ref_geometry BLOB, max_items INTEGER, "
+			   "pos INTEGER, fid INTEGER, distance DOUBLE)", xname);
+    free (xname);
+    free (vtable);
+    if (sqlite3_declare_vtab (db, buf) != SQLITE_OK)
+      {
+	  sqlite3_free (buf);
+	  *pzErr =
+	      sqlite3_mprintf
+	      ("[VirtualKNN module] CREATE VIRTUAL: invalid SQL statement \"%s\"",
+	       buf);
+	  return SQLITE_ERROR;
+      }
+    sqlite3_free (buf);
+    *ppVTab = (sqlite3_vtab *) p_vt;
+    return SQLITE_OK;
+}
+
+static int
+vknn_connect (sqlite3 * db, void *pAux, int argc, const char *const *argv,
+	      sqlite3_vtab ** ppVTab, char **pzErr)
+{
+/* connects the virtual table - simply aliases vknn_create() */
+    return vknn_create (db, pAux, argc, argv, ppVTab, pzErr);
+}
+
+static int
+vknn_best_index (sqlite3_vtab * pVTab, sqlite3_index_info * pIdxInfo)
+{
+/* best index selection */
+    int i;
+    int errors = 0;
+    int err = 1;
+    int table = 0;
+    int geom_col = 0;
+    int ref_geom = 0;
+    int max_items = 0;
+    if (pVTab)
+	pVTab = pVTab;		/* unused arg warning suppression */
+    for (i = 0; i < pIdxInfo->nConstraint; i++)
+      {
+	  /* verifying the constraints */
+	  struct sqlite3_index_constraint *p = &(pIdxInfo->aConstraint[i]);
+	  if (p->usable)
+	    {
+		if (p->iColumn == 0 && p->op == SQLITE_INDEX_CONSTRAINT_EQ)
+		    table++;
+		else if (p->iColumn == 1 && p->op == SQLITE_INDEX_CONSTRAINT_EQ)
+		    geom_col++;
+		else if (p->iColumn == 2 && p->op == SQLITE_INDEX_CONSTRAINT_EQ)
+		    ref_geom++;
+		else if (p->iColumn == 3 && p->op == SQLITE_INDEX_CONSTRAINT_EQ)
+		    max_items++;
+		else
+		    errors++;
+	    }
+      }
+    if (table == 1 && (geom_col == 0 || geom_col == 1) && ref_geom == 1
+	&& (max_items == 0 || max_items == 1) && errors == 0)
+      {
+	  /* this one is a valid KNN query */
+	  if (geom_col == 1)
+	    {
+		if (max_items == 1)
+		    pIdxInfo->idxNum = 3;
+		else
+		    pIdxInfo->idxNum = 1;
+	    }
+	  else
+	    {
+		if (max_items == 1)
+		    pIdxInfo->idxNum = 4;
+		else
+		    pIdxInfo->idxNum = 2;
+	    }
+	  pIdxInfo->estimatedCost = 1.0;
+	  for (i = 0; i < pIdxInfo->nConstraint; i++)
+	    {
+		if (pIdxInfo->aConstraint[i].usable)
+		  {
+		      pIdxInfo->aConstraintUsage[i].argvIndex = i + 1;
+		      pIdxInfo->aConstraintUsage[i].omit = 1;
+		  }
+	    }
+	  err = 0;
+      }
+    if (err)
+      {
+	  /* illegal query */
+	  pIdxInfo->idxNum = 0;
+      }
+    return SQLITE_OK;
+}
+
+static int
+vknn_disconnect (sqlite3_vtab * pVTab)
+{
+/* disconnects the virtual table */
+    VirtualKnnPtr p_vt = (VirtualKnnPtr) pVTab;
+    if (p_vt->knn_ctx != NULL)
+	vknn_free_context (p_vt->knn_ctx);
+    sqlite3_free (p_vt);
+    return SQLITE_OK;
+}
+
+static int
+vknn_destroy (sqlite3_vtab * pVTab)
+{
+/* destroys the virtual table - simply aliases vknn_disconnect() */
+    return vknn_disconnect (pVTab);
+}
+
+static int
+vknn_open (sqlite3_vtab * pVTab, sqlite3_vtab_cursor ** ppCursor)
+{
+/* opening a new cursor */
+    VirtualKnnCursorPtr cursor =
+	(VirtualKnnCursorPtr) sqlite3_malloc (sizeof (VirtualKnnCursor));
+    if (cursor == NULL)
+	return SQLITE_ERROR;
+    cursor->pVtab = (VirtualKnnPtr) pVTab;
+    cursor->eof = 1;
+    *ppCursor = (sqlite3_vtab_cursor *) cursor;
+    return SQLITE_OK;
+}
+
+static int
+vknn_close (sqlite3_vtab_cursor * pCursor)
+{
+/* closing the cursor */
+    sqlite3_free (pCursor);
+    return SQLITE_OK;
+}
+
+static int
+vknn_filter (sqlite3_vtab_cursor * pCursor, int idxNum, const char *idxStr,
+	     int argc, sqlite3_value ** argv)
+{
+/* setting up a cursor filter */
+    char *db_prefix = NULL;
+    char *table_name = NULL;
+    char *geom_column = NULL;
+    char *xtable = NULL;
+    char *xgeom = NULL;
+    char *xgeomQ;
+    char *xtableQ;
+    char *idx_name;
+    char *idx_nameQ;
+    char *sql_statement;
+    gaiaGeomCollPtr geom = NULL;
+    int ok_table = 0;
+    int ok_geom = 0;
+    int ok_max = 0;
+    int max_items = 3;
+    int is_geographic;
+    const unsigned char *blob;
+    int size;
+    int exists;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    sqlite3_stmt *stmt_dist = NULL;
+    sqlite3_stmt *stmt_rect = NULL;
+    VirtualKnnCursorPtr cursor = (VirtualKnnCursorPtr) pCursor;
+    VirtualKnnPtr knn = (VirtualKnnPtr) cursor->pVtab;
+    VKnnContextPtr vknn_context = knn->knn_ctx;
+    if (idxStr)
+	idxStr = idxStr;	/* unused arg warning suppression */
+    cursor->eof = 1;
+    if (idxStr)
+	idxStr = idxStr;	/* unused arg warning suppression */
+    cursor->eof = 1;
+    if (idxNum == 1 && argc == 3)
+      {
+	  /* retrieving the Table/Column/Geometry params */
+	  if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	    {
+		char *tn = (char *) sqlite3_value_text (argv[0]);
+		vknn_parse_table_name (tn, &db_prefix, &table_name);
+		ok_table = 1;
+	    }
+	  if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	    {
+		geom_column = (char *) sqlite3_value_text (argv[1]);
+		ok_geom = 1;
+	    }
+	  if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+	    {
+		blob = sqlite3_value_blob (argv[2]);
+		size = sqlite3_value_bytes (argv[2]);
+		geom = gaiaFromSpatiaLiteBlobWkb (blob, size);
+	    }
+	  if (ok_table && ok_geom && geom)
+	      ;
+	  else
+	    {
+		/* invalid args */
+		goto stop;
+	    }
+      }
+    if (idxNum == 2 && argc == 2)
+      {
+	  /* retrieving the Table/Geometry params */
+	  if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	    {
+		char *tn = (char *) sqlite3_value_text (argv[0]);
+		vknn_parse_table_name (tn, &db_prefix, &table_name);
+		ok_table = 1;
+	    }
+	  if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+	    {
+		blob = sqlite3_value_blob (argv[1]);
+		size = sqlite3_value_bytes (argv[1]);
+		geom = gaiaFromSpatiaLiteBlobWkb (blob, size);
+	    }
+	  if (ok_table && geom)
+	      ;
+	  else
+	    {
+		/* invalid args */
+		goto stop;
+	    }
+      }
+    if (idxNum == 3 && argc == 4)
+      {
+	  /* retrieving the Table/Column/Geometry/MaxItems params */
+	  if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	    {
+		char *tn = (char *) sqlite3_value_text (argv[0]);
+		vknn_parse_table_name (tn, &db_prefix, &table_name);
+		ok_table = 1;
+	    }
+	  if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	    {
+		geom_column = (char *) sqlite3_value_text (argv[1]);
+		ok_geom = 1;
+	    }
+	  if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+	    {
+		blob = sqlite3_value_blob (argv[2]);
+		size = sqlite3_value_bytes (argv[2]);
+		geom = gaiaFromSpatiaLiteBlobWkb (blob, size);
+	    }
+	  if (sqlite3_value_type (argv[3]) == SQLITE_INTEGER)
+	    {
+		max_items = sqlite3_value_int (argv[3]);
+		if (max_items > 1024)
+		    max_items = 1024;
+		if (max_items < 1)
+		    max_items = 1;
+		ok_max = 1;
+	    }
+	  if (ok_table && ok_geom && geom && ok_max)
+	      ;
+	  else
+	    {
+		/* invalid args */
+		goto stop;
+	    }
+      }
+    if (idxNum == 4 && argc == 3)
+      {
+	  /* retrieving the Table/Geometry/MaxItems params */
+	  if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	    {
+		char *tn = (char *) sqlite3_value_text (argv[0]);
+		vknn_parse_table_name (tn, &db_prefix, &table_name);
+		ok_table = 1;
+	    }
+	  if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+	    {
+		blob = sqlite3_value_blob (argv[1]);
+		size = sqlite3_value_bytes (argv[1]);
+		geom = gaiaFromSpatiaLiteBlobWkb (blob, size);
+	    }
+	  if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	    {
+		max_items = sqlite3_value_int (argv[2]);
+		if (max_items > 1024)
+		    max_items = 1024;
+		if (max_items < 1)
+		    max_items = 1;
+		ok_max = 1;
+	    }
+	  if (ok_table && geom && ok_max)
+	      ;
+	  else
+	    {
+		/* invalid args */
+		goto stop;
+	    }
+      }
+
+/* checking if the corresponding R*Tree exists */
+    if (ok_geom)
+	exists =
+	    vknn_check_rtree (knn->db, db_prefix, table_name, geom_column,
+			      &xtable, &xgeom, &is_geographic);
+    else
+	exists =
+	    vknn_find_rtree (knn->db, db_prefix, table_name, &xtable,
+			     &xgeom, &is_geographic);
+    if (!exists)
+	goto stop;
+
+/* building the Distance query */
+    xgeomQ = gaiaDoubleQuotedSql (xgeom);
+    xtableQ = gaiaDoubleQuotedSql (xtable);
+    if (is_geographic)
+	sql_statement =
+	    sqlite3_mprintf
+	    ("SELECT ST_Distance(?, \"%s\", 1) FROM \"%s\" WHERE rowid = ?",
+	     xgeomQ, xtableQ);
+    else
+	sql_statement =
+	    sqlite3_mprintf
+	    ("SELECT ST_Distance(?, \"%s\") FROM \"%s\" WHERE rowid = ?",
+	     xgeomQ, xtableQ);
+    free (xgeomQ);
+    free (xtableQ);
+    ret =
+	sqlite3_prepare_v2 (knn->db, sql_statement, strlen (sql_statement),
+			    &stmt_dist, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	goto stop;
+
+/* building the RTree MBR Distance query */
+    sql_statement = "SELECT ST_Distance(?, BuildMbr(?, ?, ?, ?))";
+    ret =
+	sqlite3_prepare_v2 (knn->db, sql_statement, strlen (sql_statement),
+			    &stmt_rect, NULL);
+    if (ret != SQLITE_OK)
+	goto stop;
+
+/* installing the R*Tree query callback */
+    gaiaMbrGeometry (geom);
+    vknn_init_context (vknn_context, xtable, xgeom, geom, max_items, stmt_dist,
+		       stmt_rect);
+    gaiaFreeGeomColl (geom);
+    geom = NULL;		/* releasing ownership on geom */
+    stmt_dist = NULL;		/* releasing ownership on stmt_dist */
+    stmt_rect = NULL;		/* releasing ownership on stmt_rect */
+    sqlite3_rtree_query_callback (knn->db, "knn_position", vknn_query_callback,
+				  vknn_context, NULL);
+
+/* building the RTree query */
+    idx_name = sqlite3_mprintf ("idx_%s_%s", xtable, xgeom);
+    idx_nameQ = gaiaDoubleQuotedSql (idx_name);
+    if (db_prefix == NULL)
+      {
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT pkid FROM \"%s\" WHERE pkid MATCH knn_position(1)",
+	       idx_nameQ);
+      }
+    else
+      {
+	  char *quoted_db = gaiaDoubleQuotedSql (db_prefix);
+	  sql_statement =
+	      sqlite3_mprintf
+	      ("SELECT pkid FROM \"%s\".\"%s\" WHERE pkid MATCH knn_position(1)",
+	       quoted_db, idx_nameQ);
+	  free (quoted_db);
+      }
+    free (idx_nameQ);
+    sqlite3_free (idx_name);
+    ret =
+	sqlite3_prepare_v2 (knn->db, sql_statement, strlen (sql_statement),
+			    &stmt, NULL);
+    sqlite3_free (sql_statement);
+    if (ret != SQLITE_OK)
+	goto stop;
+
+    vknn_context->curr_level = -1;
+    while (vknn_context->curr_level != 0)
+      {
+	  /* querying the R*Tree: step #1 tree MBRs */
+	  sqlite3_step (stmt);
+	  if (vknn_context->curr_level == -1)
+	      break;		/* found an empty R*Tree, preasumably */
+	  vknn_context->curr_level -= 1;
+      }
+    if (vknn_context->curr_level == 0)
+      {
+	  /* querying the R*Tree: step #2 features */
+	  sqlite3_step (stmt);
+      }
+
+    if (vknn_context->curr_items == 0)
+	cursor->eof = 1;
+    else
+	cursor->eof = 0;
+    cursor->CurrentIndex = 0;
+  stop:
+    if (geom)
+	gaiaFreeGeomColl (geom);
+    if (xtable)
+	free (xtable);
+    if (xgeom)
+	free (xgeom);
+    if (db_prefix)
+	free (db_prefix);
+    if (table_name)
+	free (table_name);
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    if (stmt_dist != NULL)
+	sqlite3_finalize (stmt_dist);
+    if (stmt_rect != NULL)
+	sqlite3_finalize (stmt_rect);
+    return SQLITE_OK;
+}
+
+static int
+vknn_next (sqlite3_vtab_cursor * pCursor)
+{
+/* fetching a next row from cursor */
+    VirtualKnnCursorPtr cursor = (VirtualKnnCursorPtr) pCursor;
+    VKnnContextPtr ctx = cursor->pVtab->knn_ctx;
+    cursor->CurrentIndex += 1;
+    if (cursor->CurrentIndex >= ctx->curr_items)
+	cursor->eof = 1;
+    return SQLITE_OK;
+}
+
+static int
+vknn_eof (sqlite3_vtab_cursor * pCursor)
+{
+/* cursor EOF */
+    VirtualKnnCursorPtr cursor = (VirtualKnnCursorPtr) pCursor;
+    return cursor->eof;
+}
+
+static int
+vknn_column (sqlite3_vtab_cursor * pCursor, sqlite3_context * pContext,
+	     int column)
+{
+/* fetching value for the Nth column */
+    VirtualKnnCursorPtr cursor = (VirtualKnnCursorPtr) pCursor;
+    VKnnContextPtr ctx = cursor->pVtab->knn_ctx;
+    VKnnItemPtr item = NULL;
+    if (cursor || column)
+	cursor = cursor;	/* unused arg warning suppression */
+    if (column)
+	column = column;	/* unused arg warning suppression */
+    if (cursor->CurrentIndex < ctx->curr_items)
+	item = ctx->knn_array + cursor->CurrentIndex;
+    if (column == 0)
+      {
+	  /* the Table Name column */
+	  sqlite3_result_text (pContext, ctx->table_name,
+			       strlen (ctx->table_name), SQLITE_STATIC);
+      }
+    else if (column == 1)
+      {
+	  /* the GeometryColumn Name column */
+	  sqlite3_result_text (pContext, ctx->column_name,
+			       strlen (ctx->column_name), SQLITE_STATIC);
+      }
+    else if (column == 2)
+      {
+	  /* the Reference Geometry column */
+	  sqlite3_result_blob (pContext, ctx->blob, ctx->blob_size,
+			       SQLITE_STATIC);
+      }
+    else if (column == 3)
+      {
+	  /* the Max Items column */
+	  sqlite3_result_int (pContext, ctx->max_items);
+      }
+    else if (column == 4)
+      {
+	  /* the index column */
+	  sqlite3_result_int (pContext, cursor->CurrentIndex + 1);
+      }
+    else if ((column == 5 || column == 6) && item != NULL)
+      {
+	  if (column == 5)
+	    {
+		/* the RowID column */
+		sqlite3_result_int64 (pContext, item->rowid);
+	    }
+	  else if (column == 6)
+	    {
+		/* the Distance column */
+		sqlite3_result_double (pContext, item->dist);
+	    }
+	  else
+	      sqlite3_result_null (pContext);
+      }
+    else
+	sqlite3_result_null (pContext);
+    return SQLITE_OK;
+}
+
+static int
+vknn_rowid (sqlite3_vtab_cursor * pCursor, sqlite_int64 * pRowid)
+{
+/* fetching the ROWID */
+    VirtualKnnCursorPtr cursor = (VirtualKnnCursorPtr) pCursor;
+    *pRowid = cursor->CurrentIndex;
+    return SQLITE_OK;
+}
+
+static int
+vknn_update (sqlite3_vtab * pVTab, int argc, sqlite3_value ** argv,
+	     sqlite_int64 * pRowid)
+{
+/* generic update [INSERT / UPDATE / DELETE */
+    if (pRowid || argc || argv || pVTab)
+	pRowid = pRowid;	/* unused arg warning suppression */
+/* read only datasource */
+    return SQLITE_READONLY;
+}
+
+static int
+vknn_begin (sqlite3_vtab * pVTab)
+{
+/* BEGIN TRANSACTION */
+    if (pVTab)
+	pVTab = pVTab;		/* unused arg warning suppression */
+    return SQLITE_OK;
+}
+
+static int
+vknn_sync (sqlite3_vtab * pVTab)
+{
+/* BEGIN TRANSACTION */
+    if (pVTab)
+	pVTab = pVTab;		/* unused arg warning suppression */
+    return SQLITE_OK;
+}
+
+static int
+vknn_commit (sqlite3_vtab * pVTab)
+{
+/* BEGIN TRANSACTION */
+    if (pVTab)
+	pVTab = pVTab;		/* unused arg warning suppression */
+    return SQLITE_OK;
+}
+
+static int
+vknn_rollback (sqlite3_vtab * pVTab)
+{
+/* BEGIN TRANSACTION */
+    if (pVTab)
+	pVTab = pVTab;		/* unused arg warning suppression */
+    return SQLITE_OK;
+}
+
+static int
+vknn_rename (sqlite3_vtab * pVTab, const char *zNew)
+{
+/* BEGIN TRANSACTION */
+    if (pVTab)
+	pVTab = pVTab;		/* unused arg warning suppression */
+    if (zNew)
+	zNew = zNew;		/* unused arg warning suppression */
+    return SQLITE_ERROR;
+}
+
+static int
+spliteKnnInit (sqlite3 * db)
+{
+    int rc = SQLITE_OK;
+    my_knn_module.iVersion = 1;
+    my_knn_module.xCreate = &vknn_create;
+    my_knn_module.xConnect = &vknn_connect;
+    my_knn_module.xBestIndex = &vknn_best_index;
+    my_knn_module.xDisconnect = &vknn_disconnect;
+    my_knn_module.xDestroy = &vknn_destroy;
+    my_knn_module.xOpen = &vknn_open;
+    my_knn_module.xClose = &vknn_close;
+    my_knn_module.xFilter = &vknn_filter;
+    my_knn_module.xNext = &vknn_next;
+    my_knn_module.xEof = &vknn_eof;
+    my_knn_module.xColumn = &vknn_column;
+    my_knn_module.xRowid = &vknn_rowid;
+    my_knn_module.xUpdate = &vknn_update;
+    my_knn_module.xBegin = &vknn_begin;
+    my_knn_module.xSync = &vknn_sync;
+    my_knn_module.xCommit = &vknn_commit;
+    my_knn_module.xRollback = &vknn_rollback;
+    my_knn_module.xFindFunction = NULL;
+    my_knn_module.xRename = &vknn_rename;
+    sqlite3_create_module_v2 (db, "VirtualKNN", &my_knn_module, NULL, 0);
+    return rc;
+}
+
+SPATIALITE_PRIVATE int
+virtual_knn_extension_init (void *xdb)
+{
+    sqlite3 *db = (sqlite3 *) xdb;
+    return spliteKnnInit (db);
+}
diff --git a/src/spatialite/virtualshape.c b/src/spatialite/virtualshape.c
index 706b405..842fdd0 100644
--- a/src/spatialite/virtualshape.c
+++ b/src/spatialite/virtualshape.c
@@ -635,9 +635,20 @@ vshp_read_row (VirtualShapeCursorPtr cursor)
 	  free (cursor->blobGeometry);
 	  cursor->blobGeometry = NULL;
       }
-    ret =
-	gaiaReadShpEntity_ex (cursor->pVtab->Shp, cursor->current_row,
-			      cursor->pVtab->Srid, cursor->pVtab->text_dates);
+    while (1)
+      {
+	  ret =
+	      gaiaReadShpEntity_ex (cursor->pVtab->Shp, cursor->current_row,
+				    cursor->pVtab->Srid,
+				    cursor->pVtab->text_dates);
+	  if (ret < 0)
+	    {
+		/* skkipping a DBF deleted Row */
+		cursor->current_row += 1;
+		continue;
+	    }
+	  break;
+      }
     if (!ret)
       {
 	  if (!(cursor->pVtab->Shp->LastError))	/* normal SHP EOF */
diff --git a/src/srsinit/epsg_inlined_prussian.c b/src/srsinit/epsg_inlined_prussian.c
index de0631b..a5c8334 100644
--- a/src/srsinit/epsg_inlined_prussian.c
+++ b/src/srsinit/epsg_inlined_prussian.c
@@ -738,11 +738,11 @@ initialize_epsg_prussian(int filter,struct epsg_defs **first, struct epsg_defs *
     add_srs_wkt(p,3,"SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,");
     add_srs_wkt(p,4,"AUTHORITY[\"EPSG\",\"7004\"]], AUTHORITY[\"EPSG\",\"6314\"]],");
     add_srs_wkt(p,5,"PRIMEM[\"ferro\",-17.66666666666667],UNIT[\"Degree\",0.017453292519943295,");
-    add_srs_wkt(p,6,"AUTHORITY[\"mj10777.de\",\"187998\"]],AUTHORITY[\"EPSG\",\"4314\"]]");
-/* mj10777: Not exsiting System, used for testing purposes. */
+    add_srs_wkt(p,6,"AUTHORITY[\"mj10777.de\",\"187998\"]],AUTHORITY[\"EPSG\",\"4314\"]]]");
+/* mj10777: Not existing System, used for testing purposes. */
     p = add_epsg_def(filter,first,last,187999,"mj10777.de",187999,"DHDN / Brandenburger Tor");
     add_proj4text(p,0,"+proj=cass +lat_0=52.41864827777778 +lon_0=13.62720366666667 ");
-    add_proj4text(p,1,"+x_0=16819.76033675660074 +y_0=-11046.08218553455117 +ellps=bessel +datum=potsdam +units=m +no_defs");
+    add_proj4text(p,1,"+x_0=16816.615499858 +y_0=-11047.322499366 +ellps=bessel +datum=potsdam +units=m +no_defs");
     add_srs_wkt(p,0,"PROJCS[\"DHDN / Soldner Brandenburger Tor\",");
     add_srs_wkt(p,1,"GEOGCS[\"DHDN\",");
     add_srs_wkt(p,2,"DATUM[\"Deutsches_Hauptdreiecksnetz\",SPHEROID[\"Bessel 1841\",");
@@ -754,7 +754,7 @@ initialize_epsg_prussian(int filter,struct epsg_defs **first, struct epsg_defs *
     add_srs_wkt(p,8,"PROJECTION[\"Cassini_Soldner\"],");
     add_srs_wkt(p,9,"PARAMETER[\"latitude_of_origin\",52.41864827777778],");
     add_srs_wkt(p,10,"PARAMETER[\"central_meridian\",13.62720366666667],");
-    add_srs_wkt(p,11,"PARAMETER[\"false_easting\",16819.76033675660074],PARAMETER[\"false_northing\",-11046.08218553455117],");
+    add_srs_wkt(p,11,"PARAMETER[\"false_easting\",16816.615499858],PARAMETER[\"false_northing\",-11047.322499366],");
     add_srs_wkt(p,12,"AUTHORITY[\"mj10777.de\",\"187999\"],AXIS[\"x\",NORTH],AXIS[\"y\",EAST]]");
     p = add_epsg_def (filter,first, last, 325833, "mj10777.de", 325833,"ETRS89 / UTM zone 33N (Brandenburg)");
     add_proj4text(p,0,"+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs");
diff --git a/src/srsinit/epsg_update/Makefile.am b/src/srsinit/epsg_update/Makefile.am
index d341910..b76ce3a 100644
--- a/src/srsinit/epsg_update/Makefile.am
+++ b/src/srsinit/epsg_update/Makefile.am
@@ -1,4 +1,4 @@
 
 EXTRA_DIST = README.txt README-obsolete.txt auto_epsg.c \
-	epsg_from_gdal.c auto_epsg_ext.c
+	epsg_from_gdal.c auto_epsg_ext.c check_srid_spatialite.sh
 
diff --git a/src/srsinit/epsg_update/Makefile.in b/src/srsinit/epsg_update/Makefile.in
index e0a1169..59c4b6a 100644
--- a/src/srsinit/epsg_update/Makefile.in
+++ b/src/srsinit/epsg_update/Makefile.in
@@ -252,7 +252,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 EXTRA_DIST = README.txt README-obsolete.txt auto_epsg.c \
-	epsg_from_gdal.c auto_epsg_ext.c
+	epsg_from_gdal.c auto_epsg_ext.c check_srid_spatialite.sh
 
 all: all-am
 
diff --git a/src/srsinit/epsg_update/README.txt b/src/srsinit/epsg_update/README.txt
index 792e043..80b191e 100644
--- a/src/srsinit/epsg_update/README.txt
+++ b/src/srsinit/epsg_update/README.txt
@@ -64,3 +64,16 @@ STEP #5: final setup
 - be sure to update as required the repository (ADD/DEL)
 - be sure to update as required Makefile.am
 - and finally commit into the repository
+
+
+
+STEP #6: pre-release final check
+--------
+- after building and installing the new libspatialite
+  incorporating the most recent SRSes defined by GDAL
+  always remember to run from the shell the test script:
+  ./check_srid_spatialite.sh
+
+- then carefully check for any possible error detected
+  by the above mentioned test script
+
diff --git a/src/srsinit/epsg_update/auto_epsg.c b/src/srsinit/epsg_update/auto_epsg.c
index ee736f0..604301c 100644
--- a/src/srsinit/epsg_update/auto_epsg.c
+++ b/src/srsinit/epsg_update/auto_epsg.c
@@ -1702,15 +1702,15 @@ do_prussian (FILE * out)
     fprintf (out,
 	     "    add_srs_wkt(p,5,\"PRIMEM[\\\"ferro\\\",-17.66666666666667],UNIT[\\\"Degree\\\",0.017453292519943295,\");\n");
     fprintf (out,
-	     "    add_srs_wkt(p,6,\"AUTHORITY[\\\"mj10777.de\\\",\\\"187998\\\"]],AUTHORITY[\\\"EPSG\\\",\\\"4314\\\"]]\");\n");
+	     "    add_srs_wkt(p,6,\"AUTHORITY[\\\"mj10777.de\\\",\\\"187998\\\"]],AUTHORITY[\\\"EPSG\\\",\\\"4314\\\"]]]\");\n");
     fprintf (out,
-	     "/* mj10777: Not exsiting System, used for testing purposes. */\n");
+	     "/* mj10777: Not existing System, used for testing purposes. */\n");
     fprintf (out,
 	     "    p = add_epsg_def(filter,first,last,187999,\"mj10777.de\",187999,\"DHDN / Brandenburger Tor\");\n");
     fprintf (out,
 	     "    add_proj4text(p,0,\"+proj=cass +lat_0=52.41864827777778 +lon_0=13.62720366666667 \");\n");
     fprintf (out,
-	     "    add_proj4text(p,1,\"+x_0=16819.76033675660074 +y_0=-11046.08218553455117 +ellps=bessel +datum=potsdam +units=m +no_defs\");\n");
+	     "    add_proj4text(p,1,\"+x_0=16816.615499858 +y_0=-11047.322499366 +ellps=bessel +datum=potsdam +units=m +no_defs\");\n");
     fprintf (out,
 	     "    add_srs_wkt(p,0,\"PROJCS[\\\"DHDN / Soldner Brandenburger Tor\\\",\");\n");
     fprintf (out, "    add_srs_wkt(p,1,\"GEOGCS[\\\"DHDN\\\",\");\n");
@@ -1733,7 +1733,7 @@ do_prussian (FILE * out)
     fprintf (out,
 	     "    add_srs_wkt(p,10,\"PARAMETER[\\\"central_meridian\\\",13.62720366666667],\");\n");
     fprintf (out,
-	     "    add_srs_wkt(p,11,\"PARAMETER[\\\"false_easting\\\",16819.76033675660074],PARAMETER[\\\"false_northing\\\",-11046.08218553455117],\");\n");
+	     "    add_srs_wkt(p,11,\"PARAMETER[\\\"false_easting\\\",16816.615499858],PARAMETER[\\\"false_northing\\\",-11047.322499366],\");\n");
     fprintf (out,
 	     "    add_srs_wkt(p,12,\"AUTHORITY[\\\"mj10777.de\\\",\\\"187999\\\"],AXIS[\\\"x\\\",NORTH],AXIS[\\\"y\\\",EAST]]\");\n");
     fprintf (out,
diff --git a/src/srsinit/epsg_update/auto_epsg_ext.c b/src/srsinit/epsg_update/auto_epsg_ext.c
index 4c57153..8d2a64d 100644
--- a/src/srsinit/epsg_update/auto_epsg_ext.c
+++ b/src/srsinit/epsg_update/auto_epsg_ext.c
@@ -1732,15 +1732,15 @@ do_prussian (FILE * out)
     fprintf (out,
 	     "    add_srs_wkt(p,5,\"PRIMEM[\\\"ferro\\\",-17.66666666666667],UNIT[\\\"Degree\\\",0.017453292519943295,\");\n");
     fprintf (out,
-	     "    add_srs_wkt(p,6,\"AUTHORITY[\\\"mj10777.de\\\",\\\"187998\\\"]],AUTHORITY[\\\"EPSG\\\",\\\"4314\\\"]]\");\n");
+	     "    add_srs_wkt(p,6,\"AUTHORITY[\\\"mj10777.de\\\",\\\"187998\\\"]],AUTHORITY[\\\"EPSG\\\",\\\"4314\\\"]]]\");\n");
     fprintf (out,
-	     "/* mj10777: Not exsiting System, used for testing purposes. */\n");
+	     "/* mj10777: Not existing System, used for testing purposes. */\n");
     fprintf (out,
 	     "    p = add_epsg_def(filter,first,last,187999,\"mj10777.de\",187999,\"DHDN / Brandenburger Tor\");\n");
     fprintf (out,
 	     "    add_proj4text(p,0,\"+proj=cass +lat_0=52.41864827777778 +lon_0=13.62720366666667 \");\n");
     fprintf (out,
-	     "    add_proj4text(p,1,\"+x_0=16819.76033675660074 +y_0=-11046.08218553455117 +ellps=bessel +datum=potsdam +units=m +no_defs\");\n");
+	     "    add_proj4text(p,1,\"+x_0=16816.615499858 +y_0=-11047.322499366 +ellps=bessel +datum=potsdam +units=m +no_defs\");\n");
     fprintf (out,
 	     "    add_srs_wkt(p,0,\"PROJCS[\\\"DHDN / Soldner Brandenburger Tor\\\",\");\n");
     fprintf (out, "    add_srs_wkt(p,1,\"GEOGCS[\\\"DHDN\\\",\");\n");
@@ -1763,7 +1763,7 @@ do_prussian (FILE * out)
     fprintf (out,
 	     "    add_srs_wkt(p,10,\"PARAMETER[\\\"central_meridian\\\",13.62720366666667],\");\n");
     fprintf (out,
-	     "    add_srs_wkt(p,11,\"PARAMETER[\\\"false_easting\\\",16819.76033675660074],PARAMETER[\\\"false_northing\\\",-11046.08218553455117],\");\n");
+	     "    add_srs_wkt(p,11,\"PARAMETER[\\\"false_easting\\\",16816.615499858],PARAMETER[\\\"false_northing\\\",-11047.322499366],\");\n");
     fprintf (out,
 	     "    add_srs_wkt(p,12,\"AUTHORITY[\\\"mj10777.de\\\",\\\"187999\\\"],AXIS[\\\"x\\\",NORTH],AXIS[\\\"y\\\",EAST]]\");\n");
     fprintf (out,
diff --git a/src/srsinit/epsg_update/check_srid_spatialite.sh b/src/srsinit/epsg_update/check_srid_spatialite.sh
new file mode 100755
index 0000000..6bb15d0
--- /dev/null
+++ b/src/srsinit/epsg_update/check_srid_spatialite.sh
@@ -0,0 +1,240 @@
+#"/bin/bash
+# ./check_srid_spatialite.sh
+#-------------------------------------------------------------------------------
+RED='\033[0;31m';
+BRED='\033[1;31m'         # Red
+BOLD='\033[1m'  # \x1B[31m
+CYAN='\033[0;36m';
+BCYAN='\033[1;36m'        # Cyan
+BROWN='\033[0;33m';
+BBROWN='\033[1;33m'        # Cyan
+GREEN='\033[0;32m';
+BGREEN='\033[1;32m'       # Green
+NC='\033[0m' # No Color
+# echo -e "\033[1mThis is bold text.\033[0m"
+#-------------------------------------------------------------------------------
+BENE="'${GREEN}Tutto bene!${NC}'";
+BENENO="'${BRED}No bene!${NC}'";
+HABE_FERTIG="${BOLD}Ich habe fertig.${NC}";
+BASE_NAME=`basename $0`;
+BASE_NAME_CUT=`basename $0 | cut -d '.' -f1`;
+MTI="${GREEN}-I->${NC}";
+MTW="${BROWN}-W->${NC}";
+MTE="${BRED}-E->${NC}";
+MESSAGE_TYPE=${MTI};
+FORCE_CREATE_DB=0;
+VALGRIND_USE=0;
+CMD_SPATIALITE=`which spatialite`;
+CMD_GDALSRSINFO=`which gdalsrsinfo`;
+CMD_SQLITE3=`which sqlite3`;
+CMD_VALGRIND=`which valgrind`;
+exit_rc=0;
+# export "SPATIALITE_SECURITY=relaxed"
+#-------------------------------------------------------------------------------
+# DateTime functions
+# - convert a date into a UNIX timestamp
+#  dt_unix_start=$(date2stamp "now");
+#  echo "convert a date into a UNIX timestamp [" $dt_unix_start "]";
+#-------------------------------------------------------------------------------
+date2stamp() 
+{
+ date --utc --date "$1" +%s
+}
+#-------------------------------------------------------------------------------
+# DateTime functions
+# calculate different in seconds from 2 timestamps
+#  dt_diff=$(daterun $dt_unix_start $dt_unix_end);
+# echo "difference [" $dt_diff "]";
+#-------------------------------------------------------------------------------
+daterun() 
+{
+ let diffSec=${2}-${1};
+ echo $diffSec;
+}
+#-------------------------------------------------------------------------------
+# DateTime functions
+# from from seconds from 2 timestamps
+# dt_diff=$(daterun $1 $2);
+# echo $(displaytime $dt_diff);
+#-------------------------------------------------------------------------------
+function displaytime 
+{
+ local T=$1;
+ local D=$((T/60/60/24));
+ local H=$((T/60/60%24));
+ local M=$((T/60%60));
+ local S=$((T%60));
+ RESULT="";
+ if [ $D -gt 0 ] 
+ then
+  RESULT="${RESULT}$D days ";
+ fi
+ if [ $H -gt 0 ] || [ ! -z "${RESULT}" ]
+ then
+  RESULT="${RESULT}$H hrs ";
+ fi
+ if [ $M -gt 0 ] || [ ! -z "${RESULT}" ]
+ then
+  RESULT="${RESULT}$M min ";
+ fi
+ RESULT="${RESULT}$S sec";
+ echo ${RESULT};
+}
+#-------------------------------------------------------------------------------
+# DateTime functions
+# calculate different in seconds from 2 timestamps
+# echo "run_time [" $(run_time $dt_diff) "]"
+#-------------------------------------------------------------------------------
+run_time() 
+{
+ dt_diff=$(daterun $1 $2);
+ echo $(displaytime "$dt_diff");
+}
+#-------------------------------------------------------------------------------
+# Start of script
+#-------------------------------------------------------------------------------
+dt_unix_start=$(date2stamp "now");
+#-------------------------------------------------------------------------------
+# Adapt db/sql diretory path where needed
+#-------------------------------------------------------------------------------
+DIR_ERROR_SRID="srid_error";
+DB_FILE="check_srid.db";
+CSV_FILE="check_srid.csv";
+SQL_CHECK="SELECT srid||'#'||srtext||'\n' FROM spatial_ref_sys WHERE srtext <> 'Undefined';";
+SQL_FILE="check_srid.sql";
+#-------------------------------------------------------------------------------
+if [ -f "${DB_FILE}" ]
+then
+ rm ${DB_FILE};
+fi
+if [ -f "${CSV_FILE}" ]
+then
+ rm ${CSV_FILE};
+fi
+if [  -f "${SQL_FILE}" ]
+then
+ rm ${SQL_FILE};
+fi
+#-------------------------------------------------------------------------------
+exit_rc=100;
+if [ ! -f "${DB_DB_FILE}" ]
+then
+ if [ ! -f "${SQL_FILE}" ]
+ then
+  echo ${SQL_CHECK} > ${SQL_FILE};
+ fi
+ echo -e "${MTI} Database will be created[${DB_PATH}] and a dump of spatial_ref_sys made [${CSV_FILE}].";
+ RESULT_TEST=`${CMD_SPATIALITE} ${DB_PATH} < ${SQL_FILE}`;
+ if [ ! -z "${RESULT_TEST}" ]
+ then
+  echo -e ${RESULT_TEST} > ${CSV_FILE};
+ else
+  echo -e "${MTE} db-creation failed rc[${DB_PATH}]";
+ fi
+ if [ -f "${CSV_FILE}" ]
+ then
+  exit_rc=0;
+ fi
+fi
+#-------------------------------------------------------------------------------
+count_line=0;
+count_srid=0;
+count_srid_error=0;
+count_srid_ok=0;
+declare -a ARRAY_SRID=( );
+declare -a ARRAY_SRTEXT=( );
+OUTPUT_FILE_SRID="srid_check.txt";
+if [ "$exit_rc" -eq "0" ]
+then
+ while read line
+ do
+  # line=${CONFIG_FILE_READ_ARRAY[$Config_File_Line_Nr]}
+  ((count_line++));
+  IFS_SAVE=$IFS;
+  IFS='#'
+  INPUT_STR_ARRAY=( ${line} );
+  IFS=$IFS_SAVE;
+  SRID_TEXT="${INPUT_STR_ARRAY[0]}";
+  SRTEXT_TEXT="${INPUT_STR_ARRAY[1]}";
+  if [ ! -z "${SRID_TEXT}" ] && [ ! -z "${SRTEXT_TEXT}" ] 
+  then
+   ((count_srid++));
+   echo -e ${SRTEXT_TEXT} > ${OUTPUT_FILE_SRID};
+   if [ -f "${OUTPUT_FILE_SRID}" ]
+   then
+    RESULT_TEST=`${CMD_GDALSRSINFO} ${OUTPUT_FILE_SRID} 2>&1`;
+    exit_rc=$?
+    # echo "-I-> result_text[${RESULT_TEST}]";
+    if [ ! -z "${RESULT_TEST}" ]
+    then
+     srid_rc=0;
+     case ${RESULT_TEST} in ERROR*)
+      srid_rc=1;
+     esac
+     if [ "$srid_rc" -eq "0" ]
+     then
+      echo -e "${MTI} gdalsrsinfo for srid[${SRID_TEXT}] rc[${srid_rc}] ";
+      ((count_srid_ok++));
+     else
+      ((count_srid_error++));
+      if [ ! -d "$DIR_ERROR_SRID" ]
+      then
+       echo -e "${MTW} creating srid-error directory[${DIR_ERROR_SRID}]";
+       mkdir $DIR_ERROR_SRID
+      fi
+      OUTPUT_FILE_SRID_ERROR="${DIR_ERROR_SRID}/srid_${SRID_TEXT}.txt";
+      echo -e ${SRTEXT_TEXT} > ${OUTPUT_FILE_SRID_ERROR};
+      echo -e "${MTE} srid[${SRID_TEXT}] srtext['${SRTEXT_TEXT}'] ";
+     fi
+    fi
+   fi
+  fi
+  #------------------------------------------------------------------------------
+  line_prev=$line;
+  #------------------------------------------------------------------------------
+ done < "${CSV_FILE}";
+ #------------------------------------------------------------------------------
+fi
+#-------------------------------------------------------------------------------
+echo -e "${MTI} removing work files (database, sql, csv and srid-output)";
+if [  -f "${DB_DB_FILE}" ]
+then
+ rm ${DB_DB_FILE}M
+fi
+if [ -f "${SQL_FILE}" ]
+then
+ rm ${SQL_FILE};
+fi
+if [ -f "${CSV_FILE}" ]
+then
+ rm ${CSV_FILE};
+fi
+if [ -f "${OUTPUT_FILE_SRID}" ]
+then
+ rm ${OUTPUT_FILE_SRID};
+fi
+#-------------------------------------------------------------------------------
+if [ "$count_srid_error" -eq "0" ]
+then
+ exit_rc=0;
+ echo -e "${MTI} gdalsrsinfo checked ${count_srid} srids. correct[${count_srid_ok}] errors[${count_srid_error}] ";
+else
+ exit_rc=10;
+ echo -e "${MTE} gdalsrsinfo checked ${count_srid} srids. correct[${count_srid_ok}] errors[${count_srid_error}] ";
+fi
+#-------------------------------------------------------------------------------
+dt_unix_end=$(date2stamp "now");
+dt_run=$(run_time $dt_unix_start $dt_unix_end)
+if [ "$exit_rc" -eq "0" ]
+then
+ RC_TEXT=$BENE;
+ TIME_RUN="time_run[${GREEN}$dt_run${NC}]"
+else
+ TIME_RUN="time_run[${BRED}$dt_run${NC}]"
+ RC_TEXT="$BENENO";
+ MESSAGE_TYPE=${MTE};
+fi
+echo -e "${MESSAGE_TYPE} ${BASE_NAME_CUT} rc=$exit_rc - ${TIME_RUN} - [${RC_TEXT}] - ${HABE_FERTIG}";
+exit $exit_rc;
+#-------------------------------------------------------------------------------
+
diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am
new file mode 100644
index 0000000..2544352
--- /dev/null
+++ b/src/topology/Makefile.am
@@ -0,0 +1,37 @@
+
+AM_CPPFLAGS = @CFLAGS@
+AM_CPPFLAGS += -I$(top_srcdir)/src/headers -I.
+
+noinst_HEADERS = topology_private.h \
+	network_private.h \
+	lwn_network.h \
+	lwn_network_private.h
+noinst_LTLIBRARIES = libtopology.la topology.la
+
+libtopology_la_SOURCES = gaia_topology.c \
+	gaia_auxtopo.c \
+	gaia_topostmts.c \
+	topo_callbacks.c \
+	lwn_network.c \
+	gaia_network.c \
+	gaia_auxnet.c \
+	gaia_netstmts.c \
+	net_callbacks.c
+
+topology_la_SOURCES = gaia_topology.c \
+	gaia_auxtopo.c \
+	gaia_topostmts.c \
+	topo_callbacks.c \
+	lwn_network.c \
+	gaia_network.c \
+	gaia_auxnet.c \
+	gaia_netstmts.c \
+	net_callbacks.c
+
+topology_la_CPPFLAGS = @CFLAGS@
+topology_la_CPPFLAGS += -I$(top_srcdir)/src/headers -I.
+topology_la_CPPFLAGS += -DLOADABLE_EXTENSION
+topology_la_LDFLAGS = -module
+topology_la_LIBTOOLFLAGS = --tag=disable-static
+
+MOSTLYCLEANFILES = *.gcna *.gcno *.gcda
diff --git a/examples/Makefile.in b/src/topology/Makefile.in
similarity index 53%
copy from examples/Makefile.in
copy to src/topology/Makefile.in
index 7255a75..7a4c22c 100644
--- a/examples/Makefile.in
+++ b/src/topology/Makefile.in
@@ -14,6 +14,7 @@
 
 @SET_MAKE@
 
+
 VPATH = @srcdir@
 am__is_gnu_make = { \
   if test -z '$(MAKELEVEL)'; then \
@@ -88,9 +89,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = demo1$(EXEEXT) demo2$(EXEEXT) demo3$(EXEEXT) \
-	demo4$(EXEEXT) demo5$(EXEEXT)
-subdir = examples
+subdir = src/topology
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -98,36 +97,34 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+	$(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-PROGRAMS = $(noinst_PROGRAMS)
-demo1_SOURCES = demo1.c
-demo1_OBJECTS = demo1.$(OBJEXT)
-demo1_LDADD = $(LDADD)
-demo1_DEPENDENCIES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtopology_la_LIBADD =
+am_libtopology_la_OBJECTS = gaia_topology.lo gaia_auxtopo.lo \
+	gaia_topostmts.lo topo_callbacks.lo lwn_network.lo \
+	gaia_network.lo gaia_auxnet.lo gaia_netstmts.lo \
+	net_callbacks.lo
+libtopology_la_OBJECTS = $(am_libtopology_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-demo2_SOURCES = demo2.c
-demo2_OBJECTS = demo2.$(OBJEXT)
-demo2_LDADD = $(LDADD)
-demo2_DEPENDENCIES =
-demo3_SOURCES = demo3.c
-demo3_OBJECTS = demo3.$(OBJEXT)
-demo3_LDADD = $(LDADD)
-demo3_DEPENDENCIES =
-demo4_SOURCES = demo4.c
-demo4_OBJECTS = demo4.$(OBJEXT)
-demo4_LDADD = $(LDADD)
-demo4_DEPENDENCIES =
-demo5_SOURCES = demo5.c
-demo5_OBJECTS = demo5.$(OBJEXT)
-demo5_LDADD = $(LDADD)
-demo5_DEPENDENCIES =
+topology_la_LIBADD =
+am_topology_la_OBJECTS = topology_la-gaia_topology.lo \
+	topology_la-gaia_auxtopo.lo topology_la-gaia_topostmts.lo \
+	topology_la-topo_callbacks.lo topology_la-lwn_network.lo \
+	topology_la-gaia_network.lo topology_la-gaia_auxnet.lo \
+	topology_la-gaia_netstmts.lo topology_la-net_callbacks.lo
+topology_la_OBJECTS = $(am_topology_la_OBJECTS)
+topology_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+	$(CCLD) $(AM_CFLAGS) $(CFLAGS) $(topology_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -162,13 +159,14 @@ AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = demo1.c demo2.c demo3.c demo4.c demo5.c
-DIST_SOURCES = demo1.c demo2.c demo3.c demo4.c demo5.c
+SOURCES = $(libtopology_la_SOURCES) $(topology_la_SOURCES)
+DIST_SOURCES = $(libtopology_la_SOURCES) $(topology_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
+HEADERS = $(noinst_HEADERS)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
 # Read a list of newline-separated strings from the standard input,
 # and print each of them once, without duplicates.  Input order is
@@ -319,11 +317,38 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-AM_CFLAGS = -I at srcdir@/../src/headers 
-AM_LDFLAGS = -L../src -lspatialite -lm $(GCOV_FLAGS)
-LDADD = @LIBXML2_LIBS@
+AM_CPPFLAGS = @CFLAGS@ -I$(top_srcdir)/src/headers -I.
+noinst_HEADERS = topology_private.h \
+	network_private.h \
+	lwn_network.h \
+	lwn_network_private.h
+
+noinst_LTLIBRARIES = libtopology.la topology.la
+libtopology_la_SOURCES = gaia_topology.c \
+	gaia_auxtopo.c \
+	gaia_topostmts.c \
+	topo_callbacks.c \
+	lwn_network.c \
+	gaia_network.c \
+	gaia_auxnet.c \
+	gaia_netstmts.c \
+	net_callbacks.c
+
+topology_la_SOURCES = gaia_topology.c \
+	gaia_auxtopo.c \
+	gaia_topostmts.c \
+	topo_callbacks.c \
+	lwn_network.c \
+	gaia_network.c \
+	gaia_auxnet.c \
+	gaia_netstmts.c \
+	net_callbacks.c
+
+topology_la_CPPFLAGS = @CFLAGS@ -I$(top_srcdir)/src/headers -I. \
+	-DLOADABLE_EXTENSION
+topology_la_LDFLAGS = -module
+topology_la_LIBTOOLFLAGS = --tag=disable-static
 MOSTLYCLEANFILES = *.gcna *.gcno *.gcda
-EXTRA_DIST = examples.doxy
 all: all-am
 
 .SUFFIXES:
@@ -337,9 +362,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/topology/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign examples/Makefile
+	  $(AUTOMAKE) --foreign src/topology/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -358,34 +383,22 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
 
-clean-noinstPROGRAMS:
-	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
-	echo " rm -f" $$list; \
-	rm -f $$list || exit $$?; \
-	test -n "$(EXEEXT)" || exit 0; \
-	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
-	echo " rm -f" $$list; \
-	rm -f $$list
-
-demo1$(EXEEXT): $(demo1_OBJECTS) $(demo1_DEPENDENCIES) $(EXTRA_demo1_DEPENDENCIES) 
-	@rm -f demo1$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo1_OBJECTS) $(demo1_LDADD) $(LIBS)
-
-demo2$(EXEEXT): $(demo2_OBJECTS) $(demo2_DEPENDENCIES) $(EXTRA_demo2_DEPENDENCIES) 
-	@rm -f demo2$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo2_OBJECTS) $(demo2_LDADD) $(LIBS)
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
 
-demo3$(EXEEXT): $(demo3_OBJECTS) $(demo3_DEPENDENCIES) $(EXTRA_demo3_DEPENDENCIES) 
-	@rm -f demo3$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo3_OBJECTS) $(demo3_LDADD) $(LIBS)
+libtopology.la: $(libtopology_la_OBJECTS) $(libtopology_la_DEPENDENCIES) $(EXTRA_libtopology_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libtopology_la_OBJECTS) $(libtopology_la_LIBADD) $(LIBS)
 
-demo4$(EXEEXT): $(demo4_OBJECTS) $(demo4_DEPENDENCIES) $(EXTRA_demo4_DEPENDENCIES) 
-	@rm -f demo4$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo4_OBJECTS) $(demo4_LDADD) $(LIBS)
-
-demo5$(EXEEXT): $(demo5_OBJECTS) $(demo5_DEPENDENCIES) $(EXTRA_demo5_DEPENDENCIES) 
-	@rm -f demo5$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(demo5_OBJECTS) $(demo5_LDADD) $(LIBS)
+topology.la: $(topology_la_OBJECTS) $(topology_la_DEPENDENCIES) $(EXTRA_topology_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(topology_la_LINK)  $(topology_la_OBJECTS) $(topology_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -393,11 +406,24 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo1.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo2.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo3.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo4.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/demo5.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_auxnet.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_auxtopo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_netstmts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_network.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_topology.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gaia_topostmts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/lwn_network.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/net_callbacks.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topo_callbacks.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-gaia_auxnet.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-gaia_auxtopo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-gaia_netstmts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-gaia_network.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-gaia_topology.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-gaia_topostmts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-lwn_network.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-net_callbacks.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/topology_la-topo_callbacks.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -420,6 +446,69 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+topology_la-gaia_topology.lo: gaia_topology.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-gaia_topology.lo -MD -MP -MF $(DEPDIR)/topology_la-gaia_topology.Tpo -c -o topology_la-gaia_topology.lo `test -f 'gaia_topology.c' || echo '$(srcdir)/'`gaia_topology.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-gaia_topology.Tpo $(DEPDIR)/topology_la-gaia_topology.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_topology.c' object='topology_la-gaia_topology.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-gaia_topology.lo `test -f 'gaia_topology.c' || echo '$(srcdir)/'`gaia_topology.c
+
+topology_la-gaia_auxtopo.lo: gaia_auxtopo.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-gaia_auxtopo.lo -MD -MP -MF $(DEPDIR)/topology_la-gaia_auxtopo.Tpo -c -o topology_la-gaia_auxtopo.lo `test -f 'gaia_auxtopo.c' || echo '$(srcdir)/'`gaia_auxtopo.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-gaia_auxtopo.Tpo $(DEPDIR)/topology_la-gaia_auxtopo.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_auxtopo.c' object='topology_la-gaia_auxtopo.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-gaia_auxtopo.lo `test -f 'gaia_auxtopo.c' || echo '$(srcdir)/'`gaia_auxtopo.c
+
+topology_la-gaia_topostmts.lo: gaia_topostmts.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-gaia_topostmts.lo -MD -MP -MF $(DEPDIR)/topology_la-gaia_topostmts.Tpo -c -o topology_la-gaia_topostmts.lo `test -f 'gaia_topostmts.c' || echo '$(srcdir)/'`gaia_topostmts.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-gaia_topostmts.Tpo $(DEPDIR)/topology_la-gaia_topostmts.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_topostmts.c' object='topology_la-gaia_topostmts.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-gaia_topostmts.lo `test -f 'gaia_topostmts.c' || echo '$(srcdir)/'`gaia_topostmts.c
+
+topology_la-topo_callbacks.lo: topo_callbacks.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-topo_callbacks.lo -MD -MP -MF $(DEPDIR)/topology_la-topo_callbacks.Tpo -c -o topology_la-topo_callbacks.lo `test -f 'topo_callbacks.c' || echo '$(srcdir)/'`topo_callbacks.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-topo_callbacks.Tpo $(DEPDIR)/topology_la-topo_callbacks.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='topo_callbacks.c' object='topology_la-topo_callbacks.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-topo_callbacks.lo `test -f 'topo_callbacks.c' || echo '$(srcdir)/'`topo_callbacks.c
+
+topology_la-lwn_network.lo: lwn_network.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-lwn_network.lo -MD -MP -MF $(DEPDIR)/topology_la-lwn_network.Tpo -c -o topology_la-lwn_network.lo `test -f 'lwn_network.c' || echo '$(srcdir)/'`lwn_network.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-lwn_network.Tpo $(DEPDIR)/topology_la-lwn_network.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lwn_network.c' object='topology_la-lwn_network.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-lwn_network.lo `test -f 'lwn_network.c' || echo '$(srcdir)/'`lwn_network.c
+
+topology_la-gaia_network.lo: gaia_network.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-gaia_network.lo -MD -MP -MF $(DEPDIR)/topology_la-gaia_network.Tpo -c -o topology_la-gaia_network.lo `test -f 'gaia_network.c' || echo '$(srcdir)/'`gaia_network.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-gaia_network.Tpo $(DEPDIR)/topology_la-gaia_network.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_network.c' object='topology_la-gaia_network.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-gaia_network.lo `test -f 'gaia_network.c' || echo '$(srcdir)/'`gaia_network.c
+
+topology_la-gaia_auxnet.lo: gaia_auxnet.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-gaia_auxnet.lo -MD -MP -MF $(DEPDIR)/topology_la-gaia_auxnet.Tpo -c -o topology_la-gaia_auxnet.lo `test -f 'gaia_auxnet.c' || echo '$(srcdir)/'`gaia_auxnet.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-gaia_auxnet.Tpo $(DEPDIR)/topology_la-gaia_auxnet.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_auxnet.c' object='topology_la-gaia_auxnet.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-gaia_auxnet.lo `test -f 'gaia_auxnet.c' || echo '$(srcdir)/'`gaia_auxnet.c
+
+topology_la-gaia_netstmts.lo: gaia_netstmts.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-gaia_netstmts.lo -MD -MP -MF $(DEPDIR)/topology_la-gaia_netstmts.Tpo -c -o topology_la-gaia_netstmts.lo `test -f 'gaia_netstmts.c' || echo '$(srcdir)/'`gaia_netstmts.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-gaia_netstmts.Tpo $(DEPDIR)/topology_la-gaia_netstmts.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gaia_netstmts.c' object='topology_la-gaia_netstmts.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-gaia_netstmts.lo `test -f 'gaia_netstmts.c' || echo '$(srcdir)/'`gaia_netstmts.c
+
+topology_la-net_callbacks.lo: net_callbacks.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT topology_la-net_callbacks.lo -MD -MP -MF $(DEPDIR)/topology_la-net_callbacks.Tpo -c -o topology_la-net_callbacks.lo `test -f 'net_callbacks.c' || echo '$(srcdir)/'`net_callbacks.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/topology_la-net_callbacks.Tpo $(DEPDIR)/topology_la-net_callbacks.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='net_callbacks.c' object='topology_la-net_callbacks.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(topology_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(topology_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o topology_la-net_callbacks.lo `test -f 'net_callbacks.c' || echo '$(srcdir)/'`net_callbacks.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -510,7 +599,7 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile $(PROGRAMS)
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
 installdirs:
 install: install-am
 install-exec: install-exec-am
@@ -545,7 +634,7 @@ maintainer-clean-generic:
 	@echo "it deletes files that may require special tools to rebuild."
 clean: clean-am
 
-clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
 	mostlyclean-am
 
 distclean: distclean-am
@@ -617,7 +706,7 @@ uninstall-am:
 .MAKE: install-am install-strip
 
 .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-	clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
 	ctags-am distclean distclean-compile distclean-generic \
 	distclean-libtool distclean-tags distdir dvi dvi-am html \
 	html-am info info-am install install-am install-data \
diff --git a/src/topology/gaia_auxnet.c b/src/topology/gaia_auxnet.c
new file mode 100644
index 0000000..255bf2e
--- /dev/null
+++ b/src/topology/gaia_auxnet.c
@@ -0,0 +1,3833 @@
+/*
+
+ gaia_auxnet.c -- implementation of the Topology-Network module methods
+    
+ version 4.3, 2015 August 12
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaia_network.h>
+#include <spatialite/gaia_topology.h>
+#include <spatialite/gaiaaux.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+
+#include <liblwgeom.h>
+#include <liblwgeom_topo.h>
+
+#include <lwn_network.h>
+
+#include "network_private.h"
+#include "topology_private.h"
+
+#define GAIA_UNUSED() if (argc || argv) argc = argc;
+
+SPATIALITE_PRIVATE void
+free_internal_cache_networks (void *firstNetwork)
+{
+/* destroying all Networks registered into the Internal Connection Cache */
+    struct gaia_network *p_net = (struct gaia_network *) firstNetwork;
+    struct gaia_network *p_net_n;
+
+    while (p_net != NULL)
+      {
+	  p_net_n = p_net->next;
+	  gaiaNetworkDestroy ((GaiaNetworkAccessorPtr) p_net);
+	  p_net = p_net_n;
+      }
+}
+
+static int
+do_create_networks (sqlite3 * handle)
+{
+/* attempting to create the Networks table (if not already existing) */
+    const char *sql;
+    char *err_msg = NULL;
+    int ret;
+
+    sql = "CREATE TABLE IF NOT EXISTS networks (\n"
+	"\tnetwork_name TEXT NOT NULL PRIMARY KEY,\n"
+	"\tspatial INTEGER NOT NULL,\n"
+	"\tsrid INTEGER NOT NULL,\n"
+	"\thas_z INTEGER NOT NULL,\n"
+	"\tallow_coincident INTEGER NOT NULL,\n"
+	"\tnext_node_id INTEGER NOT NULL DEFAULT 1,\n"
+	"\tnext_link_id INTEGER NOT NULL DEFAULT 1,\n"
+	"\tCONSTRAINT net_srid_fk FOREIGN KEY (srid) "
+	"REFERENCES spatial_ref_sys (srid))";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE networks - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating Networks triggers */
+    sql = "CREATE TRIGGER IF NOT EXISTS network_name_insert\n"
+	"BEFORE INSERT ON 'networks'\nFOR EACH ROW BEGIN\n"
+	"SELECT RAISE(ABORT,'insert on networks violates constraint: "
+	"network_name value must not contain a single quote')\n"
+	"WHERE NEW.network_name LIKE ('%''%');\n"
+	"SELECT RAISE(ABORT,'insert on networks violates constraint: "
+	"network_name value must not contain a double quote')\n"
+	"WHERE NEW.network_name LIKE ('%\"%');\n"
+	"SELECT RAISE(ABORT,'insert on networks violates constraint: "
+	"network_name value must be lower case')\n"
+	"WHERE NEW.network_name <> lower(NEW.network_name);\nEND";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SQL error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+    sql = "CREATE TRIGGER IF NOT EXISTS network_name_update\n"
+	"BEFORE UPDATE OF 'network_name' ON 'networks'\nFOR EACH ROW BEGIN\n"
+	"SELECT RAISE(ABORT,'update on networks violates constraint: "
+	"network_name value must not contain a single quote')\n"
+	"WHERE NEW.network_name LIKE ('%''%');\n"
+	"SELECT RAISE(ABORT,'update on networks violates constraint: "
+	"network_name value must not contain a double quote')\n"
+	"WHERE NEW.network_name LIKE ('%\"%');\n"
+	"SELECT RAISE(ABORT,'update on networks violates constraint: "
+	"network_name value must be lower case')\n"
+	"WHERE NEW.network_name <> lower(NEW.network_name);\nEND";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SQL error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+check_new_network (sqlite3 * handle, const char *network_name)
+{
+/* testing if some already defined DB object forbids creating the new Network */
+    char *sql;
+    char *prev;
+    char *table;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *value;
+    int error = 0;
+
+/* testing if the same Network is already defined */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.networks WHERE "
+			   "Lower(network_name) = Lower(%Q)", network_name);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if some table/geom is already defined in geometry_columns */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.geometry_columns WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", network_name);
+    sql =
+	sqlite3_mprintf
+	("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_link", network_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if some table is already defined */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM sqlite_master WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", network_name);
+    sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_link", network_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_node_geometry", network_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_link_geometry", network_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+    return 1;
+}
+
+NETWORK_PRIVATE LWN_LINE *
+gaianet_convert_linestring_to_lwnline (gaiaLinestringPtr ln, int srid,
+				       int has_z)
+{
+/* converting a Linestring into an LWN_LINE */
+    int iv;
+    LWN_LINE *line = lwn_alloc_line (ln->Points, srid, has_z);
+    for (iv = 0; iv < ln->Points; iv++)
+      {
+	  double x;
+	  double y;
+	  double z;
+	  double m;
+	  if (ln->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (ln->Coords, iv, &x, &y);
+	    }
+	  line->x[iv] = x;
+	  line->y[iv] = y;
+	  if (has_z)
+	      line->z[iv] = z;
+      }
+    return line;
+}
+
+static int
+do_create_node (sqlite3 * handle, const char *network_name, int srid, int has_z)
+{
+/* attempting to create the Network Node table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *trigger;
+    char *xtrigger;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_node", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tnode_id INTEGER PRIMARY KEY AUTOINCREMENT)",
+			   xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE network-NODE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "next_node_ins" trigger */
+    trigger = sqlite3_mprintf ("%s_node_next_ins", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_node", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE networks SET next_node_id = NEW.node_id + 1 "
+			   "WHERE Lower(network_name) = Lower(%Q) AND next_node_id < NEW.node_id + 1;\n"
+			   "END", xtrigger, xtable, network_name);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER network-NODE next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "next_node_upd" trigger */
+    trigger = sqlite3_mprintf ("%s_node_next_upd", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_node", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TRIGGER \"%s\" AFTER UPDATE OF node_id ON \"%s\"\n"
+	 "FOR EACH ROW BEGIN\n"
+	 "\tUPDATE networks SET next_node_id = NEW.node_id + 1 "
+	 "WHERE Lower(network_name) = Lower(%Q) AND next_node_id < NEW.node_id + 1;\n"
+	 "END", xtrigger, xtable, network_name);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER network-NODE next UPDATE - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Node Geometry */
+    table = sqlite3_mprintf ("%s_node", network_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'geometry', %d, 'POINT', %Q)", table,
+	 srid, has_z ? "XYZ" : "XY");
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn network-NODE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Node Geometry */
+    table = sqlite3_mprintf ("%s_node", network_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geometry')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex network-NODE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_link (sqlite3 * handle, const char *network_name, int srid, int has_z)
+{
+/* attempting to create the Network Link table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xconstraint1;
+    char *xconstraint2;
+    char *xnodes;
+    char *trigger;
+    char *xtrigger;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_link_node_start_fk", network_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_link_node_end_fk", network_name);
+    xconstraint2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", network_name);
+    xnodes = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tlink_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\tstart_node INTEGER NOT NULL,\n"
+			   "\tend_node INTEGER NOT NULL,\n"
+			   "\ttimestamp DATETIME,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (start_node) "
+			   "REFERENCES \"%s\" (node_id),\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (end_node) "
+			   "REFERENCES \"%s\" (node_id))",
+			   xtable, xconstraint1, xnodes, xconstraint2, xnodes);
+    free (xtable);
+    free (xconstraint1);
+    free (xconstraint2);
+    free (xnodes);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE network-LINK - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "next_link_ins" trigger */
+    trigger = sqlite3_mprintf ("%s_link_next_ins", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE networks SET next_link_id = NEW.link_id + 1 "
+			   "WHERE Lower(network_name) = Lower(%Q) AND next_link_id < NEW.link_id + 1;\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE link_id = NEW.link_id;"
+			   "END", xtrigger, xtable, network_name, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER network-LINK next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "link_update" trigger */
+    trigger = sqlite3_mprintf ("%s_link_update", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE link_id = NEW.link_id;"
+			   "END", xtrigger, xtable, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER topology-LINK next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "next_link_upd" trigger */
+    trigger = sqlite3_mprintf ("%s_link_next_upd", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TRIGGER \"%s\" AFTER UPDATE OF link_id ON \"%s\"\n"
+	 "FOR EACH ROW BEGIN\n"
+	 "\tUPDATE networks SET next_link_id = NEW.link_id + 1 "
+	 "WHERE Lower(network_name) = Lower(%Q) AND next_link_id < NEW.link_id + 1;\n"
+	 "END", xtrigger, xtable, network_name);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER network-LINK next UPDATE - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Link Geometry */
+    table = sqlite3_mprintf ("%s_link", network_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'geometry', %d, 'LINESTRING', %Q)",
+	 table, srid, has_z ? "XYZ" : "XY");
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn network-LINK - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Link Geometry */
+    table = sqlite3_mprintf ("%s_link", network_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geometry')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex network-LINK - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "start_node" */
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_start_node", network_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (start_node)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX link-startnode - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "end_node" */
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_end_node", network_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (end_node)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX link-endnode - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "timestamp" */
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_timestamp", network_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX link-timestamps - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_seeds (sqlite3 * handle, const char *network_name, int srid,
+		 int has_z)
+{
+/* attempting to create the Network Seeds table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xconstraint;
+    char *xlinks;
+    char *trigger;
+    char *xtrigger;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_seeds_link_fk", network_name);
+    xconstraint = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xlinks = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tseed_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\tlink_id INTEGER NOT NULL,\n"
+			   "\ttimestamp DATETIME,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (link_id) "
+			   "REFERENCES \"%s\" (link_id) ON DELETE CASCADE)",
+			   xtable, xconstraint, xlinks);
+    free (xtable);
+    free (xconstraint);
+    free (xlinks);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE network-SEEDS - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "seeds_ins" trigger */
+    trigger = sqlite3_mprintf ("%s_seeds_ins", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE seed_id = NEW.seed_id;"
+			   "END", xtrigger, xtable, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER network-SEEDS next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "seeds_update" trigger */
+    trigger = sqlite3_mprintf ("%s_seeds_update", network_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE seed_id = NEW.seed_id;"
+			   "END", xtrigger, xtable, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER network-SEED next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Seeds Geometry */
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'geometry', %d, 'POINT', %Q, 1)",
+	 table, srid, has_z ? "XYZ" : "XY");
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn network-SEEDS - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Seeds Geometry */
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geometry')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex network-SEEDS - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "link_id" */
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_link", network_name);
+    xconstraint = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (link_id)",
+			 xconstraint, xtable);
+    free (xtable);
+    free (xconstraint);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX seeds-link - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "timestamp" */
+    table = sqlite3_mprintf ("%s_seeds", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_seeds_timestamp", network_name);
+    xconstraint = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
+			 xconstraint, xtable);
+    free (xtable);
+    free (xconstraint);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX seeds-timestamps - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+GAIANET_DECLARE int
+gaiaNetworkCreate (sqlite3 * handle, const char *network_name, int spatial,
+		   int srid, int has_z, int allow_coincident)
+{
+/* attempting to create a new Network */
+    int ret;
+    char *sql;
+
+/* creating the Networks table (just in case) */
+    if (!do_create_networks (handle))
+	return 0;
+
+/* testing for forbidding objects */
+    if (!check_new_network (handle, network_name))
+	return 0;
+
+/* creating the Network own Tables */
+    if (!do_create_node (handle, network_name, srid, has_z))
+	goto error;
+    if (!do_create_link (handle, network_name, srid, has_z))
+	goto error;
+    if (!do_create_seeds (handle, network_name, srid, has_z))
+	goto error;
+
+/* registering the Network */
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.networks (network_name, "
+			   "spatial, srid, has_z, allow_coincident) VALUES (Lower(%Q), %d, %d, %d, %d)",
+			   network_name, spatial, srid, has_z,
+			   allow_coincident);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+
+    return 1;
+
+  error:
+    return 0;
+}
+
+static int
+check_existing_network (sqlite3 * handle, const char *network_name,
+			int full_check)
+{
+/* testing if a Network is already defined */
+    char *sql;
+    char *prev;
+    char *table;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *value;
+    int error = 0;
+
+/* testing if the Network is already defined */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.networks WHERE "
+			   "Lower(network_name) = Lower(%Q)", network_name);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 1)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+    if (!full_check)
+	return 1;
+
+/* testing if all table/geom are correctly defined in geometry_columns */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.geometry_columns WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", network_name);
+    sql =
+	sqlite3_mprintf
+	("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_link", network_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 2)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if all tables are already defined */
+    sql =
+	sqlite3_mprintf
+	("SELECT Count(*) FROM sqlite_master WHERE type = 'table' AND (");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", network_name);
+    sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_link", network_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_node_geometry", network_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_link_geometry", network_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q))", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 4)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+    return 1;
+}
+
+static int
+do_drop_network_table (sqlite3 * handle, const char *network_name,
+		       const char *which)
+{
+/* attempting to drop some Network table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *err_msg = NULL;
+    int ret;
+
+/* disabling the corresponding Spatial Index */
+    table = sqlite3_mprintf ("%s_%s", network_name, which);
+    sql = sqlite3_mprintf ("SELECT DisableSpatialIndex(%Q, 'geometry')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("DisableSpatialIndex network-%s - error: %s\n", which, err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* discarding the Geometry column */
+    table = sqlite3_mprintf ("%s_%s", network_name, which);
+    sql =
+	sqlite3_mprintf ("SELECT DiscardGeometryColumn(%Q, 'geometry')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("DisableGeometryColumn network-%s - error: %s\n", which,
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* dropping the main table */
+    table = sqlite3_mprintf ("%s_%s", network_name, which);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("DROP network-%s - error: %s\n", which, err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* dropping the corresponding Spatial Index */
+    table = sqlite3_mprintf ("idx_%s_%s_geometry", network_name, which);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("DROP SpatialIndex network-%s - error: %s\n", which, err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_get_network (sqlite3 * handle, const char *net_name, char **network_name,
+		int *spatial, int *srid, int *has_z, int *allow_coincident)
+{
+/* retrieving a Network configuration */
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    int ok = 0;
+    char *xnetwork_name = NULL;
+    int xsrid;
+    int xhas_z;
+    int xspatial;
+    int xallow_coincident;
+
+/* preparing the SQL query */
+    sql =
+	sqlite3_mprintf
+	("SELECT network_name, spatial, srid, has_z, allow_coincident "
+	 "FROM MAIN.networks WHERE Lower(network_name) = Lower(%Q)", net_name);
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM networks error: \"%s\"\n",
+			sqlite3_errmsg (handle));
+	  return 0;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_name = 0;
+		int ok_srid = 0;
+		int ok_z = 0;
+		int ok_spatial = 0;
+		int ok_allow_coincident = 0;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
+		  {
+		      const char *str =
+			  (const char *) sqlite3_column_text (stmt, 0);
+		      if (xnetwork_name != NULL)
+			  free (xnetwork_name);
+		      xnetwork_name = malloc (strlen (str) + 1);
+		      strcpy (xnetwork_name, str);
+		      ok_name = 1;
+		  }
+		if (sqlite3_column_type (stmt, 1) == SQLITE_INTEGER)
+		  {
+		      xspatial = sqlite3_column_int (stmt, 1);
+		      ok_spatial = 1;
+		  }
+		if (sqlite3_column_type (stmt, 2) == SQLITE_INTEGER)
+		  {
+		      xsrid = sqlite3_column_int (stmt, 2);
+		      ok_srid = 1;
+		  }
+		if (sqlite3_column_type (stmt, 3) == SQLITE_INTEGER)
+		  {
+		      xhas_z = sqlite3_column_int (stmt, 3);
+		      ok_z = 1;
+		  }
+		if (sqlite3_column_type (stmt, 4) == SQLITE_INTEGER)
+		  {
+		      xallow_coincident = sqlite3_column_int (stmt, 4);
+		      ok_allow_coincident = 1;
+		  }
+		if (ok_name && ok_spatial && ok_srid && ok_z
+		    && ok_allow_coincident)
+		  {
+		      ok = 1;
+		      break;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e
+		    ("step: SELECT FROM networks error: \"%s\"\n",
+		     sqlite3_errmsg (handle));
+		sqlite3_finalize (stmt);
+		return 0;
+	    }
+      }
+    sqlite3_finalize (stmt);
+
+    if (ok)
+      {
+	  *network_name = xnetwork_name;
+	  *srid = xsrid;
+	  *has_z = xhas_z;
+	  *spatial = xspatial;
+	  *allow_coincident = xallow_coincident;
+	  return 1;
+      }
+
+    if (xnetwork_name != NULL)
+	free (xnetwork_name);
+    return 0;
+}
+
+GAIANET_DECLARE GaiaNetworkAccessorPtr
+gaiaGetNetwork (sqlite3 * handle, const void *cache, const char *network_name)
+{
+/* attempting to get a reference to some Network Accessor Object */
+    GaiaNetworkAccessorPtr accessor;
+
+/* attempting to retrieve an alredy cached definition */
+    accessor = gaiaNetworkFromCache (cache, network_name);
+    if (accessor != NULL)
+	return accessor;
+
+/* attempting to create a new Network Accessor */
+    accessor = gaiaNetworkFromDBMS (handle, cache, network_name);
+    return accessor;
+}
+
+GAIANET_DECLARE GaiaNetworkAccessorPtr
+gaiaNetworkFromCache (const void *p_cache, const char *network_name)
+{
+/* attempting to retrieve an already defined Network Accessor Object from the Connection Cache */
+    struct gaia_network *ptr;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) p_cache;
+    if (cache == 0)
+	return NULL;
+
+    ptr = (struct gaia_network *) (cache->firstNetwork);
+    while (ptr != NULL)
+      {
+	  /* checking for an already registered Network */
+	  if (strcasecmp (network_name, ptr->network_name) == 0)
+	      return (GaiaNetworkAccessorPtr) ptr;
+	  ptr = ptr->next;
+      }
+    return NULL;
+}
+
+GAIANET_DECLARE int
+gaiaReadNetworkFromDBMS (sqlite3 *
+			 handle,
+			 const char
+			 *net_name, char **network_name, int *spatial,
+			 int *srid, int *has_z, int *allow_coincident)
+{
+/* testing for existing DBMS objects */
+    if (!check_existing_network (handle, net_name, 1))
+	return 0;
+
+/* retrieving the Network configuration */
+    if (!do_get_network
+	(handle, net_name, network_name, spatial, srid, has_z,
+	 allow_coincident))
+	return 0;
+    return 1;
+}
+
+GAIANET_DECLARE GaiaNetworkAccessorPtr
+gaiaNetworkFromDBMS (sqlite3 * handle, const void *p_cache,
+		     const char *network_name)
+{
+/* attempting to create a Network Accessor Object into the Connection Cache */
+    LWN_BE_CALLBACKS *callbacks;
+    struct gaia_network *ptr;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) p_cache;
+    if (cache == 0)
+	return NULL;
+
+/* allocating and initializing the opaque object */
+    ptr = malloc (sizeof (struct gaia_network));
+    ptr->db_handle = handle;
+    ptr->cache = cache;
+    ptr->network_name = NULL;
+    ptr->srid = -1;
+    ptr->has_z = 0;
+    ptr->spatial = 0;
+    ptr->allow_coincident = 0;
+    ptr->last_error_message = NULL;
+    ptr->lwn_iface = lwn_CreateBackendIface ((const LWN_BE_DATA *) ptr);
+    ptr->prev = cache->lastNetwork;
+    ptr->next = NULL;
+
+    callbacks = malloc (sizeof (LWN_BE_CALLBACKS));
+    callbacks->netGetSRID = netcallback_netGetSRID;
+    callbacks->netHasZ = netcallback_netHasZ;
+    callbacks->netIsSpatial = netcallback_netIsSpatial;
+    callbacks->netAllowCoincident = netcallback_netAllowCoincident;
+    callbacks->netGetGEOS = netcallback_netGetGEOS;
+    callbacks->createNetwork = NULL;
+    callbacks->loadNetworkByName = netcallback_loadNetworkByName;
+    callbacks->freeNetwork = netcallback_freeNetwork;
+    callbacks->getNetNodeWithinDistance2D =
+	netcallback_getNetNodeWithinDistance2D;
+    callbacks->getLinkWithinDistance2D = netcallback_getLinkWithinDistance2D;
+    callbacks->insertNetNodes = netcallback_insertNetNodes;
+    callbacks->getNetNodeById = netcallback_getNetNodeById;
+    callbacks->updateNetNodesById = netcallback_updateNetNodesById;
+    callbacks->deleteNetNodesById = netcallback_deleteNetNodesById;
+    callbacks->getLinkByNetNode = netcallback_getLinkByNetNode;
+    callbacks->getNextLinkId = netcallback_getNextLinkId;
+    callbacks->getNetNodeWithinBox2D = netcallback_getNetNodeWithinBox2D;
+    callbacks->getNextLinkId = netcallback_getNextLinkId;
+    callbacks->insertLinks = netcallback_insertLinks;
+    callbacks->updateLinksById = netcallback_updateLinksById;
+    callbacks->getLinkById = netcallback_getLinkById;
+    callbacks->deleteLinksById = netcallback_deleteLinksById;
+    ptr->callbacks = callbacks;
+
+    lwn_BackendIfaceRegisterCallbacks (ptr->lwn_iface, callbacks);
+    ptr->lwn_network = lwn_LoadNetwork (ptr->lwn_iface, network_name);
+
+    ptr->stmt_getNetNodeWithinDistance2D = NULL;
+    ptr->stmt_getLinkWithinDistance2D = NULL;
+    ptr->stmt_insertNetNodes = NULL;
+    ptr->stmt_deleteNetNodesById = NULL;
+    ptr->stmt_getNetNodeWithinBox2D = NULL;
+    ptr->stmt_getNextLinkId = NULL;
+    ptr->stmt_setNextLinkId = NULL;
+    ptr->stmt_insertLinks = NULL;
+    ptr->stmt_deleteLinksById = NULL;
+    if (ptr->lwn_network == NULL)
+	goto invalid;
+
+/* creating the SQL prepared statements */
+    create_toponet_prepared_stmts ((GaiaNetworkAccessorPtr) ptr);
+    return (GaiaNetworkAccessorPtr) ptr;
+
+  invalid:
+    gaiaNetworkDestroy ((GaiaNetworkAccessorPtr) ptr);
+    return NULL;
+}
+
+GAIANET_DECLARE void
+gaiaNetworkDestroy (GaiaNetworkAccessorPtr net_ptr)
+{
+/* destroying a Network Accessor Object */
+    struct gaia_network *prev;
+    struct gaia_network *next;
+    struct splite_internal_cache *cache;
+    struct gaia_network *ptr = (struct gaia_network *) net_ptr;
+    if (ptr == NULL)
+	return;
+
+    prev = ptr->prev;
+    next = ptr->next;
+    cache = (struct splite_internal_cache *) (ptr->cache);
+    if (ptr->lwn_network != NULL)
+	lwn_FreeNetwork ((LWN_NETWORK *) (ptr->lwn_network));
+    if (ptr->lwn_iface != NULL)
+	lwn_FreeBackendIface ((LWN_BE_IFACE *) (ptr->lwn_iface));
+    if (ptr->callbacks != NULL)
+	free (ptr->callbacks);
+    if (ptr->network_name != NULL)
+	free (ptr->network_name);
+    if (ptr->last_error_message != NULL)
+	free (ptr->last_error_message);
+
+    finalize_toponet_prepared_stmts (net_ptr);
+    free (ptr);
+
+/* unregistering from the Internal Cache double linked list */
+    if (prev != NULL)
+	prev->next = next;
+    if (next != NULL)
+	next->prev = prev;
+    if (cache->firstNetwork == ptr)
+	cache->firstNetwork = next;
+    if (cache->lastNetwork == ptr)
+	cache->lastNetwork = prev;
+}
+
+NETWORK_PRIVATE void
+finalize_toponet_prepared_stmts (GaiaNetworkAccessorPtr accessor)
+{
+/* finalizing the SQL prepared statements */
+    struct gaia_network *ptr = (struct gaia_network *) accessor;
+    if (ptr->stmt_getNetNodeWithinDistance2D != NULL)
+	sqlite3_finalize (ptr->stmt_getNetNodeWithinDistance2D);
+    if (ptr->stmt_getLinkWithinDistance2D != NULL)
+	sqlite3_finalize (ptr->stmt_getLinkWithinDistance2D);
+    if (ptr->stmt_insertNetNodes != NULL)
+	sqlite3_finalize (ptr->stmt_insertNetNodes);
+    if (ptr->stmt_deleteNetNodesById != NULL)
+	sqlite3_finalize (ptr->stmt_deleteNetNodesById);
+    if (ptr->stmt_getNetNodeWithinBox2D != NULL)
+	sqlite3_finalize (ptr->stmt_getNetNodeWithinBox2D);
+    if (ptr->stmt_getNextLinkId != NULL)
+	sqlite3_finalize (ptr->stmt_getNextLinkId);
+    if (ptr->stmt_setNextLinkId != NULL)
+	sqlite3_finalize (ptr->stmt_setNextLinkId);
+    if (ptr->stmt_insertLinks != NULL)
+	sqlite3_finalize (ptr->stmt_insertLinks);
+    if (ptr->stmt_deleteLinksById != NULL)
+	sqlite3_finalize (ptr->stmt_deleteLinksById);
+    ptr->stmt_getNetNodeWithinDistance2D = NULL;
+    ptr->stmt_getLinkWithinDistance2D = NULL;
+    ptr->stmt_insertNetNodes = NULL;
+    ptr->stmt_deleteNetNodesById = NULL;
+    ptr->stmt_getNetNodeWithinBox2D = NULL;
+    ptr->stmt_getNextLinkId = NULL;
+    ptr->stmt_setNextLinkId = NULL;
+    ptr->stmt_insertLinks = NULL;
+    ptr->stmt_deleteLinksById = NULL;
+}
+
+NETWORK_PRIVATE void
+create_toponet_prepared_stmts (GaiaNetworkAccessorPtr accessor)
+{
+/* creating the SQL prepared statements */
+    struct gaia_network *ptr = (struct gaia_network *) accessor;
+    finalize_toponet_prepared_stmts (accessor);
+    ptr->stmt_getNetNodeWithinDistance2D =
+	do_create_stmt_getNetNodeWithinDistance2D (accessor);
+    ptr->stmt_getLinkWithinDistance2D =
+	do_create_stmt_getLinkWithinDistance2D (accessor);
+    ptr->stmt_deleteNetNodesById = do_create_stmt_deleteNetNodesById (accessor);
+    ptr->stmt_insertNetNodes = do_create_stmt_insertNetNodes (accessor);
+    ptr->stmt_getNetNodeWithinBox2D =
+	do_create_stmt_getNetNodeWithinBox2D (accessor);
+    ptr->stmt_getNextLinkId = do_create_stmt_getNextLinkId (accessor);
+    ptr->stmt_setNextLinkId = do_create_stmt_setNextLinkId (accessor);
+    ptr->stmt_insertLinks = do_create_stmt_insertLinks (accessor);
+    ptr->stmt_deleteLinksById = do_create_stmt_deleteLinksById (accessor);
+}
+
+NETWORK_PRIVATE void
+gaianet_reset_last_error_msg (GaiaNetworkAccessorPtr accessor)
+{
+/* resets the last Network error message */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net == NULL)
+	return;
+
+    if (net->last_error_message != NULL)
+	free (net->last_error_message);
+    net->last_error_message = NULL;
+}
+
+NETWORK_PRIVATE void
+gaianet_set_last_error_msg (GaiaNetworkAccessorPtr accessor, const char *msg)
+{
+/* sets the last Network error message */
+    int len;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (msg == NULL)
+	msg = "no message available";
+
+    spatialite_e ("%s\n", msg);
+    if (net == NULL)
+	return;
+
+    if (net->last_error_message != NULL)
+	return;
+
+    len = strlen (msg);
+    net->last_error_message = malloc (len + 1);
+    strcpy (net->last_error_message, msg);
+}
+
+NETWORK_PRIVATE const char *
+gaianet_get_last_exception (GaiaNetworkAccessorPtr accessor)
+{
+/* returns the last Network error message */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net == NULL)
+	return NULL;
+
+    return net->last_error_message;
+}
+
+GAIANET_DECLARE int
+gaiaNetworkDrop (sqlite3 * handle, const char *network_name)
+{
+/* attempting to drop an already existing Network */
+    int ret;
+    char *sql;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    int count = 1;
+
+/* creating the Networks table (just in case) */
+    if (!do_create_networks (handle))
+	return 0;
+
+/* testing for existing DBMS objects */
+    if (!check_existing_network (handle, network_name, 0))
+	return 0;
+
+/* dropping the Network own Tables */
+    if (!do_drop_network_table (handle, network_name, "seeds"))
+	goto error;
+    if (!do_drop_network_table (handle, network_name, "link"))
+	goto error;
+    if (!do_drop_network_table (handle, network_name, "node"))
+	goto error;
+
+/* unregistering the Network */
+    sql =
+	sqlite3_mprintf
+	("DELETE FROM MAIN.networks WHERE Lower(network_name) = Lower(%Q)",
+	 network_name);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+
+/* counting how many Networks are still there */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.networks");
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 1;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	      count = atoi (results[(i * columns) + 0]);
+      }
+    sqlite3_free_table (results);
+    if (count == 0)
+      {
+	  /* attempting to drop the master "networks" table */
+	  sql = sqlite3_mprintf ("DROP TABLE MAIN.networks");
+	  ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
+	  sqlite3_free (sql);
+      }
+
+    return 1;
+
+  error:
+    return 0;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaAddIsoNetNode (GaiaNetworkAccessorPtr accessor, gaiaPointPtr pt)
+{
+/* LWN wrapper - AddIsoNetNode */
+    sqlite3_int64 ret;
+    LWN_POINT *point = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (pt != NULL)
+      {
+	  if (pt->DimensionModel == GAIA_XY_Z
+	      || pt->DimensionModel == GAIA_XY_Z_M)
+	      point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
+	  else
+	      point = lwn_create_point2d (network->srid, pt->X, pt->Y);
+      }
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret = lwn_AddIsoNetNode ((LWN_NETWORK *) (network->lwn_network), point);
+    lwn_free_point (point);
+
+    return ret;
+}
+
+GAIANET_DECLARE int
+gaiaMoveIsoNetNode (GaiaNetworkAccessorPtr accessor,
+		    sqlite3_int64 node, gaiaPointPtr pt)
+{
+/* LWN wrapper - MoveIsoNetNode */
+    int ret;
+    LWN_POINT *point = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (pt != NULL)
+      {
+	  if (pt->DimensionModel == GAIA_XY_Z
+	      || pt->DimensionModel == GAIA_XY_Z_M)
+	      point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
+	  else
+	      point = lwn_create_point2d (network->srid, pt->X, pt->Y);
+      }
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_MoveIsoNetNode ((LWN_NETWORK *) (network->lwn_network), node,
+			    point);
+    lwn_free_point (point);
+
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaRemIsoNetNode (GaiaNetworkAccessorPtr accessor, sqlite3_int64 node)
+{
+/* LWN wrapper - RemIsoNetNode */
+    int ret;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret = lwn_RemIsoNetNode ((LWN_NETWORK *) (network->lwn_network), node);
+
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaAddLink (GaiaNetworkAccessorPtr accessor,
+	     sqlite3_int64 start_node, sqlite3_int64 end_node,
+	     gaiaLinestringPtr ln)
+{
+/* LWN wrapper - AddLink */
+    sqlite3_int64 ret;
+    LWN_LINE *lwn_line = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (ln != NULL)
+      {
+	  lwn_line =
+	      gaianet_convert_linestring_to_lwnline (ln, network->srid,
+						     network->has_z);
+      }
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_AddLink ((LWN_NETWORK *) (network->lwn_network), start_node,
+		     end_node, lwn_line);
+
+    lwn_free_line (lwn_line);
+    return ret;
+}
+
+GAIANET_DECLARE int
+gaiaChangeLinkGeom (GaiaNetworkAccessorPtr accessor,
+		    sqlite3_int64 link_id, gaiaLinestringPtr ln)
+{
+/* LWN wrapper - ChangeLinkGeom */
+    int ret;
+    LWN_LINE *lwn_line = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (ln != NULL)
+      {
+	  lwn_line =
+	      gaianet_convert_linestring_to_lwnline (ln, network->srid,
+						     network->has_z);
+      }
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_ChangeLinkGeom ((LWN_NETWORK *) (network->lwn_network), link_id,
+			    lwn_line);
+    lwn_free_line (lwn_line);
+
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaRemoveLink (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
+{
+/* LWN wrapper - RemoveLink */
+    int ret;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret = lwn_RemoveLink ((LWN_NETWORK *) (network->lwn_network), link);
+
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaNewLogLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
+{
+/* LWN wrapper - NewLogLinkSplit  */
+    sqlite3_int64 ret;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret = lwn_NewLogLinkSplit ((LWN_NETWORK *) (network->lwn_network), link);
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaModLogLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
+{
+/* LWN wrapper - ModLogLinkSplit  */
+    sqlite3_int64 ret;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret = lwn_ModLogLinkSplit ((LWN_NETWORK *) (network->lwn_network), link);
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaNewGeoLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
+		     gaiaPointPtr pt)
+{
+/* LWN wrapper - NewGeoLinkSplit  */
+    sqlite3_int64 ret;
+    LWN_POINT *point = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (pt != NULL)
+      {
+	  if (pt->DimensionModel == GAIA_XY_Z
+	      || pt->DimensionModel == GAIA_XY_Z_M)
+	      point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
+	  else
+	      point = lwn_create_point2d (network->srid, pt->X, pt->Y);
+      }
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_NewGeoLinkSplit ((LWN_NETWORK *) (network->lwn_network), link,
+			     point);
+    lwn_free_point (point);
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaModGeoLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
+		     gaiaPointPtr pt)
+{
+/* LWN wrapper - ModGeoLinkSplit  */
+    sqlite3_int64 ret;
+    LWN_POINT *point = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (pt != NULL)
+      {
+	  if (pt->DimensionModel == GAIA_XY_Z
+	      || pt->DimensionModel == GAIA_XY_Z_M)
+	      point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
+	  else
+	      point = lwn_create_point2d (network->srid, pt->X, pt->Y);
+      }
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_ModGeoLinkSplit ((LWN_NETWORK *) (network->lwn_network), link,
+			     point);
+    lwn_free_point (point);
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaNewLinkHeal (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
+		 sqlite3_int64 anotherlink)
+{
+/* LWN wrapper - NewLinkHeal  */
+    sqlite3_int64 ret;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_NewLinkHeal ((LWN_NETWORK *) (network->lwn_network), link,
+			 anotherlink);
+
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaModLinkHeal (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
+		 sqlite3_int64 anotherlink)
+{
+/* LWN wrapper - ModLinkHeal  */
+    sqlite3_int64 ret;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    lwn_ResetErrorMsg (network->lwn_iface);
+    ret =
+	lwn_ModLinkHeal ((LWN_NETWORK *) (network->lwn_network), link,
+			 anotherlink);
+
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaGetNetNodeByPoint (GaiaNetworkAccessorPtr accessor, gaiaPointPtr pt,
+		       double tolerance)
+{
+/* LWN wrapper - GetNetNodeByPoint */
+    sqlite3_int64 ret;
+    LWN_POINT *point = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (pt != NULL)
+      {
+	  if (pt->DimensionModel == GAIA_XY_Z
+	      || pt->DimensionModel == GAIA_XY_Z_M)
+	      point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
+	  else
+	      point = lwn_create_point2d (network->srid, pt->X, pt->Y);
+      }
+    lwn_ResetErrorMsg (network->lwn_iface);
+
+    ret =
+	lwn_GetNetNodeByPoint ((LWN_NETWORK *) (network->lwn_network), point,
+			       tolerance);
+
+    lwn_free_point (point);
+    return ret;
+}
+
+GAIANET_DECLARE sqlite3_int64
+gaiaGetLinkByPoint (GaiaNetworkAccessorPtr accessor, gaiaPointPtr pt,
+		    double tolerance)
+{
+/* LWN wrapper - GetLinkByPoint */
+    sqlite3_int64 ret;
+    LWN_POINT *point = NULL;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    if (pt != NULL)
+      {
+	  if (pt->DimensionModel == GAIA_XY_Z
+	      || pt->DimensionModel == GAIA_XY_Z_M)
+	      point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
+	  else
+	      point = lwn_create_point2d (network->srid, pt->X, pt->Y);
+      }
+    lwn_ResetErrorMsg (network->lwn_iface);
+
+    ret =
+	lwn_GetLinkByPoint ((LWN_NETWORK *) (network->lwn_network), point,
+			    tolerance);
+
+    lwn_free_point (point);
+    return ret;
+}
+
+static int
+do_check_create_valid_logicalnet_table (GaiaNetworkAccessorPtr accessor)
+{
+/* attemtping to create or validate the target table */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    char *errMsg = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+/* finalizing all prepared Statements */
+    finalize_all_topo_prepared_stmts (net->cache);
+
+/* attempting to drop the table (just in case if it already exists) */
+    table = sqlite3_mprintf ("%s_valid_logicalnet", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS TEMP.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    create_all_topo_prepared_stmts (net->cache);	/* recreating prepared stsms */
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidLogicalNet exception: %s", errMsg);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+/* attempting to create the table */
+    table = sqlite3_mprintf ("%s_valid_logicalnet", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TEMP TABLE \"%s\" (\n\terror TEXT,\n"
+	 "\tprimitive1 INTEGER,\n\tprimitive2 INTEGER)", xtable);
+    free (xtable);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidLogicalNet exception: %s", errMsg);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_loginet_check_nodes (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for nodes with geometry */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT node_id FROM MAIN.\"%s\" WHERE geometry IS NOT NULL", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidLogicalNet() - Nodes error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 0);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "node has geometry", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, node_id);
+		sqlite3_bind_null (stmt, 3);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidLogicalNet() insert error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidLogicalNet() - Nodes step error: %s",
+		     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_loginet_check_links (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for links with geometry */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT link_id FROM MAIN.\"%s\" WHERE geometry IS NOT NULL", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidLogicalNet() - Links error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "link has geometry", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, link_id);
+		sqlite3_bind_null (stmt, 3);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidLogicalNet() insert error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidLogicalNet() - Links step error: %s",
+		     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaValidLogicalNet (GaiaNetworkAccessorPtr accessor)
+{
+/* generating a validity report for a given Logical Network */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net == NULL)
+	return 0;
+
+    if (!do_check_create_valid_logicalnet_table (accessor))
+	return 0;
+
+    table = sqlite3_mprintf ("%s_valid_logicalnet", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO TEMP.\"%s\" (error, primitive1, primitive2) VALUES (?, ?, ?)",
+	 xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_ValidLogicalNet error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    if (!do_loginet_check_nodes (accessor, stmt))
+	goto error;
+
+    if (!do_loginet_check_links (accessor, stmt))
+	goto error;
+
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+static int
+do_check_create_valid_spatialnet_table (GaiaNetworkAccessorPtr accessor)
+{
+/* attemtping to create or validate the target table */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    char *errMsg;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+/* attempting to drop the table (just in case if it already exists) */
+    table = sqlite3_mprintf ("%s_valid_spatialnet", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS temp.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidSpatialNet exception: %s", errMsg);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+/* attempting to create the table */
+    table = sqlite3_mprintf ("%s_valid_spatialnet", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TEMP TABLE \"%s\" (\n\terror TEXT,\n"
+	 "\tprimitive1 INTEGER,\n\tprimitive2 INTEGER)", xtable);
+    free (xtable);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidSpatialNet exception: %s", errMsg);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_spatnet_check_nodes (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for nodes without geometry */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT node_id FROM MAIN.\"%s\" WHERE geometry IS NULL", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidSpatialNet() - Nodes error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 0);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "missing node geometry", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, node_id);
+		sqlite3_bind_null (stmt, 3);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidSpatialNet() insert error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidSpatialNet() - Nodes step error: %s",
+		     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_spatnet_check_links (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for links without geometry */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT link_id FROM MAIN.\"%s\" WHERE geometry IS NULL", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidSpatialNet() - Links error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "missing link geometry", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, link_id);
+		sqlite3_bind_null (stmt, 3);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidSpatialNet() insert error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidSpatialNet() - Links step error: %s",
+		     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_spatnet_check_start_nodes (GaiaNetworkAccessorPtr accessor,
+			      sqlite3_stmt * stmt)
+{
+/* checking for links mismatching start nodes */
+    char *sql;
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT l.link_id, l.start_node FROM MAIN.\"%s\" AS l "
+			 "JOIN MAIN.\"%s\" AS n ON (l.start_node = n.node_id) "
+			 "WHERE ST_Disjoint(ST_StartPoint(l.geometry), n.geometry) = 1",
+			 xtable1, xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidSpatialNet() - StartNodes error: \"%s\"",
+	       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "geometry start mismatch", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, link_id);
+		sqlite3_bind_int64 (stmt, 3, node_id);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidSpatialNet() insert error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidSpatialNet() - StartNodes step error: %s",
+		     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_spatnet_check_end_nodes (GaiaNetworkAccessorPtr accessor,
+			    sqlite3_stmt * stmt)
+{
+/* checking for links mismatching end nodes */
+    char *sql;
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT l.link_id, l.end_node FROM MAIN.\"%s\" AS l "
+			   "JOIN MAIN.\"%s\" AS n ON (l.end_node = n.node_id) "
+			   "WHERE ST_Disjoint(ST_EndPoint(l.geometry), n.geometry) = 1",
+			   xtable1, xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidSpatialNet() - EndNodes error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "geometry end mismatch", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, link_id);
+		sqlite3_bind_int64 (stmt, 3, node_id);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidSpatialNet() insert error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidSpatialNet() - EndNodes step error: %s",
+		     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaValidSpatialNet (GaiaNetworkAccessorPtr accessor)
+{
+/* generating a validity report for a given Spatial Network */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net == NULL)
+	return 0;
+
+    if (!do_check_create_valid_spatialnet_table (accessor))
+	return 0;
+
+    table = sqlite3_mprintf ("%s_valid_spatialnet", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO TEMP.\"%s\" (error, primitive1, primitive2) VALUES (?, ?, ?)",
+	 xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_ValidSpatialNet error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    if (!do_spatnet_check_nodes (accessor, stmt))
+	goto error;
+
+    if (!do_spatnet_check_links (accessor, stmt))
+	goto error;
+
+    if (!do_spatnet_check_start_nodes (accessor, stmt))
+	goto error;
+
+    if (!do_spatnet_check_end_nodes (accessor, stmt))
+	goto error;
+
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+NETWORK_PRIVATE int
+auxnet_insert_into_network (GaiaNetworkAccessorPtr accessor,
+			    gaiaGeomCollPtr geom)
+{
+/* processing all individual geometry items */
+    sqlite3_int64 ret;
+    gaiaLinestringPtr ln;
+    gaiaPoint pt;
+    struct gaia_network *network = (struct gaia_network *) accessor;
+    if (network == NULL)
+	return 0;
+
+    ln = geom->FirstLinestring;
+    while (ln != NULL)
+      {
+	  /* looping on Linestrings items */
+	  int last = ln->Points - 1;
+	  double x;
+	  double y;
+	  double z = 0.0;
+	  double m = 0.0;
+	  sqlite3_int64 start_node;
+	  sqlite3_int64 end_node;
+	  LWN_LINE *lwn_line;
+	  lwn_ResetErrorMsg (network->lwn_iface);
+
+	  /* attempting to retrieve or insert the Start Node */
+	  if (geom->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (ln->Coords, 0, &x, &y, &z);
+	    }
+	  else if (geom->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (ln->Coords, 0, &x, &y, &z, &m);
+	    }
+	  else if (geom->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (ln->Coords, 0, &x, &y, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (ln->Coords, 0, &x, &y);
+	    }
+	  if (network->has_z)
+	    {
+		pt.DimensionModel = GAIA_XY_Z;
+		pt.X = x;
+		pt.Y = y;
+		pt.Z = z;
+	    }
+	  else
+	    {
+		pt.DimensionModel = GAIA_XY;
+		pt.X = x;
+		pt.Y = y;
+	    }
+	  start_node = gaiaGetNetNodeByPoint (accessor, &pt, 0.0);
+	  if (start_node < 0)
+	      start_node = gaiaAddIsoNetNode (accessor, &pt);
+	  if (start_node < 0)
+	    {
+		const char *msg = lwn_GetErrorMsg (network->lwn_iface);
+		gaianet_set_last_error_msg (accessor, msg);
+		goto error;
+	    }
+
+	  /* attempting to retrieve or insert the End Node */
+	  if (geom->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (ln->Coords, last, &x, &y, &z);
+	    }
+	  else if (geom->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (ln->Coords, last, &x, &y, &z, &m);
+	    }
+	  else if (geom->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (ln->Coords, last, &x, &y, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (ln->Coords, last, &x, &y);
+	    }
+	  if (network->has_z)
+	    {
+		pt.DimensionModel = GAIA_XY_Z;
+		pt.X = x;
+		pt.Y = y;
+		pt.Z = z;
+	    }
+	  else
+	    {
+		pt.DimensionModel = GAIA_XY;
+		pt.X = x;
+		pt.Y = y;
+	    }
+	  end_node = gaiaGetNetNodeByPoint (accessor, &pt, 0.0);
+	  if (end_node < 0)
+	      end_node = gaiaAddIsoNetNode (accessor, &pt);
+	  if (end_node < 0)
+	    {
+		const char *msg = lwn_GetErrorMsg (network->lwn_iface);
+		gaianet_set_last_error_msg (accessor, msg);
+		goto error;
+	    }
+
+	  lwn_line = gaianet_convert_linestring_to_lwnline (ln, network->srid,
+							    network->has_z);
+	  ret =
+	      lwn_AddLink ((LWN_NETWORK *) (network->lwn_network), start_node,
+			   end_node, lwn_line);
+	  lwn_free_line (lwn_line);
+	  if (ret <= 0)
+	    {
+		const char *msg = lwn_GetErrorMsg (network->lwn_iface);
+		gaianet_set_last_error_msg (accessor, msg);
+		goto error;
+	    }
+
+	  ln = ln->Next;
+      }
+
+    return 1;
+
+  error:
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaTopoNet_FromGeoTable (GaiaNetworkAccessorPtr accessor,
+			  const char *db_prefix, const char *table,
+			  const char *column)
+{
+/* attempting to import a whole GeoTable into a Topoology-Network */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+
+    if (net == NULL)
+	return 0;
+    if (net->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (net->cache);
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+/* building the SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (table);
+    xcolumn = gaiaDoubleQuotedSql (column);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\"", xcolumn,
+			 xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    free (xcolumn);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_FromGeoTable error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
+		    continue;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob = sqlite3_column_blob (stmt, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt, 0);
+		      gaiaGeomCollPtr geom =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
+						       gpkg_amphibious);
+		      if (geom != NULL)
+			{
+			    if (!auxnet_insert_into_network (accessor, geom))
+			      {
+				  gaiaFreeGeomColl (geom);
+				  goto error;
+			      }
+			    gaiaFreeGeomColl (geom);
+			}
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("TopoNet_FromGeoTable error: Invalid Geometry");
+			    gaianet_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoNet_FromGeoTable error: not a BLOB value");
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoNet_FromGeoTable error: \"%s\"",
+				     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+GAIANET_DECLARE gaiaGeomCollPtr
+gaiaGetLinkSeed (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
+{
+/* attempting to get a Point (seed) identifying a Network Link */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    gaiaGeomCollPtr point = NULL;
+    if (net == NULL)
+	return NULL;
+
+/* building the SQL statement */
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT geometry FROM MAIN.\"%s\" WHERE link_id = ?",
+			 xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("GetLinkSeed error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, link);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob = sqlite3_column_blob (stmt, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt, 0);
+		      gaiaGeomCollPtr geom =
+			  gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		      if (geom != NULL)
+			{
+			    int iv;
+			    double x;
+			    double y;
+			    double z = 0.0;
+			    double m = 0.0;
+			    gaiaLinestringPtr ln = geom->FirstLinestring;
+			    if (ln == NULL)
+			      {
+				  char *msg =
+				      sqlite3_mprintf
+				      ("TopoNet_GetLinkSeed error: Invalid Geometry");
+				  gaianet_set_last_error_msg (accessor, msg);
+				  sqlite3_free (msg);
+				  gaiaFreeGeomColl (geom);
+				  goto error;
+			      }
+			    iv = ln->Points / 2;
+			    if (ln->DimensionModel == GAIA_XY_Z)
+			      {
+				  gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
+			      }
+			    else if (ln->DimensionModel == GAIA_XY_M)
+			      {
+				  gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
+			      }
+			    else if (ln->DimensionModel == GAIA_XY_Z_M)
+			      {
+				  gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z,
+						    &m);
+			      }
+			    else
+			      {
+				  gaiaGetPoint (ln->Coords, iv, &x, &y);
+			      }
+			    gaiaFreeGeomColl (geom);
+			    if (net->has_z)
+			      {
+				  point = gaiaAllocGeomCollXYZ ();
+				  gaiaAddPointToGeomCollXYZ (point, x, y, z);
+			      }
+			    else
+			      {
+				  point = gaiaAllocGeomColl ();
+				  gaiaAddPointToGeomColl (point, x, y);
+			      }
+			    point->Srid = net->srid;
+			}
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("TopoNet_GetLinkSeed error: Invalid Geometry");
+			    gaianet_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoNet_GetLinkSeed error: not a BLOB value");
+		      gaianet_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoNet_GetLinkSeed error: \"%s\"",
+				     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt);
+    return point;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return NULL;
+}
+
+static int
+delete_all_seeds (struct gaia_network *net)
+{
+/* deleting all existing Seeds */
+    char *table;
+    char *xtable;
+    char *sql;
+    char *errMsg;
+    int ret;
+
+    table = sqlite3_mprintf ("%s_seeds", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+update_outdated_link_seeds (struct gaia_network *net)
+{
+/* updating all outdated Link Seeds */
+    char *table;
+    char *xseeds;
+    char *xlinks;
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt_out;
+    sqlite3_stmt *stmt_in;
+
+/* preparing the UPDATE statement */
+    table = sqlite3_mprintf ("%s_seeds", net->network_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET geometry = "
+			   "TopoNet_GetLinkSeed(%Q, link_id) WHERE link_id = ?",
+			   xseeds, net->network_name);
+    free (xseeds);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_out, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the SELECT statement */
+    table = sqlite3_mprintf ("%s_seeds", net->network_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xlinks = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT s.link_id FROM MAIN.\"%s\" AS s "
+			   "JOIN MAIN.\"%s\" AS l ON (l.link_id = s.link_id) "
+			   "WHERE s.link_id IS NOT NULL AND l.timestamp > s.timestamp",
+			   xseeds, xlinks);
+    free (xseeds);
+    free (xlinks);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		sqlite3_bind_int64 (stmt_out, 1,
+				    sqlite3_column_int64 (stmt_in, 0));
+		/* updating the Seeds table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoNet_UpdateSeeds() error: \"%s\"",
+			   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr)
+						  net, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"",
+				     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaTopoNetUpdateSeeds (GaiaNetworkAccessorPtr accessor, int incremental_mode)
+{
+/* updating all TopoNet Seeds */
+    char *table;
+    char *xseeds;
+    char *xlinks;
+    char *sql;
+    char *errMsg;
+    int ret;
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net == NULL)
+	return 0;
+
+    if (!incremental_mode)
+      {
+	  /* deleting all existing Seeds */
+	  if (!delete_all_seeds (net))
+	      return 0;
+      }
+
+/* paranoid precaution: deleting all orphan Link Seeds */
+    table = sqlite3_mprintf ("%s_seeds", net->network_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xlinks = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE link_id IN ("
+			   "SELECT s.link_id FROM MAIN.\"%s\" AS s "
+			   "LEFT JOIN MAIN.\"%s\" AS l ON (s.link_id = l.link_id) "
+			   "WHERE l.link_id IS NULL)", xseeds, xseeds, xlinks);
+    free (xseeds);
+    free (xlinks);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* updating all outdated Link Seeds */
+    if (!update_outdated_link_seeds (net))
+	return 0;
+
+/* inserting all missing Link Seeds */
+    table = sqlite3_mprintf ("%s_seeds", net->network_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xlinks = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (seed_id, link_id, geometry) "
+	 "SELECT NULL, l.link_id, TopoNet_GetLinkSeed(%Q, l.link_id) "
+	 "FROM MAIN.\"%s\" AS l "
+	 "LEFT JOIN MAIN.\"%s\" AS s ON (l.link_id = s.link_id) WHERE s.link_id IS NULL",
+	 xseeds, net->network_name, xlinks, xseeds);
+    free (xseeds);
+    free (xlinks);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static void
+do_eval_toponet_point (struct gaia_network *net, gaiaGeomCollPtr result,
+		       gaiaGeomCollPtr reference, sqlite3_stmt * stmt_node)
+{
+/* retrieving Points from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+
+/* initializing the Topo-Node query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_node);
+    sqlite3_clear_bindings (stmt_node);
+    sqlite3_bind_blob (stmt_node, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_node, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_node);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt_node, 0);
+		int blob_sz = sqlite3_column_bytes (stmt_node, 0);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      gaiaPointPtr pt = geom->FirstPoint;
+		      while (pt != NULL)
+			{
+			    /* copying all Points into the result Geometry */
+			    if (net->has_z)
+				gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
+							   pt->Z);
+			    else
+				gaiaAddPointToGeomColl (result, pt->X, pt->Y);
+			    pt = pt->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static void
+do_collect_topo_links (struct gaia_network *net, gaiaGeomCollPtr sparse,
+		       sqlite3_stmt * stmt_link, sqlite3_int64 link_id)
+{
+/* collecting Link Geometries one by one */
+    int ret;
+
+/* initializing the Topo-Link query */
+    sqlite3_reset (stmt_link);
+    sqlite3_clear_bindings (stmt_link);
+    sqlite3_bind_int64 (stmt_link, 1, link_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_link);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt_link, 0);
+		int blob_sz = sqlite3_column_bytes (stmt_link, 0);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      gaiaLinestringPtr ln = geom->FirstLinestring;
+		      while (ln != NULL)
+			{
+			    if (net->has_z)
+				auxtopo_copy_linestring3d (ln, sparse);
+			    else
+				auxtopo_copy_linestring (ln, sparse);
+			    ln = ln->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static void
+do_eval_toponet_line (struct gaia_network *net, gaiaGeomCollPtr result,
+		      gaiaGeomCollPtr reference, sqlite3_stmt * stmt_seed_link,
+		      sqlite3_stmt * stmt_link)
+{
+/* retrieving Linestrings from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr sparse;
+    gaiaGeomCollPtr rearranged;
+    gaiaLinestringPtr ln;
+
+    if (net->has_z)
+	sparse = gaiaAllocGeomCollXYZ ();
+    else
+	sparse = gaiaAllocGeomColl ();
+    sparse->Srid = net->srid;
+
+/* initializing the Topo-Seed-Link query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_seed_link);
+    sqlite3_clear_bindings (stmt_seed_link);
+    sqlite3_bind_blob (stmt_seed_link, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_seed_link, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_seed_link);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 link_id =
+		    sqlite3_column_int64 (stmt_seed_link, 0);
+		do_collect_topo_links (net, sparse, stmt_link, link_id);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		gaiaFreeGeomColl (sparse);
+		return;
+	    }
+      }
+
+/* attempting to rearrange sparse lines */
+    rearranged = gaiaLineMerge_r (net->cache, sparse);
+    gaiaFreeGeomColl (sparse);
+    if (rearranged == NULL)
+	return;
+    ln = rearranged->FirstLinestring;
+    while (ln != NULL)
+      {
+	  if (net->has_z)
+	      auxtopo_copy_linestring3d (ln, result);
+	  else
+	      auxtopo_copy_linestring (ln, result);
+	  ln = ln->Next;
+      }
+    gaiaFreeGeomColl (rearranged);
+}
+
+static gaiaGeomCollPtr
+do_eval_toponet_geom (struct gaia_network *net, gaiaGeomCollPtr geom,
+		      sqlite3_stmt * stmt_seed_link,
+		      sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_link,
+		      int out_type)
+{
+/* retrieving Topology-Network geometries via matching Seeds */
+    gaiaGeomCollPtr result;
+
+    if (net->has_z)
+	result = gaiaAllocGeomCollXYZ ();
+    else
+	result = gaiaAllocGeomColl ();
+    result->Srid = net->srid;
+    result->DeclaredType = out_type;
+
+    if (out_type == GAIA_POINT || out_type == GAIA_MULTIPOINT
+	|| out_type == GAIA_GEOMETRYCOLLECTION || out_type == GAIA_UNKNOWN)
+      {
+	  /* processing all Points */
+	  gaiaPointPtr pt = geom->FirstPoint;
+	  while (pt != NULL)
+	    {
+		gaiaPointPtr next = pt->Next;
+		gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
+		    auxtopo_make_geom_from_point (net->srid, net->has_z, pt);
+		do_eval_toponet_point (net, result, reference, stmt_node);
+		auxtopo_destroy_geom_from (reference);
+		pt->Next = next;
+		pt = pt->Next;
+	    }
+      }
+
+    if (out_type == GAIA_MULTILINESTRING || out_type == GAIA_GEOMETRYCOLLECTION
+	|| out_type == GAIA_UNKNOWN)
+      {
+	  /* processing all Linestrings */
+	  gaiaLinestringPtr ln = geom->FirstLinestring;
+	  while (ln != NULL)
+	    {
+		gaiaLinestringPtr next = ln->Next;
+		gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
+		    auxtopo_make_geom_from_line (net->srid, ln);
+		do_eval_toponet_line (net, result, reference, stmt_seed_link,
+				      stmt_link);
+		auxtopo_destroy_geom_from (reference);
+		ln->Next = next;
+		ln = ln->Next;
+	    }
+      }
+
+    if (out_type == GAIA_MULTIPOLYGON || out_type == GAIA_GEOMETRYCOLLECTION
+	|| out_type == GAIA_UNKNOWN)
+      {
+	  /* processing all Polygons */
+	  if (geom->FirstPolygon != NULL)
+	      goto error;
+      }
+
+    if (result->FirstPoint == NULL && result->FirstLinestring == NULL
+	&& result->FirstPolygon == NULL)
+	goto error;
+    return result;
+
+  error:
+    gaiaFreeGeomColl (result);
+    return NULL;
+}
+
+static int
+do_eval_toponet_seeds (struct gaia_network *net, sqlite3_stmt * stmt_ref,
+		       int ref_geom_col, sqlite3_stmt * stmt_ins,
+		       sqlite3_stmt * stmt_seed_link, sqlite3_stmt * stmt_node,
+		       sqlite3_stmt * stmt_link, int out_type)
+{
+/* querying the ref-table */
+    int ret;
+
+    sqlite3_reset (stmt_ref);
+    sqlite3_clear_bindings (stmt_ref);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_ref);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int icol;
+		int ncol = sqlite3_column_count (stmt_ref);
+		sqlite3_reset (stmt_ins);
+		sqlite3_clear_bindings (stmt_ins);
+		for (icol = 0; icol < ncol; icol++)
+		  {
+		      int col_type = sqlite3_column_type (stmt_ref, icol);
+		      if (icol == ref_geom_col)
+			{
+			    /* the geometry column */
+			    const unsigned char *blob =
+				sqlite3_column_blob (stmt_ref, icol);
+			    int blob_sz = sqlite3_column_bytes (stmt_ref, icol);
+			    gaiaGeomCollPtr geom =
+				gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+			    if (geom != NULL)
+			      {
+				  unsigned char *p_blob;
+				  int n_bytes;
+				  int gpkg_mode = 0;
+				  if (net->cache != NULL)
+				    {
+					struct splite_internal_cache *cache =
+					    (struct splite_internal_cache
+					     *) (net->cache);
+					gpkg_mode = cache->gpkg_mode;
+				    }
+				  gaiaGeomCollPtr result =
+				      do_eval_toponet_geom (net, geom,
+							    stmt_seed_link,
+							    stmt_node,
+							    stmt_link,
+							    out_type);
+				  gaiaFreeGeomColl (geom);
+				  if (result != NULL)
+				    {
+					gaiaToSpatiaLiteBlobWkbEx (result,
+								   &p_blob,
+								   &n_bytes,
+								   gpkg_mode);
+					gaiaFreeGeomColl (result);
+					sqlite3_bind_blob (stmt_ins, icol + 1,
+							   p_blob, n_bytes,
+							   free);
+				    }
+				  else
+				      sqlite3_bind_null (stmt_ins, icol + 1);
+			      }
+			    else
+				sqlite3_bind_null (stmt_ins, icol + 1);
+			    continue;
+			}
+		      switch (col_type)
+			{
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_ins, icol + 1,
+						sqlite3_column_int64 (stmt_ref,
+								      icol));
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_ins, icol + 1,
+						 sqlite3_column_double
+						 (stmt_ref, icol));
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_ins, icol + 1,
+					       (const char *)
+					       sqlite3_column_text (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			case SQLITE_BLOB:
+			    sqlite3_bind_blob (stmt_ins, icol + 1,
+					       sqlite3_column_blob (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_ins, icol + 1);
+			    break;
+			};
+		  }
+		ret = sqlite3_step (stmt_ins);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+					   sqlite3_errmsg (net->db_handle));
+		      gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr)
+						  net, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+				     sqlite3_errmsg (net->db_handle));
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+    return 1;
+}
+
+GAIANET_DECLARE int
+gaiaTopoNet_ToGeoTableGeneralize (GaiaNetworkAccessorPtr accessor,
+				  const char *db_prefix, const char *ref_table,
+				  const char *ref_column, const char *out_table,
+				  double tolerance, int with_spatial_index)
+{
+/* 
+/ attempting to create and populate a new GeoTable out from a Topology-Network
+/ (simplified/generalized version)
+*/
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt_ref = NULL;
+    sqlite3_stmt *stmt_ins = NULL;
+    sqlite3_stmt *stmt_seed_link = NULL;
+    sqlite3_stmt *stmt_node = NULL;
+    sqlite3_stmt *stmt_link = NULL;
+    int ret;
+    char *create;
+    char *select;
+    char *insert;
+    char *sql;
+    char *errMsg;
+    char *xprefix;
+    char *xtable;
+    int ref_type;
+    const char *type;
+    int out_type;
+    int ref_geom_col;
+    if (net == NULL)
+	return 0;
+
+/* incrementally updating all Topology Seeds */
+    if (!gaiaTopoNetUpdateSeeds (accessor, 1))
+	return 0;
+
+/* composing the CREATE TABLE output-table statement */
+    if (!auxtopo_create_togeotable_sql
+	(net->db_handle, db_prefix, ref_table, ref_column, out_table, &create,
+	 &select, &insert, &ref_geom_col))
+	goto error;
+
+/* creating the output-table */
+    ret = sqlite3_exec (net->db_handle, create, NULL, NULL, &errMsg);
+    sqlite3_free (create);
+    create = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* checking the Geometry Type */
+    if (!auxtopo_retrieve_geometry_type
+	(net->db_handle, db_prefix, ref_table, ref_column, &ref_type))
+	goto error;
+    switch (ref_type)
+      {
+      case GAIA_POINT:
+      case GAIA_POINTZ:
+      case GAIA_POINTM:
+      case GAIA_POINTZM:
+	  type = "POINT";
+	  out_type = GAIA_POINT;
+	  break;
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTIPOINTZM:
+	  type = "MULTIPOINT";
+	  out_type = GAIA_MULTIPOINT;
+	  break;
+      case GAIA_LINESTRING:
+      case GAIA_LINESTRINGZ:
+      case GAIA_LINESTRINGM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTILINESTRINGZM:
+	  type = "MULTILINESTRING";
+	  out_type = GAIA_MULTILINESTRING;
+	  break;
+      case GAIA_GEOMETRYCOLLECTION:
+      case GAIA_GEOMETRYCOLLECTIONZ:
+      case GAIA_GEOMETRYCOLLECTIONM:
+      case GAIA_GEOMETRYCOLLECTIONZM:
+	  type = "GEOMETRYCOLLECTION";
+	  out_type = GAIA_GEOMETRYCOLLECTION;
+	  break;
+      default:
+	  type = "GEOMETRY";
+	  out_type = GAIA_UNKNOWN;
+	  break;
+      };
+
+/* creating the output Geometry Column */
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(Lower(%Q), Lower(%Q), %d, '%s', '%s')",
+	 out_table, ref_column, net->srid, type,
+	 (net->has_z == 0) ? "XY" : "XYZ");
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    if (with_spatial_index)
+      {
+	  /* adding a Spatial Index supporting the Geometry Column */
+	  sql =
+	      sqlite3_mprintf
+	      ("SELECT CreateSpatialIndex(Lower(%Q), Lower(%Q))",
+	       out_table, ref_column);
+	  ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				     errMsg);
+		sqlite3_free (errMsg);
+		gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+/* preparing the "SELECT * FROM ref-table" query */
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, select, strlen (select), &stmt_ref,
+			    NULL);
+    sqlite3_free (select);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO out-table" query */
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, insert, strlen (insert), &stmt_ins,
+			    NULL);
+    sqlite3_free (insert);
+    insert = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Seed-Links query */
+    xprefix = sqlite3_mprintf ("%s_seeds", net->network_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT link_id FROM MAIN.\"%s\" "
+			   "WHERE ST_Intersects(geometry, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_seed_link,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Nodes query */
+    xprefix = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT geometry FROM MAIN.\"%s\" "
+			   "WHERE ST_Intersects(geometry, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_node,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Links query */
+    xprefix = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    if (tolerance > 0.0)
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT ST_SimplifyPreserveTopology(geometry, %1.6f) FROM MAIN.\"%s\" WHERE link_id = ?",
+	     tolerance, xtable, xprefix);
+    else
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT geometry FROM MAIN.\"%s\" WHERE link_id = ?", xtable,
+	     xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_link,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* evaluating feature/topology matching via coincident topo-seeds */
+    if (!do_eval_toponet_seeds
+	(net, stmt_ref, ref_geom_col, stmt_ins, stmt_seed_link, stmt_node,
+	 stmt_link, out_type))
+	goto error;
+
+    sqlite3_finalize (stmt_ref);
+    sqlite3_finalize (stmt_ins);
+    sqlite3_finalize (stmt_seed_link);
+    sqlite3_finalize (stmt_node);
+    sqlite3_finalize (stmt_link);
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    if (stmt_ref != NULL)
+	sqlite3_finalize (stmt_ref);
+    if (stmt_ins != NULL)
+	sqlite3_finalize (stmt_ins);
+    if (stmt_seed_link != NULL)
+	sqlite3_finalize (stmt_seed_link);
+    if (stmt_node != NULL)
+	sqlite3_finalize (stmt_node);
+    if (stmt_link != NULL)
+	sqlite3_finalize (stmt_link);
+    return 0;
+}
+
+GAIANET_DECLARE int
+gaiaTopoNet_ToGeoTable (GaiaNetworkAccessorPtr accessor,
+			const char *db_prefix, const char *ref_table,
+			const char *ref_column, const char *out_table,
+			int with_spatial_index)
+{
+/* attempting to create and populate a new GeoTable out from a Topology-Network */
+    return gaiaTopoNet_ToGeoTableGeneralize (accessor, db_prefix, ref_table,
+					     ref_column, out_table, -1.0,
+					     with_spatial_index);
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/gaia_auxtopo.c b/src/topology/gaia_auxtopo.c
new file mode 100644
index 0000000..d8552fb
--- /dev/null
+++ b/src/topology/gaia_auxtopo.c
@@ -0,0 +1,10507 @@
+/*
+
+ gaia_auxtopo.c -- implementation of the Topology module methods
+    
+ version 4.3, 2015 July 15
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/*
+ 
+CREDITS:
+
+this module has been completely funded by: 
+Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
+(Topology support) 
+
+CIG: 6038019AE5
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaia_topology.h>
+#include <spatialite/gaia_network.h>
+#include <spatialite/gaiaaux.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+
+#include <liblwgeom.h>
+#include <liblwgeom_topo.h>
+
+#include <lwn_network.h>
+
+#include "topology_private.h"
+#include "network_private.h"
+
+#define GAIA_UNUSED() if (argc || argv) argc = argc;
+
+SPATIALITE_PRIVATE void
+free_internal_cache_topologies (void *firstTopology)
+{
+/* destroying all Topologies registered into the Internal Connection Cache */
+    struct gaia_topology *p_topo = (struct gaia_topology *) firstTopology;
+    struct gaia_topology *p_topo_n;
+
+    while (p_topo != NULL)
+      {
+	  p_topo_n = p_topo->next;
+	  gaiaTopologyDestroy ((GaiaTopologyAccessorPtr) p_topo);
+	  p_topo = p_topo_n;
+      }
+}
+
+static int
+do_create_topologies (sqlite3 * handle)
+{
+/* attempting to create the Topologies table (if not already existing) */
+    const char *sql;
+    char *err_msg = NULL;
+    int ret;
+
+    sql = "CREATE TABLE IF NOT EXISTS topologies (\n"
+	"\ttopology_name TEXT NOT NULL PRIMARY KEY,\n"
+	"\tsrid INTEGER NOT NULL,\n"
+	"\ttolerance DOUBLE NOT NULL,\n"
+	"\thas_z INTEGER NOT NULL,\n"
+	"\tnext_edge_id INTEGER NOT NULL DEFAULT 1,\n"
+	"\tCONSTRAINT topo_srid_fk FOREIGN KEY (srid) "
+	"REFERENCES spatial_ref_sys (srid))";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topologies - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating Topologies triggers */
+    sql = "CREATE TRIGGER IF NOT EXISTS topology_name_insert\n"
+	"BEFORE INSERT ON 'topologies'\nFOR EACH ROW BEGIN\n"
+	"SELECT RAISE(ABORT,'insert on topologies violates constraint: "
+	"topology_name value must not contain a single quote')\n"
+	"WHERE NEW.topology_name LIKE ('%''%');\n"
+	"SELECT RAISE(ABORT,'insert on topologies violates constraint: "
+	"topology_name value must not contain a double quote')\n"
+	"WHERE NEW.topology_name LIKE ('%\"%');\n"
+	"SELECT RAISE(ABORT,'insert on topologies violates constraint: "
+	"topology_name value must be lower case')\n"
+	"WHERE NEW.topology_name <> lower(NEW.topology_name);\nEND";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SQL error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+    sql = "CREATE TRIGGER IF NOT EXISTS topology_name_update\n"
+	"BEFORE UPDATE OF 'topology_name' ON 'topologies'\nFOR EACH ROW BEGIN\n"
+	"SELECT RAISE(ABORT,'update on topologies violates constraint: "
+	"topology_name value must not contain a single quote')\n"
+	"WHERE NEW.topology_name LIKE ('%''%');\n"
+	"SELECT RAISE(ABORT,'update on topologies violates constraint: "
+	"topology_name value must not contain a double quote')\n"
+	"WHERE NEW.topology_name LIKE ('%\"%');\n"
+	"SELECT RAISE(ABORT,'update on topologies violates constraint: "
+	"topology_name value must be lower case')\n"
+	"WHERE NEW.topology_name <> lower(NEW.topology_name);\nEND";
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SQL error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+check_new_topology (sqlite3 * handle, const char *topo_name)
+{
+/* testing if some already defined DB object forbids creating the new Topology */
+    char *sql;
+    char *prev;
+    char *table;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *value;
+    int error = 0;
+
+/* testing if the same Topology is already defined */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.topologies WHERE "
+			   "Lower(topology_name) = Lower(%Q)", topo_name);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if some table/geom is already defined in geometry_columns */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM geometry_columns WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'mbr')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if some Spatial View is already defined in views_geometry_columns */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM views_geometry_columns WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_geoms", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'mbr')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_seeds", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if some table is already defined */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM sqlite_master WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_topolayers", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_topofeatures", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_node_geom", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_edge_geom", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_face_mbr", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_seeds_geom", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_geoms", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_seeds", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 0)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+    return 1;
+}
+
+static int
+do_create_face (sqlite3 * handle, const char *topo_name, int srid)
+{
+/* attempting to create the Topology Face table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tface_id INTEGER PRIMARY KEY AUTOINCREMENT)",
+			   xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topology-FACE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Face BBOX Geometry */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'mbr', %d, 'POLYGON', 'XY')",
+	 table, srid);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn topology-FACE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Face Geometry */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'mbr')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex topology-FACE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* inserting the default World Face */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" VALUES (0, NULL)", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("INSERT WorldFACE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_node (sqlite3 * handle, const char *topo_name, int srid, int has_z)
+{
+/* attempting to create the Topology Node table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xconstraint;
+    char *xmother;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node_face_fk", topo_name);
+    xconstraint = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xmother = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tnode_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\tcontaining_face INTEGER,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (containing_face) "
+			   "REFERENCES \"%s\" (face_id))", xtable, xconstraint,
+			   xmother);
+    free (xtable);
+    free (xconstraint);
+    free (xmother);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topology-NODE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Node Geometry */
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'geom', %d, 'POINT', %Q, 1)", table,
+	 srid, has_z ? "XYZ" : "XY");
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn topology-NODE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Node Geometry */
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geom')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex topology-NODE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "containing_face" */
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_node_contface", topo_name);
+    xconstraint = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (containing_face)",
+			 xconstraint, xtable);
+    free (xtable);
+    free (xconstraint);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX node-contface - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_edge (sqlite3 * handle, const char *topo_name, int srid, int has_z)
+{
+/* attempting to create the Topology Edge table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xconstraint1;
+    char *xconstraint2;
+    char *xconstraint3;
+    char *xconstraint4;
+    char *xnodes;
+    char *xfaces;
+    char *trigger;
+    char *xtrigger;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge_node_start_fk", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge_node_end_fk", topo_name);
+    xconstraint2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge_face_left_fk", topo_name);
+    xconstraint3 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge_face_right_fk", topo_name);
+    xconstraint4 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    xnodes = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xfaces = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tedge_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\tstart_node INTEGER NOT NULL,\n"
+			   "\tend_node INTEGER NOT NULL,\n"
+			   "\tnext_left_edge INTEGER NOT NULL,\n"
+			   "\tnext_right_edge INTEGER NOT NULL,\n"
+			   "\tleft_face INTEGER NOT NULL,\n"
+			   "\tright_face INTEGER NOT NULL,\n"
+			   "\ttimestamp DATETIME,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (start_node) "
+			   "REFERENCES \"%s\" (node_id),\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (end_node) "
+			   "REFERENCES \"%s\" (node_id),\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (left_face) "
+			   "REFERENCES \"%s\" (face_id),\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (right_face) "
+			   "REFERENCES \"%s\" (face_id))",
+			   xtable, xconstraint1, xnodes, xconstraint2, xnodes,
+			   xconstraint3, xfaces, xconstraint4, xfaces);
+    free (xtable);
+    free (xconstraint1);
+    free (xconstraint2);
+    free (xconstraint3);
+    free (xconstraint4);
+    free (xnodes);
+    free (xfaces);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topology-EDGE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "next_edge_ins" trigger */
+    trigger = sqlite3_mprintf ("%s_edge_next_ins", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE topologies SET next_edge_id = NEW.edge_id + 1 "
+			   "WHERE Lower(topology_name) = Lower(%Q) AND next_edge_id < NEW.edge_id + 1;\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE edge_id = NEW.edge_id;"
+			   "END", xtrigger, xtable, topo_name, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER topology-EDGE next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "edge_update" trigger */
+    trigger = sqlite3_mprintf ("%s_edge_update", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE edge_id = NEW.edge_id;"
+			   "END", xtrigger, xtable, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER topology-EDGE next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "next_edge_upd" trigger */
+    trigger = sqlite3_mprintf ("%s_edge_next_upd", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TRIGGER \"%s\" AFTER UPDATE OF edge_id ON \"%s\"\n"
+	 "FOR EACH ROW BEGIN\n"
+	 "\tUPDATE topologies SET next_edge_id = NEW.edge_id + 1 "
+	 "WHERE Lower(topology_name) = Lower(%Q) AND next_edge_id < NEW.edge_id + 1;\n"
+	 "END", xtrigger, xtable, topo_name);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER topology-EDGE next UPDATE - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Edge Geometry */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'geom', %d, 'LINESTRING', %Q, 1)",
+	 table, srid, has_z ? "XYZ" : "XY");
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn topology-EDGE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Edge Geometry */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geom')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex topology-EDGE - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "start_node" */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_start_node", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (start_node)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX edge-startnode - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "end_node" */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_end_node", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (end_node)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX edge-endnode - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "left_face" */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_edge_leftface", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (left_face)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX edge-leftface - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "right_face" */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_edge_rightface", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (right_face)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX edge-rightface - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "timestamp" */
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_timestamp", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX edge-timestamps - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_seeds (sqlite3 * handle, const char *topo_name, int srid, int has_z)
+{
+/* attempting to create the Topology Seeds table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xconstraint1;
+    char *xconstraint2;
+    char *xedges;
+    char *xfaces;
+    char *trigger;
+    char *xtrigger;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_seeds_edge_fk", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_seeds_face_fk", topo_name);
+    xconstraint2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xedges = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xfaces = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tseed_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\tedge_id INTEGER,\n"
+			   "\tface_id INTEGER,\n"
+			   "\ttimestamp DATETIME,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (edge_id) "
+			   "REFERENCES \"%s\" (edge_id) ON DELETE CASCADE,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (face_id) "
+			   "REFERENCES \"%s\" (face_id) ON DELETE CASCADE)",
+			   xtable, xconstraint1, xedges, xconstraint2, xfaces);
+    free (xtable);
+    free (xconstraint1);
+    free (xconstraint2);
+    free (xedges);
+    free (xfaces);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topology-SEEDS - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "seeds_ins" trigger */
+    trigger = sqlite3_mprintf ("%s_seeds_ins", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE seed_id = NEW.seed_id;"
+			   "END", xtrigger, xtable, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER topology-SEEDS next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* adding the "seeds_update" trigger */
+    trigger = sqlite3_mprintf ("%s_seeds_update", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (trigger);
+    sqlite3_free (trigger);
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
+			   "FOR EACH ROW BEGIN\n"
+			   "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+			   "WHERE seed_id = NEW.seed_id;"
+			   "END", xtrigger, xtable, xtable);
+    free (xtrigger);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CREATE TRIGGER topology-SEED next INSERT - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating the Seeds Geometry */
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(%Q, 'geom', %d, 'POINT', %Q, 1)",
+	 table, srid, has_z ? "XYZ" : "XY");
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("AddGeometryColumn topology-SEEDS - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating a Spatial Index supporting Seeds Geometry */
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geom')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("CreateSpatialIndex topology-SEEDS - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "edge_id" */
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_sdedge", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_id)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX seeds-edge - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "face_id" */
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_sdface", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (face_id)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX seeds-face - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "timestamp" */
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_seeds_timestamp", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX seeds-timestamps - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_edge_seeds (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to create the Edge Seeds view */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xview;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the view */
+    table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
+    xview = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
+			   "SELECT seed_id AS rowid, edge_id AS edge_id, geom AS geom\n"
+			   "FROM \"%s\"\n"
+			   "WHERE edge_id IS NOT NULL", xview, xtable);
+    free (xtable);
+    free (xview);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE VIEW topology-EDGE-SEEDS - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* registering a Spatial View */
+    xview = sqlite3_mprintf ("%s_edge_seeds", topo_name);
+    xtable = sqlite3_mprintf ("%s_seeds", topo_name);
+    sql = sqlite3_mprintf ("INSERT INTO views_geometry_columns (view_name, "
+			   "view_geometry, view_rowid, f_table_name, f_geometry_column, read_only) "
+			   "VALUES (Lower(%Q), 'geom', 'rowid', Lower(%Q), 'geom', 1)",
+			   xview, xtable);
+    sqlite3_free (xview);
+    sqlite3_free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("Registering Spatial VIEW topology-EDGE-SEEDS - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_face_seeds (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to create the Face Seeds view */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xview;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the view */
+    table = sqlite3_mprintf ("%s_face_seeds", topo_name);
+    xview = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_seeds", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
+			   "SELECT seed_id AS rowid, face_id AS face_id, geom AS geom\n"
+			   "FROM \"%s\"\n"
+			   "WHERE face_id IS NOT NULL", xview, xtable);
+    free (xtable);
+    free (xview);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE VIEW topology-FACE-SEEDS - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* registering a Spatial View */
+    xview = sqlite3_mprintf ("%s_face_seeds", topo_name);
+    xtable = sqlite3_mprintf ("%s_seeds", topo_name);
+    sql = sqlite3_mprintf ("INSERT INTO views_geometry_columns (view_name, "
+			   "view_geometry, view_rowid, f_table_name, f_geometry_column, read_only) "
+			   "VALUES (Lower(%Q), 'geom', 'rowid', Lower(%Q), 'geom', 1)",
+			   xview, xtable);
+    sqlite3_free (xview);
+    sqlite3_free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("Registering Spatial VIEW topology-FACE-SEEDS - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_face_geoms (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to create the Face Geoms view */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xview;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the view */
+    table = sqlite3_mprintf ("%s_face_geoms", topo_name);
+    xview = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
+			   "SELECT face_id AS rowid, ST_GetFaceGeometry(%Q, face_id) AS geom\n"
+			   "FROM \"%s\"\n"
+			   "WHERE face_id <> 0", xview, topo_name, xtable);
+    free (xtable);
+    free (xview);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE VIEW topology-FACE-GEOMS - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* registering a Spatial View */
+    xview = sqlite3_mprintf ("%s_face_geoms", topo_name);
+    xtable = sqlite3_mprintf ("%s_face", topo_name);
+    sql = sqlite3_mprintf ("INSERT INTO views_geometry_columns (view_name, "
+			   "view_geometry, view_rowid, f_table_name, f_geometry_column, read_only) "
+			   "VALUES (Lower(%Q), 'geom', 'rowid', Lower(%Q), 'mbr', 1)",
+			   xview, xtable);
+    sqlite3_free (xview);
+    sqlite3_free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("Registering Spatial VIEW topology-FACE-GEOMS - error: %s\n",
+	       err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_topolayers (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to create the TopoLayers table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xtrigger;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_topolayers", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\ttopolayer_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\ttopolayer_name NOT NULL UNIQUE)", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topology-TOPOLAYERS - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating TopoLayers triggers */
+    table = sqlite3_mprintf ("%s_topolayers", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_topolayer_name_insert", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER IF NOT EXISTS \"%s\"\n"
+			   "BEFORE INSERT ON \"%s\"\nFOR EACH ROW BEGIN\n"
+			   "SELECT RAISE(ABORT,'insert on topolayers violates constraint: "
+			   "topolayer_name value must not contain a single quote')\n"
+			   "WHERE NEW.topolayer_name LIKE ('%%''%%');\n"
+			   "SELECT RAISE(ABORT,'insert on topolayers violates constraint: "
+			   "topolayers_name value must not contain a double quote')\n"
+			   "WHERE NEW.topolayer_name LIKE ('%%\"%%');\n"
+			   "SELECT RAISE(ABORT,'insert on topolayers violates constraint: "
+			   "topolayer_name value must be lower case')\n"
+			   "WHERE NEW.topolayer_name <> lower(NEW.topolayer_name);\nEND",
+			   xtrigger, xtable);
+    free (xtable);
+    free (xtrigger);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SQL error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+    table = sqlite3_mprintf ("%s_topolayers", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_topolayer_name_update", topo_name);
+    xtrigger = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TRIGGER IF NOT EXISTS \"%s\"\n"
+			   "BEFORE UPDATE OF 'topolayer_name' ON \"%s\"\nFOR EACH ROW BEGIN\n"
+			   "SELECT RAISE(ABORT,'update on topolayers violates constraint: "
+			   "topolayer_name value must not contain a single quote')\n"
+			   "WHERE NEW.topolayer_name LIKE ('%%''%%');\n"
+			   "SELECT RAISE(ABORT,'update on topolayers violates constraint: "
+			   "topolayer_name value must not contain a double quote')\n"
+			   "WHERE NEW.topolayer_name LIKE ('%%\"%%');\n"
+			   "SELECT RAISE(ABORT,'update on topolayers violates constraint: "
+			   "topolayer_name value must be lower case')\n"
+			   "WHERE NEW.topolayer_name <> lower(NEW.topolayer_name);\nEND",
+			   xtrigger, xtable);
+    free (xtable);
+    free (xtrigger);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SQL error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_create_topofeatures (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to create the TopoFeatures table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xtable1;
+    char *xtable2;
+    char *xtable3;
+    char *xtable4;
+    char *xconstraint1;
+    char *xconstraint2;
+    char *xconstraint3;
+    char *xconstraint4;
+    char *err_msg = NULL;
+    int ret;
+
+/* creating the main table */
+    table = sqlite3_mprintf ("%s_topofeatures", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xtable3 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_topolayers", topo_name);
+    xtable4 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("fk_%s_ftnode", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("fk_%s_ftedge", topo_name);
+    xconstraint2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("fk_%s_ftface", topo_name);
+    xconstraint3 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("fk_%s_topolayer", topo_name);
+    xconstraint4 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
+			   "\tuid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+			   "\tnode_id INTEGER,\n\tedge_id INTEGER,\n"
+			   "\tface_id INTEGER,\n\ttopolayer_id INTEGER NOT NULL,\n"
+			   "\tfid INTEGER NOT NULL,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (node_id) "
+			   "REFERENCES \"%s\" (node_id) ON DELETE CASCADE,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (edge_id) "
+			   "REFERENCES \"%s\" (edge_id) ON DELETE CASCADE,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (face_id) "
+			   "REFERENCES \"%s\" (face_id) ON DELETE CASCADE,\n"
+			   "\tCONSTRAINT \"%s\" FOREIGN KEY (topolayer_id) "
+			   "REFERENCES \"%s\" (topolayer_id) ON DELETE CASCADE)",
+			   xtable, xconstraint1, xtable1, xconstraint2, xtable2,
+			   xconstraint3, xtable3, xconstraint4, xtable4);
+    free (xtable);
+    free (xtable1);
+    free (xtable2);
+    free (xtable3);
+    free (xtable4);
+    free (xconstraint1);
+    free (xconstraint2);
+    free (xconstraint3);
+    free (xconstraint4);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE TABLE topology-TOPOFEATURES - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "node_id" */
+    table = sqlite3_mprintf ("%s_topofeatures", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_ftnode", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (node_id)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX topofeatures-node - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "edge_id" */
+    table = sqlite3_mprintf ("%s_topofeatures", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_ftedge", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_id)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX topofeatures-edge - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "face_id" */
+    table = sqlite3_mprintf ("%s_topofeatures", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_ftface", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (face_id)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX topofeatures-face - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* creating an Index supporting "topolayers_id" */
+    table = sqlite3_mprintf ("%s_topofeatures", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("idx_%s_fttopolayers", topo_name);
+    xconstraint1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (topolayer_id, fid)",
+			 xconstraint1, xtable);
+    free (xtable);
+    free (xconstraint1);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("CREATE INDEX topofeatures-topolayers - error: %s\n",
+			err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopologyCreate (sqlite3 * handle, const char *topo_name, int srid,
+		    double tolerance, int has_z)
+{
+/* attempting to create a new Topology */
+    int ret;
+    char *sql;
+
+/* creating the Topologies table (just in case) */
+    if (!do_create_topologies (handle))
+	return 0;
+
+/* testing for forbidding objects */
+    if (!check_new_topology (handle, topo_name))
+	return 0;
+
+/* creating the Topology own Tables */
+    if (!do_create_face (handle, topo_name, srid))
+	goto error;
+    if (!do_create_node (handle, topo_name, srid, has_z))
+	goto error;
+    if (!do_create_edge (handle, topo_name, srid, has_z))
+	goto error;
+    if (!do_create_seeds (handle, topo_name, srid, has_z))
+	goto error;
+    if (!do_create_edge_seeds (handle, topo_name))
+	goto error;
+    if (!do_create_face_seeds (handle, topo_name))
+	goto error;
+    if (!do_create_face_geoms (handle, topo_name))
+	goto error;
+    if (!do_create_topolayers (handle, topo_name))
+	goto error;
+    if (!do_create_topofeatures (handle, topo_name))
+	goto error;
+
+/* registering the Topology */
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.topologies (topology_name, "
+			   "srid, tolerance, has_z) VALUES (Lower(%Q), %d, %f, %d)",
+			   topo_name, srid, tolerance, has_z);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+
+    return 1;
+
+  error:
+    return 0;
+}
+
+static int
+check_existing_topology (sqlite3 * handle, const char *topo_name,
+			 int full_check)
+{
+/* testing if a Topology is already defined */
+    char *sql;
+    char *prev;
+    char *table;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *value;
+    int error = 0;
+
+/* testing if the Topology is already defined */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.topologies WHERE "
+			   "Lower(topology_name) = Lower(%Q)", topo_name);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 1)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+    if (!full_check)
+	return 1;
+
+/* testing if all table/geom are correctly defined in geometry_columns */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM geometry_columns WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'mbr')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 3)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+/* testing if all Spatial Views are correctly defined in geometry_columns */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM views_geometry_columns WHERE");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s (Lower(view_name) = Lower(%Q) AND view_geometry = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_seeds", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(view_name) = Lower(%Q) AND view_geometry = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_geoms", topo_name);
+    sql =
+	sqlite3_mprintf
+	("%s OR (Lower(view_name) = Lower(%Q) AND view_geometry = 'geom')",
+	 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 3)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+
+/* testing if all tables are already defined */
+    sql =
+	sqlite3_mprintf
+	("SELECT Count(*) FROM sqlite_master WHERE (type = 'table' AND (");
+    prev = sql;
+    table = sqlite3_mprintf ("%s_node", topo_name);
+    sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_node_geom", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_edge_geom", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("idx_%s_face_mbr", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)))", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
+    sql =
+	sqlite3_mprintf ("%s OR (type = 'view' AND (Lower(name) = Lower(%Q)",
+			 prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_seeds", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    prev = sql;
+    table = sqlite3_mprintf ("%s_face_geoms", topo_name);
+    sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)))", prev, table);
+    sqlite3_free (table);
+    sqlite3_free (prev);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		value = results[(i * columns) + 0];
+		if (atoi (value) != 9)
+		    error = 1;
+	    }
+      }
+    sqlite3_free_table (results);
+    if (error)
+	return 0;
+
+    return 1;
+}
+
+static int
+do_drop_topo_face (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to drop the Topology-Face table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *err_msg = NULL;
+    int ret;
+
+/* disabling the corresponding Spatial Index */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql = sqlite3_mprintf ("SELECT DisableSpatialIndex(%Q, 'mbr')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("DisableSpatialIndex topology-face - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* discarding the Geometry column */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    sql = sqlite3_mprintf ("SELECT DiscardGeometryColumn(%Q, 'mbr')", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("DisableGeometryColumn topology-face - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* dropping the main table */
+    table = sqlite3_mprintf ("%s_face", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("DROP topology-face - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+/* dropping the corresponding Spatial Index */
+    table = sqlite3_mprintf ("idx_%s_face_mbr", topo_name);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (table);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e
+	      ("DROP SpatialIndex topology-face - error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_drop_topo_table (sqlite3 * handle, const char *topo_name, const char *which,
+		    int spatial)
+{
+/* attempting to drop some Topology table */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *err_msg = NULL;
+    int ret;
+
+    if (strcmp (which, "face") == 0)
+	return do_drop_topo_face (handle, topo_name);
+
+    if (spatial)
+      {
+	  /* disabling the corresponding Spatial Index */
+	  table = sqlite3_mprintf ("%s_%s", topo_name, which);
+	  sql =
+	      sqlite3_mprintf ("SELECT DisableSpatialIndex(%Q, 'geom')", table);
+	  ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+	  sqlite3_free (table);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		spatialite_e
+		    ("DisableSpatialIndex topology-%s - error: %s\n", which,
+		     err_msg);
+		sqlite3_free (err_msg);
+		return 0;
+	    }
+	  /* discarding the Geometry column */
+	  table = sqlite3_mprintf ("%s_%s", topo_name, which);
+	  sql =
+	      sqlite3_mprintf ("SELECT DiscardGeometryColumn(%Q, 'geom')",
+			       table);
+	  ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+	  sqlite3_free (table);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		spatialite_e
+		    ("DisableGeometryColumn topology-%s - error: %s\n", which,
+		     err_msg);
+		sqlite3_free (err_msg);
+		return 0;
+	    }
+      }
+
+/* dropping the main table */
+    table = sqlite3_mprintf ("%s_%s", topo_name, which);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("DROP topology-%s - error: %s\n", which, err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    if (spatial)
+      {
+	  /* dropping the corresponding Spatial Index */
+	  table = sqlite3_mprintf ("idx_%s_%s_geom", topo_name, which);
+	  sql = sqlite3_mprintf ("DROP TABLE IF EXISTS MAIN.\"%s\"", table);
+	  ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+	  sqlite3_free (table);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		spatialite_e
+		    ("DROP SpatialIndex topology-%s - error: %s\n", which,
+		     err_msg);
+		sqlite3_free (err_msg);
+		return 0;
+	    }
+      }
+
+    return 1;
+}
+
+static int
+do_drop_topo_view (sqlite3 * handle, const char *topo_name, const char *which)
+{
+/* attempting to drop some Topology view */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *err_msg = NULL;
+    int ret;
+
+/* unregistering the Spatial View */
+    table = sqlite3_mprintf ("%s_%s", topo_name, which);
+    sql =
+	sqlite3_mprintf
+	("DELETE FROM views_geometry_columns WHERE view_name = Lower(%Q)",
+	 table);
+    sqlite3_free (table);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("Unregister Spatial View -%s - error: %s\n", which,
+			err_msg);
+	  sqlite3_free (err_msg);
+      }
+
+/* dropping the view */
+    table = sqlite3_mprintf ("%s_%s", topo_name, which);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP VIEW IF EXISTS MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("DROP topology-%s - error: %s\n", which, err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_drop_topofeature_tables (sqlite3 * handle, const char *topo_name)
+{
+/* dropping any eventual topofeatures table */
+    char *table;
+    char *xtable;
+    char *sql;
+    char *err_msg = NULL;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+
+    table = sqlite3_mprintf ("%s_topolayers", topo_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT topolayer_id FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 1;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		const char *id = results[(i * columns) + 0];
+		table = sqlite3_mprintf ("%s_topofeatures_%s", topo_name, id);
+		xtable = gaiaDoubleQuotedSql (table);
+		sqlite3_free (table);
+		sql =
+		    sqlite3_mprintf ("DROP TABLE IF EXISTS MAIN.\"%s\"",
+				     xtable);
+		free (xtable);
+		ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
+		sqlite3_free (sql);
+		if (ret != SQLITE_OK)
+		  {
+		      spatialite_e ("DROP topology-features (%s) - error: %s\n",
+				    id, err_msg);
+		      sqlite3_free (err_msg);
+		      return 0;
+		  }
+	    }
+      }
+    sqlite3_free_table (results);
+    return 1;
+}
+
+static int
+do_get_topology (sqlite3 * handle, const char *topo_name, char **topology_name,
+		 int *srid, double *tolerance, int *has_z)
+{
+/* retrieving a Topology configuration */
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    int ok = 0;
+    char *xtopology_name = NULL;
+    int xsrid;
+    double xtolerance;
+    int xhas_z;
+
+/* preparing the SQL query */
+    sql =
+	sqlite3_mprintf
+	("SELECT topology_name, srid, tolerance, has_z FROM MAIN.topologies WHERE "
+	 "Lower(topology_name) = Lower(%Q)", topo_name);
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM topologys error: \"%s\"\n",
+			sqlite3_errmsg (handle));
+	  return 0;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_name = 0;
+		int ok_srid = 0;
+		int ok_tolerance = 0;
+		int ok_z = 0;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
+		  {
+		      const char *str =
+			  (const char *) sqlite3_column_text (stmt, 0);
+		      if (xtopology_name != NULL)
+			  free (xtopology_name);
+		      xtopology_name = malloc (strlen (str) + 1);
+		      strcpy (xtopology_name, str);
+		      ok_name = 1;
+		  }
+		if (sqlite3_column_type (stmt, 1) == SQLITE_INTEGER)
+		  {
+		      xsrid = sqlite3_column_int (stmt, 1);
+		      ok_srid = 1;
+		  }
+		if (sqlite3_column_type (stmt, 2) == SQLITE_FLOAT)
+		  {
+		      xtolerance = sqlite3_column_double (stmt, 2);
+		      ok_tolerance = 1;
+		  }
+		if (sqlite3_column_type (stmt, 3) == SQLITE_INTEGER)
+		  {
+		      xhas_z = sqlite3_column_int (stmt, 3);
+		      ok_z = 1;
+		  }
+		if (ok_name && ok_srid && ok_tolerance && ok_z)
+		  {
+		      ok = 1;
+		      break;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e
+		    ("step: SELECT FROM topologies error: \"%s\"\n",
+		     sqlite3_errmsg (handle));
+		sqlite3_finalize (stmt);
+		return 0;
+	    }
+      }
+    sqlite3_finalize (stmt);
+
+    if (ok)
+      {
+	  *topology_name = xtopology_name;
+	  *srid = xsrid;
+	  *tolerance = xtolerance;
+	  *has_z = xhas_z;
+	  return 1;
+      }
+
+    if (xtopology_name != NULL)
+	free (xtopology_name);
+    return 0;
+}
+
+GAIATOPO_DECLARE GaiaTopologyAccessorPtr
+gaiaGetTopology (sqlite3 * handle, const void *cache, const char *topo_name)
+{
+/* attempting to get a reference to some Topology Accessor Object */
+    GaiaTopologyAccessorPtr accessor;
+
+/* attempting to retrieve an alredy cached definition */
+    accessor = gaiaTopologyFromCache (cache, topo_name);
+    if (accessor != NULL)
+	return accessor;
+
+/* attempting to create a new Topology Accessor */
+    accessor = gaiaTopologyFromDBMS (handle, cache, topo_name);
+    return accessor;
+}
+
+GAIATOPO_DECLARE GaiaTopologyAccessorPtr
+gaiaTopologyFromCache (const void *p_cache, const char *topo_name)
+{
+/* attempting to retrieve an already defined Topology Accessor Object from the Connection Cache */
+    struct gaia_topology *ptr;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) p_cache;
+    if (cache == 0)
+	return NULL;
+
+    ptr = (struct gaia_topology *) (cache->firstTopology);
+    while (ptr != NULL)
+      {
+	  /* checking for an already registered Topology */
+	  if (strcasecmp (topo_name, ptr->topology_name) == 0)
+	      return (GaiaTopologyAccessorPtr) ptr;
+	  ptr = ptr->next;
+      }
+    return NULL;
+}
+
+GAIATOPO_DECLARE int
+gaiaReadTopologyFromDBMS (sqlite3 *
+			  handle,
+			  const char
+			  *topo_name, char **topology_name, int *srid,
+			  double *tolerance, int *has_z)
+{
+/* testing for existing DBMS objects */
+    if (!check_existing_topology (handle, topo_name, 1))
+	return 0;
+
+/* retrieving the Topology configuration */
+    if (!do_get_topology
+	(handle, topo_name, topology_name, srid, tolerance, has_z))
+	return 0;
+    return 1;
+}
+
+GAIATOPO_DECLARE GaiaTopologyAccessorPtr
+gaiaTopologyFromDBMS (sqlite3 * handle, const void *p_cache,
+		      const char *topo_name)
+{
+/* attempting to create a Topology Accessor Object into the Connection Cache */
+    LWT_BE_CALLBACKS *callbacks;
+    struct gaia_topology *ptr;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) p_cache;
+    if (cache == 0)
+	return NULL;
+
+/* allocating and initializing the opaque object */
+    ptr = malloc (sizeof (struct gaia_topology));
+    ptr->db_handle = handle;
+    ptr->cache = cache;
+    ptr->topology_name = NULL;
+    ptr->srid = -1;
+    ptr->tolerance = 0;
+    ptr->has_z = 0;
+    ptr->inside_lwt_callback = 0;
+    ptr->last_error_message = NULL;
+    ptr->lwt_iface = lwt_CreateBackendIface ((const LWT_BE_DATA *) ptr);
+    ptr->prev = cache->lastTopology;
+    ptr->next = NULL;
+
+    callbacks = malloc (sizeof (LWT_BE_CALLBACKS));
+    callbacks->lastErrorMessage = callback_lastErrorMessage;
+    callbacks->topoGetSRID = callback_topoGetSRID;
+    callbacks->topoGetPrecision = callback_topoGetPrecision;
+    callbacks->topoHasZ = callback_topoHasZ;
+    callbacks->createTopology = NULL;
+    callbacks->loadTopologyByName = callback_loadTopologyByName;
+    callbacks->freeTopology = callback_freeTopology;
+    callbacks->getNodeById = callback_getNodeById;
+    callbacks->getNodeWithinDistance2D = callback_getNodeWithinDistance2D;
+    callbacks->insertNodes = callback_insertNodes;
+    callbacks->getEdgeById = callback_getEdgeById;
+    callbacks->getEdgeWithinDistance2D = callback_getEdgeWithinDistance2D;
+    callbacks->getNextEdgeId = callback_getNextEdgeId;
+    callbacks->insertEdges = callback_insertEdges;
+    callbacks->updateEdges = callback_updateEdges;
+    callbacks->getFaceById = callback_getFaceById;
+    callbacks->getFaceContainingPoint = callback_getFaceContainingPoint;
+    callbacks->deleteEdges = callback_deleteEdges;
+    callbacks->getNodeWithinBox2D = callback_getNodeWithinBox2D;
+    callbacks->getEdgeWithinBox2D = callback_getEdgeWithinBox2D;
+    callbacks->getEdgeByNode = callback_getEdgeByNode;
+    callbacks->updateNodes = callback_updateNodes;
+    callbacks->insertFaces = callback_insertFaces;
+    callbacks->updateFacesById = callback_updateFacesById;
+    callbacks->deleteFacesById = callback_deleteFacesById;
+    callbacks->getRingEdges = callback_getRingEdges;
+    callbacks->updateEdgesById = callback_updateEdgesById;
+    callbacks->getEdgeByFace = callback_getEdgeByFace;
+    callbacks->getNodeByFace = callback_getNodeByFace;
+    callbacks->updateNodesById = callback_updateNodesById;
+    callbacks->deleteNodesById = callback_deleteNodesById;
+    callbacks->updateTopoGeomEdgeSplit = callback_updateTopoGeomEdgeSplit;
+    callbacks->updateTopoGeomFaceSplit = callback_updateTopoGeomFaceSplit;
+    callbacks->checkTopoGeomRemEdge = callback_checkTopoGeomRemEdge;
+    callbacks->updateTopoGeomFaceHeal = callback_updateTopoGeomFaceHeal;
+    callbacks->checkTopoGeomRemNode = callback_checkTopoGeomRemNode;
+    callbacks->updateTopoGeomEdgeHeal = callback_updateTopoGeomEdgeHeal;
+    callbacks->getFaceWithinBox2D = callback_getFaceWithinBox2D;
+    ptr->callbacks = callbacks;
+
+    lwt_BackendIfaceRegisterCallbacks (ptr->lwt_iface, callbacks);
+    ptr->lwt_topology = lwt_LoadTopology (ptr->lwt_iface, topo_name);
+
+    ptr->stmt_getNodeWithinDistance2D = NULL;
+    ptr->stmt_insertNodes = NULL;
+    ptr->stmt_getEdgeWithinDistance2D = NULL;
+    ptr->stmt_getNextEdgeId = NULL;
+    ptr->stmt_setNextEdgeId = NULL;
+    ptr->stmt_insertEdges = NULL;
+    ptr->stmt_getFaceContainingPoint_1 = NULL;
+    ptr->stmt_getFaceContainingPoint_2 = NULL;
+    ptr->stmt_deleteEdges = NULL;
+    ptr->stmt_getNodeWithinBox2D = NULL;
+    ptr->stmt_getEdgeWithinBox2D = NULL;
+    ptr->stmt_getFaceWithinBox2D = NULL;
+    ptr->stmt_updateNodes = NULL;
+    ptr->stmt_insertFaces = NULL;
+    ptr->stmt_updateFacesById = NULL;
+    ptr->stmt_deleteFacesById = NULL;
+    ptr->stmt_deleteNodesById = NULL;
+    ptr->stmt_getRingEdges = NULL;
+    if (ptr->lwt_topology == NULL)
+	goto invalid;
+
+/* creating the SQL prepared statements */
+    create_topogeo_prepared_stmts ((GaiaTopologyAccessorPtr) ptr);
+
+    return (GaiaTopologyAccessorPtr) ptr;
+
+  invalid:
+    gaiaTopologyDestroy ((GaiaTopologyAccessorPtr) ptr);
+    return NULL;
+}
+
+GAIATOPO_DECLARE void
+gaiaTopologyDestroy (GaiaTopologyAccessorPtr topo_ptr)
+{
+/* destroying a Topology Accessor Object */
+    struct gaia_topology *prev;
+    struct gaia_topology *next;
+    struct splite_internal_cache *cache;
+    struct gaia_topology *ptr = (struct gaia_topology *) topo_ptr;
+    if (ptr == NULL)
+	return;
+
+    prev = ptr->prev;
+    next = ptr->next;
+    cache = (struct splite_internal_cache *) (ptr->cache);
+    if (ptr->lwt_topology != NULL)
+	lwt_FreeTopology ((LWT_TOPOLOGY *) (ptr->lwt_topology));
+    if (ptr->lwt_iface != NULL)
+	lwt_FreeBackendIface ((LWT_BE_IFACE *) (ptr->lwt_iface));
+    if (ptr->callbacks != NULL)
+	free (ptr->callbacks);
+    if (ptr->topology_name != NULL)
+	free (ptr->topology_name);
+    if (ptr->last_error_message != NULL)
+	free (ptr->last_error_message);
+
+    finalize_topogeo_prepared_stmts (topo_ptr);
+    free (ptr);
+
+/* unregistering from the Internal Cache double linked list */
+    if (prev != NULL)
+	prev->next = next;
+    if (next != NULL)
+	next->prev = prev;
+    if (cache->firstTopology == ptr)
+	cache->firstTopology = next;
+    if (cache->lastTopology == ptr)
+	cache->lastTopology = prev;
+}
+
+TOPOLOGY_PRIVATE void
+finalize_topogeo_prepared_stmts (GaiaTopologyAccessorPtr accessor)
+{
+/* finalizing the SQL prepared statements */
+    struct gaia_topology *ptr = (struct gaia_topology *) accessor;
+    if (ptr->stmt_getNodeWithinDistance2D != NULL)
+	sqlite3_finalize (ptr->stmt_getNodeWithinDistance2D);
+    if (ptr->stmt_insertNodes != NULL)
+	sqlite3_finalize (ptr->stmt_insertNodes);
+    if (ptr->stmt_getEdgeWithinDistance2D != NULL)
+	sqlite3_finalize (ptr->stmt_getEdgeWithinDistance2D);
+    if (ptr->stmt_getNextEdgeId != NULL)
+	sqlite3_finalize (ptr->stmt_getNextEdgeId);
+    if (ptr->stmt_setNextEdgeId != NULL)
+	sqlite3_finalize (ptr->stmt_setNextEdgeId);
+    if (ptr->stmt_insertEdges != NULL)
+	sqlite3_finalize (ptr->stmt_insertEdges);
+    if (ptr->stmt_getFaceContainingPoint_1 != NULL)
+	sqlite3_finalize (ptr->stmt_getFaceContainingPoint_1);
+    if (ptr->stmt_getFaceContainingPoint_2 != NULL)
+	sqlite3_finalize (ptr->stmt_getFaceContainingPoint_2);
+    if (ptr->stmt_deleteEdges != NULL)
+	sqlite3_finalize (ptr->stmt_deleteEdges);
+    if (ptr->stmt_getNodeWithinBox2D != NULL)
+	sqlite3_finalize (ptr->stmt_getNodeWithinBox2D);
+    if (ptr->stmt_getEdgeWithinBox2D != NULL)
+	sqlite3_finalize (ptr->stmt_getEdgeWithinBox2D);
+    if (ptr->stmt_getFaceWithinBox2D != NULL)
+	sqlite3_finalize (ptr->stmt_getFaceWithinBox2D);
+    if (ptr->stmt_updateNodes != NULL)
+	sqlite3_finalize (ptr->stmt_updateNodes);
+    if (ptr->stmt_insertFaces != NULL)
+	sqlite3_finalize (ptr->stmt_insertFaces);
+    if (ptr->stmt_updateFacesById != NULL)
+	sqlite3_finalize (ptr->stmt_updateFacesById);
+    if (ptr->stmt_deleteFacesById != NULL)
+	sqlite3_finalize (ptr->stmt_deleteFacesById);
+    if (ptr->stmt_deleteNodesById != NULL)
+	sqlite3_finalize (ptr->stmt_deleteNodesById);
+    if (ptr->stmt_getRingEdges != NULL)
+	sqlite3_finalize (ptr->stmt_getRingEdges);
+    ptr->stmt_getNodeWithinDistance2D = NULL;
+    ptr->stmt_insertNodes = NULL;
+    ptr->stmt_getEdgeWithinDistance2D = NULL;
+    ptr->stmt_getNextEdgeId = NULL;
+    ptr->stmt_setNextEdgeId = NULL;
+    ptr->stmt_insertEdges = NULL;
+    ptr->stmt_getFaceContainingPoint_1 = NULL;
+    ptr->stmt_getFaceContainingPoint_2 = NULL;
+    ptr->stmt_deleteEdges = NULL;
+    ptr->stmt_getNodeWithinBox2D = NULL;
+    ptr->stmt_getEdgeWithinBox2D = NULL;
+    ptr->stmt_getFaceWithinBox2D = NULL;
+    ptr->stmt_updateNodes = NULL;
+    ptr->stmt_insertFaces = NULL;
+    ptr->stmt_updateFacesById = NULL;
+    ptr->stmt_deleteFacesById = NULL;
+    ptr->stmt_deleteNodesById = NULL;
+    ptr->stmt_getRingEdges = NULL;
+}
+
+TOPOLOGY_PRIVATE void
+create_topogeo_prepared_stmts (GaiaTopologyAccessorPtr accessor)
+{
+/* creating the SQL prepared statements */
+    struct gaia_topology *ptr = (struct gaia_topology *) accessor;
+    finalize_topogeo_prepared_stmts (accessor);
+    ptr->stmt_getNodeWithinDistance2D =
+	do_create_stmt_getNodeWithinDistance2D (accessor);
+    ptr->stmt_insertNodes = do_create_stmt_insertNodes (accessor);
+    ptr->stmt_getEdgeWithinDistance2D =
+	do_create_stmt_getEdgeWithinDistance2D (accessor);
+    ptr->stmt_getNextEdgeId = do_create_stmt_getNextEdgeId (accessor);
+    ptr->stmt_setNextEdgeId = do_create_stmt_setNextEdgeId (accessor);
+    ptr->stmt_insertEdges = do_create_stmt_insertEdges (accessor);
+    ptr->stmt_getFaceContainingPoint_1 =
+	do_create_stmt_getFaceContainingPoint_1 (accessor);
+    ptr->stmt_getFaceContainingPoint_2 =
+	do_create_stmt_getFaceContainingPoint_2 (accessor);
+    ptr->stmt_deleteEdges = NULL;
+    ptr->stmt_getNodeWithinBox2D = do_create_stmt_getNodeWithinBox2D (accessor);
+    ptr->stmt_getEdgeWithinBox2D = do_create_stmt_getEdgeWithinBox2D (accessor);
+    ptr->stmt_getFaceWithinBox2D = do_create_stmt_getFaceWithinBox2D (accessor);
+    ptr->stmt_updateNodes = NULL;
+    ptr->stmt_insertFaces = do_create_stmt_insertFaces (accessor);
+    ptr->stmt_updateFacesById = do_create_stmt_updateFacesById (accessor);
+    ptr->stmt_deleteFacesById = do_create_stmt_deleteFacesById (accessor);
+    ptr->stmt_deleteNodesById = do_create_stmt_deleteNodesById (accessor);
+    ptr->stmt_getRingEdges = do_create_stmt_getRingEdges (accessor);
+}
+
+TOPOLOGY_PRIVATE void
+finalize_all_topo_prepared_stmts (const void *p_cache)
+{
+/* finalizing all Topology-related prepared Stms */
+    struct gaia_topology *p_topo;
+    struct gaia_network *p_network;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) p_cache;
+    if (cache == NULL)
+	return;
+    if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
+	return;
+
+    p_topo = (struct gaia_topology *) cache->firstTopology;
+    while (p_topo != NULL)
+      {
+	  finalize_topogeo_prepared_stmts ((GaiaTopologyAccessorPtr) p_topo);
+	  p_topo = p_topo->next;
+      }
+
+    p_network = (struct gaia_network *) cache->firstNetwork;
+    while (p_network != NULL)
+      {
+	  finalize_toponet_prepared_stmts ((GaiaNetworkAccessorPtr) p_network);
+	  p_network = p_network->next;
+      }
+}
+
+TOPOLOGY_PRIVATE void
+create_all_topo_prepared_stmts (const void *p_cache)
+{
+/* (re)creating all Topology-related prepared Stms */
+    struct gaia_topology *p_topo;
+    struct gaia_network *p_network;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) p_cache;
+    if (cache == NULL)
+	return;
+    if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
+	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
+	return;
+
+    p_topo = (struct gaia_topology *) cache->firstTopology;
+    while (p_topo != NULL)
+      {
+	  create_topogeo_prepared_stmts ((GaiaTopologyAccessorPtr) p_topo);
+	  p_topo = p_topo->next;
+      }
+
+    p_network = (struct gaia_network *) cache->firstNetwork;
+    while (p_network != NULL)
+      {
+	  create_toponet_prepared_stmts ((GaiaNetworkAccessorPtr) p_network);
+	  p_network = p_network->next;
+      }
+}
+
+TOPOLOGY_PRIVATE void
+gaiatopo_reset_last_error_msg (GaiaTopologyAccessorPtr accessor)
+{
+/* resets the last Topology error message */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return;
+
+    if (topo->last_error_message != NULL)
+	free (topo->last_error_message);
+    topo->last_error_message = NULL;
+}
+
+TOPOLOGY_PRIVATE void
+gaiatopo_set_last_error_msg (GaiaTopologyAccessorPtr accessor, const char *msg)
+{
+/* sets the last Topology error message */
+    int len;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (msg == NULL)
+	msg = "no message available";
+
+    spatialite_e ("%s\n", msg);
+    if (topo == NULL)
+	return;
+
+    if (topo->last_error_message != NULL)
+	return;
+
+    len = strlen (msg);
+    topo->last_error_message = malloc (len + 1);
+    strcpy (topo->last_error_message, msg);
+}
+
+TOPOLOGY_PRIVATE const char *
+gaiatopo_get_last_exception (GaiaTopologyAccessorPtr accessor)
+{
+/* returns the last Topology error message */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return NULL;
+
+    return topo->last_error_message;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopologyDrop (sqlite3 * handle, const char *topo_name)
+{
+/* attempting to drop an already existing Topology */
+    int ret;
+    char *sql;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    int count = 1;
+
+/* creating the Topologies table (just in case) */
+    if (!do_create_topologies (handle))
+	return 0;
+
+/* testing for existing DBMS objects */
+    if (!check_existing_topology (handle, topo_name, 0))
+	return 0;
+
+/* dropping all topofeature tables (if any) */
+    if (!do_drop_topofeature_tables (handle, topo_name))
+	goto error;
+
+/* dropping the Topology own Tables */
+    if (!do_drop_topo_view (handle, topo_name, "edge_seeds"))
+	goto error;
+    if (!do_drop_topo_view (handle, topo_name, "face_seeds"))
+	goto error;
+    if (!do_drop_topo_view (handle, topo_name, "face_geoms"))
+	goto error;
+    if (!do_drop_topo_table (handle, topo_name, "topofeatures", 0))
+	goto error;
+    if (!do_drop_topo_table (handle, topo_name, "topolayers", 0))
+	goto error;
+    if (!do_drop_topo_table (handle, topo_name, "seeds", 1))
+	goto error;
+    if (!do_drop_topo_table (handle, topo_name, "edge", 1))
+	goto error;
+    if (!do_drop_topo_table (handle, topo_name, "node", 1))
+	goto error;
+    if (!do_drop_topo_table (handle, topo_name, "face", 1))
+	goto error;
+
+/* unregistering the Topology */
+    sql =
+	sqlite3_mprintf
+	("DELETE FROM MAIN.topologies WHERE Lower(topology_name) = Lower(%Q)",
+	 topo_name);
+    ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+
+/* counting how many Topologies are still there */
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.topologies");
+    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 1;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	      count = atoi (results[(i * columns) + 0]);
+      }
+    sqlite3_free_table (results);
+    if (count == 0)
+      {
+	  /* attempting to drop the master "topologies" table */
+	  sql = sqlite3_mprintf ("DROP TABLE MAIN.topologies");
+	  ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
+	  sqlite3_free (sql);
+      }
+
+    return 1;
+
+  error:
+    return 0;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaAddIsoNode (GaiaTopologyAccessorPtr accessor,
+		sqlite3_int64 face, gaiaPointPtr pt, int skip_checks)
+{
+/* LWT wrapper - AddIsoNode */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_AddIsoNode ((LWT_TOPOLOGY *) (topo->lwt_topology), face, lw_pt,
+			skip_checks);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwpoint_free (lw_pt);
+    return ret;
+}
+
+GAIATOPO_DECLARE int
+gaiaMoveIsoNode (GaiaTopologyAccessorPtr accessor,
+		 sqlite3_int64 node, gaiaPointPtr pt)
+{
+/* LWT wrapper - MoveIsoNode */
+    int ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret = lwt_MoveIsoNode ((LWT_TOPOLOGY *) (topo->lwt_topology), node, lw_pt);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwpoint_free (lw_pt);
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIATOPO_DECLARE int
+gaiaRemIsoNode (GaiaTopologyAccessorPtr accessor, sqlite3_int64 node)
+{
+/* LWT wrapper - RemIsoNode */
+    int ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret = lwt_RemoveIsoNode ((LWT_TOPOLOGY *) (topo->lwt_topology), node);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaAddIsoEdge (GaiaTopologyAccessorPtr accessor,
+		sqlite3_int64 start_node, sqlite3_int64 end_node,
+		gaiaLinestringPtr ln)
+{
+/* LWT wrapper - AddIsoEdge */
+    sqlite3_int64 ret;
+    LWLINE *lw_line;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    lw_line = gaia_convert_linestring_to_lwline (ln, topo->srid, topo->has_z);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_AddIsoEdge ((LWT_TOPOLOGY *) (topo->lwt_topology), start_node,
+			end_node, lw_line);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwline_free (lw_line);
+    return ret;
+}
+
+GAIATOPO_DECLARE int
+gaiaRemIsoEdge (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge)
+{
+/* LWT wrapper - RemIsoEdge */
+    int ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret = lwt_RemIsoEdge ((LWT_TOPOLOGY *) (topo->lwt_topology), edge);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIATOPO_DECLARE int
+gaiaChangeEdgeGeom (GaiaTopologyAccessorPtr accessor,
+		    sqlite3_int64 edge_id, gaiaLinestringPtr ln)
+{
+/* LWT wrapper - ChangeEdgeGeom  */
+    int ret;
+    LWLINE *lw_line;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    lw_line = gaia_convert_linestring_to_lwline (ln, topo->srid, topo->has_z);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_ChangeEdgeGeom ((LWT_TOPOLOGY *) (topo->lwt_topology), edge_id,
+			    lw_line);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwline_free (lw_line);
+    if (ret == 0)
+	return 1;
+    return 0;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaModEdgeSplit (GaiaTopologyAccessorPtr accessor,
+		  sqlite3_int64 edge, gaiaPointPtr pt, int skip_checks)
+{
+/* LWT wrapper - ModEdgeSplit */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_ModEdgeSplit ((LWT_TOPOLOGY *) (topo->lwt_topology), edge, lw_pt,
+			  skip_checks);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwpoint_free (lw_pt);
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaNewEdgesSplit (GaiaTopologyAccessorPtr accessor,
+		   sqlite3_int64 edge, gaiaPointPtr pt, int skip_checks)
+{
+/* LWT wrapper - NewEdgesSplit */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_NewEdgesSplit ((LWT_TOPOLOGY *) (topo->lwt_topology), edge, lw_pt,
+			   skip_checks);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwpoint_free (lw_pt);
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaAddEdgeModFace (GaiaTopologyAccessorPtr accessor,
+		    sqlite3_int64 start_node, sqlite3_int64 end_node,
+		    gaiaLinestringPtr ln, int skip_checks)
+{
+/* LWT wrapper - AddEdgeModFace */
+    sqlite3_int64 ret;
+    LWLINE *lw_line;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    lw_line = gaia_convert_linestring_to_lwline (ln, topo->srid, topo->has_z);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_AddEdgeModFace ((LWT_TOPOLOGY *) (topo->lwt_topology), start_node,
+			    end_node, lw_line, skip_checks);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwline_free (lw_line);
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaAddEdgeNewFaces (GaiaTopologyAccessorPtr accessor,
+		     sqlite3_int64 start_node, sqlite3_int64 end_node,
+		     gaiaLinestringPtr ln, int skip_checks)
+{
+/* LWT wrapper - AddEdgeNewFaces */
+    sqlite3_int64 ret;
+    LWLINE *lw_line;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    lw_line = gaia_convert_linestring_to_lwline (ln, topo->srid, topo->has_z);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_AddEdgeNewFaces ((LWT_TOPOLOGY *) (topo->lwt_topology), start_node,
+			     end_node, lw_line, skip_checks);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwline_free (lw_line);
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaRemEdgeNewFace (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id)
+{
+/* LWT wrapper - RemEdgeNewFace */
+    sqlite3_int64 ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret = lwt_RemEdgeNewFace ((LWT_TOPOLOGY *) (topo->lwt_topology), edge_id);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaRemEdgeModFace (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id)
+{
+/* LWT wrapper - RemEdgeModFace */
+    sqlite3_int64 ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret = lwt_RemEdgeModFace ((LWT_TOPOLOGY *) (topo->lwt_topology), edge_id);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaNewEdgeHeal (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id1,
+		 sqlite3_int64 edge_id2)
+{
+/* LWT wrapper - NewEdgeHeal */
+    sqlite3_int64 ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_NewEdgeHeal ((LWT_TOPOLOGY *) (topo->lwt_topology), edge_id1,
+			 edge_id2);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaModEdgeHeal (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id1,
+		 sqlite3_int64 edge_id2)
+{
+/* LWT wrapper - ModEdgeHeal */
+    sqlite3_int64 ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_ModEdgeHeal ((LWT_TOPOLOGY *) (topo->lwt_topology), edge_id1,
+			 edge_id2);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE gaiaGeomCollPtr
+gaiaGetFaceGeometry (GaiaTopologyAccessorPtr accessor, sqlite3_int64 face)
+{
+/* LWT wrapper - GetFaceGeometry */
+    LWGEOM *result = NULL;
+    LWPOLY *lwpoly;
+    int has_z = 0;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    int iv;
+    int ib;
+    double x;
+    double y;
+    double z;
+    gaiaGeomCollPtr geom;
+    gaiaPolygonPtr pg;
+    gaiaRingPtr rng;
+    int dimension_model;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (topo->inside_lwt_callback == 0)
+      {
+	  /* locking the semaphore if not already inside a callback context */
+	  splite_lwgeom_semaphore_lock ();
+	  splite_lwgeomtopo_init ();
+	  gaiaResetLwGeomMsg ();
+      }
+
+    result = lwt_GetFaceGeometry ((LWT_TOPOLOGY *) (topo->lwt_topology), face);
+
+    if (topo->inside_lwt_callback == 0)
+      {
+	  /* unlocking the semaphore if not already inside a callback context */
+	  splite_lwgeom_init ();
+	  splite_lwgeom_semaphore_unlock ();
+      }
+
+    if (result == NULL)
+	return NULL;
+
+/* converting the result as a Gaia Geometry */
+    lwpoly = (LWPOLY *) result;
+    if (lwpoly->nrings <= 0)
+      {
+	  /* empty geometry */
+	  lwgeom_free (result);
+	  return NULL;
+      }
+    pa = lwpoly->rings[0];
+    if (pa->npoints <= 0)
+      {
+	  /* empty geometry */
+	  lwgeom_free (result);
+	  return NULL;
+      }
+    if (FLAGS_GET_Z (pa->flags))
+	has_z = 1;
+    if (has_z)
+      {
+	  dimension_model = GAIA_XY_Z;
+	  geom = gaiaAllocGeomCollXYZ ();
+      }
+    else
+      {
+	  dimension_model = GAIA_XY;
+	  geom = gaiaAllocGeomColl ();
+      }
+    pg = gaiaAddPolygonToGeomColl (geom, pa->npoints, lwpoly->nrings - 1);
+    rng = pg->Exterior;
+    for (iv = 0; iv < pa->npoints; iv++)
+      {
+	  /* copying Exterior Ring vertices */
+	  getPoint4d_p (pa, iv, &pt4d);
+	  x = pt4d.x;
+	  y = pt4d.y;
+	  if (has_z)
+	      z = pt4d.z;
+	  else
+	      z = 0.0;
+	  if (dimension_model == GAIA_XY_Z)
+	    {
+		gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
+	    }
+	  else
+	    {
+		gaiaSetPoint (rng->Coords, iv, x, y);
+	    }
+      }
+    for (ib = 1; ib < lwpoly->nrings; ib++)
+      {
+	  has_z = 0;
+	  pa = lwpoly->rings[ib];
+	  if (FLAGS_GET_Z (pa->flags))
+	      has_z = 1;
+	  rng = gaiaAddInteriorRing (pg, ib - 1, pa->npoints);
+	  for (iv = 0; iv < pa->npoints; iv++)
+	    {
+		/* copying Exterior Ring vertices */
+		getPoint4d_p (pa, iv, &pt4d);
+		x = pt4d.x;
+		y = pt4d.y;
+		if (has_z)
+		    z = pt4d.z;
+		else
+		    z = 0.0;
+		if (dimension_model == GAIA_XY_Z)
+		  {
+		      gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
+		  }
+		else
+		  {
+		      gaiaSetPoint (rng->Coords, iv, x, y);
+		  }
+	    }
+      }
+    lwgeom_free (result);
+    geom->DeclaredType = GAIA_POLYGON;
+    geom->Srid = topo->srid;
+    return geom;
+}
+
+static int
+do_check_create_faceedges_table (GaiaTopologyAccessorPtr accessor)
+{
+/* attemtping to create or validate the target table */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int exists = 0;
+    int ok_face_id = 0;
+    int ok_sequence = 0;
+    int ok_edge_id = 0;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+/* testing for an already existing table */
+    table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("PRAGMA TEMP.table_info(\"%s\")", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s", errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *name = results[(i * columns) + 1];
+	  const char *type = results[(i * columns) + 2];
+	  const char *notnull = results[(i * columns) + 3];
+	  const char *dflt_value = results[(i * columns) + 4];
+	  const char *pk = results[(i * columns) + 5];
+	  if (strcmp (name, "face_id") == 0 && strcmp (type, "INTEGER") == 0
+	      && strcmp (notnull, "1") == 0 && dflt_value == NULL
+	      && strcmp (pk, "1") == 0)
+	      ok_face_id = 1;
+	  if (strcmp (name, "sequence") == 0 && strcmp (type, "INTEGER") == 0
+	      && strcmp (notnull, "1") == 0 && dflt_value == NULL
+	      && strcmp (pk, "2") == 0)
+	      ok_sequence = 1;
+	  if (strcmp (name, "edge_id") == 0 && strcmp (type, "INTEGER") == 0
+	      && strcmp (notnull, "1") == 0 && dflt_value == NULL
+	      && strcmp (pk, "0") == 0)
+	      ok_edge_id = 1;
+	  exists = 1;
+      }
+    sqlite3_free_table (results);
+    if (ok_face_id && ok_sequence && ok_edge_id)
+	return 1;		/* already existing and valid */
+
+    if (exists)
+	return 0;		/* already existing but invalid */
+
+/* attempting to create the table */
+    table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TEMP TABLE \"%s\" (\n\tface_id INTEGER NOT NULL,\n"
+	 "\tsequence INTEGER NOT NULL,\n\tedge_id INTEGER NOT NULL,\n"
+	 "\tCONSTRAINT pk_topo_facee_edges PRIMARY KEY (face_id, sequence))",
+	 xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s", errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_populate_faceedges_table (GaiaTopologyAccessorPtr accessor,
+			     sqlite3_int64 face, LWT_ELEMID * edges,
+			     int num_edges)
+{
+/* populating the target table */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    int i;
+    sqlite3_stmt *stmt = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+/* deleting all rows belonging to Face (if any) */
+    table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM TEMP.\"%s\" WHERE face_id = ?", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, face);
+    ret = sqlite3_step (stmt);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	;
+    else
+      {
+	  char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+    sqlite3_finalize (stmt);
+    stmt = NULL;
+
+/* preparing the INSERT statement */
+    table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO TEMP.\"%s\" (face_id, sequence, edge_id) VALUES (?, ?, ?)",
+	 xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+    for (i = 0; i < num_edges; i++)
+      {
+	  /* inserting all Face/Edges */
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_int64 (stmt, 1, face);
+	  sqlite3_bind_int (stmt, 2, i + 1);
+	  sqlite3_bind_int64 (stmt, 3, *(edges + i));
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      ;
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+GAIATOPO_DECLARE int
+gaiaGetFaceEdges (GaiaTopologyAccessorPtr accessor, sqlite3_int64 face)
+{
+/* LWT wrapper - GetFaceEdges */
+    LWT_ELEMID *edges = NULL;
+    int num_edges;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    /* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+
+    num_edges =
+	lwt_GetFaceEdges ((LWT_TOPOLOGY *) (topo->lwt_topology), face, &edges);
+
+    /* unlocking the semaphore */
+    splite_lwgeom_init ();
+    splite_lwgeom_semaphore_unlock ();
+
+    if (num_edges < 0)
+	return 0;
+
+    if (num_edges > 0)
+      {
+	  /* attemtping to create or validate the target table */
+	  if (!do_check_create_faceedges_table (accessor))
+	    {
+		lwfree (edges);
+		return 0;
+	    }
+
+	  /* populating the target table */
+	  if (!do_populate_faceedges_table (accessor, face, edges, num_edges))
+	    {
+		lwfree (edges);
+		return 0;
+	    }
+      }
+    lwfree (edges);
+    return 1;
+}
+
+static int
+do_check_create_validate_topogeo_table (GaiaTopologyAccessorPtr accessor)
+{
+/* attemtping to create or validate the target table */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    char *errMsg = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+/* finalizing all prepared Statements */
+    finalize_all_topo_prepared_stmts (topo->cache);
+
+/* attempting to drop the table (just in case if it already exists) */
+    table = sqlite3_mprintf ("%s_validate_topogeo", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE IF EXISTS temp.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    create_all_topo_prepared_stmts (topo->cache);	/* recreating prepared stsms */
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidSpatialNet exception: %s", errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+/* attempting to create the table */
+    table = sqlite3_mprintf ("%s_validate_topogeo", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("CREATE TEMP TABLE \"%s\" (\n\terror TEXT,\n"
+	 "\tprimitive1 INTEGER,\n\tprimitive2 INTEGER)", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidateTopoGeo exception: %s", errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_topo_check_coincident_nodes (GaiaTopologyAccessorPtr accessor,
+				sqlite3_stmt * stmt)
+{
+/* checking for coincident nodes */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT n1.node_id, n2.node_id FROM MAIN.\"%s\" AS n1 "
+			 "JOIN MAIN.\"%s\" AS n2 ON (n1.node_id <> n2.node_id AND "
+			 "ST_Equals(n1.geom, n2.geom) = 1 AND n2.node_id IN "
+			 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geom' AND search_frame = n1.geom))",
+			 xtable, xtable, table);
+    sqlite3_free (table);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - CoicidentNodes error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id1 = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 node_id2 = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "coincident nodes", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, node_id1);
+		sqlite3_bind_int64 (stmt, 3, node_id2);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #1 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - CoicidentNodes step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_edge_node (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for edge-node crossing */
+    char *sql;
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("SELECT e.edge_id, n.node_id FROM MAIN.\"%s\" AS e "
+			   "JOIN MAIN.\"%s\" AS n ON (ST_Distance(e.geom, n.geom) <= 0 "
+			   "AND ST_Disjoint(ST_StartPoint(e.geom), n.geom) = 1 AND "
+			   "ST_Disjoint(ST_EndPoint(e.geom), n.geom) = 1 AND n.node_id IN "
+			   "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
+			   "f_geometry_column = 'geom' AND search_frame = e.geom))",
+			   xtable1, xtable2, table);
+    sqlite3_free (table);
+    free (xtable1);
+    free (xtable2);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - EdgeCrossedNode error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "edge crossed node", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, node_id);
+		sqlite3_bind_int64 (stmt, 3, edge_id);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #2 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - EdgeCrossedNode step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_non_simple (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for non-simple edges */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT edge_id FROM MAIN.\"%s\" WHERE ST_IsSimple(geom) = 0", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - NonSimpleEdge error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "edge not simple", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, edge_id);
+		sqlite3_bind_null (stmt, 3);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #3 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - NonSimpleEdge step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_edge_edge (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for edge-edge crossing */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT e1.edge_id, e2.edge_id FROM MAIN.\"%s\" AS e1 "
+			 "JOIN MAIN.\"%s\" AS e2 ON (e1.edge_id <> e2.edge_id AND "
+			 "ST_Crosses(e1.geom, e2.geom) = 1 AND e2.edge_id IN "
+			 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geom' AND search_frame = e1.geom))",
+			 xtable, xtable, table);
+    sqlite3_free (table);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - EdgeCrossesEdge error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id1 = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 edge_id2 = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "edge crosses edge", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, edge_id1);
+		sqlite3_bind_int64 (stmt, 3, edge_id2);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #4 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - EdgeCrossesEdge step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_start_nodes (GaiaTopologyAccessorPtr accessor,
+			   sqlite3_stmt * stmt)
+{
+/* checking for edges mismatching start nodes */
+    char *sql;
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT e.edge_id, e.start_node FROM MAIN.\"%s\" AS e "
+			 "JOIN MAIN.\"%s\" AS n ON (e.start_node = n.node_id) "
+			 "WHERE ST_Disjoint(ST_StartPoint(e.geom), n.geom) = 1",
+			 xtable1, xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - StartNodes error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "geometry start mismatch", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, edge_id);
+		sqlite3_bind_int64 (stmt, 3, node_id);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #5 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - StartNodes step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_end_nodes (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
+{
+/* checking for edges mismatching end nodes */
+    char *sql;
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT e.edge_id, e.end_node FROM MAIN.\"%s\" AS e "
+			   "JOIN MAIN.\"%s\" AS n ON (e.end_node = n.node_id) "
+			   "WHERE ST_Disjoint(ST_EndPoint(e.geom), n.geom) = 1",
+			   xtable1, xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidateTopoGeo() - EndNodes error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "geometry end mismatch", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, edge_id);
+		sqlite3_bind_int64 (stmt, 3, node_id);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #6 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - EndNodes step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_face_no_edges (GaiaTopologyAccessorPtr accessor,
+			     sqlite3_stmt * stmt)
+{
+/* checking for faces with no edges */
+    char *sql;
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT f.face_id, Count(e1.edge_id) AS cnt1, "
+			   "Count(e2.edge_id) AS cnt2 FROM MAIN.\"%s\" AS f "
+			   "LEFT JOIN MAIN.\"%s\" AS e1 ON (f.face_id = e1.left_face) "
+			   "LEFT JOIN MAIN.\"%s\" AS e2 ON (f.face_id = e2.right_face) "
+			   "GROUP BY f.face_id HAVING cnt1 = 0 AND cnt2 = 0",
+			   xtable1, xtable2, xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - FaceNoEdges error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id = sqlite3_column_int64 (stmt_in, 0);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "face without edges", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, face_id);
+		sqlite3_bind_null (stmt, 3);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #7 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - FaceNoEdges step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_no_universal_face (GaiaTopologyAccessorPtr accessor,
+				 sqlite3_stmt * stmt)
+{
+/* checking for missing universal face */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int count = 0;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\" WHERE face_id = 0",
+			 xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  count = atoi (results[(i * columns) + 0]);
+      }
+    sqlite3_free_table (results);
+
+    if (count <= 0)
+      {
+	  /* reporting the error */
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_text (stmt, 1, "no universal face", -1, SQLITE_STATIC);
+	  sqlite3_bind_null (stmt, 2);
+	  sqlite3_bind_null (stmt, 3);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      ;
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() insert #8 error: \"%s\"",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+
+    return 1;
+}
+
+static int
+do_topo_check_create_aux_faces (GaiaTopologyAccessorPtr accessor)
+{
+/* creating the aux-Face temp table */
+    char *table;
+    char *xtable;
+    char *sql;
+    char *errMsg;
+    int ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+/* creating the aux-face Temp Table */
+    table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE TEMPORARY TABLE \"%s\" (\n"
+			   "\tface_id INTEGER PRIMARY KEY,\n\tgeom BLOB)",
+			   xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("CREATE TEMPORARY TABLE aux_face - error: %s\n",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* creating the exotic spatial index */
+    table =
+	sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name,
+			 getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("CREATE VIRTUAL TABLE temp.\"%s\" USING RTree "
+			   "(id_face, x_min, x_max, y_min, y_max)", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("CREATE TEMPORARY TABLE aux_face - error: %s\n",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_topo_check_build_aux_faces (GaiaTopologyAccessorPtr accessor,
+			       sqlite3_stmt * stmt)
+{
+/* populating the aux-face Temp Table */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    sqlite3_stmt *stmt_rtree = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+/* preparing the input SQL statement */
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT face_id, ST_GetFaceGeometry(%Q, face_id) "
+			   "FROM MAIN.\"%s\" WHERE face_id <> 0",
+			   topo->topology_name, xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - GetFaceGeometry error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the output SQL statement */
+    table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO TEMP.\"%s\" (face_id, geom) VALUES (?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_ValidateTopoGeo() - AuxFace error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the RTree SQL statement */
+    table =
+	sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name,
+			 getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("INSERT INTO TEMP.\"%s\" "
+			   "(id_face, x_min, x_max, y_min, y_max) VALUES (?, ?, ?, ?, ?)",
+			   xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rtree,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - AuxFaceRTree error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		gaiaGeomCollPtr geom = NULL;
+		const unsigned char *blob;
+		int blob_sz;
+		sqlite3_int64 face_id = sqlite3_column_int64 (stmt_in, 0);
+		if (sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
+		  {
+		      blob = sqlite3_column_blob (stmt_in, 1);
+		      blob_sz = sqlite3_column_bytes (stmt_in, 1);
+		      geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		  }
+		if (geom == NULL)
+		  {
+		      /* reporting the error */
+		      sqlite3_reset (stmt);
+		      sqlite3_clear_bindings (stmt);
+		      sqlite3_bind_text (stmt, 1, "invalid face geometry", -1,
+					 SQLITE_STATIC);
+		      sqlite3_bind_int64 (stmt, 2, face_id);
+		      sqlite3_bind_null (stmt, 3);
+		      ret = sqlite3_step (stmt);
+		      if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+			  ;
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("ST_ValidateTopoGeo() insert #9 error: \"%s\"",
+				 sqlite3_errmsg (topo->db_handle));
+			    gaiatopo_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      double xmin = geom->MinX;
+		      double xmax = geom->MaxX;
+		      double ymin = geom->MinY;
+		      double ymax = geom->MaxY;
+		      gaiaFreeGeomColl (geom);
+		      /* inserting into AuxFace */
+		      sqlite3_reset (stmt_out);
+		      sqlite3_clear_bindings (stmt_out);
+		      sqlite3_bind_int64 (stmt_out, 1, face_id);
+		      sqlite3_bind_blob (stmt_out, 2, blob, blob_sz,
+					 SQLITE_STATIC);
+		      ret = sqlite3_step (stmt_out);
+		      if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+			  ;
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("ST_ValidateTopoGeo() insert #10 error: \"%s\"",
+				 sqlite3_errmsg (topo->db_handle));
+			    gaiatopo_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		      /* updating the AuxFaceRTree */
+		      sqlite3_reset (stmt_rtree);
+		      sqlite3_clear_bindings (stmt_rtree);
+		      sqlite3_bind_int64 (stmt_rtree, 1, face_id);
+		      sqlite3_bind_double (stmt_rtree, 2, xmin);
+		      sqlite3_bind_double (stmt_rtree, 3, xmax);
+		      sqlite3_bind_double (stmt_rtree, 4, ymin);
+		      sqlite3_bind_double (stmt_rtree, 5, ymax);
+		      ret = sqlite3_step (stmt_rtree);
+		      if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+			  ;
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("ST_ValidateTopoGeo() insert #11 error: \"%s\"",
+				 sqlite3_errmsg (topo->db_handle));
+			    gaiatopo_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - GetFaceGeometry step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    sqlite3_finalize (stmt_rtree);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out == NULL)
+	sqlite3_finalize (stmt_out);
+    if (stmt_rtree == NULL)
+	sqlite3_finalize (stmt_rtree);
+    return 0;
+}
+
+static int
+do_topo_check_overlapping_faces (GaiaTopologyAccessorPtr accessor,
+				 sqlite3_stmt * stmt)
+{
+/* checking for overlapping faces */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *rtree;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+
+    table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name,
+			     getpid ());
+    rtree = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT a.face_id, b.face_id FROM TEMP.\"%s\" AS a, TEMP.\"%s\" AS b "
+	 "WHERE a.geom IS NOT NULL AND a.face_id <> b.face_id AND ST_Overlaps(a.geom, b.geom) = 1 "
+	 "AND b.face_id IN (SELECT id_face FROM TEMP.\"%s\" WHERE x_min <= MbrMaxX(a.geom) "
+	 "AND x_max >= MbrMinX(a.geom) AND y_min <= MbrMaxY(a.geom) AND y_max >= MbrMinY(a.geom))",
+	 xtable, xtable, rtree);
+    free (xtable);
+    free (rtree);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - OverlappingFaces error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id1 = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 face_id2 = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "face overlaps face", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, face_id1);
+		sqlite3_bind_int64 (stmt, 3, face_id2);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #12 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - OverlappingFaces step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_face_within_face (GaiaTopologyAccessorPtr accessor,
+				sqlite3_stmt * stmt)
+{
+/* checking for face-within-face */
+    char *sql;
+    char *table;
+    char *xtable;
+    char *rtree;
+    int ret;
+    sqlite3_stmt *stmt_in = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+
+    table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name,
+			     getpid ());
+    rtree = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT a.face_id, b.face_id FROM TEMP.\"%s\" AS a, TEMP.\"%s\" AS b "
+	 "WHERE a.geom IS NOT NULL AND a.face_id <> b.face_id AND ST_Within(a.geom, b.geom) = 1 "
+	 "AND b.face_id IN (SELECT id_face FROM TEMP.\"%s\" WHERE x_min <= MbrMaxX(a.geom) "
+	 "AND x_max >= MbrMinX(a.geom) AND y_min <= MbrMaxY(a.geom) AND y_max >= MbrMinY(a.geom))",
+	 xtable, xtable, rtree);
+    free (xtable);
+    free (rtree);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("ST_ValidateTopoGeo() - FaceWithinFace error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id1 = sqlite3_column_int64 (stmt_in, 0);
+		sqlite3_int64 face_id2 = sqlite3_column_int64 (stmt_in, 1);
+		/* reporting the error */
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_text (stmt, 1, "face within face", -1,
+				   SQLITE_STATIC);
+		sqlite3_bind_int64 (stmt, 2, face_id1);
+		sqlite3_bind_int64 (stmt, 3, face_id2);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("ST_ValidateTopoGeo() insert #13 error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("ST_ValidateTopoGeo() - FaceWithinFace step error: %s",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt_in);
+
+    return 1;
+
+  error:
+    if (stmt_in == NULL)
+	sqlite3_finalize (stmt_in);
+    return 0;
+}
+
+static int
+do_topo_check_drop_aux_faces (GaiaTopologyAccessorPtr accessor)
+{
+/* dropping the aux-Face temp table */
+    char *table;
+    char *xtable;
+    char *sql;
+    char *errMsg;
+    int ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+/* finalizing all prepared Statements */
+    finalize_all_topo_prepared_stmts (topo->cache);
+
+/* dropping the aux-face Temp Table */
+    table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE TEMP.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    create_all_topo_prepared_stmts (topo->cache);	/* recreating prepared stsms */
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("DROP TABLE temp.aux_face - error: %s\n",
+				       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* dropping the aux-face Temp RTree */
+    table =
+	sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name,
+			 getpid ());
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE TEMP.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("DROP TABLE temp.aux_face_rtree - error: %s\n",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaValidateTopoGeo (GaiaTopologyAccessorPtr accessor)
+{
+/* generating a validity report for a given Topology */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (!do_check_create_validate_topogeo_table (accessor))
+	return 0;
+
+    table = sqlite3_mprintf ("%s_validate_topogeo", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO TEMP.\"%s\" (error, primitive1, primitive2) VALUES (?, ?, ?)",
+	 xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("ST_ValidateTopoGeo error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    if (!do_topo_check_coincident_nodes (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_edge_node (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_non_simple (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_edge_edge (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_start_nodes (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_end_nodes (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_face_no_edges (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_no_universal_face (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_create_aux_faces (accessor))
+	goto error;
+
+    if (!do_topo_check_build_aux_faces (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_overlapping_faces (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_face_within_face (accessor, stmt))
+	goto error;
+
+    if (!do_topo_check_drop_aux_faces (accessor))
+	goto error;
+
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaGetNodeByPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
+		    double tolerance)
+{
+/* LWT wrapper - GetNodeByPoint */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_GetNodeByPoint ((LWT_TOPOLOGY *) (topo->lwt_topology), lw_pt,
+			    tolerance);
+    lwpoint_free (lw_pt);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaGetEdgeByPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
+		    double tolerance)
+{
+/* LWT wrapper - GetEdgeByPoint */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_GetEdgeByPoint ((LWT_TOPOLOGY *) (topo->lwt_topology), lw_pt,
+			    tolerance);
+    lwpoint_free (lw_pt);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaGetFaceByPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
+		    double tolerance)
+{
+/* LWT wrapper - GetFaceByPoint */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_GetFaceByPoint ((LWT_TOPOLOGY *) (topo->lwt_topology), lw_pt,
+			    tolerance);
+    lwpoint_free (lw_pt);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE sqlite3_int64
+gaiaTopoGeo_AddPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
+		      double tolerance)
+{
+/* LWT wrapper - AddPoint */
+    sqlite3_int64 ret;
+    int has_z = 0;
+    LWPOINT *lw_pt;
+    POINTARRAY *pa;
+    POINT4D point;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
+	has_z = 1;
+    pa = ptarray_construct (has_z, 0, 1);
+    point.x = pt->X;
+    point.y = pt->Y;
+    if (has_z)
+	point.z = pt->Z;
+    ptarray_set_point4d (pa, 0, &point);
+    lw_pt = lwpoint_construct (topo->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    ret =
+	lwt_AddPoint ((LWT_TOPOLOGY *) (topo->lwt_topology), lw_pt, tolerance);
+    lwpoint_free (lw_pt);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    return ret;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_AddLineString (GaiaTopologyAccessorPtr accessor,
+			   gaiaLinestringPtr ln, double tolerance,
+			   sqlite3_int64 ** edge_ids, int *ids_count)
+{
+/* LWT wrapper - AddLinestring */
+    int ret = 0;
+    LWT_ELEMID *edgeids;
+    int nedges;
+    int i;
+    sqlite3_int64 *ids;
+    LWLINE *lw_line;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    lw_line = gaia_convert_linestring_to_lwline (ln, topo->srid, topo->has_z);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    edgeids =
+	lwt_AddLine ((LWT_TOPOLOGY *) (topo->lwt_topology), lw_line, tolerance,
+		     &nedges);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwline_free (lw_line);
+    if (edgeids != NULL)
+      {
+	  ids = malloc (sizeof (sqlite3_int64) * nedges);
+	  for (i = 0; i < nedges; i++)
+	      ids[i] = edgeids[i];
+	  *edge_ids = ids;
+	  *ids_count = nedges;
+	  ret = 1;
+	  lwfree (edgeids);
+      }
+    return ret;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_AddPolygon (GaiaTopologyAccessorPtr accessor, gaiaPolygonPtr pg,
+			double tolerance, sqlite3_int64 ** face_ids,
+			int *ids_count)
+{
+/* LWT wrapper - AddPolygon */
+    int ret = 0;
+    LWT_ELEMID *faceids;
+    int nfaces;
+    int i;
+    sqlite3_int64 *ids;
+    LWPOLY *lw_polyg;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    lw_polyg = gaia_convert_polygon_to_lwpoly (pg, topo->srid, topo->has_z);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+    splite_lwgeomtopo_init ();
+    gaiaResetLwGeomMsg ();
+    faceids =
+	lwt_AddPolygon ((LWT_TOPOLOGY *) (topo->lwt_topology), lw_polyg,
+			tolerance, &nfaces);
+    splite_lwgeom_init ();
+
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+
+    lwpoly_free (lw_polyg);
+    if (faceids != NULL)
+      {
+	  ids = malloc (sizeof (sqlite3_int64) * nfaces);
+	  for (i = 0; i < nfaces; i++)
+	      ids[i] = faceids[i];
+	  *face_ids = ids;
+	  *ids_count = nfaces;
+	  ret = 1;
+	  lwfree (faceids);
+      }
+    return ret;
+}
+
+static void
+do_split_line (gaiaGeomCollPtr geom, gaiaDynamicLinePtr dyn)
+{
+/* inserting a new linestring into the collection of split lines */
+    int points = 0;
+    int iv = 0;
+    gaiaPointPtr pt;
+    gaiaLinestringPtr ln;
+
+    pt = dyn->First;
+    while (pt != NULL)
+      {
+	  /* counting how many points */
+	  points++;
+	  pt = pt->Next;
+      }
+
+    ln = gaiaAddLinestringToGeomColl (geom, points);
+    pt = dyn->First;
+    while (pt != NULL)
+      {
+	  /* copying all points */
+	  if (ln->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaSetPointXYZ (ln->Coords, iv, pt->X, pt->Y, pt->Z);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaSetPointXYM (ln->Coords, iv, pt->X, pt->Y, pt->M);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaSetPointXYZM (ln->Coords, iv, pt->X, pt->Y, pt->Z, pt->M);
+	    }
+	  else
+	    {
+		gaiaSetPoint (ln->Coords, iv, pt->X, pt->Y);
+	    }
+	  iv++;
+	  pt = pt->Next;
+      }
+}
+
+static void
+do_geom_split_line (gaiaGeomCollPtr geom, gaiaLinestringPtr in,
+		    int line_max_points, double max_length)
+{
+/* splitting a Linestring into a collection of shorter Linestrings */
+    int iv;
+    int count = 0;
+    int split = 0;
+    double tot_length = 0.0;
+    gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
+
+    for (iv = 0; iv < in->Points; iv++)
+      {
+	  /* consuming all Points from the input Linestring */
+	  double ox;
+	  double oy;
+	  double x;
+	  double y;
+	  double z = 0.0;
+	  double m = 0.0;
+	  if (in->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (in->Coords, iv, &x, &y, &z);
+	    }
+	  else if (in->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (in->Coords, iv, &x, &y, &m);
+	    }
+	  else if (in->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (in->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (in->Coords, iv, &x, &y);
+	    }
+
+	  split = 0;
+	  if (max_length > 0.0)
+	    {
+		if (tot_length > max_length)
+		    split = 1;
+	    }
+	  if (line_max_points > 0)
+	    {
+		if (count == line_max_points)
+		    split = 1;
+	    }
+	  if (split && count >= 2)
+	    {
+		/* line break */
+		double oz;
+		double om;
+		ox = dyn->Last->X;
+		oy = dyn->Last->Y;
+		if (in->DimensionModel == GAIA_XY_Z
+		    || in->DimensionModel == GAIA_XY_Z_M)
+		    oz = dyn->Last->Z;
+		if (in->DimensionModel == GAIA_XY_M
+		    || in->DimensionModel == GAIA_XY_Z_M)
+		    om = dyn->Last->M;
+		do_split_line (geom, dyn);
+		gaiaFreeDynamicLine (dyn);
+		dyn = gaiaAllocDynamicLine ();
+		/* reinserting the last point */
+		if (in->DimensionModel == GAIA_XY_Z)
+		    gaiaAppendPointZToDynamicLine (dyn, ox, oy, oz);
+		else if (in->DimensionModel == GAIA_XY_M)
+		    gaiaAppendPointMToDynamicLine (dyn, ox, oy, om);
+		else if (in->DimensionModel == GAIA_XY_Z_M)
+		    gaiaAppendPointZMToDynamicLine (dyn, ox, oy, oz, om);
+		else
+		    gaiaAppendPointToDynamicLine (dyn, ox, oy);
+		count = 1;
+		tot_length = 0.0;
+	    }
+
+	  /* inserting a point */
+	  if (in->DimensionModel == GAIA_XY_Z)
+	      gaiaAppendPointZToDynamicLine (dyn, x, y, z);
+	  else if (in->DimensionModel == GAIA_XY_M)
+	      gaiaAppendPointMToDynamicLine (dyn, x, y, m);
+	  else if (in->DimensionModel == GAIA_XY_Z_M)
+	      gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
+	  else
+	      gaiaAppendPointToDynamicLine (dyn, x, y);
+	  if (count > 0)
+	    {
+		if (max_length > 0.0)
+		  {
+		      double dist =
+			  sqrt (((ox - x) * (ox - x)) + ((oy - y) * (oy - y)));
+		      tot_length += dist;
+		  }
+	    }
+	  ox = x;
+	  oy = y;
+	  count++;
+      }
+
+    if (dyn->First != NULL)
+      {
+	  /* flushing the last Line */
+	  do_split_line (geom, dyn);
+      }
+    gaiaFreeDynamicLine (dyn);
+}
+
+static gaiaGeomCollPtr
+do_linearize (gaiaGeomCollPtr geom)
+{
+/* attempts to transform Polygon Rings into a (multi)linestring */
+    gaiaGeomCollPtr result;
+    gaiaLinestringPtr new_ln;
+    gaiaPolygonPtr pg;
+    gaiaRingPtr rng;
+    int iv;
+    int ib;
+    double x;
+    double y;
+    double m;
+    double z;
+    if (!geom)
+	return NULL;
+
+    if (geom->DimensionModel == GAIA_XY_Z_M)
+	result = gaiaAllocGeomCollXYZM ();
+    else if (geom->DimensionModel == GAIA_XY_Z)
+	result = gaiaAllocGeomCollXYZ ();
+    else if (geom->DimensionModel == GAIA_XY_M)
+	result = gaiaAllocGeomCollXYM ();
+    else
+	result = gaiaAllocGeomColl ();
+    result->Srid = geom->Srid;
+
+    pg = geom->FirstPolygon;
+    while (pg)
+      {
+	  /* dissolving any POLYGON as simple LINESTRINGs (rings) */
+	  rng = pg->Exterior;
+	  new_ln = gaiaAddLinestringToGeomColl (result, rng->Points);
+	  for (iv = 0; iv < rng->Points; iv++)
+	    {
+		/* copying the EXTERIOR RING as LINESTRING */
+		if (geom->DimensionModel == GAIA_XY_Z_M)
+		  {
+		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
+		      gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
+		  }
+		else if (geom->DimensionModel == GAIA_XY_Z)
+		  {
+		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
+		      gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
+		  }
+		else if (geom->DimensionModel == GAIA_XY_M)
+		  {
+		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
+		      gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
+		  }
+		else
+		  {
+		      gaiaGetPoint (rng->Coords, iv, &x, &y);
+		      gaiaSetPoint (new_ln->Coords, iv, x, y);
+		  }
+	    }
+	  for (ib = 0; ib < pg->NumInteriors; ib++)
+	    {
+		rng = pg->Interiors + ib;
+		new_ln = gaiaAddLinestringToGeomColl (result, rng->Points);
+		for (iv = 0; iv < rng->Points; iv++)
+		  {
+		      /* copying an INTERIOR RING as LINESTRING */
+		      if (geom->DimensionModel == GAIA_XY_Z_M)
+			{
+			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
+			    gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
+			}
+		      else if (geom->DimensionModel == GAIA_XY_Z)
+			{
+			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
+			    gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
+			}
+		      else if (geom->DimensionModel == GAIA_XY_M)
+			{
+			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
+			    gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
+			}
+		      else
+			{
+			    gaiaGetPoint (rng->Coords, iv, &x, &y);
+			    gaiaSetPoint (new_ln->Coords, iv, x, y);
+			}
+		  }
+	    }
+	  pg = pg->Next;
+      }
+    if (result->FirstLinestring == NULL)
+      {
+	  gaiaFreeGeomColl (result);
+	  return NULL;
+      }
+    return result;
+}
+
+GAIATOPO_DECLARE gaiaGeomCollPtr
+gaiaTopoGeo_SubdivideLines (gaiaGeomCollPtr geom, int line_max_points,
+			    double max_length)
+{
+/* subdividing a (multi)Linestring into collection of simpler Linestrings */
+    gaiaLinestringPtr ln;
+    gaiaGeomCollPtr result;
+
+    if (geom == NULL)
+	return NULL;
+
+    if (geom->FirstPoint != NULL)
+	return NULL;
+    if (geom->FirstLinestring == NULL && geom->FirstPolygon != NULL)
+	return NULL;
+
+    if (geom->DimensionModel == GAIA_XY_Z)
+	result = gaiaAllocGeomCollXYZ ();
+    else if (geom->DimensionModel == GAIA_XY_M)
+	result = gaiaAllocGeomCollXYM ();
+    else if (geom->DimensionModel == GAIA_XY_Z_M)
+	result = gaiaAllocGeomCollXYZM ();
+    else
+	result = gaiaAllocGeomColl ();
+    result->Srid = geom->Srid;
+    result->DeclaredType = GAIA_MULTILINESTRING;
+    ln = geom->FirstLinestring;
+    while (ln != NULL)
+      {
+	  do_geom_split_line (result, ln, line_max_points, max_length);
+	  ln = ln->Next;
+      }
+
+    if (geom->FirstPolygon != NULL)
+      {
+	  /* transforming all Polygon Rings into Linestrings */
+	  gaiaGeomCollPtr pg_rings = do_linearize (geom);
+	  if (pg_rings != NULL)
+	    {
+		ln = pg_rings->FirstLinestring;
+		while (ln != NULL)
+		  {
+		      do_geom_split_line (result, ln, line_max_points,
+					  max_length);
+		      ln = ln->Next;
+		  }
+		gaiaFreeGeomColl (pg_rings);
+	    }
+      }
+    return result;
+}
+
+TOPOLOGY_PRIVATE int
+auxtopo_insert_into_topology (GaiaTopologyAccessorPtr accessor,
+			      gaiaGeomCollPtr geom, double tolerance,
+			      int line_max_points, double max_length)
+{
+/* processing all individual geometry items */
+    gaiaPointPtr pt;
+    gaiaLinestringPtr ln;
+    gaiaGeomCollPtr g;
+    gaiaGeomCollPtr split = NULL;
+    gaiaGeomCollPtr pg_rings;
+    sqlite3_int64 *ids;
+    int ids_count;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    pt = geom->FirstPoint;
+    while (pt != NULL)
+      {
+	  /* looping on Point items */
+	  if (gaiaTopoGeo_AddPoint (accessor, pt, tolerance) < 0)
+	      return 0;
+	  pt = pt->Next;
+      }
+
+    if (line_max_points <= 0 && max_length <= 0.0)
+	g = geom;
+    else
+      {
+	  /* subdividing Linestrings */
+	  split =
+	      gaiaTopoGeo_SubdivideLines (geom, line_max_points, max_length);
+	  if (split != NULL)
+	      g = split;
+	  else
+	      g = geom;
+      }
+    ln = g->FirstLinestring;
+    while (ln != NULL)
+      {
+	  /* looping on Linestrings items */
+	  if (gaiaTopoGeo_AddLineString
+	      (accessor, ln, tolerance, &ids, &ids_count) == 0)
+	      return 0;
+	  if (ids != NULL)
+	      free (ids);
+	  ln = ln->Next;
+      }
+    if (split != NULL)
+	gaiaFreeGeomColl (split);
+    split = NULL;
+
+/* transforming all Polygon Rings into Linestrings */
+    pg_rings = do_linearize (geom);
+    if (pg_rings != NULL)
+      {
+	  if (line_max_points <= 0 && max_length <= 0.0)
+	      g = pg_rings;
+	  else
+	    {
+		/* subdividng Linestrings */
+		split =
+		    gaiaTopoGeo_SubdivideLines (pg_rings, line_max_points,
+						max_length);
+		if (split != NULL)
+		    g = split;
+		else
+		    g = pg_rings;
+	    }
+	  ln = g->FirstLinestring;
+	  while (ln != NULL)
+	    {
+		/* looping on Linestrings items */
+		if (gaiaTopoGeo_AddLineString
+		    (accessor, ln, tolerance, &ids, &ids_count) == 0)
+		    return 0;
+		if (ids != NULL)
+		    free (ids);
+		ln = ln->Next;
+	    }
+	  gaiaFreeGeomColl (pg_rings);
+	  if (split != NULL)
+	      gaiaFreeGeomColl (split);
+	  split = NULL;
+      }
+
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_FromGeoTable (GaiaTopologyAccessorPtr accessor,
+			  const char *db_prefix, const char *table,
+			  const char *column, double tolerance,
+			  int line_max_points, double max_length)
+{
+/* attempting to import a whole GeoTable into a Topology-Geometry */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    char *xcolumn;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+
+    if (topo == NULL)
+	return 0;
+    if (topo->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (topo->cache);
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+/* building the SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (table);
+    xcolumn = gaiaDoubleQuotedSql (column);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\"", xcolumn,
+			 xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    free (xcolumn);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_FromGeoTable error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
+		    continue;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob = sqlite3_column_blob (stmt, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt, 0);
+		      gaiaGeomCollPtr geom =
+			  gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
+						       gpkg_amphibious);
+		      if (geom != NULL)
+			{
+			    if (!auxtopo_insert_into_topology
+				(accessor, geom, tolerance, line_max_points,
+				 max_length))
+			      {
+				  gaiaFreeGeomColl (geom);
+				  goto error;
+			      }
+			    gaiaFreeGeomColl (geom);
+			}
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("TopoGeo_FromGeoTable error: Invalid Geometry");
+			    gaiatopo_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_FromGeoTable error: not a BLOB value");
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_FromGeoTable error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+GAIATOPO_DECLARE gaiaGeomCollPtr
+gaiaGetEdgeSeed (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge)
+{
+/* attempting to get a Point (seed) identifying a Topology Edge */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    gaiaGeomCollPtr point = NULL;
+    if (topo == NULL)
+	return NULL;
+
+/* building the SQL statement */
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
+			 xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("GetEdgeSeed error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, edge);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob = sqlite3_column_blob (stmt, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt, 0);
+		      gaiaGeomCollPtr geom =
+			  gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		      if (geom != NULL)
+			{
+			    int iv;
+			    double x;
+			    double y;
+			    double z = 0.0;
+			    double m = 0.0;
+			    gaiaLinestringPtr ln = geom->FirstLinestring;
+			    if (ln == NULL)
+			      {
+				  char *msg =
+				      sqlite3_mprintf
+				      ("TopoGeo_GetEdgeSeed error: Invalid Geometry");
+				  gaiatopo_set_last_error_msg (accessor, msg);
+				  sqlite3_free (msg);
+				  gaiaFreeGeomColl (geom);
+				  goto error;
+			      }
+			    if (ln->Points == 2)
+			      {
+				  /*
+				     // special case: if the Edge has only 2 points then
+				     // the Seed will always be placed on the first point
+				   */
+				  iv = 0;
+			      }
+			    else
+			      {
+				  /* ordinary case: placing the Seed into the middle */
+				  iv = ln->Points / 2;
+			      }
+			    if (ln->DimensionModel == GAIA_XY_Z)
+			      {
+				  gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
+			      }
+			    else if (ln->DimensionModel == GAIA_XY_M)
+			      {
+				  gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
+			      }
+			    else if (ln->DimensionModel == GAIA_XY_Z_M)
+			      {
+				  gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z,
+						    &m);
+			      }
+			    else
+			      {
+				  gaiaGetPoint (ln->Coords, iv, &x, &y);
+			      }
+			    gaiaFreeGeomColl (geom);
+			    if (topo->has_z)
+			      {
+				  point = gaiaAllocGeomCollXYZ ();
+				  gaiaAddPointToGeomCollXYZ (point, x, y, z);
+			      }
+			    else
+			      {
+				  point = gaiaAllocGeomColl ();
+				  gaiaAddPointToGeomColl (point, x, y);
+			      }
+			    point->Srid = topo->srid;
+			}
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("TopoGeo_GetEdgeSeed error: Invalid Geometry");
+			    gaiatopo_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_GetEdgeSeed error: not a BLOB value");
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_GetEdgeSeed error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt);
+    return point;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return NULL;
+}
+
+GAIATOPO_DECLARE gaiaGeomCollPtr
+gaiaGetFaceSeed (GaiaTopologyAccessorPtr accessor, sqlite3_int64 face)
+{
+/* attempting to get a Point (seed) identifying a Topology Face */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    gaiaGeomCollPtr point = NULL;
+    if (topo == NULL)
+	return NULL;
+
+/* building the SQL statement */
+    sql =
+	sqlite3_mprintf ("SELECT ST_PointOnSurface(ST_GetFaceGeometry(%Q, ?))",
+			 topo->topology_name);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("GetFaceSeed error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, face);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
+		  {
+		      const unsigned char *blob = sqlite3_column_blob (stmt, 0);
+		      int blob_sz = sqlite3_column_bytes (stmt, 0);
+		      point = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		      if (point == NULL)
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("TopoGeo_GetFaceSeed error: Invalid Geometry");
+			    gaiatopo_set_last_error_msg (accessor, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_GetFaceSeed error: not a BLOB value");
+		      gaiatopo_set_last_error_msg (accessor, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_GetFaceSeed error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt);
+    return point;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return NULL;
+}
+
+static int
+delete_all_seeds (struct gaia_topology *topo)
+{
+/* deleting all existing Seeds */
+    char *table;
+    char *xtable;
+    char *sql;
+    char *errMsg;
+    int ret;
+
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+update_outdated_edge_seeds (struct gaia_topology *topo)
+{
+/* updating all outdated Edge Seeds */
+    char *table;
+    char *xseeds;
+    char *xedges;
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt_out;
+    sqlite3_stmt *stmt_in;
+
+/* preparing the UPDATE statement */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET geom = "
+			   "TopoGeo_GetEdgeSeed(%Q, edge_id) WHERE edge_id = ?",
+			   xseeds, topo->topology_name);
+    free (xseeds);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the SELECT statement */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xedges = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT s.edge_id FROM MAIN.\"%s\" AS s "
+			   "JOIN MAIN.\"%s\" AS e ON (e.edge_id = s.edge_id) "
+			   "WHERE s.edge_id IS NOT NULL AND e.timestamp > s.timestamp",
+			   xseeds, xedges);
+    free (xseeds);
+    free (xedges);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		sqlite3_bind_int64 (stmt_out, 1,
+				    sqlite3_column_int64 (stmt_in, 0));
+		/* updating the Seeds table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_UpdateSeeds() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+update_outdated_face_seeds (struct gaia_topology *topo)
+{
+/* updating all outdated Face Seeds */
+    char *table;
+    char *xseeds;
+    char *xedges;
+    char *xfaces;
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt_out;
+    sqlite3_stmt *stmt_in;
+
+/* preparing the UPDATE statement */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET geom = "
+			   "TopoGeo_GetFaceSeed(%Q, face_id) WHERE face_id = ?",
+			   xseeds, topo->topology_name);
+    free (xseeds);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the SELECT statement */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xedges = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xfaces = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT x.face_id FROM MAIN.\"%s\" AS s, "
+			   "(SELECT f.face_id AS face_id, Max(e.timestamp) AS max_tm "
+			   "FROM MAIN.\"%s\" AS f "
+			   "JOIN MAIN.\"%s\" AS e ON (e.left_face = f.face_id OR e.right_face = f.face_id) "
+			   "GROUP BY f.face_id) AS x "
+			   "WHERE s.face_id IS NOT NULL AND s.face_id = x.face_id AND x.max_tm > s.timestamp",
+			   xseeds, xfaces, xedges);
+    free (xseeds);
+    free (xedges);
+    free (xfaces);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		sqlite3_bind_int64 (stmt_out, 1,
+				    sqlite3_column_int64 (stmt_in, 0));
+		/* updating the Seeds table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_UpdateSeeds() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeoUpdateSeeds (GaiaTopologyAccessorPtr accessor, int incremental_mode)
+{
+/* updating all TopoGeo Seeds */
+    char *table;
+    char *xseeds;
+    char *xedges;
+    char *xfaces;
+    char *sql;
+    char *errMsg;
+    int ret;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    if (!incremental_mode)
+      {
+	  /* deleting all existing Seeds */
+	  if (!delete_all_seeds (topo))
+	      return 0;
+      }
+
+/* paranoid precaution: deleting all orphan Edge Seeds */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xedges = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE edge_id IN ("
+			   "SELECT s.edge_id FROM MAIN.\"%s\" AS s "
+			   "LEFT JOIN MAIN.\"%s\" AS e ON (s.edge_id = e.edge_id) "
+			   "WHERE s.edge_id IS NOT NULL AND e.edge_id IS NULL)",
+			   xseeds, xseeds, xedges);
+    free (xseeds);
+    free (xedges);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* paranoid precaution: deleting all orphan Face Seeds */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xfaces = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE face_id IN ("
+			   "SELECT s.face_id FROM MAIN.\"%s\" AS s "
+			   "LEFT JOIN MAIN.\"%s\" AS f ON (s.face_id = f.face_id) "
+			   "WHERE s.face_id IS NOT NULL AND f.face_id IS NULL)",
+			   xseeds, xseeds, xfaces);
+    free (xseeds);
+    free (xfaces);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* updating all outdated Edge Seeds */
+    if (!update_outdated_edge_seeds (topo))
+	return 0;
+
+/* updating all outdated Facee Seeds */
+    if (!update_outdated_face_seeds (topo))
+	return 0;
+
+/* inserting all missing Edge Seeds */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xedges = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (seed_id, edge_id, face_id, geom) "
+	 "SELECT NULL, e.edge_id, NULL, TopoGeo_GetEdgeSeed(%Q, e.edge_id) "
+	 "FROM MAIN.\"%s\" AS e "
+	 "LEFT JOIN MAIN.\"%s\" AS s ON (e.edge_id = s.edge_id) WHERE s.edge_id IS NULL",
+	 xseeds, topo->topology_name, xedges, xseeds);
+    free (xseeds);
+    free (xedges);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    /* inserting all missing Face Seeds */
+    table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xseeds = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xfaces = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (seed_id, edge_id, face_id, geom) "
+	 "SELECT NULL, NULL, f.face_id, TopoGeo_GetFaceSeed(%Q, f.face_id) "
+	 "FROM MAIN.\"%s\" AS f "
+	 "LEFT JOIN MAIN.\"%s\" AS s ON (f.face_id = s.face_id) "
+	 "WHERE s.face_id IS NULL AND f.face_id <> 0", xseeds,
+	 topo->topology_name, xfaces, xseeds);
+    free (xseeds);
+    free (xfaces);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static gaiaGeomCollPtr
+make_geom_from_polyg (int srid, gaiaPolygonPtr pg)
+{
+/* quick constructor: Geometry based on external polyg */
+    gaiaGeomCollPtr reference;
+    if (pg->DimensionModel == GAIA_XY_Z_M)
+	reference = gaiaAllocGeomCollXYZM ();
+    else if (pg->DimensionModel == GAIA_XY_Z)
+	reference = gaiaAllocGeomCollXYZ ();
+    else if (pg->DimensionModel == GAIA_XY_M)
+	reference = gaiaAllocGeomCollXYM ();
+    else
+	reference = gaiaAllocGeomColl ();
+    reference->Srid = srid;
+    pg->Next = NULL;
+    reference->FirstPolygon = pg;
+    reference->LastPolygon = pg;
+    return reference;
+}
+
+static void
+do_eval_topogeo_point (struct gaia_topology *topo, gaiaGeomCollPtr result,
+		       gaiaGeomCollPtr reference, sqlite3_stmt * stmt_node)
+{
+/* retrieving Points from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+
+/* initializing the Topo-Node query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_node);
+    sqlite3_clear_bindings (stmt_node);
+    sqlite3_bind_blob (stmt_node, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_node, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_node);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt_node, 0);
+		int blob_sz = sqlite3_column_bytes (stmt_node, 0);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      gaiaPointPtr pt = geom->FirstPoint;
+		      while (pt != NULL)
+			{
+			    /* copying all Points into the result Geometry */
+			    if (topo->has_z)
+				gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
+							   pt->Z);
+			    else
+				gaiaAddPointToGeomColl (result, pt->X, pt->Y);
+			    pt = pt->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static void
+do_collect_topo_edges (struct gaia_topology *topo, gaiaGeomCollPtr sparse,
+		       sqlite3_stmt * stmt_edge, sqlite3_int64 edge_id)
+{
+/* collecting Edge Geometries one by one */
+    int ret;
+
+/* initializing the Topo-Edge query */
+    sqlite3_reset (stmt_edge);
+    sqlite3_clear_bindings (stmt_edge);
+    sqlite3_bind_int64 (stmt_edge, 1, edge_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_edge);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt_edge, 0);
+		int blob_sz = sqlite3_column_bytes (stmt_edge, 0);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      gaiaLinestringPtr ln = geom->FirstLinestring;
+		      while (ln != NULL)
+			{
+			    if (topo->has_z)
+				auxtopo_copy_linestring3d (ln, sparse);
+			    else
+				auxtopo_copy_linestring (ln, sparse);
+			    ln = ln->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static void
+do_eval_topogeo_line (struct gaia_topology *topo, gaiaGeomCollPtr result,
+		      gaiaGeomCollPtr reference, sqlite3_stmt * stmt_seed_edge,
+		      sqlite3_stmt * stmt_edge)
+{
+/* retrieving Linestrings from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr sparse;
+    gaiaGeomCollPtr rearranged;
+    gaiaLinestringPtr ln;
+
+    if (topo->has_z)
+	sparse = gaiaAllocGeomCollXYZ ();
+    else
+	sparse = gaiaAllocGeomColl ();
+    sparse->Srid = topo->srid;
+
+/* initializing the Topo-Seed-Edge query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_seed_edge);
+    sqlite3_clear_bindings (stmt_seed_edge);
+    sqlite3_bind_blob (stmt_seed_edge, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_seed_edge, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_seed_edge);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id =
+		    sqlite3_column_int64 (stmt_seed_edge, 0);
+		do_collect_topo_edges (topo, sparse, stmt_edge, edge_id);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		gaiaFreeGeomColl (sparse);
+		return;
+	    }
+      }
+
+/* attempting to rearrange sparse lines */
+    rearranged = gaiaLineMerge_r (topo->cache, sparse);
+    gaiaFreeGeomColl (sparse);
+    if (rearranged == NULL)
+	return;
+    ln = rearranged->FirstLinestring;
+    while (ln != NULL)
+      {
+	  if (topo->has_z)
+	      auxtopo_copy_linestring3d (ln, result);
+	  else
+	      auxtopo_copy_linestring (ln, result);
+	  ln = ln->Next;
+      }
+    gaiaFreeGeomColl (rearranged);
+}
+
+static void
+do_explode_topo_face (struct gaia_topology *topo, struct face_edges *list,
+		      sqlite3_stmt * stmt_face, sqlite3_int64 face_id)
+{
+/* exploding all Edges required by the same face */
+    int ret;
+
+/* initializing the Topo-Face query */
+    sqlite3_reset (stmt_face);
+    sqlite3_clear_bindings (stmt_face);
+    sqlite3_bind_int64 (stmt_face, 1, face_id);
+    sqlite3_bind_int64 (stmt_face, 2, face_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_face);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_face, 0);
+		sqlite3_int64 left_face = sqlite3_column_int64 (stmt_face, 1);
+		sqlite3_int64 right_face = sqlite3_column_int64 (stmt_face, 2);
+		const unsigned char *blob = sqlite3_column_blob (stmt_face, 3);
+		int blob_sz = sqlite3_column_bytes (stmt_face, 3);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		    auxtopo_add_face_edge (list, face_id, edge_id, left_face,
+					   right_face, geom);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static void
+do_copy_ring3d (gaiaRingPtr in, gaiaRingPtr out)
+{
+/* inserting/copying a Ring 3D into another Ring */
+    int iv;
+    double x;
+    double y;
+    double z;
+    for (iv = 0; iv < in->Points; iv++)
+      {
+	  gaiaGetPointXYZ (in->Coords, iv, &x, &y, &z);
+	  gaiaSetPointXYZ (out->Coords, iv, x, y, z);
+      }
+}
+
+static void
+do_copy_ring (gaiaRingPtr in, gaiaRingPtr out)
+{
+/* inserting/copying a Ring into another Ring */
+    int iv;
+    double x;
+    double y;
+    for (iv = 0; iv < in->Points; iv++)
+      {
+	  gaiaGetPoint (in->Coords, iv, &x, &y);
+	  gaiaSetPoint (out->Coords, iv, x, y);
+      }
+}
+
+static void
+do_copy_polygon3d (gaiaPolygonPtr in, gaiaGeomCollPtr geom)
+{
+/* inserting/copying a Polygon 3D into another Geometry */
+    int ib;
+    gaiaRingPtr rng_out;
+    gaiaRingPtr rng_in = in->Exterior;
+    gaiaPolygonPtr out =
+	gaiaAddPolygonToGeomColl (geom, rng_in->Points, in->NumInteriors);
+    rng_out = out->Exterior;
+    do_copy_ring3d (rng_in, rng_out);
+    for (ib = 0; ib < in->NumInteriors; ib++)
+      {
+	  rng_in = in->Interiors + ib;
+	  rng_out = gaiaAddInteriorRing (out, ib, rng_in->Points);
+	  do_copy_ring3d (rng_in, rng_out);
+      }
+}
+
+static void
+do_copy_polygon (gaiaPolygonPtr in, gaiaGeomCollPtr geom)
+{
+/* inserting/copying a Polygon into another Geometry */
+    int ib;
+    gaiaRingPtr rng_out;
+    gaiaRingPtr rng_in = in->Exterior;
+    gaiaPolygonPtr out =
+	gaiaAddPolygonToGeomColl (geom, rng_in->Points, in->NumInteriors);
+    rng_out = out->Exterior;
+    do_copy_ring (rng_in, rng_out);
+    for (ib = 0; ib < in->NumInteriors; ib++)
+      {
+	  rng_in = in->Interiors + ib;
+	  rng_out = gaiaAddInteriorRing (out, ib, rng_in->Points);
+	  do_copy_ring (rng_in, rng_out);
+      }
+}
+
+static void
+do_copy_filter_polygon3d (gaiaPolygonPtr in, gaiaGeomCollPtr geom,
+			  const void *cache, double tolerance)
+{
+/* inserting/copying a Polygon 3D into another Geometry (with tolerance) */
+    int ib;
+    gaiaGeomCollPtr polyg;
+    gaiaPolygonPtr pg;
+    gaiaRingPtr rng_out;
+    gaiaRingPtr rng_in = in->Exterior;
+    gaiaPolygonPtr out;
+    double area;
+    int ret;
+    int numints = 0;
+
+    polyg = gaiaAllocGeomCollXYZ ();
+    pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
+    rng_out = pg->Exterior;
+    do_copy_ring3d (rng_in, rng_out);
+    ret = gaiaGeomCollArea_r (cache, polyg, &area);
+    gaiaFreeGeomColl (polyg);
+    if (!ret)
+	return;
+    if ((tolerance * tolerance) > area)
+	return;			/* skipping smaller polygons */
+
+    for (ib = 0; ib < in->NumInteriors; ib++)
+      {
+	  /* counting how many interior rings do we really have */
+	  rng_in = in->Interiors + ib;
+	  polyg = gaiaAllocGeomCollXYZ ();
+	  pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
+	  rng_out = pg->Exterior;
+	  do_copy_ring3d (rng_in, rng_out);
+	  ret = gaiaGeomCollArea_r (cache, polyg, &area);
+	  gaiaFreeGeomColl (polyg);
+	  if (!ret)
+	      continue;
+	  if ((tolerance * tolerance) > area)
+	      continue;		/* skipping smaller holes */
+	  numints++;
+      }
+
+    rng_in = in->Exterior;
+    out = gaiaAddPolygonToGeomColl (geom, rng_in->Points, numints);
+    rng_out = out->Exterior;
+    do_copy_ring3d (rng_in, rng_out);
+    numints = 0;
+    for (ib = 0; ib < in->NumInteriors; ib++)
+      {
+	  /* copying interior rings */
+	  rng_in = in->Interiors + ib;
+	  polyg = gaiaAllocGeomCollXYZ ();
+	  pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
+	  rng_out = pg->Exterior;
+	  do_copy_ring3d (rng_in, rng_out);
+	  ret = gaiaGeomCollArea_r (cache, polyg, &area);
+	  gaiaFreeGeomColl (polyg);
+	  if (!ret)
+	      continue;
+	  if ((tolerance * tolerance) > area)
+	      continue;		/* skipping smaller holes */
+	  rng_out = gaiaAddInteriorRing (out, numints++, rng_in->Points);
+	  do_copy_ring3d (rng_in, rng_out);
+      }
+}
+
+static void
+do_copy_filter_polygon (gaiaPolygonPtr in, gaiaGeomCollPtr geom,
+			const void *cache, double tolerance)
+{
+/* inserting/copying a Polygon into another Geometry (with tolerance) */
+    int ib;
+    gaiaGeomCollPtr polyg;
+    gaiaPolygonPtr pg;
+    gaiaRingPtr rng_out;
+    gaiaRingPtr rng_in = in->Exterior;
+    gaiaPolygonPtr out;
+    double area;
+    int ret;
+    int numints = 0;
+
+    polyg = gaiaAllocGeomColl ();
+    pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
+    rng_out = pg->Exterior;
+    do_copy_ring (rng_in, rng_out);
+    ret = gaiaGeomCollArea_r (cache, polyg, &area);
+    gaiaFreeGeomColl (polyg);
+    if (!ret)
+	return;
+    if ((tolerance * tolerance) > area)
+	return;			/* skipping smaller polygons */
+
+    for (ib = 0; ib < in->NumInteriors; ib++)
+      {
+	  /* counting how many interior rings do we really have */
+	  rng_in = in->Interiors + ib;
+	  polyg = gaiaAllocGeomColl ();
+	  pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
+	  rng_out = pg->Exterior;
+	  do_copy_ring (rng_in, rng_out);
+	  ret = gaiaGeomCollArea_r (cache, polyg, &area);
+	  gaiaFreeGeomColl (polyg);
+	  if (!ret)
+	      continue;
+	  if ((tolerance * tolerance) > area)
+	      continue;		/* skipping smaller holes */
+	  numints++;
+      }
+
+    rng_in = in->Exterior;
+    out = gaiaAddPolygonToGeomColl (geom, rng_in->Points, numints);
+    rng_out = out->Exterior;
+    do_copy_ring (rng_in, rng_out);
+    numints = 0;
+    for (ib = 0; ib < in->NumInteriors; ib++)
+      {
+	  /* copying interior rings */
+	  rng_in = in->Interiors + ib;
+	  polyg = gaiaAllocGeomColl ();
+	  pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
+	  rng_out = pg->Exterior;
+	  do_copy_ring (rng_in, rng_out);
+	  ret = gaiaGeomCollArea_r (cache, polyg, &area);
+	  gaiaFreeGeomColl (polyg);
+	  if (!ret)
+	      continue;
+	  if ((tolerance * tolerance) > area)
+	      continue;		/* skipping smaller holes */
+	  rng_out = gaiaAddInteriorRing (out, numints++, rng_in->Points);
+	  do_copy_ring (rng_in, rng_out);
+      }
+}
+
+static void
+do_eval_topo_polyg (struct gaia_topology *topo, gaiaGeomCollPtr result,
+		    gaiaGeomCollPtr reference, sqlite3_stmt * stmt_seed_face,
+		    sqlite3_stmt * stmt_face)
+{
+/* retrieving Polygons from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr rearranged;
+    gaiaPolygonPtr pg;
+    struct face_edges *list =
+	auxtopo_create_face_edges (topo->has_z, topo->srid);
+
+/* initializing the Topo-Seed-Face query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_seed_face);
+    sqlite3_clear_bindings (stmt_seed_face);
+    sqlite3_bind_blob (stmt_seed_face, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_seed_face, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_seed_face);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id =
+		    sqlite3_column_int64 (stmt_seed_face, 0);
+		do_explode_topo_face (topo, list, stmt_face, face_id);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		auxtopo_free_face_edges (list);
+		return;
+	    }
+      }
+
+/* attempting to rearrange sparse lines into Polygons */
+    auxtopo_select_valid_face_edges (list);
+    rearranged = auxtopo_polygonize_face_edges (list, topo->cache);
+    auxtopo_free_face_edges (list);
+    if (rearranged == NULL)
+	return;
+    pg = rearranged->FirstPolygon;
+    while (pg != NULL)
+      {
+	  if (topo->has_z)
+	      do_copy_polygon3d (pg, result);
+	  else
+	      do_copy_polygon (pg, result);
+	  pg = pg->Next;
+      }
+    gaiaFreeGeomColl (rearranged);
+}
+
+static void
+do_eval_topo_polyg_generalize (struct gaia_topology *topo,
+			       gaiaGeomCollPtr result,
+			       gaiaGeomCollPtr reference,
+			       sqlite3_stmt * stmt_seed_face,
+			       sqlite3_stmt * stmt_face, double tolerance)
+{
+/* retrieving Polygons from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr rearranged;
+    gaiaPolygonPtr pg;
+    struct face_edges *list =
+	auxtopo_create_face_edges (topo->has_z, topo->srid);
+
+/* initializing the Topo-Seed-Face query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_seed_face);
+    sqlite3_clear_bindings (stmt_seed_face);
+    sqlite3_bind_blob (stmt_seed_face, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_seed_face, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_seed_face);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id =
+		    sqlite3_column_int64 (stmt_seed_face, 0);
+		do_explode_topo_face (topo, list, stmt_face, face_id);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		auxtopo_free_face_edges (list);
+		return;
+	    }
+      }
+
+/* attempting to rearrange sparse lines into Polygons */
+    auxtopo_select_valid_face_edges (list);
+    rearranged = auxtopo_polygonize_face_edges_generalize (list, topo->cache);
+    auxtopo_free_face_edges (list);
+    if (rearranged == NULL)
+	return;
+    pg = rearranged->FirstPolygon;
+    while (pg != NULL)
+      {
+	  if (topo->has_z)
+	      do_copy_filter_polygon3d (pg, result, topo->cache, tolerance);
+	  else
+	      do_copy_filter_polygon (pg, result, topo->cache, tolerance);
+	  pg = pg->Next;
+      }
+    gaiaFreeGeomColl (rearranged);
+}
+
+static gaiaGeomCollPtr
+do_eval_topogeo_geom (struct gaia_topology *topo, gaiaGeomCollPtr geom,
+		      sqlite3_stmt * stmt_seed_edge,
+		      sqlite3_stmt * stmt_seed_face, sqlite3_stmt * stmt_node,
+		      sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_face,
+		      int out_type, double tolerance)
+{
+/* retrieving Topology-Geometry geometries via matching Seeds */
+    gaiaGeomCollPtr result;
+
+    if (topo->has_z)
+	result = gaiaAllocGeomCollXYZ ();
+    else
+	result = gaiaAllocGeomColl ();
+    result->Srid = topo->srid;
+    result->DeclaredType = out_type;
+
+    if (out_type == GAIA_POINT || out_type == GAIA_MULTIPOINT
+	|| out_type == GAIA_GEOMETRYCOLLECTION || out_type == GAIA_UNKNOWN)
+      {
+	  /* processing all Points */
+	  gaiaPointPtr pt = geom->FirstPoint;
+	  while (pt != NULL)
+	    {
+		gaiaPointPtr next = pt->Next;
+		gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
+		    auxtopo_make_geom_from_point (topo->srid, topo->has_z, pt);
+		do_eval_topogeo_point (topo, result, reference, stmt_node);
+		auxtopo_destroy_geom_from (reference);
+		pt->Next = next;
+		pt = pt->Next;
+	    }
+      }
+
+    if (out_type == GAIA_MULTILINESTRING || out_type == GAIA_GEOMETRYCOLLECTION
+	|| out_type == GAIA_UNKNOWN)
+      {
+	  /* processing all Linestrings */
+	  gaiaLinestringPtr ln = geom->FirstLinestring;
+	  while (ln != NULL)
+	    {
+		gaiaLinestringPtr next = ln->Next;
+		gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
+		    auxtopo_make_geom_from_line (topo->srid, ln);
+		do_eval_topogeo_line (topo, result, reference, stmt_seed_edge,
+				      stmt_edge);
+		auxtopo_destroy_geom_from (reference);
+		ln->Next = next;
+		ln = ln->Next;
+	    }
+      }
+
+    if (out_type == GAIA_MULTIPOLYGON || out_type == GAIA_GEOMETRYCOLLECTION
+	|| out_type == GAIA_UNKNOWN)
+      {
+	  /* processing all Polygons */
+	  gaiaPolygonPtr pg = geom->FirstPolygon;
+	  while (pg != NULL)
+	    {
+		gaiaPolygonPtr next = pg->Next;
+		gaiaGeomCollPtr reference =
+		    make_geom_from_polyg (topo->srid, pg);
+		if (tolerance > 0.0)
+		    do_eval_topo_polyg_generalize (topo, result, reference,
+						   stmt_seed_face, stmt_face,
+						   tolerance);
+		else
+		    do_eval_topo_polyg (topo, result, reference, stmt_seed_face,
+					stmt_face);
+		auxtopo_destroy_geom_from (reference);
+		pg->Next = next;
+		pg = pg->Next;
+	    }
+      }
+
+    if (result->FirstPoint == NULL && result->FirstLinestring == NULL
+	&& result->FirstPolygon == NULL)
+	goto error;
+    return result;
+
+  error:
+    gaiaFreeGeomColl (result);
+    return NULL;
+}
+
+static int
+do_eval_topogeo_seeds (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
+		       int ref_geom_col, sqlite3_stmt * stmt_ins,
+		       sqlite3_stmt * stmt_seed_edge,
+		       sqlite3_stmt * stmt_seed_face, sqlite3_stmt * stmt_node,
+		       sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_face,
+		       int out_type, double tolerance)
+{
+/* querying the ref-table */
+    int ret;
+
+    sqlite3_reset (stmt_ref);
+    sqlite3_clear_bindings (stmt_ref);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_ref);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int icol;
+		int ncol = sqlite3_column_count (stmt_ref);
+		sqlite3_reset (stmt_ins);
+		sqlite3_clear_bindings (stmt_ins);
+		for (icol = 0; icol < ncol; icol++)
+		  {
+		      int col_type = sqlite3_column_type (stmt_ref, icol);
+		      if (icol == ref_geom_col)
+			{
+			    /* the geometry column */
+			    const unsigned char *blob =
+				sqlite3_column_blob (stmt_ref, icol);
+			    int blob_sz = sqlite3_column_bytes (stmt_ref, icol);
+			    gaiaGeomCollPtr geom =
+				gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+			    if (geom != NULL)
+			      {
+				  unsigned char *p_blob;
+				  int n_bytes;
+				  int gpkg_mode = 0;
+				  if (topo->cache != NULL)
+				    {
+					struct splite_internal_cache *cache =
+					    (struct splite_internal_cache
+					     *) (topo->cache);
+					gpkg_mode = cache->gpkg_mode;
+				    }
+				  gaiaGeomCollPtr result =
+				      do_eval_topogeo_geom (topo, geom,
+							    stmt_seed_edge,
+							    stmt_seed_face,
+							    stmt_node,
+							    stmt_edge,
+							    stmt_face,
+							    out_type,
+							    tolerance);
+				  gaiaFreeGeomColl (geom);
+				  if (result != NULL)
+				    {
+					gaiaToSpatiaLiteBlobWkbEx (result,
+								   &p_blob,
+								   &n_bytes,
+								   gpkg_mode);
+					gaiaFreeGeomColl (result);
+					sqlite3_bind_blob (stmt_ins, icol + 1,
+							   p_blob, n_bytes,
+							   free);
+				    }
+				  else
+				      sqlite3_bind_null (stmt_ins, icol + 1);
+			      }
+			    else
+				sqlite3_bind_null (stmt_ins, icol + 1);
+			    continue;
+			}
+		      switch (col_type)
+			{
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_ins, icol + 1,
+						sqlite3_column_int64 (stmt_ref,
+								      icol));
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_ins, icol + 1,
+						 sqlite3_column_double
+						 (stmt_ref, icol));
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_ins, icol + 1,
+					       (const char *)
+					       sqlite3_column_text (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			case SQLITE_BLOB:
+			    sqlite3_bind_blob (stmt_ins, icol + 1,
+					       sqlite3_column_blob (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_ins, icol + 1);
+			    break;
+			};
+		  }
+		ret = sqlite3_step (stmt_ins);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+					   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_ToGeoTableGeneralize (GaiaTopologyAccessorPtr accessor,
+				  const char *db_prefix, const char *ref_table,
+				  const char *ref_column, const char *out_table,
+				  double tolerance, int with_spatial_index)
+{
+/* 
+/ attempting to create and populate a new GeoTable out from a Topology-Geometry 
+/ (simplified/generalized form)
+*/
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt_ref = NULL;
+    sqlite3_stmt *stmt_ins = NULL;
+    sqlite3_stmt *stmt_seed_edge = NULL;
+    sqlite3_stmt *stmt_seed_face = NULL;
+    sqlite3_stmt *stmt_node = NULL;
+    sqlite3_stmt *stmt_edge = NULL;
+    sqlite3_stmt *stmt_face = NULL;
+    int ret;
+    char *create;
+    char *select;
+    char *insert;
+    char *sql;
+    char *errMsg;
+    char *xprefix;
+    char *xtable;
+    int ref_type;
+    const char *type;
+    int out_type;
+    int ref_geom_col;
+    if (topo == NULL)
+	return 0;
+
+/* incrementally updating all Topology Seeds */
+    if (!gaiaTopoGeoUpdateSeeds (accessor, 1))
+	return 0;
+
+/* composing the CREATE TABLE output-table statement */
+    if (!auxtopo_create_togeotable_sql
+	(topo->db_handle, db_prefix, ref_table, ref_column, out_table, &create,
+	 &select, &insert, &ref_geom_col))
+	goto error;
+
+/* creating the output-table */
+    ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
+    sqlite3_free (create);
+    create = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* checking the Geometry Type */
+    if (!auxtopo_retrieve_geometry_type
+	(topo->db_handle, db_prefix, ref_table, ref_column, &ref_type))
+	goto error;
+    switch (ref_type)
+      {
+      case GAIA_POINT:
+      case GAIA_POINTZ:
+      case GAIA_POINTM:
+      case GAIA_POINTZM:
+	  type = "POINT";
+	  out_type = GAIA_POINT;
+	  break;
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTIPOINTZM:
+	  type = "MULTIPOINT";
+	  out_type = GAIA_MULTIPOINT;
+	  break;
+      case GAIA_LINESTRING:
+      case GAIA_LINESTRINGZ:
+      case GAIA_LINESTRINGM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTILINESTRINGZM:
+	  type = "MULTILINESTRING";
+	  out_type = GAIA_MULTILINESTRING;
+	  break;
+      case GAIA_POLYGON:
+      case GAIA_POLYGONZ:
+      case GAIA_POLYGONM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_MULTIPOLYGONM:
+      case GAIA_MULTIPOLYGONZM:
+	  type = "MULTIPOLYGON";
+	  out_type = GAIA_MULTIPOLYGON;
+	  break;
+      case GAIA_GEOMETRYCOLLECTION:
+      case GAIA_GEOMETRYCOLLECTIONZ:
+      case GAIA_GEOMETRYCOLLECTIONM:
+      case GAIA_GEOMETRYCOLLECTIONZM:
+	  type = "GEOMETRYCOLLECTION";
+	  out_type = GAIA_GEOMETRYCOLLECTION;
+	  break;
+      default:
+	  type = "GEOMETRY";
+	  out_type = GAIA_UNKNOWN;
+	  break;
+      };
+
+/* creating the output Geometry Column */
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(Lower(%Q), Lower(%Q), %d, '%s', '%s')",
+	 out_table, ref_column, topo->srid, type,
+	 (topo->has_z == 0) ? "XY" : "XYZ");
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    if (with_spatial_index)
+      {
+	  /* adding a Spatial Index supporting the Geometry Column */
+	  sql =
+	      sqlite3_mprintf
+	      ("SELECT CreateSpatialIndex(Lower(%Q), Lower(%Q))",
+	       out_table, ref_column);
+	  ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				     errMsg);
+		sqlite3_free (errMsg);
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+/* preparing the "SELECT * FROM ref-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
+			    NULL);
+    sqlite3_free (select);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO out-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
+			    NULL);
+    sqlite3_free (insert);
+    insert = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Seed-Edges query */
+    xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" "
+			   "WHERE edge_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_seed_edge,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Seed-Faces query */
+    xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT face_id FROM MAIN.\"%s\" "
+			   "WHERE face_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_seed_face,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Nodes query */
+    xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" "
+			   "WHERE ST_Intersects(geom, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Edges query */
+    xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    if (tolerance > 0.0)
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT ST_SimplifyPreserveTopology(geom, %1.6f) FROM MAIN.\"%s\" WHERE edge_id = ?",
+	     tolerance, xtable, xprefix);
+    else
+	sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
+			       xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Faces query */
+    xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    if (tolerance > 0.0)
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT edge_id, left_face, right_face, ST_SimplifyPreserveTopology(geom, %1.6f) FROM MAIN.\"%s\" "
+	     "WHERE left_face = ? OR right_face = ?", tolerance, xtable);
+    else
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT edge_id, left_face, right_face, geom FROM MAIN.\"%s\" "
+	     "WHERE left_face = ? OR right_face = ?", xtable);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* evaluating feature/topology matching via coincident topo-seeds */
+    if (!do_eval_topogeo_seeds
+	(topo, stmt_ref, ref_geom_col, stmt_ins, stmt_seed_edge, stmt_seed_face,
+	 stmt_node, stmt_edge, stmt_face, out_type, tolerance))
+	goto error;
+
+    sqlite3_finalize (stmt_ref);
+    sqlite3_finalize (stmt_ins);
+    sqlite3_finalize (stmt_seed_edge);
+    sqlite3_finalize (stmt_seed_face);
+    sqlite3_finalize (stmt_node);
+    sqlite3_finalize (stmt_edge);
+    sqlite3_finalize (stmt_face);
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    if (stmt_ref != NULL)
+	sqlite3_finalize (stmt_ref);
+    if (stmt_ins != NULL)
+	sqlite3_finalize (stmt_ins);
+    if (stmt_seed_edge != NULL)
+	sqlite3_finalize (stmt_seed_edge);
+    if (stmt_seed_face != NULL)
+	sqlite3_finalize (stmt_seed_face);
+    if (stmt_node != NULL)
+	sqlite3_finalize (stmt_node);
+    if (stmt_edge != NULL)
+	sqlite3_finalize (stmt_edge);
+    if (stmt_face != NULL)
+	sqlite3_finalize (stmt_face);
+    return 0;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_ToGeoTable (GaiaTopologyAccessorPtr accessor,
+			const char *db_prefix, const char *ref_table,
+			const char *ref_column, const char *out_table,
+			int with_spatial_index)
+{
+/* attempting to create and populate a new GeoTable out from a Topology-Geometry */
+    return gaiaTopoGeo_ToGeoTableGeneralize (accessor, db_prefix, ref_table,
+					     ref_column, out_table, -1.0,
+					     with_spatial_index);
+}
+
+static struct face_item *
+create_face_item (sqlite3_int64 face_id)
+{
+/* creating a Face Item */
+    struct face_item *item = malloc (sizeof (struct face_item));
+    item->face_id = face_id;
+    item->next = NULL;
+    return item;
+}
+
+static void
+destroy_face_item (struct face_item *item)
+{
+/* destroying a Face Item */
+    if (item == NULL)
+	return;
+    free (item);
+}
+
+static struct face_edge_item *
+create_face_edge_item (sqlite3_int64 edge_id, sqlite3_int64 left_face,
+		       sqlite3_int64 right_face, gaiaGeomCollPtr geom)
+{
+/* creating a Face-Edge Item */
+    struct face_edge_item *item = malloc (sizeof (struct face_edge_item));
+    item->edge_id = edge_id;
+    item->left_face = left_face;
+    item->right_face = right_face;
+    item->geom = geom;
+    item->count = 0;
+    item->next = NULL;
+    return item;
+}
+
+static void
+destroy_face_edge_item (struct face_edge_item *item)
+{
+/* destroying a Face-Edge Item */
+    if (item == NULL)
+	return;
+    if (item->geom != NULL)
+	gaiaFreeGeomColl (item->geom);
+    free (item);
+}
+
+TOPOLOGY_PRIVATE struct face_edges *
+auxtopo_create_face_edges (int has_z, int srid)
+{
+/* creating an empty Face-Edges list */
+    struct face_edges *list = malloc (sizeof (struct face_edges));
+    list->has_z = has_z;
+    list->srid = srid;
+    list->first_edge = NULL;
+    list->last_edge = NULL;
+    list->first_face = NULL;
+    list->last_face = NULL;
+    return list;
+}
+
+TOPOLOGY_PRIVATE void
+auxtopo_free_face_edges (struct face_edges *list)
+{
+/* destroying a Face-Edges list */
+    struct face_edge_item *fe;
+    struct face_edge_item *fen;
+    struct face_item *f;
+    struct face_item *fn;
+    if (list == NULL)
+	return;
+
+    fe = list->first_edge;
+    while (fe != NULL)
+      {
+	  /* destroying all Face-Edge items */
+	  fen = fe->next;
+	  destroy_face_edge_item (fe);
+	  fe = fen;
+      }
+    f = list->first_face;
+    while (f != NULL)
+      {
+	  /* destroying all Face items */
+	  fn = f->next;
+	  destroy_face_item (f);
+	  f = fn;
+      }
+    free (list);
+}
+
+TOPOLOGY_PRIVATE void
+auxtopo_add_face_edge (struct face_edges *list, sqlite3_int64 face_id,
+		       sqlite3_int64 edge_id, sqlite3_int64 left_face,
+		       sqlite3_int64 right_face, gaiaGeomCollPtr geom)
+{
+/* adding a Face-Edge Item into the list */
+    struct face_item *f;
+    struct face_edge_item *fe =
+	create_face_edge_item (edge_id, left_face, right_face, geom);
+    if (list->first_edge == NULL)
+	list->first_edge = fe;
+    if (list->last_edge != NULL)
+	list->last_edge->next = fe;
+    list->last_edge = fe;
+
+    f = list->first_face;
+    while (f != NULL)
+      {
+	  if (f->face_id == face_id)
+	      return;
+	  f = f->next;
+      }
+
+    /* inserting the Face-ID into the list */
+    f = create_face_item (face_id);
+    if (list->first_face == NULL)
+	list->first_face = f;
+    if (list->last_face != NULL)
+	list->last_face->next = f;
+    list->last_face = f;
+}
+
+TOPOLOGY_PRIVATE void
+auxtopo_select_valid_face_edges (struct face_edges *list)
+{
+/* identifying all useless Edges */
+    struct face_edge_item *fe = list->first_edge;
+    while (fe != NULL)
+      {
+	  struct face_item *f = list->first_face;
+	  while (f != NULL)
+	    {
+		if (f->face_id == fe->left_face)
+		    fe->count += 1;
+		if (f->face_id == fe->right_face)
+		    fe->count += 1;
+		f = f->next;
+	    }
+	  fe = fe->next;
+      }
+}
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr
+auxtopo_polygonize_face_edges (struct face_edges *list, const void *cache)
+{
+/* attempting to reaggregrate Polygons from valid Edges */
+    gaiaGeomCollPtr sparse;
+    gaiaGeomCollPtr rearranged;
+
+    if (list->has_z)
+	sparse = gaiaAllocGeomCollXYZ ();
+    else
+	sparse = gaiaAllocGeomColl ();
+    sparse->Srid = list->srid;
+
+    struct face_edge_item *fe = list->first_edge;
+    while (fe != NULL)
+      {
+	  if (fe->count < 2)
+	    {
+		/* found a valid Edge: adding to the MultiListring */
+		gaiaLinestringPtr ln = fe->geom->FirstLinestring;
+		while (ln != NULL)
+		  {
+		      if (list->has_z)
+			  auxtopo_copy_linestring3d (ln, sparse);
+		      else
+			  auxtopo_copy_linestring (ln, sparse);
+		      ln = ln->Next;
+		  }
+	    }
+	  fe = fe->next;
+      }
+    rearranged = gaiaPolygonize_r (cache, sparse, 0);
+    gaiaFreeGeomColl (sparse);
+    return rearranged;
+}
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr
+auxtopo_polygonize_face_edges_generalize (struct face_edges * list,
+					  const void *cache)
+{
+/* attempting to reaggregrate Polygons from valid Edges */
+    gaiaGeomCollPtr sparse;
+    gaiaGeomCollPtr renoded;
+    gaiaGeomCollPtr rearranged;
+
+    if (list->has_z)
+	sparse = gaiaAllocGeomCollXYZ ();
+    else
+	sparse = gaiaAllocGeomColl ();
+    sparse->Srid = list->srid;
+
+    struct face_edge_item *fe = list->first_edge;
+    while (fe != NULL)
+      {
+	  if (fe->count < 2)
+	    {
+		/* found a valid Edge: adding to the MultiListring */
+		gaiaLinestringPtr ln = fe->geom->FirstLinestring;
+		while (ln != NULL)
+		  {
+		      if (list->has_z)
+			  auxtopo_copy_linestring3d (ln, sparse);
+		      else
+			  auxtopo_copy_linestring (ln, sparse);
+		      ln = ln->Next;
+		  }
+	    }
+	  fe = fe->next;
+      }
+    renoded = gaiaNodeLines (sparse);
+    gaiaFreeGeomColl (sparse);
+    if (renoded == NULL)
+	return NULL;
+    rearranged = gaiaPolygonize_r (cache, renoded, 0);
+    gaiaFreeGeomColl (renoded);
+    return rearranged;
+}
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr
+auxtopo_make_geom_from_point (int srid, int has_z, gaiaPointPtr pt)
+{
+/* quick constructor: Geometry based on external point */
+    gaiaGeomCollPtr reference;
+    if (has_z)
+	reference = gaiaAllocGeomCollXYZ ();
+    else
+	reference = gaiaAllocGeomColl ();
+    reference->Srid = srid;
+    pt->Next = NULL;
+    reference->FirstPoint = pt;
+    reference->LastPoint = pt;
+    return reference;
+}
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr
+auxtopo_make_geom_from_line (int srid, gaiaLinestringPtr ln)
+{
+/* quick constructor: Geometry based on external line */
+    gaiaGeomCollPtr reference;
+    if (ln->DimensionModel == GAIA_XY_Z_M)
+	reference = gaiaAllocGeomCollXYZM ();
+    else if (ln->DimensionModel == GAIA_XY_Z)
+	reference = gaiaAllocGeomCollXYZ ();
+    else if (ln->DimensionModel == GAIA_XY_M)
+	reference = gaiaAllocGeomCollXYM ();
+    else
+	reference = gaiaAllocGeomColl ();
+    reference->Srid = srid;
+    ln->Next = NULL;
+    reference->FirstLinestring = ln;
+    reference->LastLinestring = ln;
+    return reference;
+}
+
+TOPOLOGY_PRIVATE void
+auxtopo_copy_linestring3d (gaiaLinestringPtr in, gaiaGeomCollPtr geom)
+{
+/* inserting/copying a Linestring 3D into another Geometry */
+    int iv;
+    double x;
+    double y;
+    double z;
+    gaiaLinestringPtr out = gaiaAddLinestringToGeomColl (geom, in->Points);
+    for (iv = 0; iv < in->Points; iv++)
+      {
+	  gaiaGetPointXYZ (in->Coords, iv, &x, &y, &z);
+	  gaiaSetPointXYZ (out->Coords, iv, x, y, z);
+      }
+}
+
+TOPOLOGY_PRIVATE void
+auxtopo_copy_linestring (gaiaLinestringPtr in, gaiaGeomCollPtr geom)
+{
+/* inserting/copying a Linestring into another Geometry */
+    int iv;
+    double x;
+    double y;
+    gaiaLinestringPtr out = gaiaAddLinestringToGeomColl (geom, in->Points);
+    for (iv = 0; iv < in->Points; iv++)
+      {
+	  gaiaGetPoint (in->Coords, iv, &x, &y);
+	  gaiaSetPoint (out->Coords, iv, x, y);
+      }
+}
+
+TOPOLOGY_PRIVATE void
+auxtopo_destroy_geom_from (gaiaGeomCollPtr reference)
+{
+/* safely destroying a reference geometry */
+    if (reference == NULL)
+	return;
+
+/* releasing ownership on external points, lines and polygs */
+    reference->FirstPoint = NULL;
+    reference->LastPoint = NULL;
+    reference->FirstLinestring = NULL;
+    reference->LastLinestring = NULL;
+    reference->FirstPolygon = NULL;
+    reference->LastPolygon = NULL;
+
+    gaiaFreeGeomColl (reference);
+}
+
+TOPOLOGY_PRIVATE int
+auxtopo_retrieve_geometry_type (sqlite3 * db_handle, const char *db_prefix,
+				const char *table, const char *column,
+				int *ref_type)
+{
+/* attempting to retrive the reference Geometry Type */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    char *xprefix;
+    int type = -1;
+
+/* querying GEOMETRY_COLUMNS */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT geometry_type "
+	 "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) AND "
+	 "Lower(f_geometry_column) = Lower(%Q)", xprefix, table, column);
+    free (xprefix);
+    ret =
+	sqlite3_get_table (db_handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  type = atoi (results[(i * columns) + 0]);
+      }
+    sqlite3_free_table (results);
+
+    if (type < 0)
+	return 0;
+
+    *ref_type = type;
+    return 1;
+}
+
+TOPOLOGY_PRIVATE int
+auxtopo_create_togeotable_sql (sqlite3 * db_handle, const char *db_prefix,
+			       const char *ref_table, const char *ref_column,
+			       const char *out_table, char **xcreate,
+			       char **xselect, char **xinsert,
+			       int *ref_geom_col)
+{
+/* composing the CREATE TABLE output-table statement */
+    char *create = NULL;
+    char *select = NULL;
+    char *insert = NULL;
+    char *prev;
+    char *sql;
+    char *xprefix;
+    char *xtable;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *name;
+    const char *type;
+    int notnull;
+    int pk_no;
+    int ret;
+    int first_create = 1;
+    int first_select = 1;
+    int first_insert = 1;
+    int npk = 0;
+    int ipk;
+    int ncols = 0;
+    int icol;
+    int ref_col = 0;
+    int xref_geom_col;
+
+    *xcreate = NULL;
+    *xselect = NULL;
+    *xinsert = NULL;
+    *ref_geom_col = -1;
+
+    xtable = gaiaDoubleQuotedSql (out_table);
+    create = sqlite3_mprintf ("CREATE TABLE MAIN.\"%s\" (", xtable);
+    select = sqlite3_mprintf ("SELECT ");
+    insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (", xtable);
+    free (xtable);
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (ref_table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret = sqlite3_get_table (db_handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		/* counting how many PK columns are there */
+		if (atoi (results[(i * columns) + 5]) != 0)
+		    npk++;
+	    }
+	  for (i = 1; i <= rows; i++)
+	    {
+		name = results[(i * columns) + 1];
+		type = results[(i * columns) + 2];
+		notnull = atoi (results[(i * columns) + 3]);
+		pk_no = atoi (results[(i * columns) + 5]);
+		/* SELECT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = select;
+		if (first_select)
+		    select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_select = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		if (strcasecmp (name, ref_column) == 0)
+		  {
+		      /* saving the index of ref-geometry */
+		      xref_geom_col = ref_col;
+		  }
+		ref_col++;
+		/* INSERT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = insert;
+		if (first_insert)
+		    insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_insert = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ncols++;
+		/* CREATE: adding a column definition */
+		if (strcasecmp (name, ref_column) == 0)
+		  {
+		      /* skipping the geometry column */
+		      continue;
+		  }
+		prev = create;
+		xprefix = gaiaDoubleQuotedSql (name);
+		if (first_create)
+		  {
+		      first_create = 0;
+		      if (notnull)
+			  create =
+			      sqlite3_mprintf ("%s\n\t\"%s\" %s NOT NULL", prev,
+					       xprefix, type);
+		      else
+			  create =
+			      sqlite3_mprintf ("%s\n\t\"%s\" %s", prev, xprefix,
+					       type);
+		  }
+		else
+		  {
+		      if (notnull)
+			  create =
+			      sqlite3_mprintf ("%s,\n\t\"%s\" %s NOT NULL",
+					       prev, xprefix, type);
+		      else
+			  create =
+			      sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev,
+					       xprefix, type);
+		  }
+		free (xprefix);
+		sqlite3_free (prev);
+		if (npk == 1 && pk_no != 0)
+		  {
+		      /* declaring a single-column Primary Key */
+		      prev = create;
+		      create = sqlite3_mprintf ("%s PRIMARY KEY", prev);
+		      sqlite3_free (prev);
+		  }
+	    }
+	  if (npk > 1)
+	    {
+		/* declaring a multi-column Primary Key */
+		prev = create;
+		sql = sqlite3_mprintf ("pk_%s", out_table);
+		xprefix = gaiaDoubleQuotedSql (sql);
+		sqlite3_free (sql);
+		create =
+		    sqlite3_mprintf ("%s,\n\tCONSTRAINT \"%s\" PRIMARY KEY (",
+				     prev, xprefix);
+		free (xprefix);
+		sqlite3_free (prev);
+		for (ipk = 1; ipk <= npk; ipk++)
+		  {
+		      /* searching a Primary Key column */
+		      for (i = 1; i <= rows; i++)
+			{
+			    if (atoi (results[(i * columns) + 5]) == ipk)
+			      {
+				  /* declaring a Primary Key column */
+				  name = results[(i * columns) + 1];
+				  xprefix = gaiaDoubleQuotedSql (name);
+				  prev = create;
+				  if (ipk == 1)
+				      create =
+					  sqlite3_mprintf ("%s\"%s\"", prev,
+							   xprefix);
+				  else
+				      create =
+					  sqlite3_mprintf ("%s, \"%s\"", prev,
+							   xprefix);
+				  free (xprefix);
+				  sqlite3_free (prev);
+			      }
+			}
+		  }
+		prev = create;
+		create = sqlite3_mprintf ("%s)", prev);
+		sqlite3_free (prev);
+	    }
+      }
+    sqlite3_free_table (results);
+
+/* completing the SQL statements */
+    prev = create;
+    create = sqlite3_mprintf ("%s)", prev);
+    sqlite3_free (prev);
+    prev = select;
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (ref_table);
+    select = sqlite3_mprintf ("%s FROM \"%s\".\"%s\"", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = insert;
+    insert = sqlite3_mprintf ("%s) VALUES (", prev);
+    sqlite3_free (prev);
+    for (icol = 0; icol < ncols; icol++)
+      {
+	  prev = insert;
+	  if (icol == 0)
+	      insert = sqlite3_mprintf ("%s?", prev);
+	  else
+	      insert = sqlite3_mprintf ("%s, ?", prev);
+	  sqlite3_free (prev);
+      }
+    prev = insert;
+    insert = sqlite3_mprintf ("%s)", prev);
+    sqlite3_free (prev);
+
+    *xcreate = create;
+    *xselect = select;
+    *xinsert = insert;
+    *ref_geom_col = xref_geom_col;
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    return 0;
+}
+
+static int
+is_geometry_column (sqlite3 * db_handle, const char *db_prefix,
+		    const char *table, const char *column)
+{
+/* testing for Geometry columns */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    char *xprefix;
+    int count = 0;
+
+/* querying GEOMETRY_COLUMNS */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT Count(*) "
+	 "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) AND "
+	 "Lower(f_geometry_column) = Lower(%Q)", xprefix, table, column);
+    free (xprefix);
+    ret =
+	sqlite3_get_table (db_handle, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  count = atoi (results[(i * columns) + 0]);
+      }
+    sqlite3_free_table (results);
+
+    if (count > 0)
+	return 1;
+    return 0;
+}
+
+static int
+auxtopo_create_features_sql (sqlite3 * db_handle, const char *db_prefix,
+			     const char *ref_table, const char *ref_column,
+			     const char *topology_name,
+			     sqlite3_int64 topolayer_id, char **xcreate,
+			     char **xselect, char **xinsert)
+{
+/* composing the CREATE TABLE fatures-table statement */
+    char *create = NULL;
+    char *select = NULL;
+    char *insert = NULL;
+    char *prev;
+    char *sql;
+    char *xprefix;
+    char *xgeom;
+    char *table;
+    char *xtable;
+    char dummy[64];
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *name;
+    const char *type;
+    int notnull;
+    int ret;
+    int first_select = 1;
+    int first_insert = 1;
+    int ncols = 0;
+    int icol;
+    int ref_col = 0;
+
+    *xcreate = NULL;
+    *xselect = NULL;
+    *xinsert = NULL;
+
+    sprintf (dummy, "%lld", topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topology_name, dummy);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    create =
+	sqlite3_mprintf
+	("CREATE TABLE MAIN.\"%s\" (\n\tfid INTEGER PRIMARY KEY AUTOINCREMENT",
+	 xtable);
+    select = sqlite3_mprintf ("SELECT ");
+    insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (", xtable);
+    free (xtable);
+
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (ref_table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret = sqlite3_get_table (db_handle, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		name = results[(i * columns) + 1];
+		type = results[(i * columns) + 2];
+		notnull = atoi (results[(i * columns) + 3]);
+		if (strcasecmp(name, "fid") == 0)
+		continue;
+		if (is_geometry_column (db_handle, db_prefix, ref_table, name))
+		    continue;
+		if (ref_column != NULL)
+		  {
+		      if (strcasecmp (ref_column, name) == 0)
+			  continue;
+		  }
+		/* SELECT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = select;
+		if (first_select)
+		    select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_select = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ref_col++;
+		/* INSERT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = insert;
+		if (first_insert)
+		    insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_insert = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ncols++;
+		/* CREATE: adding a column definition */
+		prev = create;
+		xprefix = gaiaDoubleQuotedSql (name);
+		if (notnull)
+		    create =
+			sqlite3_mprintf ("%s,\n\t\"%s\" %s NOT NULL",
+					 prev, xprefix, type);
+		else
+		    create =
+			sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev,
+					 xprefix, type);
+		free (xprefix);
+		sqlite3_free (prev);
+	    }
+      }
+    sqlite3_free_table (results);
+
+/* completing the SQL statements */
+    prev = create;
+    create = sqlite3_mprintf ("%s)", prev);
+    sqlite3_free (prev);
+    prev = select;
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (ref_table);
+    if (ref_column != NULL)
+      {
+	  xgeom = gaiaDoubleQuotedSql (ref_column);
+	  select =
+	      sqlite3_mprintf ("%s, \"%s\" FROM \"%s\".\"%s\"", prev, xgeom,
+			       xprefix, xtable);
+	  free (xgeom);
+      }
+    else
+	select =
+	    sqlite3_mprintf ("%s FROM \"%s\".\"%s\"", prev, xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = insert;
+    insert = sqlite3_mprintf ("%s) VALUES (", prev);
+    sqlite3_free (prev);
+    for (icol = 0; icol < ncols; icol++)
+      {
+	  prev = insert;
+	  if (icol == 0)
+	      insert = sqlite3_mprintf ("%s?", prev);
+	  else
+	      insert = sqlite3_mprintf ("%s, ?", prev);
+	  sqlite3_free (prev);
+      }
+    prev = insert;
+    insert = sqlite3_mprintf ("%s)", prev);
+    sqlite3_free (prev);
+
+    *xcreate = create;
+    *xselect = select;
+    *xinsert = insert;
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    return 0;
+}
+
+static int
+do_register_topolayer (struct gaia_topology *topo, const char *topolayer_name,
+		       sqlite3_int64 * topolayer_id)
+{
+/* attempting to register a new TopoLayer */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    char *err_msg = NULL;
+
+    table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO \"%s\" (topolayer_name) VALUES (Lower(%Q))", xtable,
+	 topolayer_name);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &err_msg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("RegisterTopoLayer error: \"%s\"", err_msg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    *topolayer_id = sqlite3_last_insert_rowid (topo->db_handle);
+    return 1;
+}
+
+static int
+do_eval_topolayer_point (struct gaia_topology *topo, gaiaGeomCollPtr reference,
+			 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_rels,
+			 sqlite3_int64 topolayer_id, sqlite3_int64 fid)
+{
+/* retrieving Points from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+
+/* initializing the Topo-Node query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_node);
+    sqlite3_clear_bindings (stmt_node);
+    sqlite3_bind_blob (stmt_node, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_node, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_node);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt_node, 0);
+		sqlite3_reset (stmt_rels);
+		sqlite3_clear_bindings (stmt_rels);
+		sqlite3_bind_int64 (stmt_rels, 1, node_id);
+		sqlite3_bind_null (stmt_rels, 2);
+		sqlite3_bind_null (stmt_rels, 3);
+		sqlite3_bind_int64 (stmt_rels, 4, topolayer_id);
+		sqlite3_bind_int64 (stmt_rels, 5, fid);
+		ret = sqlite3_step (stmt_rels);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_CreateTopoLayer error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+    return 1;
+}
+
+static int
+do_eval_topolayer_line (struct gaia_topology *topo, gaiaGeomCollPtr reference,
+			sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_rels,
+			sqlite3_int64 topolayer_id, sqlite3_int64 fid)
+{
+/* retrieving Linestrings from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+
+/* initializing the Topo-Edge query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_edge);
+    sqlite3_clear_bindings (stmt_edge);
+    sqlite3_bind_blob (stmt_edge, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_edge, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_edge);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_edge, 0);
+		sqlite3_reset (stmt_rels);
+		sqlite3_clear_bindings (stmt_rels);
+		sqlite3_bind_null (stmt_rels, 1);
+		sqlite3_bind_int64 (stmt_rels, 2, edge_id);
+		sqlite3_bind_null (stmt_rels, 3);
+		sqlite3_bind_int64 (stmt_rels, 4, topolayer_id);
+		sqlite3_bind_int64 (stmt_rels, 5, fid);
+		ret = sqlite3_step (stmt_rels);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_CreateTopoLayer error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+    return 1;
+}
+
+static int
+do_eval_topolayer_polyg (struct gaia_topology *topo, gaiaGeomCollPtr reference,
+			 sqlite3_stmt * stmt_face, sqlite3_stmt * stmt_rels,
+			 sqlite3_int64 topolayer_id, sqlite3_int64 fid)
+{
+/* retrieving Polygon from Topology */
+    int ret;
+    unsigned char *p_blob;
+    int n_bytes;
+
+/* initializing the Topo-Face query */
+    gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
+    sqlite3_reset (stmt_face);
+    sqlite3_clear_bindings (stmt_face);
+    sqlite3_bind_blob (stmt_face, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
+    sqlite3_bind_blob (stmt_face, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
+    free (p_blob);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_face);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id = sqlite3_column_int64 (stmt_face, 0);
+		sqlite3_reset (stmt_rels);
+		sqlite3_clear_bindings (stmt_rels);
+		sqlite3_bind_null (stmt_rels, 1);
+		sqlite3_bind_null (stmt_rels, 2);
+		sqlite3_bind_int64 (stmt_rels, 3, face_id);
+		sqlite3_bind_int64 (stmt_rels, 4, topolayer_id);
+		sqlite3_bind_int64 (stmt_rels, 5, fid);
+		ret = sqlite3_step (stmt_rels);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_CreateTopoLayer error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+    return 1;
+}
+
+static int
+do_eval_topolayer_geom (struct gaia_topology *topo, gaiaGeomCollPtr geom,
+			sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
+			sqlite3_stmt * stmt_face, sqlite3_stmt * stmt_rels,
+			sqlite3_int64 topolayer_id, sqlite3_int64 fid)
+{
+/* retrieving Features via matching Seeds/Geometries */
+    gaiaPointPtr pt;
+    gaiaLinestringPtr ln;
+    gaiaPolygonPtr pg;
+    int ret;
+
+    /* processing all Points */
+    pt = geom->FirstPoint;
+    while (pt != NULL)
+      {
+	  gaiaPointPtr next = pt->Next;
+	  gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
+	      auxtopo_make_geom_from_point (topo->srid, topo->has_z, pt);
+	  ret =
+	      do_eval_topolayer_point (topo, reference, stmt_node, stmt_rels,
+				       topolayer_id, fid);
+	  auxtopo_destroy_geom_from (reference);
+	  pt->Next = next;
+	  if (ret == 0)
+	      return 0;
+	  pt = pt->Next;
+      }
+
+    /* processing all Linestrings */
+    ln = geom->FirstLinestring;
+    while (ln != NULL)
+      {
+	  gaiaLinestringPtr next = ln->Next;
+	  gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
+	      auxtopo_make_geom_from_line (topo->srid, ln);
+	  ret =
+	      do_eval_topolayer_line (topo, reference, stmt_edge, stmt_rels,
+				      topolayer_id, fid);
+	  auxtopo_destroy_geom_from (reference);
+	  ln->Next = next;
+	  if (ret == 0)
+	      return 0;
+	  ln = ln->Next;
+      }
+
+    /* processing all Polygons */
+    pg = geom->FirstPolygon;
+    while (pg != NULL)
+      {
+	  gaiaPolygonPtr next = pg->Next;
+	  gaiaGeomCollPtr reference = make_geom_from_polyg (topo->srid, pg);
+	  ret = do_eval_topolayer_polyg (topo, reference, stmt_face, stmt_rels,
+					 topolayer_id, fid);
+	  auxtopo_destroy_geom_from (reference);
+	  pg->Next = next;
+	  if (ret == 0)
+	      return 0;
+	  pg = pg->Next;
+      }
+
+    return 1;
+}
+
+static int
+do_eval_topolayer_seeds (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
+			 sqlite3_stmt * stmt_ins, sqlite3_stmt * stmt_rels,
+			 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
+			 sqlite3_stmt * stmt_face, sqlite3_int64 topolayer_id)
+{
+/* querying the ref-table */
+    int ret;
+
+    sqlite3_reset (stmt_ref);
+    sqlite3_clear_bindings (stmt_ref);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  gaiaGeomCollPtr geom = NULL;
+	  sqlite3_int64 fid;
+	  ret = sqlite3_step (stmt_ref);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int icol;
+		int ncol = sqlite3_column_count (stmt_ref);
+		sqlite3_reset (stmt_ins);
+		sqlite3_clear_bindings (stmt_ins);
+		for (icol = 0; icol < ncol; icol++)
+		  {
+		      int col_type = sqlite3_column_type (stmt_ref, icol);
+		      if (icol == ncol - 1)
+			{
+			    /* the last column is always expected to be the geometry column */
+			    const unsigned char *blob =
+				sqlite3_column_blob (stmt_ref, icol);
+			    int blob_sz = sqlite3_column_bytes (stmt_ref, icol);
+			    geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+			    continue;
+			}
+		      switch (col_type)
+			{
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_ins, icol + 1,
+						sqlite3_column_int64 (stmt_ref,
+								      icol));
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_ins, icol + 1,
+						 sqlite3_column_double
+						 (stmt_ref, icol));
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_ins, icol + 1,
+					       (const char *)
+					       sqlite3_column_text (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			case SQLITE_BLOB:
+			    sqlite3_bind_blob (stmt_ins, icol + 1,
+					       sqlite3_column_blob (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_ins, icol + 1);
+			    break;
+			};
+		  }
+		ret = sqlite3_step (stmt_ins);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+		fid = sqlite3_last_insert_rowid (topo->db_handle);
+		/* evaluating the feature's geometry */
+		if (geom != NULL)
+		  {
+		      ret =
+			  do_eval_topolayer_geom (topo, geom, stmt_node,
+						  stmt_edge, stmt_face,
+						  stmt_rels, topolayer_id, fid);
+		      gaiaFreeGeomColl (geom);
+		      if (ret == 0)
+			  return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_CreateTopoLayer (GaiaTopologyAccessorPtr accessor,
+			     const char *db_prefix, const char *ref_table,
+			     const char *ref_column, const char *topolayer_name)
+{
+/* attempting to create a TopoLayer */
+    sqlite3_int64 topolayer_id;
+    sqlite3_stmt *stmt_ref = NULL;
+    sqlite3_stmt *stmt_ins = NULL;
+    sqlite3_stmt *stmt_rels = NULL;
+    sqlite3_stmt *stmt_node = NULL;
+    sqlite3_stmt *stmt_edge = NULL;
+    sqlite3_stmt *stmt_face = NULL;
+    int ret;
+    char *sql;
+    char *create;
+    char *select;
+    char *insert;
+    char *xprefix;
+    char *table;
+    char *xtable;
+    char *errMsg;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    if (topo == NULL)
+	return 0;
+
+/* attempting to register a new TopoLayer */
+    if (!do_register_topolayer (topo, topolayer_name, &topolayer_id))
+	return 0;
+
+/* incrementally updating all Topology Seeds */
+    if (!gaiaTopoGeoUpdateSeeds (accessor, 1))
+	return 0;
+
+/* composing the CREATE TABLE feature-table statement */
+    if (!auxtopo_create_features_sql
+	(topo->db_handle, db_prefix, ref_table, ref_column, topo->topology_name,
+	 topolayer_id, &create, &select, &insert))
+	goto error;
+
+/* creating the feature-table */
+    ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
+    sqlite3_free (create);
+    create = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "SELECT * FROM ref-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
+			    NULL);
+    sqlite3_free (select);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO features-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
+			    NULL);
+    sqlite3_free (insert);
+    insert = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO features-ref" query */
+    table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO \"%s\" (node_id, edge_id, face_id, topolayer_id, fid) "
+	 "VALUES (?, ?, ?, ?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rels,
+			    NULL);
+    sqlite3_free (sql);
+    sql = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Seed-Edges query */
+    xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" "
+			   "WHERE edge_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Seed-Faces query */
+    xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT face_id FROM MAIN.\"%s\" "
+			   "WHERE face_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Nodes query */
+    xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT node_id FROM MAIN.\"%s\" "
+			   "WHERE ST_Intersects(geom, ?) = 1 AND ROWID IN ("
+			   "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* evaluating feature/topology matching via coincident topo-seeds */
+    if (!do_eval_topolayer_seeds
+	(topo, stmt_ref, stmt_ins, stmt_rels, stmt_node, stmt_edge, stmt_face,
+	 topolayer_id))
+	goto error;
+
+    sqlite3_finalize (stmt_ref);
+    sqlite3_finalize (stmt_ins);
+    sqlite3_finalize (stmt_rels);
+    sqlite3_finalize (stmt_node);
+    sqlite3_finalize (stmt_edge);
+    sqlite3_finalize (stmt_face);
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    if (stmt_ref != NULL)
+	sqlite3_finalize (stmt_ref);
+    if (stmt_ins != NULL)
+	sqlite3_finalize (stmt_ins);
+    if (stmt_rels != NULL)
+	sqlite3_finalize (stmt_rels);
+    if (stmt_node != NULL)
+	sqlite3_finalize (stmt_node);
+    if (stmt_edge != NULL)
+	sqlite3_finalize (stmt_edge);
+    if (stmt_face != NULL)
+	sqlite3_finalize (stmt_face);
+    return 0;
+}
+
+static int
+do_populate_topolayer (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
+		       sqlite3_stmt * stmt_ins)
+{
+/* querying the ref-table */
+    int ret;
+
+    sqlite3_reset (stmt_ref);
+    sqlite3_clear_bindings (stmt_ref);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_ref);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int icol;
+		int ncol = sqlite3_column_count (stmt_ref);
+		sqlite3_reset (stmt_ins);
+		sqlite3_clear_bindings (stmt_ins);
+		for (icol = 0; icol < ncol; icol++)
+		  {
+		      int col_type = sqlite3_column_type (stmt_ref, icol);
+		      switch (col_type)
+			{
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_ins, icol + 1,
+						sqlite3_column_int64 (stmt_ref,
+								      icol));
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_ins, icol + 1,
+						 sqlite3_column_double
+						 (stmt_ref, icol));
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_ins, icol + 1,
+					       (const char *)
+					       sqlite3_column_text (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			case SQLITE_BLOB:
+			    sqlite3_bind_blob (stmt_ins, icol + 1,
+					       sqlite3_column_blob (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_ins, icol + 1);
+			    break;
+			};
+		  }
+		ret = sqlite3_step (stmt_ins);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_InitTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_InitTopoLayer() error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_InitTopoLayer (GaiaTopologyAccessorPtr accessor,
+			   const char *db_prefix, const char *ref_table,
+			   const char *topolayer_name)
+{
+/* attempting to create a TopoLayer */
+    sqlite3_int64 topolayer_id;
+    sqlite3_stmt *stmt_ref = NULL;
+    sqlite3_stmt *stmt_ins = NULL;
+    int ret;
+    char *create;
+    char *select;
+    char *insert;
+    char *errMsg;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    if (topo == NULL)
+	return 0;
+
+/* attempting to register a new TopoLayer */
+    if (!do_register_topolayer (topo, topolayer_name, &topolayer_id))
+	return 0;
+
+/* composing the CREATE TABLE feature-table statement */
+    if (!auxtopo_create_features_sql
+	(topo->db_handle, db_prefix, ref_table, NULL, topo->topology_name,
+	 topolayer_id, &create, &select, &insert))
+	goto error;
+
+/* creating the feature-table */
+    ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
+    sqlite3_free (create);
+    create = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_InitTopoLayer() error: \"%s\"",
+				       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "SELECT * FROM ref-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
+			    NULL);
+    sqlite3_free (select);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO features-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
+			    NULL);
+    sqlite3_free (insert);
+    insert = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* populating the TopoFeatures table */
+    if (!do_populate_topolayer (topo, stmt_ref, stmt_ins))
+	goto error;
+
+    sqlite3_finalize (stmt_ref);
+    sqlite3_finalize (stmt_ins);
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    if (stmt_ref != NULL)
+	sqlite3_finalize (stmt_ref);
+    if (stmt_ins != NULL)
+	sqlite3_finalize (stmt_ins);
+    return 0;
+}
+
+static int
+check_topolayer (struct gaia_topology *topo, const char *topolayer_name,
+		 sqlite3_int64 * topolayer_id)
+{
+/* checking if a TopoLayer do really exist */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    int found = 0;
+    sqlite3_stmt *stmt = NULL;
+
+/* creating the SQL statement - SELECT */
+    table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT topolayer_id FROM \"%s\" WHERE topolayer_name = Lower(%Q)",
+	 xtable, topolayer_name);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Check_TopoLayer() error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* retrieving the TopoLayer ID */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		*topolayer_id = sqlite3_column_int64 (stmt, 0);
+		found = 1;
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("Check_TopoLayer() error: \"%s\"",
+					     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    if (!found)
+	goto error;
+
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+static int
+do_unregister_topolayer (struct gaia_topology *topo, const char *topolayer_name,
+			 sqlite3_int64 * topolayer_id)
+{
+/* attempting to unregister a existing TopoLayer */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    sqlite3_int64 id;
+    sqlite3_stmt *stmt = NULL;
+
+    if (!check_topolayer (topo, topolayer_name, &id))
+	return 0;
+
+/* creating the first SQL statement - DELETE */
+    table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM \"%s\" WHERE topolayer_id = ?", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    create_all_topo_prepared_stmts (topo->cache);	/* recreating prepared stsms */
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* deleting the TopoLayer */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, id);
+    ret = sqlite3_step (stmt);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	;
+    else
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    *topolayer_id = id;
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_RemoveTopoLayer (GaiaTopologyAccessorPtr accessor,
+			     const char *topolayer_name)
+{
+/* attempting to remove a TopoLayer */
+    sqlite3_int64 topolayer_id;
+    int ret;
+    char *sql;
+    char *errMsg;
+    char *table;
+    char *xtable;
+    char *xtable2;
+    char dummy[64];
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+
+    if (topo == NULL)
+	return 0;
+
+/* deleting all Feature relations */
+    table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM \"%s\" WHERE topolayer_id = "
+			   "(SELECT topolayer_id FROM \"%s\" WHERE topolayer_name = Lower(%Q))",
+			   xtable, xtable2, topolayer_name);
+    free (xtable);
+    free (xtable2);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: %s\n",
+				       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* unregistering the TopoLayer */
+    if (!do_unregister_topolayer (topo, topolayer_name, &topolayer_id))
+	return 0;
+
+/* finalizing all prepared Statements */
+    finalize_all_topo_prepared_stmts (topo->cache);
+
+/* dropping the TopoFeatures Table */
+    sprintf (dummy, "%lld", topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DROP TABLE \"%s\"", xtable);
+    free (xtable);
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    create_all_topo_prepared_stmts (topo->cache);	/* recreating prepared stsms */
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: %s\n",
+				       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+is_unique_geom_name (sqlite3 * sqlite, const char *table, const char *geom)
+{
+/* checking for duplicate names */
+    char *xtable;
+    char *sql;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *name;
+
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", xtable);
+    free (xtable);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		name = results[(i * columns) + 1];
+		if (strcasecmp (name, geom) == 0)
+		    continue;
+	    }
+      }
+    sqlite3_free_table (results);
+
+    return 1;
+}
+
+static int
+auxtopo_create_export_sql (struct gaia_topology *topo,
+			   const char *topolayer_name, const char *out_table,
+			   char **xcreate, char **xselect, char **xinsert,
+			   char **geometry, sqlite3_int64 * topolayer_id)
+{
+/* composing the CREATE TABLE export-table statement */
+    char *create = NULL;
+    char *select = NULL;
+    char *insert = NULL;
+    char *prev;
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xprefix;
+    char dummy[64];
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *name;
+    const char *type;
+    int notnull;
+    int ret;
+    int first_select = 1;
+    int first_insert = 1;
+    int ncols = 0;
+    int icol;
+    int ref_col = 0;
+    char *geometry_name;
+    int geom_alias = 0;
+
+    *xcreate = NULL;
+    *xselect = NULL;
+    *xinsert = NULL;
+
+/* checking the TopoLayer */
+    if (!check_topolayer (topo, topolayer_name, topolayer_id))
+	return 0;
+
+    xtable = gaiaDoubleQuotedSql (out_table);
+    create =
+	sqlite3_mprintf
+	("CREATE TABLE MAIN.\"%s\" (\n\tfid INTEGER PRIMARY KEY", xtable);
+    select = sqlite3_mprintf ("SELECT fid, ");
+    insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (fid, ", xtable);
+    free (xtable);
+    sprintf (dummy, "%lld", *topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		name = results[(i * columns) + 1];
+		if (strcmp (name, "fid") == 0)
+		    continue;
+		type = results[(i * columns) + 2];
+		notnull = atoi (results[(i * columns) + 3]);
+		/* SELECT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = select;
+		if (first_select)
+		    select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_select = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ref_col++;
+		/* INSERT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = insert;
+		if (first_insert)
+		    insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_insert = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ncols++;
+		/* CREATE: adding a column definition */
+		prev = create;
+		xprefix = gaiaDoubleQuotedSql (name);
+		if (notnull)
+		    create =
+			sqlite3_mprintf ("%s,\n\t\"%s\" %s NOT NULL",
+					 prev, xprefix, type);
+		else
+		    create =
+			sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev,
+					 xprefix, type);
+		free (xprefix);
+		sqlite3_free (prev);
+	    }
+      }
+    sqlite3_free_table (results);
+
+    geometry_name = malloc (strlen ("geometry") + 1);
+    strcpy (geometry_name, "geometry");
+    sprintf (dummy, "%lld", *topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    while (1)
+      {
+	  /* searching an unique Geometry name */
+	  if (is_unique_geom_name (topo->db_handle, table, geometry_name))
+	      break;
+	  sprintf (dummy, "geom_%d", ++geom_alias);
+	  free (geometry_name);
+	  geometry_name = malloc (strlen (dummy) + 1);
+	  strcpy (geometry_name, dummy);
+      }
+    sqlite3_free (table);
+
+/* completing the SQL statements */
+    prev = create;
+    create = sqlite3_mprintf ("%s)", prev);
+    sqlite3_free (prev);
+    prev = select;
+    sprintf (dummy, "%lld", *topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    select = sqlite3_mprintf ("%s FROM MAIN.\"%s\"", prev, xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = insert;
+    insert = sqlite3_mprintf ("%s, \"%s\") VALUES (?, ", prev, geometry_name);
+    sqlite3_free (prev);
+    for (icol = 0; icol < ncols; icol++)
+      {
+	  prev = insert;
+	  if (icol == 0)
+	      insert = sqlite3_mprintf ("%s?", prev);
+	  else
+	      insert = sqlite3_mprintf ("%s, ?", prev);
+	  sqlite3_free (prev);
+      }
+    prev = insert;
+    insert = sqlite3_mprintf ("%s, ?)", prev);
+    sqlite3_free (prev);
+
+    *xcreate = create;
+    *xselect = select;
+    *xinsert = insert;
+    *geometry = geometry_name;
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    return 0;
+}
+
+static int
+auxtopo_retrieve_export_geometry_type (struct gaia_topology *topo,
+				       const char *topolayer_name,
+				       int *ref_type)
+{
+/* determining the Geometry Type for Export TopoLayer */
+    char *table;
+    char *xtable;
+    char *xtable2;
+    char *sql;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    int nodes;
+    int edges;
+    int faces;
+
+    table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT Count(f.node_id), Count(f.edge_id), Count(f.face_id) "
+	 "FROM \"%s\" AS l JOIN \"%s\" AS f ON (l.topolayer_id = f.topolayer_id) "
+	 "WHERE l.topolayer_name = Lower(%Q)", xtable, xtable2, topolayer_name);
+    free (xtable);
+    free (xtable2);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		nodes = atoi (results[(i * columns) + 0]);
+		edges = atoi (results[(i * columns) + 1]);
+		faces = atoi (results[(i * columns) + 2]);
+	    }
+      }
+    sqlite3_free_table (results);
+
+    *ref_type = GAIA_UNKNOWN;
+    if (nodes && !edges && !faces)
+	*ref_type = GAIA_POINT;
+    if (!nodes && edges && !faces)
+	*ref_type = GAIA_LINESTRING;
+    if (!nodes && !edges && faces)
+	*ref_type = GAIA_POLYGON;
+
+    return 1;
+}
+
+static void
+do_eval_topo_node (struct gaia_topology *topo, sqlite3_stmt * stmt_node,
+		   sqlite3_int64 node_id, gaiaGeomCollPtr result)
+{
+/* retrieving Points from Topology Nodes */
+    int ret;
+
+/* initializing the Topo-Node query */
+    sqlite3_reset (stmt_node);
+    sqlite3_clear_bindings (stmt_node);
+    sqlite3_bind_int64 (stmt_node, 1, node_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_node);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt_node, 0);
+		int blob_sz = sqlite3_column_bytes (stmt_node, 0);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      gaiaPointPtr pt = geom->FirstPoint;
+		      while (pt != NULL)
+			{
+			    /* copying all Points into the result Geometry */
+			    if (topo->has_z)
+				gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
+							   pt->Z);
+			    else
+				gaiaAddPointToGeomColl (result, pt->X, pt->Y);
+			    pt = pt->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("TopoGeo_FeatureFromTopoLayer error: \"%s\"",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static void
+do_eval_topo_edge (struct gaia_topology *topo, sqlite3_stmt * stmt_edge,
+		   sqlite3_int64 edge_id, gaiaGeomCollPtr result)
+{
+/* retrieving Linestrings from Topology Edges */
+    int ret;
+
+/* initializing the Topo-Edge query */
+    sqlite3_reset (stmt_edge);
+    sqlite3_clear_bindings (stmt_edge);
+    sqlite3_bind_int64 (stmt_edge, 1, edge_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_edge);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt_edge, 0);
+		int blob_sz = sqlite3_column_bytes (stmt_edge, 0);
+		gaiaGeomCollPtr geom =
+		    gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      gaiaLinestringPtr ln = geom->FirstLinestring;
+		      while (ln != NULL)
+			{
+			    /* copying all Linestrings into the result Geometry */
+			    if (topo->has_z)
+				auxtopo_copy_linestring3d (ln, result);
+			    else
+				auxtopo_copy_linestring (ln, result);
+			    ln = ln->Next;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("TopoGeo_FeatureFromTopoLayer error: \"%s\"",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return;
+	    }
+      }
+}
+
+static gaiaGeomCollPtr
+do_eval_topo_geometry (struct gaia_topology *topo, sqlite3_stmt * stmt_rels,
+		       sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
+		       sqlite3_stmt * stmt_face, sqlite3_int64 fid,
+		       sqlite3_int64 topolayer_id, int out_type)
+{
+/* materializing a Geometry out of Topology */
+    int ret;
+    gaiaGeomCollPtr geom;
+    gaiaGeomCollPtr sparse_lines;
+    struct face_edges *list =
+	auxtopo_create_face_edges (topo->has_z, topo->srid);
+
+    if (topo->has_z)
+      {
+	  geom = gaiaAllocGeomCollXYZ ();
+	  sparse_lines = gaiaAllocGeomCollXYZ ();
+      }
+    else
+      {
+	  geom = gaiaAllocGeomColl ();
+	  sparse_lines = gaiaAllocGeomColl ();
+      }
+    geom->Srid = topo->srid;
+    geom->DeclaredType = out_type;
+
+    sqlite3_reset (stmt_rels);
+    sqlite3_clear_bindings (stmt_rels);
+    sqlite3_bind_int64 (stmt_rels, 1, topolayer_id);
+    sqlite3_bind_int64 (stmt_rels, 2, fid);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  sqlite3_int64 id;
+	  ret = sqlite3_step (stmt_rels);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt_rels, 0) != SQLITE_NULL)
+		  {
+		      id = sqlite3_column_int64 (stmt_rels, 0);
+		      do_eval_topo_node (topo, stmt_node, id, geom);
+		  }
+		if (sqlite3_column_type (stmt_rels, 1) != SQLITE_NULL)
+		  {
+		      id = sqlite3_column_int64 (stmt_rels, 1);
+		      do_eval_topo_edge (topo, stmt_edge, id, sparse_lines);
+		  }
+		if (sqlite3_column_type (stmt_rels, 2) != SQLITE_NULL)
+		  {
+		      id = sqlite3_column_int64 (stmt_rels, 2);
+		      do_explode_topo_face (topo, list, stmt_face, id);
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("TopoGeo_FeatureFromTopoLayer() error: \"%s\"",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+
+    if (sparse_lines->FirstLinestring != NULL)
+      {
+	  /* attempting to better rearrange sparse lines */
+	  gaiaGeomCollPtr rearranged =
+	      gaiaLineMerge_r (topo->cache, sparse_lines);
+	  gaiaFreeGeomColl (sparse_lines);
+	  if (rearranged != NULL)
+	    {
+		gaiaLinestringPtr ln = rearranged->FirstLinestring;
+		while (ln != NULL)
+		  {
+		      if (topo->has_z)
+			  auxtopo_copy_linestring3d (ln, geom);
+		      else
+			  auxtopo_copy_linestring (ln, geom);
+		      ln = ln->Next;
+		  }
+		gaiaFreeGeomColl (rearranged);
+	    }
+      }
+    else
+	gaiaFreeGeomColl (sparse_lines);
+    sparse_lines = NULL;
+
+    if (list->first_edge != NULL)
+      {
+	  /* attempting to rearrange sparse lines into Polygons */
+	  auxtopo_select_valid_face_edges (list);
+	  gaiaGeomCollPtr rearranged =
+	      auxtopo_polygonize_face_edges (list, topo->cache);
+	  auxtopo_free_face_edges (list);
+	  if (rearranged != NULL)
+	    {
+		gaiaPolygonPtr pg = rearranged->FirstPolygon;
+		while (pg != NULL)
+		  {
+		      if (topo->has_z)
+			  do_copy_polygon3d (pg, geom);
+		      else
+			  do_copy_polygon (pg, geom);
+		      pg = pg->Next;
+		  }
+		gaiaFreeGeomColl (rearranged);
+	    }
+      }
+
+    if (geom->FirstPoint == NULL && geom->FirstLinestring == NULL
+	&& geom->FirstPolygon == NULL)
+	goto error;
+    return geom;
+
+  error:
+    gaiaFreeGeomColl (geom);
+    if (sparse_lines != NULL)
+	gaiaFreeGeomColl (sparse_lines);
+    return NULL;
+}
+
+static int
+do_eval_topogeo_features (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
+			  sqlite3_stmt * stmt_ins, sqlite3_stmt * stmt_rels,
+			  sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
+			  sqlite3_stmt * stmt_face, sqlite3_int64 topolayer_id,
+			  int out_type)
+{
+/* querying the ref-table */
+    int ret;
+
+    sqlite3_reset (stmt_ref);
+    sqlite3_clear_bindings (stmt_ref);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  gaiaGeomCollPtr geom = NULL;
+	  sqlite3_int64 fid;
+	  ret = sqlite3_step (stmt_ref);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int icol;
+		int ncol = sqlite3_column_count (stmt_ref);
+		fid = sqlite3_column_int64 (stmt_ref, 0);
+		sqlite3_reset (stmt_ins);
+		sqlite3_clear_bindings (stmt_ins);
+		for (icol = 0; icol < ncol; icol++)
+		  {
+		      int col_type = sqlite3_column_type (stmt_ref, icol);
+		      switch (col_type)
+			{
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_ins, icol + 1,
+						sqlite3_column_int64 (stmt_ref,
+								      icol));
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_ins, icol + 1,
+						 sqlite3_column_double
+						 (stmt_ref, icol));
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_ins, icol + 1,
+					       (const char *)
+					       sqlite3_column_text (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			case SQLITE_BLOB:
+			    sqlite3_bind_blob (stmt_ins, icol + 1,
+					       sqlite3_column_blob (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_ins, icol + 1);
+			    break;
+			};
+		  }
+		/* the Geometry column */
+		ncol = sqlite3_bind_parameter_count (stmt_ins);
+		geom =
+		    do_eval_topo_geometry (topo, stmt_rels, stmt_node,
+					   stmt_edge, stmt_face, fid,
+					   topolayer_id, out_type);
+		if (geom != NULL)
+		  {
+		      unsigned char *p_blob;
+		      int n_bytes;
+		      gaiaToSpatiaLiteBlobWkb (geom, &p_blob, &n_bytes);
+		      sqlite3_bind_blob (stmt_ins, ncol, p_blob, n_bytes,
+					 SQLITE_TRANSIENT);
+		      free (p_blob);
+		      gaiaFreeGeomColl (geom);
+		  }
+		else
+		    sqlite3_bind_null (stmt_ins, ncol);
+		ret = sqlite3_step (stmt_ins);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_ExportTopoLayer (GaiaTopologyAccessorPtr accessor,
+			     const char *topolayer_name, const char *out_table,
+			     int with_spatial_index, int create_only)
+{
+/* attempting to export a full TopoLayer */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt_ref = NULL;
+    sqlite3_stmt *stmt_ins = NULL;
+    sqlite3_stmt *stmt_rels = NULL;
+    sqlite3_stmt *stmt_node = NULL;
+    sqlite3_stmt *stmt_edge = NULL;
+    sqlite3_stmt *stmt_face = NULL;
+    int ret;
+    char *create = NULL;
+    char *select = NULL;
+    char *insert;
+    char *geometry_name;
+    char *sql;
+    char *errMsg;
+    char *xprefix;
+    char *table;
+    char *xtable;
+    int ref_type;
+    const char *type;
+    int out_type;
+    sqlite3_int64 topolayer_id;
+    if (topo == NULL)
+	return 0;
+
+/* composing the CREATE TABLE output-table statement */
+    if (!auxtopo_create_export_sql
+	(topo, topolayer_name, out_table, &create,
+	 &select, &insert, &geometry_name, &topolayer_id))
+	goto error;
+
+/* creating the output-table */
+    ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
+    sqlite3_free (create);
+    create = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* checking the Geometry Type */
+    if (!auxtopo_retrieve_export_geometry_type
+	(topo, topolayer_name, &ref_type))
+	goto error;
+    switch (ref_type)
+      {
+      case GAIA_POINT:
+	  type = "MULTIPOINT";
+	  out_type = GAIA_MULTIPOINT;
+	  break;
+      case GAIA_LINESTRING:
+	  type = "MULTILINESTRING";
+	  out_type = GAIA_MULTILINESTRING;
+	  break;
+      case GAIA_POLYGON:
+	  type = "MULTIPOLYGON";
+	  out_type = GAIA_MULTIPOLYGON;
+	  break;
+      case GAIA_GEOMETRYCOLLECTION:
+	  type = "GEOMETRYCOLLECTION";
+	  out_type = GAIA_GEOMETRYCOLLECTION;
+	  break;
+      default:
+	  type = "GEOMETRY";
+	  out_type = GAIA_UNKNOWN;
+	  break;
+      };
+
+/* creating the output Geometry Column */
+    sql =
+	sqlite3_mprintf
+	("SELECT AddGeometryColumn(Lower(%Q), %Q, %d, '%s', '%s')",
+	 out_table, geometry_name, topo->srid, type,
+	 (topo->has_z == 0) ? "XY" : "XYZ");
+    ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       errMsg);
+	  sqlite3_free (errMsg);
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    if (with_spatial_index)
+      {
+	  /* creating a Spatial Index supporting the Geometry Column */
+	  sql =
+	      sqlite3_mprintf
+	      ("SELECT CreateSpatialIndex(Lower(%Q), %Q)",
+	       out_table, geometry_name);
+	  ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+				     errMsg);
+		sqlite3_free (errMsg);
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    free (geometry_name);
+    if (create_only)
+      {
+	  sqlite3_free (select);
+	  sqlite3_free (insert);
+	  return 1;
+      }
+
+/* preparing the "SELECT * FROM topo-features-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
+			    NULL);
+    sqlite3_free (select);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO out-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
+			    NULL);
+    sqlite3_free (insert);
+    insert = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "SELECT * FROM topo-features" query */
+    table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT node_id, edge_id, face_id FROM \"%s\" "
+			   "WHERE topolayer_id = ? AND fid = ?", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rels,
+			    NULL);
+    sqlite3_free (sql);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Nodes query */
+    xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE node_id = ?",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Edges query */
+    xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Faces query */
+    xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT edge_id, left_face, right_face, geom FROM MAIN.\"%s\" "
+	 "WHERE left_face = ? OR right_face = ?", xtable);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* evaluating TopoLayer's Features */
+    if (!do_eval_topogeo_features
+	(topo, stmt_ref, stmt_ins, stmt_rels, stmt_node, stmt_edge, stmt_face,
+	 topolayer_id, out_type))
+	goto error;
+
+    sqlite3_finalize (stmt_ref);
+    sqlite3_finalize (stmt_ins);
+    sqlite3_finalize (stmt_rels);
+    sqlite3_finalize (stmt_node);
+    sqlite3_finalize (stmt_edge);
+    sqlite3_finalize (stmt_face);
+    return 1;
+
+  error:
+    if (create != NULL)
+	sqlite3_free (create);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    if (stmt_ref != NULL)
+	sqlite3_finalize (stmt_ref);
+    if (stmt_ins != NULL)
+	sqlite3_finalize (stmt_ins);
+    if (stmt_rels != NULL)
+	sqlite3_finalize (stmt_rels);
+    if (stmt_node != NULL)
+	sqlite3_finalize (stmt_node);
+    if (stmt_edge != NULL)
+	sqlite3_finalize (stmt_edge);
+    if (stmt_face != NULL)
+	sqlite3_finalize (stmt_face);
+    return 0;
+}
+
+static int
+check_output_table (struct gaia_topology *topo, const char *out_table,
+		    int *out_type)
+{
+/* checking the output table */
+    char *sql;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    int count = 0;
+    int type;
+
+    sql =
+	sqlite3_mprintf
+	("SELECT geometry_type FROM MAIN.geometry_columns WHERE f_table_name = Lower(%Q)",
+	 out_table);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	return 0;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		type = atoi (results[(i * columns) + 0]);
+		count++;
+	    }
+      }
+    sqlite3_free_table (results);
+
+    if (count != 1)
+	return 0;
+
+    switch (type)
+      {
+      case GAIA_POINT:
+      case GAIA_POINTZ:
+      case GAIA_POINTM:
+      case GAIA_POINTZM:
+	  *out_type = GAIA_POINT;
+	  break;
+      case GAIA_MULTIPOINT:
+      case GAIA_MULTIPOINTZ:
+      case GAIA_MULTIPOINTM:
+      case GAIA_MULTIPOINTZM:
+	  *out_type = GAIA_MULTIPOINT;
+	  break;
+      case GAIA_LINESTRING:
+      case GAIA_LINESTRINGZ:
+      case GAIA_LINESTRINGM:
+      case GAIA_LINESTRINGZM:
+      case GAIA_MULTILINESTRING:
+      case GAIA_MULTILINESTRINGZ:
+      case GAIA_MULTILINESTRINGM:
+      case GAIA_MULTILINESTRINGZM:
+	  *out_type = GAIA_MULTILINESTRING;
+	  break;
+      case GAIA_POLYGON:
+      case GAIA_POLYGONZ:
+      case GAIA_POLYGONM:
+      case GAIA_POLYGONZM:
+      case GAIA_MULTIPOLYGON:
+      case GAIA_MULTIPOLYGONZ:
+      case GAIA_MULTIPOLYGONM:
+      case GAIA_MULTIPOLYGONZM:
+	  *out_type = GAIA_MULTIPOLYGON;
+	  break;
+      case GAIA_GEOMETRYCOLLECTION:
+      case GAIA_GEOMETRYCOLLECTIONZ:
+      case GAIA_GEOMETRYCOLLECTIONM:
+      case GAIA_GEOMETRYCOLLECTIONZM:
+	  *out_type = GAIA_GEOMETRYCOLLECTION;
+	  break;
+      default:
+	  *out_type = GAIA_UNKNOWN;
+	  break;
+      };
+    return 1;
+}
+
+static int
+auxtopo_export_feature_sql (struct gaia_topology *topo,
+			    const char *topolayer_name, const char *out_table,
+			    char **xselect, char **xinsert,
+			    sqlite3_int64 * topolayer_id, int *out_type)
+{
+/* composing the CREATE TABLE insert-feature statement */
+    char *select = NULL;
+    char *insert = NULL;
+    char *prev;
+    char *sql;
+    char *table;
+    char *xtable;
+    char *xprefix;
+    char dummy[64];
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    const char *name;
+    int ret;
+    int first_select = 1;
+    int first_insert = 1;
+    int ncols = 0;
+    int icol;
+    int ref_col = 0;
+    char *geometry_name = NULL;
+    int geom_alias = 0;
+
+    *xselect = NULL;
+    *xinsert = NULL;
+
+/* checking the TopoLayer */
+    if (!check_topolayer (topo, topolayer_name, topolayer_id))
+	return 0;
+
+/* checking the output table */
+    if (!check_output_table (topo, out_table, out_type))
+	return 0;
+
+    xtable = gaiaDoubleQuotedSql (out_table);
+    select = sqlite3_mprintf ("SELECT fid, ");
+    insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (fid, ", xtable);
+    free (xtable);
+    sprintf (dummy, "%lld", *topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+	goto error;
+    if (rows < 1)
+	;
+    else
+      {
+	  for (i = 1; i <= rows; i++)
+	    {
+		name = results[(i * columns) + 1];
+		if (strcmp (name, "fid") == 0)
+		    continue;
+		/* SELECT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = select;
+		if (first_select)
+		    select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_select = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ref_col++;
+		/* INSERT: adding a column */
+		xprefix = gaiaDoubleQuotedSql (name);
+		prev = insert;
+		if (first_insert)
+		    insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
+		else
+		    insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
+		first_insert = 0;
+		free (xprefix);
+		sqlite3_free (prev);
+		ncols++;
+	    }
+      }
+    sqlite3_free_table (results);
+
+    geometry_name = malloc (strlen ("geometry") + 1);
+    strcpy (geometry_name, "geometry");
+    sprintf (dummy, "%lld", *topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    while (1)
+      {
+	  /* searching an unique Geometry name */
+	  if (is_unique_geom_name (topo->db_handle, table, geometry_name))
+	      break;
+	  sprintf (dummy, "geom_%d", ++geom_alias);
+	  free (geometry_name);
+	  geometry_name = malloc (strlen (dummy) + 1);
+	  strcpy (geometry_name, dummy);
+      }
+    sqlite3_free (table);
+
+/* completing the SQL statements */
+    prev = select;
+    sprintf (dummy, "%lld", *topolayer_id);
+    table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    select =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE fid = ?", prev, xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    prev = insert;
+    insert = sqlite3_mprintf ("%s, \"%s\") VALUES (?, ", prev, geometry_name);
+    sqlite3_free (prev);
+    for (icol = 0; icol < ncols; icol++)
+      {
+	  prev = insert;
+	  if (icol == 0)
+	      insert = sqlite3_mprintf ("%s?", prev);
+	  else
+	      insert = sqlite3_mprintf ("%s, ?", prev);
+	  sqlite3_free (prev);
+      }
+    prev = insert;
+    insert = sqlite3_mprintf ("%s, ?)", prev);
+    sqlite3_free (prev);
+
+    free (geometry_name);
+    *xselect = select;
+    *xinsert = insert;
+    return 1;
+
+  error:
+    if (geometry_name != NULL)
+	free (geometry_name);
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    return 0;
+}
+
+static int
+do_eval_topogeo_single_feature (struct gaia_topology *topo,
+				sqlite3_stmt * stmt_ref,
+				sqlite3_stmt * stmt_ins,
+				sqlite3_stmt * stmt_rels,
+				sqlite3_stmt * stmt_node,
+				sqlite3_stmt * stmt_edge,
+				sqlite3_stmt * stmt_face,
+				sqlite3_int64 topolayer_id, int out_type,
+				sqlite3_int64 fid)
+{
+/* querying the ref-table */
+    int ret;
+    int count = 0;
+
+    sqlite3_reset (stmt_ref);
+    sqlite3_clear_bindings (stmt_ref);
+    sqlite3_bind_int64 (stmt_ref, 1, fid);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  gaiaGeomCollPtr geom = NULL;
+	  ret = sqlite3_step (stmt_ref);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int icol;
+		int ncol = sqlite3_column_count (stmt_ref);
+		sqlite3_reset (stmt_ins);
+		sqlite3_clear_bindings (stmt_ins);
+		for (icol = 0; icol < ncol; icol++)
+		  {
+		      int col_type = sqlite3_column_type (stmt_ref, icol);
+		      switch (col_type)
+			{
+			case SQLITE_INTEGER:
+			    sqlite3_bind_int64 (stmt_ins, icol + 1,
+						sqlite3_column_int64 (stmt_ref,
+								      icol));
+			    break;
+			case SQLITE_FLOAT:
+			    sqlite3_bind_double (stmt_ins, icol + 1,
+						 sqlite3_column_double
+						 (stmt_ref, icol));
+			    break;
+			case SQLITE_TEXT:
+			    sqlite3_bind_text (stmt_ins, icol + 1,
+					       (const char *)
+					       sqlite3_column_text (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			case SQLITE_BLOB:
+			    sqlite3_bind_blob (stmt_ins, icol + 1,
+					       sqlite3_column_blob (stmt_ref,
+								    icol),
+					       sqlite3_column_bytes (stmt_ref,
+								     icol),
+					       SQLITE_STATIC);
+			    break;
+			default:
+			    sqlite3_bind_null (stmt_ins, icol + 1);
+			    break;
+			};
+		  }
+		/* the Geometry column */
+		ncol = sqlite3_bind_parameter_count (stmt_ins);
+		geom =
+		    do_eval_topo_geometry (topo, stmt_rels, stmt_node,
+					   stmt_edge, stmt_face, fid,
+					   topolayer_id, out_type);
+		if (geom != NULL)
+		  {
+		      unsigned char *p_blob;
+		      int n_bytes;
+		      gaiaToSpatiaLiteBlobWkb (geom, &p_blob, &n_bytes);
+		      sqlite3_bind_blob (stmt_ins, ncol, p_blob, n_bytes,
+					 SQLITE_TRANSIENT);
+		      free (p_blob);
+		      gaiaFreeGeomColl (geom);
+		  }
+		else
+		    sqlite3_bind_null (stmt_ins, ncol);
+		ret = sqlite3_step (stmt_ins);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      char *msg =
+			  sqlite3_mprintf
+			  ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			   sqlite3_errmsg (topo->db_handle));
+		      gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
+						   topo, msg);
+		      sqlite3_free (msg);
+		      return 0;
+		  }
+		count++;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("InsertFeatureFromTopoLayer() error: \"%s\"",
+		     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		return 0;
+	    }
+      }
+
+    if (count <= 0)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("InsertFeatureFromTopoLayer(): not existing TopoFeature");
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+    return 1;
+}
+
+GAIATOPO_DECLARE int
+gaiaTopoGeo_InsertFeatureFromTopoLayer (GaiaTopologyAccessorPtr accessor,
+					const char *topolayer_name,
+					const char *out_table,
+					sqlite3_int64 fid)
+{
+/* attempting to insert a single TopoLayer's Feature into the output GeoTable */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt_ref = NULL;
+    sqlite3_stmt *stmt_ins = NULL;
+    sqlite3_stmt *stmt_rels = NULL;
+    sqlite3_stmt *stmt_node = NULL;
+    sqlite3_stmt *stmt_edge = NULL;
+    sqlite3_stmt *stmt_face = NULL;
+    int ret;
+    char *select;
+    char *insert;
+    char *sql;
+    char *xprefix;
+    char *table;
+    char *xtable;
+    int out_type;
+    sqlite3_int64 topolayer_id;
+    if (topo == NULL)
+	return 0;
+
+/* composing the SQL statements */
+    if (!auxtopo_export_feature_sql
+	(topo, topolayer_name, out_table, &select, &insert, &topolayer_id,
+	 &out_type))
+	goto error;
+
+/* preparing the "SELECT * FROM topo-features-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
+			    NULL);
+    sqlite3_free (select);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the "INSERT INTO out-table" query */
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
+			    NULL);
+    sqlite3_free (insert);
+    insert = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  goto error;
+      }
+
+/* preparing the "SELECT * FROM topo-features" query */
+    table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT node_id, edge_id, face_id FROM \"%s\" "
+			   "WHERE topolayer_id = ? AND fid = ?", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rels,
+			    NULL);
+    sqlite3_free (sql);
+    select = NULL;
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Nodes query */
+    xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE node_id = ?",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Edges query */
+    xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
+			   xtable, xprefix);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* preparing the Topo-Faces query */
+    xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (xprefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT edge_id, left_face, right_face, geom FROM MAIN.\"%s\" "
+	 "WHERE left_face = ? OR right_face = ?", xtable);
+    free (xtable);
+    sqlite3_free (xprefix);
+    ret =
+	sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+/* evaluating TopoLayer's Features */
+    if (!do_eval_topogeo_single_feature
+	(topo, stmt_ref, stmt_ins, stmt_rels, stmt_node, stmt_edge, stmt_face,
+	 topolayer_id, out_type, fid))
+	goto error;
+
+    sqlite3_finalize (stmt_ref);
+    sqlite3_finalize (stmt_ins);
+    sqlite3_finalize (stmt_rels);
+    sqlite3_finalize (stmt_node);
+    sqlite3_finalize (stmt_edge);
+    sqlite3_finalize (stmt_face);
+    return 1;
+
+  error:
+    if (select != NULL)
+	sqlite3_free (select);
+    if (insert != NULL)
+	sqlite3_free (insert);
+    if (stmt_ref != NULL)
+	sqlite3_finalize (stmt_ref);
+    if (stmt_ins != NULL)
+	sqlite3_finalize (stmt_ins);
+    if (stmt_rels != NULL)
+	sqlite3_finalize (stmt_rels);
+    if (stmt_node != NULL)
+	sqlite3_finalize (stmt_node);
+    if (stmt_edge != NULL)
+	sqlite3_finalize (stmt_edge);
+    if (stmt_face != NULL)
+	sqlite3_finalize (stmt_face);
+    return 0;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/gaia_netstmts.c b/src/topology/gaia_netstmts.c
new file mode 100644
index 0000000..6488230
--- /dev/null
+++ b/src/topology/gaia_netstmts.c
@@ -0,0 +1,378 @@
+/*
+
+ gaia_netstmts.c -- implementation of Topology-Network prepared statements
+    
+ version 4.3, 2015 August 11
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaiaaux.h>
+#include <spatialite/gaia_network.h>
+
+#include <spatialite_private.h>
+
+#include <lwn_network.h>
+
+#include "network_private.h"
+
+#define GAIA_UNUSED() if (argc || argv) argc = argc;
+
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_getNetNodeWithinDistance2D (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the getNetNodeWithinDistance2D prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT node_id FROM MAIN.\"%s\" "
+			 "WHERE ST_Distance(geometry, MakePoint(?, ?)) <= ? AND ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geometry' AND search_frame = BuildCircleMBR(?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("Prepare_getNetNodeWithinDistance2D error: \"%s\"",
+	       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_getLinkWithinDistance2D (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the getLinkWithinDistance2D prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT link_id FROM MAIN.\"%s\" "
+			 "WHERE ST_Distance(geometry, MakePoint(?, ?)) <= ? AND ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geometry' AND search_frame = BuildCircleMBR(?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getLinkWithinDistance2D error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_insertNetNodes (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the insertNetNodes prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO \"%s\" (node_id, geometry) VALUES (?, ?)", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_insertNetNodes error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_insertLinks (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the insertLinks prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO \"%s\" (link_id, start_node, end_node, geometry) "
+	 "VALUES (?, ?, ?, ?)", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_insertLinks error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_deleteNetNodesById (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the deleteNodesById prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE node_id = ?", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_deleteNetNodesById error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_getNetNodeWithinBox2D (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the getNetNodeWithinBox2D prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT node_id FROM MAIN.\"%s\" WHERE ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geometry' AND search_frame = BuildMBR(?, ?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getNetNodeWithinBox2D error: \"%s\"",
+			       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_getNextLinkId (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the getNextLinkId prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    if (net == NULL)
+	return NULL;
+
+    sql =
+	sqlite3_mprintf
+	("SELECT next_link_id FROM MAIN.networks WHERE Lower(network_name) = Lower(%Q)",
+	 net->network_name);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getNextLinkId error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_setNextLinkId (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the setNextLinkId prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    if (net == NULL)
+	return NULL;
+
+    sql =
+	sqlite3_mprintf
+	("UPDATE MAIN.networks SET next_link_id = next_link_id + 1 "
+	 "WHERE Lower(network_name) = Lower(%Q)", net->network_name);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_setNextLinkId error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+NETWORK_PRIVATE sqlite3_stmt *
+do_create_stmt_deleteLinksById (GaiaNetworkAccessorPtr accessor)
+{
+/* attempting to create the deleteNodesById prepared statement */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (net == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE link_id = ?", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_deleteLinksById error: \"%s\"",
+				       sqlite3_errmsg (net->db_handle));
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/gaia_network.c b/src/topology/gaia_network.c
new file mode 100644
index 0000000..a6781fc
--- /dev/null
+++ b/src/topology/gaia_network.c
@@ -0,0 +1,4189 @@
+/*
+
+ gaia_network.c -- implementation of Topology-Network SQL functions
+    
+ version 4.3, 2015 August 11
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaia_network.h>
+#include <spatialite/gaia_topology.h>
+#include <spatialite/gaiaaux.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+
+#include <lwn_network.h>
+
+#include "network_private.h"
+
+#include <liblwgeom.h>
+#include <liblwgeom_topo.h>
+#include "topology_private.h"
+
+#define GAIA_UNUSED() if (argc || argv) argc = argc;
+
+
+SPATIALITE_PRIVATE void
+start_net_savepoint (const void *handle, const void *data)
+{
+/* starting a new SAVEPOINT */
+    char *sql;
+    int ret;
+    char *err_msg;
+    sqlite3 *sqlite = (sqlite3 *) handle;
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) data;
+    if (sqlite == NULL || cache == NULL)
+	return;
+
+/* creating an unique SavePoint name */
+    if (cache->network_savepoint_name != NULL)
+	sqlite3_free (cache->network_savepoint_name);
+    cache->network_savepoint_name = NULL;
+    cache->network_savepoint_name =
+	sqlite3_mprintf ("netsvpt%04x", cache->next_network_savepoint);
+    if (cache->next_network_savepoint >= 0xffffffffu)
+	cache->next_network_savepoint = 0;
+    else
+	cache->next_network_savepoint += 1;
+
+/* starting a SavePoint */
+    sql = sqlite3_mprintf ("SAVEPOINT %s", cache->network_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+}
+
+SPATIALITE_PRIVATE void
+release_net_savepoint (const void *handle, const void *data)
+{
+/* releasing the current SAVEPOINT (if any) */
+    char *sql;
+    int ret;
+    char *err_msg;
+    sqlite3 *sqlite = (sqlite3 *) handle;
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) data;
+    if (sqlite == NULL || cache == NULL)
+	return;
+    if (cache->network_savepoint_name == NULL)
+	return;
+
+/* releasing the current SavePoint */
+    sql =
+	sqlite3_mprintf ("RELEASE SAVEPOINT %s", cache->network_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+    sqlite3_free (cache->network_savepoint_name);
+    cache->network_savepoint_name = NULL;
+}
+
+SPATIALITE_PRIVATE void
+rollback_net_savepoint (const void *handle, const void *data)
+{
+/* rolling back the current SAVEPOINT (if any) */
+    char *sql;
+    int ret;
+    char *err_msg;
+    sqlite3 *sqlite = (sqlite3 *) handle;
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) data;
+    if (sqlite == NULL || cache == NULL)
+	return;
+    if (cache->network_savepoint_name == NULL)
+	return;
+
+/* rolling back the current SavePoint */
+    sql =
+	sqlite3_mprintf ("ROLLBACK TO SAVEPOINT %s",
+			 cache->network_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+/* releasing the current SavePoint */
+    sql =
+	sqlite3_mprintf ("RELEASE SAVEPOINT %s", cache->network_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+    sqlite3_free (cache->network_savepoint_name);
+    cache->network_savepoint_name = NULL;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetLastNetworkException (const void *xcontext, int argc,
+				 const void *xargv)
+{
+/* SQL function:
+/ GetLastNetworkException  ( text network-name )
+/
+/ returns: the more recent exception raised by given Topology-Network
+/ NULL on invalid args (or when there is no pending exception)
+*/
+    const char *network_name;
+    GaiaNetworkAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+    sqlite3_result_text (context, gaianet_get_last_exception (accessor), -1,
+			 SQLITE_STATIC);
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_CreateNetwork (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_InitTopoNet ( text network-name )
+/ CreateNetwork ( text network-name )
+/ CreateNetwork ( text network-name, bool spatial )
+/ CreateNetwork ( text network-name, bool spatial, int srid )
+/ CreateNetwork ( text network-name, bool spatial, int srid, bool hasZ )
+/ CreateNetwork ( text network-name, bool spatial, int srid, bool hasZ,
+/                 bool allow_coincident )
+/
+/ returns: 1 on success, 0 on failure
+/ -1 on invalid args
+*/
+    int ret;
+    const char *network_name;
+    int srid = -1;
+    int has_z = 0;
+    int spatial = 0;
+    int allow_coincident = 1;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (argc >= 2)
+      {
+	  if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	      spatial = sqlite3_value_int (argv[1]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+    if (argc >= 3)
+      {
+	  if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	      srid = sqlite3_value_int (argv[2]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+    if (argc >= 4)
+      {
+	  if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[3]) == SQLITE_INTEGER)
+	      has_z = sqlite3_value_int (argv[3]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+    if (argc >= 5)
+      {
+	  if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[4]) == SQLITE_INTEGER)
+	      allow_coincident = sqlite3_value_int (argv[4]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+
+    start_net_savepoint (sqlite, cache);
+    ret =
+	gaiaNetworkCreate (sqlite, network_name, spatial, srid, has_z,
+			   allow_coincident);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    sqlite3_result_int (context, ret);
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_DropNetwork (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ DropNetwork ( text network-name )
+/
+/ returns: 1 on success, 0 on failure
+/ -1 on invalid args
+*/
+    int ret;
+    const char *network_name;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GaiaNetworkAccessorPtr accessor;
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor != NULL)
+	gaiaNetworkDestroy (accessor);
+
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaNetworkDrop (sqlite, network_name);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    sqlite3_result_int (context, ret);
+}
+
+static int
+check_matching_srid_dims (GaiaNetworkAccessorPtr accessor, int srid, int dims)
+{
+/* checking for matching SRID and DIMs */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net->srid != srid)
+	return 0;
+    if (net->has_z)
+      {
+	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
+	      ;
+	  else
+	      return 0;
+      }
+    else
+      {
+	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
+	      return 0;
+      }
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_AddIsoNetNode (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_AddIsoNetNode ( text network-name, Geometry point )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt = NULL;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+      {
+	  if (net->spatial)
+	      goto spatial_err;
+      }
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  if (net->spatial == 0)
+	      goto logical_err;
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+
+	  /* attempting to get a Point Geometry */
+	  point =
+	      gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+					   gpkg_amphibious);
+	  if (!point)
+	      goto invalid_arg;
+	  if (point->FirstLinestring != NULL)
+	      invalid = 1;
+	  if (point->FirstPolygon != NULL)
+	      invalid = 1;
+	  if (point->FirstPoint != point->LastPoint
+	      || point->FirstPoint == NULL)
+	      invalid = 1;
+	  if (invalid)
+	      goto invalid_arg;
+
+	  if (!check_matching_srid_dims
+	      (accessor, point->Srid, point->DimensionModel))
+	      goto invalid_geom;
+	  pt = point->FirstPoint;
+      }
+    else
+	goto invalid_arg;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaAddIsoNetNode (accessor, pt);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (point != NULL)
+      {
+	  gaiaFreeGeomColl (point);
+	  point = NULL;
+      }
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+
+  spatial_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Spatial Network can't accept null geometry.",
+			  -1);
+    return;
+
+  logical_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Logical Network can't accept not null geometry.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_MoveIsoNetNode (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_MoveIsoNetNode ( text network-name, int node_id, Geometry point )
+/
+/ returns: TEXT (description of new location)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *net_name;
+    sqlite3_int64 node_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt = NULL;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	net_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, net_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+      {
+	  if (net->spatial)
+	      goto spatial_err;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  if (net->spatial == 0)
+	      goto logical_err;
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+
+	  /* attempting to get a Point Geometry */
+	  point =
+	      gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+					   gpkg_amphibious);
+	  if (!point)
+	      goto invalid_arg;
+	  if (point->FirstLinestring != NULL)
+	      invalid = 1;
+	  if (point->FirstPolygon != NULL)
+	      invalid = 1;
+	  if (point->FirstPoint != point->LastPoint
+	      || point->FirstPoint == NULL)
+	      invalid = 1;
+	  if (invalid)
+	      goto invalid_arg;
+	  if (!check_matching_srid_dims
+	      (accessor, point->Srid, point->DimensionModel))
+	      goto invalid_geom;
+	  pt = point->FirstPoint;
+      }
+    else
+	goto invalid_arg;
+    sprintf (xid, "%lld", node_id);
+    if (pt == NULL)
+	newpos =
+	    sqlite3_mprintf ("Isolated Node %s moved to NULL location", xid);
+    else
+	newpos =
+	    sqlite3_mprintf ("Isolated Node %s moved to location %f,%f", xid,
+			     pt->X, pt->Y);
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaMoveIsoNetNode (accessor, node_id, pt);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    point = NULL;
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_net:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+
+  spatial_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Spatial Network can't accept null geometry.",
+			  -1);
+    return;
+
+  logical_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Logical Network can't accept not null geometry.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_RemIsoNetNode (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_RemIsoNetNode ( text network-name, int node_id )
+/
+/ returns: TEXT (description of operation)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *network_name;
+    sqlite3_int64 node_id;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    sprintf (xid, "%lld", node_id);
+    newpos = sqlite3_mprintf ("Isolated NetNode %s removed", xid);
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaRemIsoNetNode (accessor, node_id);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_net:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_AddLink (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_AddLink ( text network-name, int start_node_id, int end_node_id, Geometry linestring )
+/
+/ returns: the ID of the inserted Link on success, 0 on failure
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 start_node_id;
+    sqlite3_int64 end_node_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr line = NULL;
+    gaiaLinestringPtr ln = NULL;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	start_node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	end_node_id = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+      {
+	  if (net->spatial)
+	      goto spatial_err;
+      }
+    else if (sqlite3_value_type (argv[3]) == SQLITE_BLOB)
+      {
+	  if (net->spatial == 0)
+	      goto logical_err;
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[3]);
+	  n_bytes = sqlite3_value_bytes (argv[3]);
+
+/* attempting to get a Linestring Geometry */
+	  line =
+	      gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+					   gpkg_amphibious);
+	  if (!line)
+	      goto invalid_arg;
+	  if (line->FirstPoint != NULL)
+	      invalid = 1;
+	  if (line->FirstPolygon != NULL)
+	      invalid = 1;
+	  if (line->FirstLinestring != line->LastLinestring
+	      || line->FirstLinestring == NULL)
+	      invalid = 1;
+	  if (invalid)
+	      goto invalid_arg;
+	  if (!check_matching_srid_dims
+	      (accessor, line->Srid, line->DimensionModel))
+	      goto invalid_geom;
+	  ln = line->FirstLinestring;
+      }
+    else
+	goto invalid_arg;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaAddLink (accessor, start_node_id, end_node_id, ln);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    line = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  spatial_err:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Spatial Network can't accept null geometry.",
+			  -1);
+    return;
+
+  logical_err:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Logical Network can't accept not null geometry.",
+			  -1);
+    return;
+
+  invalid_geom:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ChangeLinkGeom (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ChangeLinkGeom ( text network-name, int link_id, Geometry linestring )
+/
+/ returns: TEXT (description of operation)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr line = NULL;
+    gaiaLinestringPtr ln = NULL;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+      {
+	  if (net->spatial)
+	      goto spatial_err;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  if (net->spatial == 0)
+	      goto logical_err;
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+
+	  /* attempting to get a Linestring Geometry */
+	  line =
+	      gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+					   gpkg_amphibious);
+	  if (!line)
+	      goto invalid_arg;
+	  if (line->FirstPoint != NULL)
+	      invalid = 1;
+	  if (line->FirstPolygon != NULL)
+	      invalid = 1;
+	  if (line->FirstLinestring != line->LastLinestring
+	      || line->FirstLinestring == NULL)
+	      invalid = 1;
+	  if (invalid)
+	      goto invalid_arg;
+
+	  if (!check_matching_srid_dims
+	      (accessor, line->Srid, line->DimensionModel))
+	      goto invalid_geom;
+	  ln = line->FirstLinestring;
+      }
+    else
+	goto invalid_arg;
+    sprintf (xid, "%lld", link_id);
+    newpos = sqlite3_mprintf ("Link %s changed", xid);
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaChangeLinkGeom (accessor, link_id, ln);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    line = NULL;
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_net:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+
+  spatial_err:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Spatial Network can't accept null geometry.",
+			  -1);
+    return;
+
+  logical_err:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Logical Network can't accept not null geometry.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_RemoveLink (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_RemoveLink ( text network-name, int link_id )
+/
+/ returns: TEXT (description of operation)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    sprintf (xid, "%lld", link_id);
+    newpos = sqlite3_mprintf ("Link %s removed", xid);
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaRemoveLink (accessor, link_id);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_net:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_NewLogLinkSplit (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_NewLogLinkSplit ( text network-name, int link_id )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial)
+	goto spatial_err;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaNewLogLinkSplit (accessor, link_id);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  spatial_err:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - ST_NewLogLinkSplit can't support Spatial Network; try using ST_NewGeoLinkSplit.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ModLogLinkSplit (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ModLogLinkSplit ( text network-name, int link_id )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial)
+	goto spatial_err;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaModLogLinkSplit (accessor, link_id);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  spatial_err:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - ST_ModLogLinkSplit can't support Spatial Network; try using ST_ModGeoLinkSplit.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_NewGeoLinkSplit (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_NewGeoLinkSplit ( text network-name, int link_id, Geometry point )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto spatial_err;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+    pt = point->FirstPoint;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaNewGeoLinkSplit (accessor, link_id, pt);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+
+  spatial_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Spatial Network can't accept null geometry.",
+			  -1);
+    return;
+
+  logical_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - ST_NewGeoLinkSplit can't support Logical Network; try using ST_NewLogLinkSplit.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ModGeoLinkSplit (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ModGeoLinkSplit ( text network-name, int link_id, Geometry point )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto spatial_err;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+    pt = point->FirstPoint;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaModGeoLinkSplit (accessor, link_id, pt);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+
+  spatial_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - Spatial Network can't accept null geometry.",
+			  -1);
+    return;
+
+  logical_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - ST_ModGeoLinkSplit can't support Logical Network; try using ST_ModLogLinkSplit.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_NewLinkHeal (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_NewLinkHeal ( text network-name, int link_id, int anotherlink_id )
+/
+/ returns: the ID of the removed Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    sqlite3_int64 anotherlink_id;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	anotherlink_id = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaNewLinkHeal (accessor, link_id, anotherlink_id);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ModLinkHeal (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ModLinkHeal ( text network-name, int link_id )
+/
+/ returns: the ID of the removed Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    sqlite3_int64 link_id;
+    sqlite3_int64 anotherlink_id;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	anotherlink_id = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaModLinkHeal (accessor, link_id, anotherlink_id);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+static int
+check_empty_network (struct gaia_network *net)
+{
+/* checking for an empty Network */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int already_populated = 0;
+
+/* testing NODE */
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (net->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  if (atoi (results[(i * columns) + 0]) > 0)
+	      already_populated = 1;
+      }
+    sqlite3_free_table (results);
+    if (already_populated)
+	return 0;
+
+/* testing LINK */
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (net->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  if (atoi (results[(i * columns) + 0]) > 0)
+	      already_populated = 1;
+      }
+    sqlite3_free_table (results);
+    if (already_populated)
+	return 0;
+
+    return 1;
+}
+
+static int
+do_loginet_from_tgeo (struct gaia_network *net, struct gaia_topology *topo)
+{
+/* populating a Logical Network starting from an existing Topology */
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    char *sql;
+    char *errMsg;
+    int ret;
+
+/* preparing the SQL statement - NODE */
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("INSERT INTO \"%s\" (node_id, geometry) "
+			   "SELECT node_id, NULL FROM MAIN.\"%s\"", xtable1,
+			   xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_LogiNetFromTGeo() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* preparing the SQL statement - LINK */
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (link_id, start_node, end_node, geometry) "
+	 "SELECT edge_id, start_node, end_node, NULL FROM MAIN.\"%s\"", xtable1,
+	 xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_LogiNetFromTGeo() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_LogiNetFromTGeo (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_LogiNetFromTGeo ( text network-name, text topology-name )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *network_name;
+    const char *topo_name;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    GaiaTopologyAccessorPtr accessor2;
+    struct gaia_topology *topo;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial)
+	goto spatial_err;
+    if (!check_empty_network (net))
+	goto non_empty;
+
+/* attempting to get a Topology Accessor */
+    accessor2 = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor2 == NULL)
+	goto no_topo;
+    topo = (struct gaia_topology *) accessor2;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = do_loginet_from_tgeo (net, topo);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  spatial_err:
+    sqlite3_result_error (context,
+			  "ST_LogiNetFromTGeo() cannot be applied to Spatial Network.",
+			  -1);
+    return;
+
+  non_empty:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - non-empty network.", -1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+static int
+check_matching_topo_net (struct gaia_network *net, struct gaia_topology *topo)
+{
+/* checking for matching SRID and DIMs */
+    if (net->srid != topo->srid)
+	return 0;
+    if (net->has_z != topo->has_z)
+	return 0;
+    return 1;
+}
+
+static int
+do_spatnet_from_tgeo (struct gaia_network *net, struct gaia_topology *topo)
+{
+/* populating a Spatial Network starting from an existing Topology */
+    char *table;
+    char *xtable1;
+    char *xtable2;
+    char *sql;
+    char *errMsg;
+    int ret;
+
+/* preparing the SQL statement - NODE */
+    table = sqlite3_mprintf ("%s_node", net->network_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (node_id, geometry) "
+			   "SELECT node_id, geom FROM MAIN.\"%s\"", xtable1,
+			   xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_SpatNetFromTGeo() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+/* preparing the SQL statement - LINK */
+    table = sqlite3_mprintf ("%s_link", net->network_name);
+    xtable1 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable2 = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (link_id, start_node, end_node, geometry) "
+	 "SELECT edge_id, start_node, end_node, geom FROM MAIN.\"%s\"", xtable1,
+	 xtable2);
+    free (xtable1);
+    free (xtable2);
+    ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("ST_SpatNetFromTGeo() error: \"%s\"", errMsg);
+	  sqlite3_free (errMsg);
+	  gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
+	  sqlite3_free (msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_SpatNetFromTGeo (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_SpatNetFromTGeo ( text network-name, text topology-name )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *network_name;
+    const char *topo_name;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    GaiaTopologyAccessorPtr accessor2;
+    struct gaia_topology *topo;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+    if (!check_empty_network (net))
+	goto non_empty;
+
+/* attempting to get a Topology Accessor */
+    accessor2 = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor2 == NULL)
+	goto no_topo;
+    topo = (struct gaia_topology *) accessor2;
+    if (!check_matching_topo_net (net, topo))
+	goto mismatching;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = do_spatnet_from_tgeo (net, topo);
+    if (ret <= 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (ret <= 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  logical_err:
+    sqlite3_result_error (context,
+			  "ST_SpatNetFromTGeo() cannot be applied to Logical Network.",
+			  -1);
+    return;
+
+  non_empty:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - non-empty network.", -1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  mismatching:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - mismatching SRID or dimensions.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ValidLogicalNet (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ValidLogicalNet ( text network-name )
+/
+/ create/update a table containing an validation report for a given
+/ Logical Network
+/
+/ returns NULL on success
+/ raises an exception on failure
+*/
+    const char *network_name;
+    int ret;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial)
+	goto spatial_err;
+    if (check_empty_network (net))
+	goto empty;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaValidLogicalNet (accessor);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_null (context);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  spatial_err:
+    sqlite3_result_error (context,
+			  "ST_ValidLogicalNet() cannot be applied to Spatial Network.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  empty:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - empty network.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ValidSpatialNet (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ValidSpatialNet ( text network-name )
+/
+/ create/update a table containing an validation report for a given
+/ Spatial Network
+/
+/ returns NULL on success
+/ raises an exception on failure
+*/
+    const char *network_name;
+    int ret;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+    if (check_empty_network (net))
+	goto empty;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaValidSpatialNet (accessor);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_null (context);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  logical_err:
+    sqlite3_result_error (context,
+			  "ST_ValidSpatialNet() cannot be applied to Logical Network.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  empty:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - empty network.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_SpatNetFromGeom (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_SpatNetFromGeom ( text network-name , blob geom-collection )
+/
+/ creates and populates an empty Network by importing a Geometry-collection
+/
+/ returns NULL on success
+/ raises an exception on failure
+*/
+    const char *network_name;
+    int ret;
+    const unsigned char *blob;
+    int blob_sz;
+    gaiaGeomCollPtr geom = NULL;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  blob = sqlite3_value_blob (argv[1]);
+	  blob_sz = sqlite3_value_bytes (argv[1]);
+	  geom =
+	      gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
+					   gpkg_amphibious);
+      }
+    else
+	goto invalid_arg;
+    if (geom == NULL)
+	goto not_geom;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+    if (!check_empty_network (net))
+	goto not_empty;
+    if (!check_matching_srid_dims (accessor, geom->Srid, geom->DimensionModel))
+	goto invalid_geom;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = auxnet_insert_into_network (accessor, geom);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_null (context);
+    gaiaFreeGeomColl (geom);
+    return;
+
+  no_net:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  logical_err:
+    sqlite3_result_error (context,
+			  "ST_ValidSpatialNet() cannot be applied to Logical Network.",
+			  -1);
+    return;
+
+  null_arg:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  not_empty:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - non-empty network.", -1);
+    return;
+
+  not_geom:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - not a Geometry.", -1);
+    return;
+
+  invalid_geom:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid Geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetNetNodeByPoint (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ GetNetNodeByPoint ( text network-name, Geometry point, double tolerance )
+/
+/ returns: the ID of some Node on success, 0 if no Node was found
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    double tolerance;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+    pt = point->FirstPoint;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaGetNetNodeByPoint (accessor, pt, tolerance);
+    if (ret < 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret < 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  logical_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "GetNetNodekByPoint() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetLinkByPoint (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ GetLinkByPoint ( text network-name, Geometry point, double tolerance )
+/
+/ returns: the ID of some Link on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *network_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    double tolerance;
+    int invalid = 0;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+    pt = point->FirstPoint;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaGetLinkByPoint (accessor, pt, tolerance);
+    if (ret < 0)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret < 0)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_net:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  logical_err:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "GetLinkByPoint() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+static int
+check_matching_srid_dims_class (GaiaNetworkAccessorPtr accessor, int srid,
+				int dims, int linear)
+{
+/* checking for matching SRID and DIMs */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net->srid != srid)
+	return 0;
+    if (!linear)
+	return 0;
+    if (net->has_z)
+      {
+	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
+	      ;
+	  else
+	      return 0;
+      }
+    else
+      {
+	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
+	      return 0;
+      }
+    return 1;
+}
+
+static int
+check_input_geonet_table (sqlite3 * sqlite, const char *db_prefix,
+			  const char *table, const char *column, char **xtable,
+			  char **xcolumn, int *srid, int *dims, int *linear)
+{
+/* checking if an input GeoTable do really exist */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    char *xprefix;
+    int len;
+    int count = 0;
+    char *xx_table = NULL;
+    char *xx_column = NULL;
+    char *ztable;
+    int xtype;
+    int xdims;
+    int xsrid;
+
+    *xtable = NULL;
+    *xcolumn = NULL;
+    *srid = -1;
+    *dims = GAIA_XY;
+    *linear = 1;
+
+/* querying GEOMETRY_COLUMNS */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    if (column == NULL)
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT f_table_name, f_geometry_column, geometry_type, srid "
+	     "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q)",
+	     xprefix, table);
+    else
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT f_table_name, f_geometry_column, geometry_type, srid "
+	     "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) AND "
+	     "Lower(f_geometry_column) = Lower(%Q)", xprefix, table, column);
+    free (xprefix);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *table_name = results[(i * columns) + 0];
+	  const char *column_name = results[(i * columns) + 1];
+	  xtype = atoi (results[(i * columns) + 2]);
+	  xsrid = atoi (results[(i * columns) + 3]);
+	  len = strlen (table_name);
+	  if (xx_table != NULL)
+	      free (xx_table);
+	  xx_table = malloc (len + 1);
+	  strcpy (xx_table, table_name);
+	  len = strlen (column_name);
+	  if (xx_column != NULL)
+	      free (xx_column);
+	  xx_column = malloc (len + 1);
+	  strcpy (xx_column, column_name);
+	  count++;
+      }
+    sqlite3_free_table (results);
+
+    if (count != 1)
+      {
+	  if (xx_table != NULL)
+	      free (xx_table);
+	  if (xx_column != NULL)
+	      free (xx_column);
+	  return 0;
+      }
+
+/* testing if the GeoTable do really exist */
+    count = 0;
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    ztable = gaiaDoubleQuotedSql (xx_table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, ztable);
+    free (xprefix);
+    free (ztable);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *column_name = results[(i * columns) + 1];
+	  if (strcasecmp (column_name, xx_column) == 0)
+	      count++;
+      }
+    sqlite3_free_table (results);
+
+    if (count != 1)
+      {
+	  if (xx_table != NULL)
+	      free (xx_table);
+	  if (xx_column != NULL)
+	      free (xx_column);
+	  return 0;
+      }
+
+    switch (xtype)
+      {
+      case 2:
+      case 5:
+	  xdims = GAIA_XY;
+	  break;
+      case 1002:
+      case 1005:
+	  xdims = GAIA_XY_Z;
+	  break;
+      case 2002:
+      case 2005:
+	  xdims = GAIA_XY_M;
+	  break;
+      case 3002:
+      case 3005:
+	  xdims = GAIA_XY_Z_M;
+	  break;
+      default:
+	  *linear = 0;
+	  break;
+      };
+    *xtable = xx_table;
+    *xcolumn = xx_column;
+    *srid = xsrid;
+    *dims = xdims;
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoNet_FromGeoTable (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoNet_FromGeoTable ( text network-name, text db-prefix, text table,
+/                        text column )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *network_name;
+    const char *db_prefix;
+    const char *table;
+    const char *column;
+    char *xtable = NULL;
+    char *xcolumn = NULL;
+    int srid;
+    int dims;
+    int linear;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+/* checking the input GeoTable */
+    if (!check_input_geonet_table
+	(sqlite, db_prefix, table, column, &xtable, &xcolumn, &srid, &dims,
+	 &linear))
+	goto no_input;
+    if (!check_matching_srid_dims_class (accessor, srid, dims, linear))
+	goto invalid_geom;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaTopoNet_FromGeoTable (accessor, db_prefix, xtable, xcolumn);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    free (xtable);
+    free (xcolumn);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_net:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  no_input:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid input GeoTable.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID, dimensions or class).",
+			  -1);
+    return;
+
+  logical_err:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "FromGeoTable() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+static int
+check_reference_geonet_table (sqlite3 * sqlite, const char *db_prefix,
+			      const char *table, const char *column,
+			      char **xtable, char **xcolumn, int *srid,
+			      int *linear)
+{
+    int dims;
+    return check_input_geonet_table (sqlite, db_prefix, table, column, xtable,
+				     xcolumn, srid, &dims, linear);
+}
+
+static int
+check_matching_srid_class (GaiaNetworkAccessorPtr accessor, int srid,
+			   int linear)
+{
+/* checking for matching SRID */
+    struct gaia_network *net = (struct gaia_network *) accessor;
+    if (net->srid != srid)
+	return 0;
+    if (!linear)
+	return 0;
+    return 1;
+}
+
+static int
+check_output_geonet_table (sqlite3 * sqlite, const char *table)
+{
+/* checking if an output GeoTable do already exist */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    int count = 0;
+    char *ztable;
+
+/* querying GEOMETRY_COLUMNS */
+    sql =
+	sqlite3_mprintf
+	("SELECT f_table_name, f_geometry_column "
+	 "FROM MAIN.geometry_columns WHERE Lower(f_table_name) = Lower(%Q)",
+	 table);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+
+    if (count != 0)
+	return 0;
+
+/* testing if the Table already exist */
+    count = 0;
+    ztable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", ztable);
+    free (ztable);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+
+    if (count != 0)
+	return 0;
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoNet_ToGeoTable (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoNet_ToGeoTable ( text network-name, text db-prefix, text ref_table,
+/                      text ref_column, text out_table )
+/ TopoNet_ToGeoTable ( text network-name, text db-prefix, text ref_table,
+/                      text ref_column, text out_table, int with_spatial_index )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *network_name;
+    const char *db_prefix;
+    const char *ref_table;
+    const char *ref_column;
+    const char *out_table;
+    int with_spatial_index = 0;
+    char *xreftable = NULL;
+    char *xrefcolumn = NULL;
+    int srid;
+    int linear;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	ref_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	ref_column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	ref_column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[4]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[4]);
+    else
+	goto invalid_arg;
+    if (argc >= 6)
+      {
+	  if (sqlite3_value_type (argv[5]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[5]) == SQLITE_INTEGER)
+	      with_spatial_index = sqlite3_value_int (argv[5]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+/* checking the reference GeoTable */
+    if (!check_reference_geonet_table
+	(sqlite, db_prefix, ref_table, ref_column, &xreftable, &xrefcolumn,
+	 &srid, &linear))
+	goto no_reference;
+    if (!check_matching_srid_class (accessor, srid, linear))
+	goto invalid_geom;
+
+/* checking the output GeoTable */
+    if (!check_output_geonet_table (sqlite, out_table))
+	goto err_output;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoNet_ToGeoTable (accessor, db_prefix, xreftable, xrefcolumn,
+				out_table, with_spatial_index);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    free (xreftable);
+    free (xrefcolumn);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_net:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  no_reference:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoNet_ToGeoTable: invalid reference GeoTable.",
+			  -1);
+    return;
+
+  err_output:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoNet_ToGeoTable: output GeoTable already exists.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID or class).",
+			  -1);
+    return;
+
+  logical_err:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoNet_ToGeoTable() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoNet_ToGeoTableGeneralize (const void *xcontext, int argc,
+				      const void *xargv)
+{
+/* SQL function:
+/ TopoNet_ToGeoTableGeneralize ( text network-name, text db-prefix, 
+/                                text ref_table, text ref_column,
+/                                text out_table, int tolerance, 
+/                                int with_spatial_index )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *network_name;
+    const char *db_prefix;
+    const char *ref_table;
+    const char *ref_column;
+    const char *out_table;
+    double tolerance = 0.0;
+    int with_spatial_index = 0;
+    char *xreftable = NULL;
+    char *xrefcolumn = NULL;
+    int srid;
+    int linear;
+    GaiaNetworkAccessorPtr accessor;
+    struct gaia_network *net;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	ref_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	ref_column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	ref_column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[4]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[4]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[5]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[5]) == SQLITE_INTEGER)
+      {
+	  int val = sqlite3_value_int (argv[5]);
+	  tolerance = val;
+      }
+    else if (sqlite3_value_type (argv[5]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_double (argv[5]);
+    else
+	goto invalid_arg;
+    if (argc >= 7)
+      {
+	  if (sqlite3_value_type (argv[6]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[6]) == SQLITE_INTEGER)
+	      with_spatial_index = sqlite3_value_int (argv[6]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+/* checking the reference GeoTable */
+    if (!check_reference_geonet_table
+	(sqlite, db_prefix, ref_table, ref_column, &xreftable, &xrefcolumn,
+	 &srid, &linear))
+	goto no_reference;
+    if (!check_matching_srid_class (accessor, srid, linear))
+	goto invalid_geom;
+
+/* checking the output GeoTable */
+    if (!check_output_geonet_table (sqlite, out_table))
+	goto err_output;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoNet_ToGeoTableGeneralize (accessor, db_prefix, xreftable,
+					  xrefcolumn, out_table, tolerance,
+					  with_spatial_index);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    free (xreftable);
+    free (xrefcolumn);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  gaianet_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_net:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  no_reference:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoNet_ToGeoTableGeneralize: invalid reference GeoTable.",
+			  -1);
+    return;
+
+  err_output:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoNet_ToGeoTableGeneralize: output GeoTable already exists.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID or class).",
+			  -1);
+    return;
+
+  logical_err:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoNet_ToGeoTableGeneralize() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+static int
+do_clone_netnode (const char *db_prefix, const char *in_network,
+		  struct gaia_network *net_out)
+{
+/* cloning NODE */
+    char *sql;
+    char *table;
+    char *xprefix;
+    char *xtable;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    int ret;
+
+/* preparing the input SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    table = sqlite3_mprintf ("%s_node", in_network);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT node_id, geometry FROM \"%s\".\"%s\"", xprefix,
+			 xtable);
+    free (xprefix);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net_out->db_handle, sql, strlen (sql), &stmt_in,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM \"node\" error: \"%s\"",
+			sqlite3_errmsg (net_out->db_handle));
+	  goto error;
+      }
+
+/* preparing the output SQL statement */
+    table = sqlite3_mprintf ("%s_node", net_out->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (node_id, geometry) "
+			   "VALUES (?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net_out->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("INSERT INTO \"node\" error: \"%s\"",
+			sqlite3_errmsg (net_out->db_handle));
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 1,
+					sqlite3_column_int64 (stmt_in, 0));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 1) == SQLITE_NULL)
+		    sqlite3_bind_null (stmt_out, 2);
+		else if (sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
+		    sqlite3_bind_blob (stmt_out, 2,
+				       sqlite3_column_blob (stmt_in, 1),
+				       sqlite3_column_bytes (stmt_in, 1),
+				       SQLITE_STATIC);
+		else
+		    goto invalid_value;
+		/* inserting into the output table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      spatialite_e ("INSERT INTO \"node\" step error: \"%s\"",
+				    sqlite3_errmsg (net_out->db_handle));
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e ("SELECT FROM \"node\" step error: %s",
+			      sqlite3_errmsg (net_out->db_handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  invalid_value:
+    spatialite_e ("SELECT FROM \"node\": found an invalid value");
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+do_clone_link (const char *db_prefix, const char *in_network,
+	       struct gaia_network *net_out)
+{
+/* cloning LINK */
+    char *sql;
+    char *table;
+    char *xprefix;
+    char *xtable;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    int ret;
+
+/* preparing the input SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    table = sqlite3_mprintf ("%s_link", in_network);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT link_id, start_node, end_node, geometry FROM \"%s\".\"%s\"",
+	 xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net_out->db_handle, sql, strlen (sql), &stmt_in,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM \"link\" error: \"%s\"",
+			sqlite3_errmsg (net_out->db_handle));
+	  goto error;
+      }
+
+/* preparing the output SQL statement */
+    table = sqlite3_mprintf ("%s_link", net_out->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (link_id, start_node, end_node, "
+	 "geometry) VALUES (?, ?, ?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (net_out->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("INSERT INTO \"link\" error: \"%s\"",
+			sqlite3_errmsg (net_out->db_handle));
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 1,
+					sqlite3_column_int64 (stmt_in, 0));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 1) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 2,
+					sqlite3_column_int64 (stmt_in, 1));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 2) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 3,
+					sqlite3_column_int64 (stmt_in, 2));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 3) == SQLITE_NULL)
+		    sqlite3_bind_null (stmt_out, 4);
+		else if (sqlite3_column_type (stmt_in, 3) == SQLITE_BLOB)
+		    sqlite3_bind_blob (stmt_out, 4,
+				       sqlite3_column_blob (stmt_in, 3),
+				       sqlite3_column_bytes (stmt_in, 3),
+				       SQLITE_STATIC);
+		else
+		    goto invalid_value;
+		/* inserting into the output table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      spatialite_e ("INSERT INTO \"link\" step error: \"%s\"",
+				    sqlite3_errmsg (net_out->db_handle));
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e ("SELECT FROM \"link\" step error: %s",
+			      sqlite3_errmsg (net_out->db_handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  invalid_value:
+    spatialite_e ("SELECT FROM \"link\": found an invalid value");
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+do_clone_network (const char *db_prefix, const char *in_network,
+		  GaiaNetworkAccessorPtr accessor)
+{
+/* cloning a full Network */
+    struct gaia_network *net_out = (struct gaia_network *) accessor;
+
+/* cloning NODE */
+    if (!do_clone_netnode (db_prefix, in_network, net_out))
+	return 0;
+
+/* cloning LINK */
+    if (!do_clone_link (db_prefix, in_network, net_out))
+	return 0;
+
+    return 1;
+}
+
+static char *
+gaiaGetAttachedNetwork (sqlite3 * handle, const char *db_prefix,
+			const char *network_name, int *spatial, int *srid,
+			int *has_z, int *allow_coincident)
+{
+/* attempting to retrieve the Input Network for TopoNet_Clone */
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    int ok = 0;
+    char *xprefix;
+    char *xnetwork_name = NULL;
+    int xspatial;
+    int xsrid;
+    int xhas_z;
+    int xallow_coincident;
+
+/* preparing the SQL query */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT network_name, spatial, srid, has_z, allow_coincident "
+	 "FROM \"%s\".networks WHERE Lower(network_name) = Lower(%Q)", xprefix,
+	 network_name);
+    free (xprefix);
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM networks error: \"%s\"\n",
+			sqlite3_errmsg (handle));
+	  return NULL;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_name = 0;
+		int ok_srid = 0;
+		int ok_z = 0;
+		int ok_spatial = 0;
+		int ok_allow_coincident = 0;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
+		  {
+		      const char *str =
+			  (const char *) sqlite3_column_text (stmt, 0);
+		      if (xnetwork_name != NULL)
+			  free (xnetwork_name);
+		      xnetwork_name = malloc (strlen (str) + 1);
+		      strcpy (xnetwork_name, str);
+		      ok_name = 1;
+		  }
+		if (sqlite3_column_type (stmt, 1) == SQLITE_INTEGER)
+		  {
+		      xspatial = sqlite3_column_int (stmt, 1);
+		      ok_spatial = 1;
+		  }
+		if (sqlite3_column_type (stmt, 2) == SQLITE_INTEGER)
+		  {
+		      xsrid = sqlite3_column_int (stmt, 2);
+		      ok_srid = 1;
+		  }
+		if (sqlite3_column_type (stmt, 3) == SQLITE_INTEGER)
+		  {
+		      xhas_z = sqlite3_column_int (stmt, 3);
+		      ok_z = 1;
+		  }
+		if (sqlite3_column_type (stmt, 4) == SQLITE_INTEGER)
+		  {
+		      xallow_coincident = sqlite3_column_int (stmt, 4);
+		      ok_allow_coincident = 1;
+		  }
+		if (ok_name && ok_spatial && ok_srid && ok_z
+		    && ok_allow_coincident)
+		  {
+		      ok = 1;
+		      break;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e
+		    ("step: SELECT FROM networks error: \"%s\"\n",
+		     sqlite3_errmsg (handle));
+		sqlite3_finalize (stmt);
+		return NULL;
+	    }
+      }
+    sqlite3_finalize (stmt);
+
+    if (ok)
+      {
+	  *spatial = xspatial;
+	  *srid = xsrid;
+	  *has_z = xhas_z;
+	  *allow_coincident = xallow_coincident;
+	  return xnetwork_name;
+      }
+
+    if (xnetwork_name != NULL)
+	free (xnetwork_name);
+    return NULL;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoNet_Clone (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoNet_Clone ( text db-prefix, text in-network-name, text out-network-name )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *db_prefix = "MAIN";
+    const char *in_network_name;
+    const char *out_network_name;
+    char *input_network_name = NULL;
+    int spatial;
+    int srid;
+    int has_z;
+    int allow_coincident;
+    GaiaNetworkAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	in_network_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	out_network_name = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+
+/* checking the origin Network */
+    input_network_name =
+	gaiaGetAttachedNetwork (sqlite, db_prefix, in_network_name, &spatial,
+				&srid, &has_z, &allow_coincident);
+    if (input_network_name == NULL)
+	goto no_net;
+
+/* attempting to create the destination Network */
+    start_net_savepoint (sqlite, cache);
+    ret =
+	gaiaNetworkCreate (sqlite, out_network_name, spatial, srid,
+			   has_z, allow_coincident);
+    if (!ret)
+      {
+	  rollback_net_savepoint (sqlite, cache);
+	  goto no_net2;
+      }
+
+/* attempting to get a Network Accessor (destination) */
+    accessor = gaiaGetNetwork (sqlite, cache, out_network_name);
+    if (accessor == NULL)
+      {
+	  rollback_net_savepoint (sqlite, cache);
+	  goto no_net2;
+      }
+
+/* cloning Network */
+    ret = do_clone_network (db_prefix, input_network_name, accessor);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  sqlite3_result_error (context, "Clone Network failure", -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    free (input_network_name);
+    return;
+
+  no_net:
+    if (input_network_name != NULL)
+	free (input_network_name);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name (origin).",
+			  -1);
+    return;
+
+  no_net2:
+    if (input_network_name != NULL)
+	free (input_network_name);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name (destination).",
+			  -1);
+    return;
+
+  null_arg:
+    if (input_network_name != NULL)
+	free (input_network_name);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (input_network_name != NULL)
+	free (input_network_name);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoNet_GetLinkSeed (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoNet_GetLinkSeed ( text network-name, int link_id )
+/
+/ returns: a Point (seed) identifying the Link
+/ raises an exception on failure
+*/
+    const char *network_name;
+    sqlite3_int64 link_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr geom;
+    GaiaNetworkAccessorPtr accessor;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    struct gaia_network *net;
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	gpkg_mode = cache->gpkg_mode;
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	link_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+    gaianet_reset_last_error_msg (accessor);
+    geom = gaiaGetLinkSeed (accessor, link_id);
+    if (geom == NULL)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  if (msg != NULL)
+	    {
+		gaianet_set_last_error_msg (accessor, msg);
+		sqlite3_result_error (context, msg, -1);
+		return;
+	    }
+	  sqlite3_result_null (context);
+	  return;
+      }
+    gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+    gaiaFreeGeomColl (geom);
+    if (p_blob == NULL)
+	sqlite3_result_null (context);
+    else
+	sqlite3_result_blob (context, p_blob, n_bytes, free);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  logical_err:
+    sqlite3_result_error (context,
+			  "TopoNet_GetLinkSeed() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoNet_UpdateSeeds (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoNet_UpdateSeeds ( text network-name )
+/ TopoNet_UpdateSeeds ( text network-name, int incremental_mode )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    const char *network_name;
+    int incremental_mode = 1;
+    int ret;
+    GaiaNetworkAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    struct gaia_network *net;
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	network_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (argc >= 2)
+      {
+	  if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	      incremental_mode = sqlite3_value_int (argv[1]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Network Accessor */
+    accessor = gaiaGetNetwork (sqlite, cache, network_name);
+    if (accessor == NULL)
+	goto no_net;
+    net = (struct gaia_network *) accessor;
+    if (net->spatial == 0)
+	goto logical_err;
+
+    gaianet_reset_last_error_msg (accessor);
+    start_net_savepoint (sqlite, cache);
+    ret = gaiaTopoNetUpdateSeeds (accessor, incremental_mode);
+    if (!ret)
+	rollback_net_savepoint (sqlite, cache);
+    else
+	release_net_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = lwn_GetErrorMsg (net->lwn_iface);
+	  if (msg != NULL)
+	    {
+		gaianet_set_last_error_msg (accessor, msg);
+		sqlite3_result_error (context, msg, -1);
+		return;
+	    }
+	  sqlite3_result_null (context);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_net:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid network name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  logical_err:
+    sqlite3_result_error (context,
+			  "TopoNet_UpdateSeeds() cannot be applied to Logical Network.",
+			  -1);
+    return;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/gaia_topology.c b/src/topology/gaia_topology.c
new file mode 100644
index 0000000..7174db4
--- /dev/null
+++ b/src/topology/gaia_topology.c
@@ -0,0 +1,5479 @@
+/*
+
+ gaia_topology.c -- implementation of Topology SQL functions
+    
+ version 4.3, 2015 July 15
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/*
+ 
+CREDITS:
+
+this module has been completely funded by:
+Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
+(Topology support) 
+
+CIG: 6038019AE5
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaia_topology.h>
+#include <spatialite/gaiaaux.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+
+#include <liblwgeom.h>
+#include <liblwgeom_topo.h>
+
+#include "topology_private.h"
+
+#define GAIA_UNUSED() if (argc || argv) argc = argc;
+
+
+SPATIALITE_PRIVATE void
+start_topo_savepoint (const void *handle, const void *data)
+{
+/* starting a new SAVEPOINT */
+    char *sql;
+    int ret;
+    char *err_msg;
+    sqlite3 *sqlite = (sqlite3 *) handle;
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) data;
+    if (sqlite == NULL || cache == NULL)
+	return;
+
+/* creating an unique SavePoint name */
+    if (cache->topo_savepoint_name != NULL)
+	sqlite3_free (cache->topo_savepoint_name);
+    cache->topo_savepoint_name = NULL;
+    cache->topo_savepoint_name =
+	sqlite3_mprintf ("toposvpt%04x", cache->next_topo_savepoint);
+    if (cache->next_topo_savepoint >= 0xffffffffu)
+	cache->next_topo_savepoint = 0;
+    else
+	cache->next_topo_savepoint += 1;
+
+/* starting a SavePoint */
+    sql = sqlite3_mprintf ("SAVEPOINT %s", cache->topo_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+}
+
+SPATIALITE_PRIVATE void
+release_topo_savepoint (const void *handle, const void *data)
+{
+/* releasing the current SAVEPOINT (if any) */
+    char *sql;
+    int ret;
+    char *err_msg;
+    sqlite3 *sqlite = (sqlite3 *) handle;
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) data;
+    if (sqlite == NULL || cache == NULL)
+	return;
+    if (cache->topo_savepoint_name == NULL)
+	return;
+
+/* releasing the current SavePoint */
+    sql = sqlite3_mprintf ("RELEASE SAVEPOINT %s", cache->topo_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+    sqlite3_free (cache->topo_savepoint_name);
+    cache->topo_savepoint_name = NULL;
+}
+
+SPATIALITE_PRIVATE void
+rollback_topo_savepoint (const void *handle, const void *data)
+{
+/* rolling back the current SAVEPOINT (if any) */
+    char *sql;
+    int ret;
+    char *err_msg;
+    sqlite3 *sqlite = (sqlite3 *) handle;
+    struct splite_internal_cache *cache = (struct splite_internal_cache *) data;
+    if (sqlite == NULL || cache == NULL)
+	return;
+    if (cache->topo_savepoint_name == NULL)
+	return;
+
+/* rolling back the current SavePoint */
+    sql =
+	sqlite3_mprintf ("ROLLBACK TO SAVEPOINT %s",
+			 cache->topo_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+/* releasing the current SavePoint */
+    sql = sqlite3_mprintf ("RELEASE SAVEPOINT %s", cache->topo_savepoint_name);
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("%s - error: %s\n", sql, err_msg);
+	  sqlite3_free (err_msg);
+      }
+    sqlite3_free (sql);
+    sqlite3_free (cache->topo_savepoint_name);
+    cache->topo_savepoint_name = NULL;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetLastTopologyException (const void *xcontext, int argc,
+				  const void *xargv)
+{
+/* SQL function:
+/ GetLastTopologyException  ( text topology-name )
+/
+/ returns: the more recent exception raised by given Topology
+/ NULL on invalid args (or when there is no pending exception)
+*/
+    const char *topo_name;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+      {
+	  sqlite3_result_null (context);
+	  return;
+      }
+
+    sqlite3_result_text (context, gaiatopo_get_last_exception (accessor), -1,
+			 SQLITE_STATIC);
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_CreateTopology (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_InitTopoGeo ( text topology-name )
+/ CreateTopology ( text topology-name )
+/ CreateTopology ( text topology-name, int srid )
+/ CreateTopology ( text topology-name, int srid, double tolerance )
+/ CreateTopology ( text topology-name, int srid, double tolerance, 
+/                  bool hasZ )
+/
+/ returns: 1 on success, 0 on failure
+/ -1 on invalid args
+*/
+    int ret;
+    const char *topo_name;
+    int srid = -1;
+    double tolerance = 0.0;
+    int has_z = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+    if (argc >= 2)
+      {
+	  if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	      srid = sqlite3_value_int (argv[1]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+    if (argc >= 3)
+      {
+	  if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	      tolerance = sqlite3_value_double (argv[2]);
+	  else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	    {
+		int tol = sqlite3_value_int (argv[2]);
+		tolerance = tol;
+	    }
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+    if (argc >= 4)
+      {
+	  if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	      ;
+	  else if (sqlite3_value_type (argv[3]) == SQLITE_INTEGER)
+	      has_z = sqlite3_value_int (argv[3]);
+	  else
+	    {
+		sqlite3_result_int (context, -1);
+		return;
+	    }
+      }
+
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaTopologyCreate (sqlite, topo_name, srid, tolerance, has_z);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    sqlite3_result_int (context, ret);
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_DropTopology (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ DropTopology ( text topology-name )
+/
+/ returns: 1 on success, 0 on failure
+/ -1 on invalid args
+*/
+    int ret;
+    const char *topo_name;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GaiaTopologyAccessorPtr accessor;
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+      {
+	  sqlite3_result_int (context, -1);
+	  return;
+      }
+
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor != NULL)
+	gaiaTopologyDestroy (accessor);
+
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaTopologyDrop (sqlite, topo_name);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    sqlite3_result_int (context, ret);
+}
+
+static int
+check_matching_srid_dims (GaiaTopologyAccessorPtr accessor, int srid, int dims)
+{
+/* checking for matching SRID and DIMs */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo->srid != srid)
+	return 0;
+    if (topo->has_z)
+      {
+	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
+	      ;
+	  else
+	      return 0;
+      }
+    else
+      {
+	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
+	      return 0;
+      }
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_AddIsoNode (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_AddIsoNode ( text topology-name, int face_id, Geometry point )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 face_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	face_id = -1;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+      {
+	  face_id = sqlite3_value_int64 (argv[1]);
+	  if (face_id <= 0)
+	      face_id = -1;
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+    pt = point->FirstPoint;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaAddIsoNode (accessor, face_id, pt, 0);
+    if (ret <= 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_MoveIsoNode (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_MoveIsoNode ( text topology-name, int node_id, Geometry point )
+/
+/ returns: TEXT (description of new location)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *topo_name;
+    sqlite3_int64 node_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+    pt = point->FirstPoint;
+    sprintf (xid, "%lld", node_id);
+    newpos =
+	sqlite3_mprintf ("Isolated Node %s moved to location %f,%f", xid, pt->X,
+			 pt->Y);
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaMoveIsoNode (accessor, node_id, pt);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_topo:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_RemIsoNode (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_RemIsoNode ( text topology-name, int node_id )
+/
+/ returns: TEXT (description of operation)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *topo_name;
+    sqlite3_int64 node_id;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    sprintf (xid, "%lld", node_id);
+    newpos = sqlite3_mprintf ("Isolated Node %s removed", xid);
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaRemIsoNode (accessor, node_id);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_topo:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_AddIsoEdge (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_AddIsoEdge ( text topology-name, int start_node_id, int end_node_id, Geometry linestring )
+/
+/ returns: the ID of the inserted Edge on success, 0 on failure
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    sqlite3_int64 start_node_id;
+    sqlite3_int64 end_node_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr line = NULL;
+    gaiaLinestringPtr ln;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	start_node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	end_node_id = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[3]);
+	  n_bytes = sqlite3_value_bytes (argv[3]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Linestring Geometry */
+    line =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!line)
+	goto invalid_arg;
+    if (line->FirstPoint != NULL)
+	invalid = 1;
+    if (line->FirstPolygon != NULL)
+	invalid = 1;
+    if (line->FirstLinestring != line->LastLinestring
+	|| line->FirstLinestring == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims (accessor, line->Srid, line->DimensionModel))
+	goto invalid_geom;
+    ln = line->FirstLinestring;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaAddIsoEdge (accessor, start_node_id, end_node_id, ln);
+    if (ret <= 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (line);
+    line = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, ret);
+    return;
+
+  no_topo:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_RemIsoEdge (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_RemIsoEdge ( text topology-name, int edfe_id )
+/
+/ returns: TEXT (description of operation)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    sprintf (xid, "%lld", edge_id);
+    newpos = sqlite3_mprintf ("Isolated Edge %s removed", xid);
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaRemIsoEdge (accessor, edge_id);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_topo:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_RemEdgeModFace (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_RemEdgeModFace ( text topology-name, int edge_id )
+/
+/ returns: ID of the Face that takes up the space previously occupied by the removed edge
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaRemEdgeModFace (accessor, edge_id);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_RemEdgeNewFace (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_RemEdgeNewFace ( text topology-name, int edge_id )
+/
+/ returns: ID of the created Face 
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaRemEdgeNewFace (accessor, edge_id);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ChangeEdgeGeom (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ChangeEdgeGeom ( text topology-name, int edge_id, Geometry linestring )
+/
+/ returns: TEXT (description of operation)
+/ raises an exception on failure
+*/
+    char xid[80];
+    char *newpos = NULL;
+    int ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr line = NULL;
+    gaiaLinestringPtr ln;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Linestring Geometry */
+    line =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!line)
+	goto invalid_arg;
+    if (line->FirstPoint != NULL)
+	invalid = 1;
+    if (line->FirstPolygon != NULL)
+	invalid = 1;
+    if (line->FirstLinestring != line->LastLinestring
+	|| line->FirstLinestring == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims (accessor, line->Srid, line->DimensionModel))
+	goto invalid_geom;
+    ln = line->FirstLinestring;
+    sprintf (xid, "%lld", edge_id);
+    newpos = sqlite3_mprintf ("Edge %s changed", xid);
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaChangeEdgeGeom (accessor, edge_id, ln);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (line);
+    line = NULL;
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  if (newpos != NULL)
+	      sqlite3_free (newpos);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_text (context, newpos, strlen (newpos), sqlite3_free);
+    return;
+
+  no_topo:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (newpos != NULL)
+	sqlite3_free (newpos);
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ModEdgeSplit (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ModEdgeSplit ( text topology-name, int edge_id, Geometry point )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+    pt = point->FirstPoint;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaModEdgeSplit (accessor, edge_id, pt, 0);
+    if (ret <= 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, ret);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_NewEdgesSplit (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_NewEdgesSplit ( text topology-name, int edge_id, Geometry point )
+/
+/ returns: the ID of the inserted Node on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[2]);
+	  n_bytes = sqlite3_value_bytes (argv[2]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+      {
+	  goto invalid_arg;
+	  return;
+      }
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+    pt = point->FirstPoint;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaNewEdgesSplit (accessor, edge_id, pt, 0);
+    if (ret <= 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, ret);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_AddEdgeModFace (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_AddEdgeModFace ( text topology-name, int start_node_id, int end_node_id, Geometry linestring )
+/
+/ returns: the ID of the inserted Edge on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 start_node_id;
+    sqlite3_int64 end_node_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr line = NULL;
+    gaiaLinestringPtr ln;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	start_node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	end_node_id = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[3]);
+	  n_bytes = sqlite3_value_bytes (argv[3]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Linestring Geometry */
+    line =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!line)
+	goto invalid_arg;
+    if (line->FirstPoint != NULL)
+	invalid = 1;
+    if (line->FirstPolygon != NULL)
+	invalid = 1;
+    if (line->FirstLinestring != line->LastLinestring
+	|| line->FirstLinestring == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims (accessor, line->Srid, line->DimensionModel))
+	goto invalid_geom;
+    ln = line->FirstLinestring;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaAddEdgeModFace (accessor, start_node_id, end_node_id, ln, 0);
+    if (ret <= 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (line);
+    line = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, ret);
+    return;
+
+  no_topo:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_AddEdgeNewFaces (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_AddEdgeNewFaces ( text topology-name, int start_node_id, int end_node_id, Geometry linestring )
+/
+/ returns: the ID of the inserted Edge on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 start_node_id;
+    sqlite3_int64 end_node_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr line = NULL;
+    gaiaLinestringPtr ln;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	start_node_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	end_node_id = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[3]);
+	  n_bytes = sqlite3_value_bytes (argv[3]);
+      }
+    else
+	goto invalid_arg;
+
+/* attempting to get a Linestring Geometry */
+    line =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!line)
+	goto invalid_arg;
+    if (line->FirstPoint != NULL)
+	invalid = 1;
+    if (line->FirstPolygon != NULL)
+	invalid = 1;
+    if (line->FirstLinestring != line->LastLinestring
+	|| line->FirstLinestring == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims (accessor, line->Srid, line->DimensionModel))
+	goto invalid_geom;
+    ln = line->FirstLinestring;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaAddEdgeNewFaces (accessor, start_node_id, end_node_id, ln, 0);
+    if (ret <= 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (line);
+    line = NULL;
+    if (ret <= 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, ret);
+    return;
+
+  no_topo:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (line != NULL)
+	gaiaFreeGeomColl (line);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ModEdgeHeal (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ModEdgeHeal ( text topology-name, int edge_id1, int edge_id2 )
+/
+/ returns: ID of the removed Node
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id1;
+    sqlite3_int64 edge_id2;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id1 = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	edge_id2 = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaModEdgeHeal (accessor, edge_id1, edge_id2);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_NewEdgeHeal (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_NewEdgeHeal ( text topology-name, int edge_id1, int edge_id2 )
+/
+/ returns: ID of the removed Node
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    sqlite3_int64 edge_id1;
+    sqlite3_int64 edge_id2;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id1 = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+	edge_id2 = sqlite3_value_int64 (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaNewEdgeHeal (accessor, edge_id1, edge_id2);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetFaceGeometry (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_GetFaceGeometry ( text topology-name, int face_id )
+/
+/ returns: the Face's geometry (Polygon)
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    sqlite3_int64 face_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr geom;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	gpkg_mode = cache->gpkg_mode;
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	face_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    geom = gaiaGetFaceGeometry (accessor, face_id);
+    if (geom == NULL)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  if (msg != NULL)
+	    {
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_result_error (context, msg, -1);
+		return;
+	    }
+	  sqlite3_result_null (context);
+	  return;
+      }
+    gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+    gaiaFreeGeomColl (geom);
+    if (p_blob == NULL)
+	sqlite3_result_null (context);
+    else
+	sqlite3_result_blob (context, p_blob, n_bytes, free);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetFaceEdges (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_GetFaceEdges ( text topology-name, int face_id )
+/
+/ create/update a table containing an ordered list of EdgeIDs
+/
+/ returns NULL on success
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    sqlite3_int64 face_id;
+    int ret;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	face_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaGetFaceEdges (accessor, face_id);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_null (context);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+static int
+check_empty_topology (struct gaia_topology *topo)
+{
+/* checking for an empty Topology */
+    char *sql;
+    char *table;
+    char *xtable;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int already_populated = 0;
+
+/* testing NODE */
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  if (atoi (results[(i * columns) + 0]) > 0)
+	      already_populated = 1;
+      }
+    sqlite3_free_table (results);
+    if (already_populated)
+	return 0;
+
+/* testing EDGE */
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\"", xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  if (atoi (results[(i * columns) + 0]) > 0)
+	      already_populated = 1;
+      }
+    sqlite3_free_table (results);
+    if (already_populated)
+	return 0;
+
+/* testing FACE */
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\" WHERE face_id <> 0",
+			 xtable);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  if (atoi (results[(i * columns) + 0]) > 0)
+	      already_populated = 1;
+      }
+    sqlite3_free_table (results);
+    if (already_populated)
+	return 0;
+
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_ValidateTopoGeo (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_ValidateTopoGeo ( text topology-name )
+/
+/ create/update a table containing an validation report for a given TopoGeo
+/
+/ returns NULL on success
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    int ret;
+    GaiaTopologyAccessorPtr accessor;
+    struct gaia_topology *topo;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    topo = (struct gaia_topology *) accessor;
+    if (check_empty_topology (topo))
+	goto empty;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaValidateTopoGeo (accessor);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_null (context);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  empty:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - empty topology.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_CreateTopoGeo (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ ST_CreateTopoGeo ( text topology-name , blob geom-collection )
+/
+/ creates and populates an empty Topology by importing a Geometry-collection
+/
+/ returns NULL on success
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    int ret;
+    const unsigned char *blob;
+    int blob_sz;
+    gaiaGeomCollPtr geom = NULL;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    GaiaTopologyAccessorPtr accessor;
+    struct gaia_topology *topo;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  blob = sqlite3_value_blob (argv[1]);
+	  blob_sz = sqlite3_value_bytes (argv[1]);
+	  geom =
+	      gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
+					   gpkg_amphibious);
+      }
+    else
+	goto invalid_arg;
+    if (geom == NULL)
+	goto not_geom;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    topo = (struct gaia_topology *) accessor;
+    if (!check_empty_topology (topo))
+	goto not_empty;
+    if (!check_matching_srid_dims (accessor, geom->Srid, geom->DimensionModel))
+	goto invalid_geom;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = auxtopo_insert_into_topology (accessor, geom, 0.0, -1, -1);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_null (context);
+    gaiaFreeGeomColl (geom);
+    return;
+
+  no_topo:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  not_empty:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - non-empty topology.", -1);
+    return;
+
+  not_geom:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - not a Geometry.", -1);
+    return;
+
+  invalid_geom:
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid Geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetNodeByPoint (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ GetNodeByPoint ( text topology-name, Geometry point, double tolerance )
+/
+/ returns: the ID of some Node on success, 0 if no Node was found
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    double tolerance;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    pt = point->FirstPoint;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaGetNodeByPoint (accessor, pt, tolerance);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetEdgeByPoint (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ GetEdgeByPoint ( text topology-name, Geometry point, double tolerance )
+/
+/ returns: the ID of some Edge on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    double tolerance;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    pt = point->FirstPoint;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaGetEdgeByPoint (accessor, pt, tolerance);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_GetFaceByPoint (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ GetFaceByPoint ( text topology-name, Geometry point, double tolerance )
+/
+/ returns: the ID of some Face on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 ret;
+    const char *topo_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    double tolerance;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint != point->LastPoint || point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    pt = point->FirstPoint;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaGetFaceByPoint (accessor, pt, tolerance);
+    if (ret < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (ret < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int64 (context, ret);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_AddPoint (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_AddPoint ( text topology-name, Geometry (multi)point, double tolerance )
+/
+/ returns: a comma separated list of all IDs of corresponding Nodes on success
+/ raises an exception on failure
+*/
+    sqlite3_int64 node_id;
+    char xnode_id[64];
+    char *retlist = NULL;
+    char *savelist;
+    const char *topo_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr point = NULL;
+    gaiaPointPtr pt;
+    double tolerance;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Point Geometry */
+    point =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!point)
+	goto invalid_arg;
+    if (point->FirstLinestring != NULL)
+	invalid = 1;
+    if (point->FirstPolygon != NULL)
+	invalid = 1;
+    if (point->FirstPoint == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims
+	(accessor, point->Srid, point->DimensionModel))
+	goto invalid_geom;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    pt = point->FirstPoint;
+    while (pt != NULL)
+      {
+	  /* looping on elementary Points */
+	  node_id = gaiaTopoGeo_AddPoint (accessor, pt, tolerance);
+	  if (node_id < 0)
+	      break;
+	  sprintf (xnode_id, "%lld", node_id);
+	  if (retlist == NULL)
+	      retlist = sqlite3_mprintf ("%s", xnode_id);
+	  else
+	    {
+		savelist = retlist;
+		retlist = sqlite3_mprintf ("%s, %s", savelist, xnode_id);
+		sqlite3_free (savelist);
+	    }
+	  pt = pt->Next;
+      }
+
+    if (node_id < 0)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (point);
+    point = NULL;
+    if (node_id < 0)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  if (retlist != NULL)
+	      sqlite3_free (retlist);
+	  return;
+      }
+    sqlite3_result_text (context, retlist, strlen (retlist), sqlite3_free);
+    return;
+
+  no_topo:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (point != NULL)
+	gaiaFreeGeomColl (point);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_AddLineString (const void *xcontext, int argc,
+			       const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_AddLineString ( text topology-name, Geometry (multi)linestring, double tolerance )
+/
+/ returns: a comma separated list of all IDs of corresponding Edges on success
+/ raises an exception on failure
+*/
+    int ret;
+    char xedge_id[64];
+    sqlite3_int64 *edge_ids = NULL;
+    int ids_count = 0;
+    char *retlist = NULL;
+    char *savelist;
+    int i;
+    const char *topo_name;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr linestring = NULL;
+    gaiaLinestringPtr ln;
+    double tolerance;
+    int invalid = 0;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[1]);
+	  n_bytes = sqlite3_value_bytes (argv[1]);
+      }
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[2]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[2]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Linestring Geometry */
+    linestring =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!linestring)
+	goto invalid_arg;
+    if (linestring->FirstPoint != NULL)
+	invalid = 1;
+    if (linestring->FirstPolygon != NULL)
+	invalid = 1;
+    if (linestring->FirstLinestring == NULL)
+	invalid = 1;
+    if (invalid)
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+    if (!check_matching_srid_dims
+	(accessor, linestring->Srid, linestring->DimensionModel))
+	goto invalid_geom;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ln = linestring->FirstLinestring;
+    while (ln != NULL)
+      {
+	  /* looping on individual Linestrings */
+	  ret =
+	      gaiaTopoGeo_AddLineString (accessor, ln, tolerance, &edge_ids,
+					 &ids_count);
+	  if (!ret)
+	      break;
+	  for (i = 0; i < ids_count; i++)
+	    {
+		sprintf (xedge_id, "%lld", edge_ids[i]);
+		if (retlist == NULL)
+		    retlist = sqlite3_mprintf ("%s", xedge_id);
+		else
+		  {
+		      savelist = retlist;
+		      retlist = sqlite3_mprintf ("%s, %s", savelist, xedge_id);
+		      sqlite3_free (savelist);
+		  }
+	    }
+	  free (edge_ids);
+	  ln = ln->Next;
+      }
+
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    gaiaFreeGeomColl (linestring);
+    linestring = NULL;
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  sqlite3_free (retlist);
+	  return;
+      }
+    sqlite3_result_text (context, retlist, strlen (retlist), sqlite3_free);
+    return;
+
+  no_topo:
+    if (linestring != NULL)
+	gaiaFreeGeomColl (linestring);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    if (linestring != NULL)
+	gaiaFreeGeomColl (linestring);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (linestring != NULL)
+	gaiaFreeGeomColl (linestring);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (linestring != NULL)
+	gaiaFreeGeomColl (linestring);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_SubdivideLines (const void *xcontext, int argc,
+				const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_SubdivideLines ( Geometry geom, int line_max_points,
+/                          double max_length )
+/
+/ returns: a MultiLinestring or NULL on failure
+*/
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr geom;
+    gaiaGeomCollPtr result;
+    int line_max_points = -1;
+    double max_length = -1.0;
+    int gpkg_amphibious = 0;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+      {
+	  gpkg_amphibious = cache->gpkg_amphibious_mode;
+	  gpkg_mode = cache->gpkg_mode;
+      }
+    if (sqlite3_value_type (argv[0]) == SQLITE_BLOB)
+      {
+	  p_blob = (unsigned char *) sqlite3_value_blob (argv[0]);
+	  n_bytes = sqlite3_value_bytes (argv[0]);
+      }
+    else
+	goto err;
+    if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	line_max_points = sqlite3_value_int (argv[1]);
+    else
+	goto err;
+    if (sqlite3_value_type (argv[2]) == SQLITE_INTEGER)
+      {
+	  int max = sqlite3_value_int (argv[2]);
+	  max_length = max;
+      }
+    else if (sqlite3_value_type (argv[2]) == SQLITE_FLOAT)
+	max_length = sqlite3_value_int (argv[2]);
+    else
+	goto err;
+
+    if (line_max_points < 2)
+	line_max_points = -1;
+
+/* attempting to get a Geometry */
+    geom =
+	gaiaFromSpatiaLiteBlobWkbEx (p_blob, n_bytes, gpkg_mode,
+				     gpkg_amphibious);
+    if (!geom)
+	goto err;
+
+/* splitting the geometry */
+    result = gaiaTopoGeo_SubdivideLines (geom, line_max_points, max_length);
+    gaiaFreeGeomColl (geom);
+    if (result == NULL)
+	goto err;
+    gaiaToSpatiaLiteBlobWkbEx (result, &p_blob, &n_bytes, gpkg_mode);
+    gaiaFreeGeomColl (result);
+    if (p_blob == NULL)
+	sqlite3_result_null (context);
+    else
+	sqlite3_result_blob (context, p_blob, n_bytes, free);
+    return;
+
+  err:
+    sqlite3_result_null (context);
+    return;
+}
+
+static int
+check_input_geo_table (sqlite3 * sqlite, const char *db_prefix,
+		       const char *table, const char *column, char **xtable,
+		       char **xcolumn, int *srid, int *dims)
+{
+/* checking if an input GeoTable do really exist */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    char *xprefix;
+    int len;
+    int count = 0;
+    char *xx_table = NULL;
+    char *xx_column = NULL;
+    char *ztable;
+    int xtype;
+    int xdims;
+    int xsrid;
+
+    *xtable = NULL;
+    *xcolumn = NULL;
+    *srid = -1;
+    *dims = GAIA_XY;
+
+/* querying GEOMETRY_COLUMNS */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    if (column == NULL)
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT f_table_name, f_geometry_column, geometry_type, srid "
+	     "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q)",
+	     xprefix, table);
+    else
+	sql =
+	    sqlite3_mprintf
+	    ("SELECT f_table_name, f_geometry_column, geometry_type, srid "
+	     "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) AND "
+	     "Lower(f_geometry_column) = Lower(%Q)", xprefix, table, column);
+    free (xprefix);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *table_name = results[(i * columns) + 0];
+	  const char *column_name = results[(i * columns) + 1];
+	  xtype = atoi (results[(i * columns) + 2]);
+	  xsrid = atoi (results[(i * columns) + 3]);
+	  len = strlen (table_name);
+	  if (xx_table != NULL)
+	      free (xx_table);
+	  xx_table = malloc (len + 1);
+	  strcpy (xx_table, table_name);
+	  len = strlen (column_name);
+	  if (xx_column != NULL)
+	      free (xx_column);
+	  xx_column = malloc (len + 1);
+	  strcpy (xx_column, column_name);
+	  count++;
+      }
+    sqlite3_free_table (results);
+
+    if (count != 1)
+      {
+	  if (xx_table != NULL)
+	      free (xx_table);
+	  if (xx_column != NULL)
+	      free (xx_column);
+	  return 0;
+      }
+
+/* testing if the GeoTable do really exist */
+    count = 0;
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    ztable = gaiaDoubleQuotedSql (xx_table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, ztable);
+    free (xprefix);
+    free (ztable);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  const char *column_name = results[(i * columns) + 1];
+	  if (strcasecmp (column_name, xx_column) == 0)
+	      count++;
+      }
+    sqlite3_free_table (results);
+
+    if (count != 1)
+      {
+	  if (xx_table != NULL)
+	      free (xx_table);
+	  if (xx_column != NULL)
+	      free (xx_column);
+	  return 0;
+      }
+
+    switch (xtype)
+      {
+      case 0:
+      case 1:
+      case 2:
+      case 3:
+      case 4:
+      case 5:
+      case 6:
+      case 7:
+	  xdims = GAIA_XY;
+	  break;
+      case 1000:
+      case 1001:
+      case 1002:
+      case 1003:
+      case 1004:
+      case 1005:
+      case 1006:
+      case 1007:
+	  xdims = GAIA_XY_Z;
+	  break;
+      case 2000:
+      case 2001:
+      case 2002:
+      case 2003:
+      case 2004:
+      case 2005:
+      case 2006:
+      case 2007:
+	  xdims = GAIA_XY_M;
+	  break;
+      case 3000:
+      case 3001:
+      case 3002:
+      case 3003:
+      case 3004:
+      case 3005:
+      case 3006:
+      case 3007:
+	  xdims = GAIA_XY_Z_M;
+	  break;
+      };
+    *xtable = xx_table;
+    *xcolumn = xx_column;
+    *srid = xsrid;
+    *dims = xdims;
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_FromGeoTable (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_FromGeoTable ( text topology-name, text db-prefix, text table,
+/                        text column, double tolerance )
+/ TopoGeo_FromGeoTable ( text topology-name, text db-prefix, text table,
+/                        text column, double tolerance, int line_max_points,
+/                        double max_length )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *db_prefix;
+    const char *table;
+    const char *column;
+    char *xtable = NULL;
+    char *xcolumn = NULL;
+    int srid;
+    int dims;
+    double tolerance;
+    int line_max_points = -1;
+    double max_length = -1.0;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[4]) == SQLITE_INTEGER)
+      {
+	  int t = sqlite3_value_int (argv[4]);
+	  tolerance = t;
+      }
+    else if (sqlite3_value_type (argv[4]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_int (argv[4]);
+    else
+	goto invalid_arg;
+    if (argc >= 6)
+      {
+	  if (sqlite3_value_type (argv[5]) == SQLITE_INTEGER)
+	      line_max_points = sqlite3_value_int (argv[5]);
+	  else
+	      goto invalid_arg;
+      }
+    if (argc >= 7)
+      {
+	  if (sqlite3_value_type (argv[6]) == SQLITE_INTEGER)
+	    {
+		int max = sqlite3_value_int (argv[6]);
+		max_length = max;
+	    }
+	  else if (sqlite3_value_type (argv[6]) == SQLITE_FLOAT)
+	      max_length = sqlite3_value_double (argv[6]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the input GeoTable */
+    if (!check_input_geo_table
+	(sqlite, db_prefix, table, column, &xtable, &xcolumn, &srid, &dims))
+	goto no_input;
+    if (!check_matching_srid_dims (accessor, srid, dims))
+	goto invalid_geom;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_FromGeoTable (accessor, db_prefix, xtable, xcolumn,
+				  tolerance, line_max_points, max_length);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    free (xtable);
+    free (xcolumn);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  no_input:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid input GeoTable.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xtable != NULL)
+	free (xtable);
+    if (xcolumn != NULL)
+	free (xcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID or dimensions).",
+			  -1);
+    return;
+}
+
+static int
+check_matching_srid (GaiaTopologyAccessorPtr accessor, int srid)
+{
+/* checking for matching SRID */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo->srid != srid)
+	return 0;
+    return 1;
+}
+
+static int
+check_reference_geo_table (sqlite3 * sqlite, const char *db_prefix,
+			   const char *table, const char *column, char **xtable,
+			   char **xcolumn, int *srid)
+{
+    int dims;
+    return check_input_geo_table (sqlite, db_prefix, table, column, xtable,
+				  xcolumn, srid, &dims);
+}
+
+static int
+check_reference_table (sqlite3 * sqlite, const char *db_prefix,
+		       const char *table)
+{
+/* checking if an input GeoTable do really exist */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    char *xprefix;
+    int count = 0;
+    char *xtable;
+
+/* testing if the Table do really exist */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+
+    if (count < 1)
+	return 0;
+    return 1;
+}
+
+static int
+check_output_geo_table (sqlite3 * sqlite, const char *table)
+{
+/* checking if an output GeoTable do already exist */
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    char *sql;
+    int count = 0;
+    char *ztable;
+
+/* querying GEOMETRY_COLUMNS */
+    sql =
+	sqlite3_mprintf
+	("SELECT f_table_name, f_geometry_column "
+	 "FROM MAIN.geometry_columns WHERE Lower(f_table_name) = Lower(%Q)",
+	 table);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+
+    if (count != 0)
+	return 0;
+
+/* testing if the Table already exist */
+    count = 0;
+    ztable = gaiaDoubleQuotedSql (table);
+    sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", ztable);
+    free (ztable);
+    ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+	count++;
+    sqlite3_free_table (results);
+
+    if (count != 0)
+	return 0;
+    return 1;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_ToGeoTable (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_ToGeoTable ( text topology-name, text db-prefix, text ref_table,
+/                      text ref_column, text out_table )
+/ TopoGeo_ToGeoTable ( text topology-name, text db-prefix, text ref_table,
+/                      text ref_column, text out_table, int with-spatial-index )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *db_prefix;
+    const char *ref_table;
+    const char *ref_column;
+    const char *out_table;
+    int with_spatial_index = 0;
+    char *xreftable = NULL;
+    char *xrefcolumn = NULL;
+    int srid;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	ref_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	ref_column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	ref_column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[4]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[4]);
+    else
+	goto invalid_arg;
+    if (argc >= 6)
+      {
+	  if (sqlite3_value_type (argv[5]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[5]) == SQLITE_INTEGER)
+	      with_spatial_index = sqlite3_value_int (argv[5]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the reference GeoTable */
+    if (!check_reference_geo_table
+	(sqlite, db_prefix, ref_table, ref_column, &xreftable, &xrefcolumn,
+	 &srid))
+	goto no_reference;
+    if (!check_matching_srid (accessor, srid))
+	goto invalid_geom;
+
+/* checking the output GeoTable */
+    if (!check_output_geo_table (sqlite, out_table))
+	goto err_output;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_ToGeoTable (accessor, db_prefix, xreftable, xrefcolumn,
+				out_table, with_spatial_index);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    free (xreftable);
+    free (xrefcolumn);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  no_reference:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_ToGeoTable: invalid reference GeoTable.",
+			  -1);
+    return;
+
+  err_output:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_ToGeoTable: output GeoTable already exists.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_ToGeoTableGeneralize (const void *xcontext, int argc,
+				      const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_ToGeoTableGeneralize ( text topology-name, text db-prefix,
+/                                text ref_table, text ref_column,
+/                                text out_table, double tolerance )
+/ TopoGeo_ToGeoTableGeneralize ( text topology-name, text db-prefix,
+/                                text ref_table, text ref_column,
+/                                text out_table, double tolerance,
+/                                int with-spatial-index )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *db_prefix;
+    const char *ref_table;
+    const char *ref_column;
+    const char *out_table;
+    double tolerance = 0.0;
+    int with_spatial_index = 0;
+    char *xreftable = NULL;
+    char *xrefcolumn = NULL;
+    int srid;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	ref_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	ref_column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	ref_column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[4]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[4]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[5]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[5]) == SQLITE_INTEGER)
+      {
+	  int val = sqlite3_value_int (argv[5]);
+	  tolerance = val;
+      }
+    else if (sqlite3_value_type (argv[5]) == SQLITE_FLOAT)
+	tolerance = sqlite3_value_double (argv[5]);
+    else
+	goto invalid_arg;
+    if (argc >= 7)
+      {
+	  if (sqlite3_value_type (argv[6]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[6]) == SQLITE_INTEGER)
+	      with_spatial_index = sqlite3_value_int (argv[6]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the reference GeoTable */
+    if (!check_reference_geo_table
+	(sqlite, db_prefix, ref_table, ref_column, &xreftable, &xrefcolumn,
+	 &srid))
+	goto no_reference;
+    if (!check_matching_srid (accessor, srid))
+	goto invalid_geom;
+
+/* checking the output GeoTable */
+    if (!check_output_geo_table (sqlite, out_table))
+	goto err_output;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_ToGeoTableGeneralize (accessor, db_prefix, xreftable,
+					  xrefcolumn, out_table, tolerance,
+					  with_spatial_index);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    free (xreftable);
+    free (xrefcolumn);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  no_reference:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_ToGeoTableGeneralize: invalid reference GeoTable.",
+			  -1);
+    return;
+
+  err_output:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_ToGeoTableGeneralize: output GeoTable already exists.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID).",
+			  -1);
+    return;
+}
+
+static int
+do_clone_face (const char *db_prefix, const char *in_topology_name,
+	       struct gaia_topology *topo_out)
+{
+/* cloning FACE */
+    char *sql;
+    char *table;
+    char *xprefix;
+    char *xtable;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    int ret;
+
+/* preparing the input SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    table = sqlite3_mprintf ("%s_face", in_topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT face_id, mbr FROM \"%s\".\"%s\" WHERE face_id <> 0",
+	 xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo_out->db_handle, sql, strlen (sql), &stmt_in,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM \"face\" error: \"%s\"",
+			sqlite3_errmsg (topo_out->db_handle));
+	  goto error;
+      }
+
+/* preparing the output SQL statement */
+    table = sqlite3_mprintf ("%s_face", topo_out->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (face_id, mbr) VALUES (?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo_out->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("INSERT INTO \"face\" error: \"%s\"",
+			sqlite3_errmsg (topo_out->db_handle));
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 1,
+					sqlite3_column_int64 (stmt_in, 0));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 1) == SQLITE_NULL)
+		    sqlite3_bind_null (stmt_out, 2);
+		else if (sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
+		    sqlite3_bind_blob (stmt_out, 2,
+				       sqlite3_column_blob (stmt_in, 1),
+				       sqlite3_column_bytes (stmt_in, 1),
+				       SQLITE_STATIC);
+		else
+		    goto invalid_value;
+		/* inserting into the output table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      spatialite_e ("INSERT INTO \"face\" step error: \"%s\"",
+				    sqlite3_errmsg (topo_out->db_handle));
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e ("SELECT FROM \"face\" step error: %s",
+			      sqlite3_errmsg (topo_out->db_handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  invalid_value:
+    spatialite_e ("SELECT FROM \"face\": found an invalid value");
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+do_clone_node (const char *db_prefix, const char *in_topology_name,
+	       struct gaia_topology *topo_out)
+{
+/* cloning NODE */
+    char *sql;
+    char *table;
+    char *xprefix;
+    char *xtable;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    int ret;
+
+/* preparing the input SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    table = sqlite3_mprintf ("%s_node", in_topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT node_id, containing_face, geom FROM \"%s\".\"%s\"", xprefix,
+	 xtable);
+    free (xprefix);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo_out->db_handle, sql, strlen (sql), &stmt_in,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM \"node\" error: \"%s\"",
+			sqlite3_errmsg (topo_out->db_handle));
+	  goto error;
+      }
+
+/* preparing the output SQL statement */
+    table = sqlite3_mprintf ("%s_node", topo_out->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (node_id, containing_face, geom) "
+	 "VALUES (?, ?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo_out->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("INSERT INTO \"node\" error: \"%s\"",
+			sqlite3_errmsg (topo_out->db_handle));
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 1,
+					sqlite3_column_int64 (stmt_in, 0));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 1) == SQLITE_NULL)
+		    sqlite3_bind_null (stmt_out, 2);
+		else if (sqlite3_column_type (stmt_in, 1) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 2,
+					sqlite3_column_int64 (stmt_in, 1));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 2) == SQLITE_BLOB)
+		    sqlite3_bind_blob (stmt_out, 3,
+				       sqlite3_column_blob (stmt_in, 2),
+				       sqlite3_column_bytes (stmt_in, 2),
+				       SQLITE_STATIC);
+		else
+		    goto invalid_value;
+		/* inserting into the output table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      spatialite_e ("INSERT INTO \"node\" step error: \"%s\"",
+				    sqlite3_errmsg (topo_out->db_handle));
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e ("SELECT FROM \"node\" step error: %s",
+			      sqlite3_errmsg (topo_out->db_handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  invalid_value:
+    spatialite_e ("SELECT FROM \"node\": found an invalid value");
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+do_clone_edge (const char *db_prefix, const char *in_topology_name,
+	       struct gaia_topology *topo_out)
+{
+/* cloning EDGE */
+    char *sql;
+    char *table;
+    char *xprefix;
+    char *xtable;
+    sqlite3_stmt *stmt_in = NULL;
+    sqlite3_stmt *stmt_out = NULL;
+    int ret;
+
+/* preparing the input SQL statement */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    table = sqlite3_mprintf ("%s_edge", in_topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT edge_id, start_node, end_node, next_left_edge, "
+	 "next_right_edge, left_face, right_face, geom FROM \"%s\".\"%s\"",
+	 xprefix, xtable);
+    free (xprefix);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo_out->db_handle, sql, strlen (sql), &stmt_in,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM \"edge\" error: \"%s\"",
+			sqlite3_errmsg (topo_out->db_handle));
+	  goto error;
+      }
+
+/* preparing the output SQL statement */
+    table = sqlite3_mprintf ("%s_edge", topo_out->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (edge_id, start_node, end_node, "
+	 "next_left_edge, next_right_edge, left_face, right_face, geom) "
+	 "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", xtable);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (topo_out->db_handle, sql, strlen (sql), &stmt_out,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("INSERT INTO \"edge\" error: \"%s\"",
+			sqlite3_errmsg (topo_out->db_handle));
+	  goto error;
+      }
+
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_reset (stmt_out);
+		sqlite3_clear_bindings (stmt_out);
+		if (sqlite3_column_type (stmt_in, 0) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 1,
+					sqlite3_column_int64 (stmt_in, 0));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 1) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 2,
+					sqlite3_column_int64 (stmt_in, 1));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 2) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 3,
+					sqlite3_column_int64 (stmt_in, 2));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 3) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 4,
+					sqlite3_column_int64 (stmt_in, 3));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 4) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 5,
+					sqlite3_column_int64 (stmt_in, 4));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 5) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 6,
+					sqlite3_column_int64 (stmt_in, 5));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 6) == SQLITE_INTEGER)
+		    sqlite3_bind_int64 (stmt_out, 7,
+					sqlite3_column_int64 (stmt_in, 6));
+		else
+		    goto invalid_value;
+		if (sqlite3_column_type (stmt_in, 7) == SQLITE_BLOB)
+		    sqlite3_bind_blob (stmt_out, 8,
+				       sqlite3_column_blob (stmt_in, 7),
+				       sqlite3_column_bytes (stmt_in, 7),
+				       SQLITE_STATIC);
+		else
+		    goto invalid_value;
+		/* inserting into the output table */
+		ret = sqlite3_step (stmt_out);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      spatialite_e ("INSERT INTO \"edge\" step error: \"%s\"",
+				    sqlite3_errmsg (topo_out->db_handle));
+		      goto error;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e ("SELECT FROM \"edge\" step error: %s",
+			      sqlite3_errmsg (topo_out->db_handle));
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt_in);
+    sqlite3_finalize (stmt_out);
+    return 1;
+
+  invalid_value:
+    spatialite_e ("SELECT FROM \"edge\": found an invalid value");
+
+  error:
+    if (stmt_in != NULL)
+	sqlite3_finalize (stmt_in);
+    if (stmt_out != NULL)
+	sqlite3_finalize (stmt_out);
+    return 0;
+}
+
+static int
+do_clone_topology (const char *db_prefix, const char *in_topology,
+		   GaiaTopologyAccessorPtr accessor)
+{
+/* cloning a full Topology */
+    struct gaia_topology *topo_out = (struct gaia_topology *) accessor;
+
+/* cloning FACE */
+    if (!do_clone_face (db_prefix, in_topology, topo_out))
+	return 0;
+
+/* cloning NODE */
+    if (!do_clone_node (db_prefix, in_topology, topo_out))
+	return 0;
+
+/* cloning EDGE */
+    if (!do_clone_edge (db_prefix, in_topology, topo_out))
+	return 0;
+
+    return 1;
+}
+
+static char *
+gaiaGetAttachedTopology (sqlite3 * handle, const char *db_prefix,
+			 const char *topo_name, int *srid, double *tolerance,
+			 int *has_z)
+{
+/* attempting to retrieve the Input Topology for TopoGeo_Clone */
+    char *sql;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    int ok = 0;
+    char *xprefix;
+    char *xtopology_name = NULL;
+    int xsrid;
+    double xtolerance;
+    int xhas_z;
+
+/* preparing the SQL query */
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    sql =
+	sqlite3_mprintf
+	("SELECT topology_name, srid, tolerance, has_z FROM \"%s\".topologies WHERE "
+	 "Lower(topology_name) = Lower(%Q)", xprefix, topo_name);
+    free (xprefix);
+    ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  spatialite_e ("SELECT FROM topologys error: \"%s\"\n",
+			sqlite3_errmsg (handle));
+	  return NULL;
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_name = 0;
+		int ok_srid = 0;
+		int ok_tolerance = 0;
+		int ok_z = 0;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
+		  {
+		      const char *str =
+			  (const char *) sqlite3_column_text (stmt, 0);
+		      if (xtopology_name != NULL)
+			  free (xtopology_name);
+		      xtopology_name = malloc (strlen (str) + 1);
+		      strcpy (xtopology_name, str);
+		      ok_name = 1;
+		  }
+		if (sqlite3_column_type (stmt, 1) == SQLITE_INTEGER)
+		  {
+		      xsrid = sqlite3_column_int (stmt, 1);
+		      ok_srid = 1;
+		  }
+		if (sqlite3_column_type (stmt, 2) == SQLITE_FLOAT)
+		  {
+		      xtolerance = sqlite3_column_double (stmt, 2);
+		      ok_tolerance = 1;
+		  }
+		if (sqlite3_column_type (stmt, 3) == SQLITE_INTEGER)
+		  {
+		      xhas_z = sqlite3_column_int (stmt, 3);
+		      ok_z = 1;
+		  }
+		if (ok_name && ok_srid && ok_tolerance && ok_z)
+		  {
+		      ok = 1;
+		      break;
+		  }
+	    }
+	  else
+	    {
+		spatialite_e
+		    ("step: SELECT FROM topologies error: \"%s\"\n",
+		     sqlite3_errmsg (handle));
+		sqlite3_finalize (stmt);
+		return NULL;
+	    }
+      }
+    sqlite3_finalize (stmt);
+
+    if (ok)
+      {
+	  *srid = xsrid;
+	  *tolerance = xtolerance;
+	  *has_z = xhas_z;
+	  return xtopology_name;
+      }
+
+    if (xtopology_name != NULL)
+	free (xtopology_name);
+    return NULL;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_Clone (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_Clone ( text db-prefix, text in-topology-name, text out-topology-name )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *db_prefix = "MAIN";
+    const char *in_topo_name;
+    const char *out_topo_name;
+    char *input_topo_name = NULL;
+    int srid;
+    double tolerance;
+    int has_z;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	in_topo_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	out_topo_name = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+
+/* checking the origin Topology */
+    input_topo_name =
+	gaiaGetAttachedTopology (sqlite, db_prefix, in_topo_name, &srid,
+				 &tolerance, &has_z);
+    if (input_topo_name == NULL)
+	goto no_topo;
+
+/* attempting to create the destination Topology */
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaTopologyCreate (sqlite, out_topo_name, srid, tolerance, has_z);
+    if (!ret)
+      {
+	  rollback_topo_savepoint (sqlite, cache);
+	  goto no_topo2;
+      }
+
+/* attempting to get a Topology Accessor (destination) */
+    accessor = gaiaGetTopology (sqlite, cache, out_topo_name);
+    if (accessor == NULL)
+	goto no_topo2;
+
+/* cloning Topology */
+    ret = do_clone_topology (db_prefix, input_topo_name, accessor);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  sqlite3_result_error (context, "Clone Topology failure", -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    if (input_topo_name != NULL)
+	free (input_topo_name);
+    return;
+
+  no_topo:
+    if (input_topo_name != NULL)
+	free (input_topo_name);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name (origin).",
+			  -1);
+    return;
+
+  no_topo2:
+    if (input_topo_name != NULL)
+	free (input_topo_name);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name (destination).",
+			  -1);
+    return;
+
+  null_arg:
+    if (input_topo_name != NULL)
+	free (input_topo_name);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (input_topo_name != NULL)
+	free (input_topo_name);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_GetEdgeSeed (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_GetEdgeSeed ( text topology-name, int edge_id )
+/
+/ returns: a Point (seed) identifying the Edge
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    sqlite3_int64 edge_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr geom;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	gpkg_mode = cache->gpkg_mode;
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	edge_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    geom = gaiaGetEdgeSeed (accessor, edge_id);
+    if (geom == NULL)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  if (msg != NULL)
+	    {
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_result_error (context, msg, -1);
+		return;
+	    }
+	  sqlite3_result_null (context);
+	  return;
+      }
+    gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+    gaiaFreeGeomColl (geom);
+    if (p_blob == NULL)
+	sqlite3_result_null (context);
+    else
+	sqlite3_result_blob (context, p_blob, n_bytes, free);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_GetFaceSeed (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_GetFaceSeed ( text topology-name, int face_id )
+/
+/ returns: a Point (seed) identifying the Edge
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    sqlite3_int64 face_id;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr geom;
+    GaiaTopologyAccessorPtr accessor;
+    int gpkg_mode = 0;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (cache != NULL)
+	gpkg_mode = cache->gpkg_mode;
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	face_id = sqlite3_value_int64 (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    geom = gaiaGetFaceSeed (accessor, face_id);
+    if (geom == NULL)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  if (msg != NULL)
+	    {
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_result_error (context, msg, -1);
+		return;
+	    }
+	  sqlite3_result_null (context);
+	  return;
+      }
+    gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+    gaiaFreeGeomColl (geom);
+    if (p_blob == NULL)
+	sqlite3_result_null (context);
+    else
+	sqlite3_result_blob (context, p_blob, n_bytes, free);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_UpdateSeeds (const void *xcontext, int argc, const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_UpdateSeeds ( text topology-name )
+/ TopoGeo_UpdateSeeds ( text topology-name, int incremental_mode )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    const char *topo_name;
+    int incremental_mode = 1;
+    int ret;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (argc >= 2)
+      {
+	  if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[1]) == SQLITE_INTEGER)
+	      incremental_mode = sqlite3_value_int (argv[1]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaTopoGeoUpdateSeeds (accessor, incremental_mode);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  if (msg != NULL)
+	    {
+		gaiatopo_set_last_error_msg (accessor, msg);
+		sqlite3_result_error (context, msg, -1);
+		return;
+	    }
+	  sqlite3_result_null (context);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+static int
+topolayer_exists (GaiaTopologyAccessorPtr accessor, const char *topolayer_name)
+{
+/* checking if a TopoLayer is already defined */
+    char *table;
+    char *xtable;
+    char *sql;
+    int ret;
+    int i;
+    char **results;
+    int rows;
+    int columns;
+    char *errMsg = NULL;
+    int count = 0;
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    if (topo == NULL)
+	return 0;
+
+    table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT Count(*) FROM MAIN.\"%s\" WHERE topolayer_name = Lower(%Q)",
+	 xtable, topolayer_name);
+    free (xtable);
+    ret =
+	sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
+			   &errMsg);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  sqlite3_free (errMsg);
+	  return 0;
+      }
+    for (i = 1; i <= rows; i++)
+      {
+	  count = atoi (results[(i * columns) + 0]);
+      }
+    sqlite3_free_table (results);
+
+    if (count == 0)
+	return 0;
+    return 1;
+}
+
+static int
+check_view (struct gaia_topology *topo, const char *db_prefix,
+	    const char *table, const char *column)
+{
+/* checking a candidate View (or unregistered Table) for valid Geoms */
+    char *sql;
+    char *xcolumn;
+    char *xprefix;
+    char *xtable;
+    int ret;
+    sqlite3_stmt *stmt = NULL;
+    int nulls = 0;
+    int others = 0;
+    int geoms = 0;
+    int wrong_srids = 0;
+
+    xcolumn = gaiaDoubleQuotedSql (column);
+    xprefix = gaiaDoubleQuotedSql (db_prefix);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\"", xcolumn, xprefix,
+			 xtable);
+    free (xcolumn);
+    free (xprefix);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		gaiaGeomCollPtr geom = NULL;
+		const unsigned char *blob;
+		int blob_sz;
+		if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
+		    nulls++;
+		else if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
+		  {
+		      blob = sqlite3_column_blob (stmt, 0);
+		      blob_sz = sqlite3_column_bytes (stmt, 0);
+		      geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		      if (geom)
+			{
+			    if (geom->Srid != topo->srid)
+				wrong_srids++;
+			    gaiaFreeGeomColl (geom);
+			    geoms++;
+			}
+		      else
+			  others++;
+		  }
+		else
+		    others++;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("TopoGeo_CreateTopoLayer step error: %s",
+				     sqlite3_errmsg (topo->db_handle));
+		gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
+					     msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_finalize (stmt);
+    if (geoms == 0)
+	return 0;
+    if (others != 0)
+	return 0;
+    if (wrong_srids != 0)
+	return 0;
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_CreateTopoLayer (const void *xcontext, int argc,
+				 const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_CreateTopoLayer ( text topology-name, text db-prefix, text ref_table,
+/                           text ref_column, text topolayer_name )
+/ TopoGeo_CreateTopoLayer ( text topology-name, text db-prefix, text ref_table,
+/                           text ref_column, text topolayer_name, 
+/                           boolean is_view )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *db_prefix;
+    const char *ref_table;
+    const char *ref_column;
+    const char *topolayer_name;
+    int is_view = 0;
+    char *xreftable = NULL;
+    char *xrefcolumn = NULL;
+    int srid;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	ref_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	ref_column = NULL;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	ref_column = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[4]) == SQLITE_TEXT)
+	topolayer_name = (const char *) sqlite3_value_text (argv[4]);
+    else
+	goto invalid_arg;
+    if (argc >= 6)
+      {
+	  if (sqlite3_value_type (argv[5]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[5]) == SQLITE_INTEGER)
+	      is_view = sqlite3_value_int (argv[5]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+    if (is_view)
+      {
+	  /* checking a View (or an unregistered geo-table) */
+	  struct gaia_topology *topo = (struct gaia_topology *) accessor;
+	  if (ref_column == NULL)
+	      goto null_view_geom;
+	  if (!check_view (topo, db_prefix, ref_table, ref_column))
+	      goto invalid_view;
+	  xreftable = malloc (strlen (ref_table) + 1);
+	  strcpy (xreftable, ref_table);
+	  xrefcolumn = malloc (strlen (ref_column) + 1);
+	  strcpy (xrefcolumn, ref_column);
+      }
+    else
+      {
+	  /* checking the reference GeoTable */
+	  if (!check_reference_geo_table
+	      (sqlite, db_prefix, ref_table, ref_column, &xreftable,
+	       &xrefcolumn, &srid))
+	      goto no_reference;
+	  if (!check_matching_srid (accessor, srid))
+	      goto invalid_geom;
+      }
+
+/* checking the output TopoLayer */
+    if (topolayer_exists (accessor, topolayer_name))
+	goto err_output;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_CreateTopoLayer (accessor, db_prefix, xreftable, xrefcolumn,
+				     topolayer_name);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    free (xreftable);
+    free (xrefcolumn);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  no_reference:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_CreateTopoLayer: invalid reference GeoTable.",
+			  -1);
+    return;
+
+  null_view_geom:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_CreateTopoLayer: IsView requires an explicit Geometry column-name.",
+			  -1);
+    return;
+
+  invalid_view:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_CreateTopoLayer: invalid reference View (invalid Geometry).",
+			  -1);
+    return;
+
+  err_output:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "TopoGeo_CreateTopoLayer: a TopoLayer of the same name already exists.",
+			  -1);
+    return;
+
+  null_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+
+  invalid_geom:
+    if (xreftable != NULL)
+	free (xreftable);
+    if (xrefcolumn != NULL)
+	free (xrefcolumn);
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID).",
+			  -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_InitTopoLayer (const void *xcontext, int argc,
+			       const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_InitTopoLayer ( text topology-name, text db-prefix, text ref_table,
+/                         text topolayer_name )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *db_prefix;
+    const char *ref_table;
+    const char *topolayer_name;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	db_prefix = "main";
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	db_prefix = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	ref_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_TEXT)
+	topolayer_name = (const char *) sqlite3_value_text (argv[3]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the reference Table */
+    if (!check_reference_table (sqlite, db_prefix, ref_table))
+	goto no_reference;
+
+/* checking the output TopoLayer */
+    if (topolayer_exists (accessor, topolayer_name))
+	goto err_output;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_InitTopoLayer (accessor, db_prefix, ref_table,
+				   topolayer_name);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  no_reference:
+    sqlite3_result_error (context,
+			  "TopoGeo_InitTopoLayer: invalid reference Table.",
+			  -1);
+    return;
+
+  err_output:
+    sqlite3_result_error (context,
+			  "TopoGeo_InitTopoLayer: a TopoLayer of the same name already exists.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_RemoveTopoLayer (const void *xcontext, int argc,
+				 const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_RemoveTopoLayer ( text topology-name, text topolayer_name )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *topolayer_name;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	topolayer_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the TopoLayer */
+    if (!topolayer_exists (accessor, topolayer_name))
+	goto err_topolayer;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret = gaiaTopoGeo_RemoveTopoLayer (accessor, topolayer_name);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  err_topolayer:
+    sqlite3_result_error (context,
+			  "TopoGeo_RemoveTopoLayer: not existing TopoLayer.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_ExportTopoLayer (const void *xcontext, int argc,
+				 const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_ExportTopoLayer ( text topology-name, text topolayer_name,
+/                           text out_table )
+/ TopoGeo_ExportTopoLayer ( text topology-name, text topolayer_name,
+/                           text out_table, integer with-spatial-index )
+/ TopoGeo_ExportTopoLayer ( text topology-name, text topolayer_name,
+/                           text out_table, integer with-spatial-index,
+/                           integer create-only )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *topolayer_name;
+    const char *out_table;
+    int with_spatial_index = 0;
+    int create_only = 0;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	topolayer_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (argc >= 4)
+      {
+	  if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[3]) == SQLITE_INTEGER)
+	      with_spatial_index = sqlite3_value_int (argv[3]);
+	  else
+	      goto invalid_arg;
+      }
+    if (argc >= 5)
+      {
+	  if (sqlite3_value_type (argv[4]) == SQLITE_NULL)
+	      goto null_arg;
+	  else if (sqlite3_value_type (argv[4]) == SQLITE_INTEGER)
+	      create_only = sqlite3_value_int (argv[4]);
+	  else
+	      goto invalid_arg;
+      }
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the input TopoLayer */
+    if (!topolayer_exists (accessor, topolayer_name))
+	goto err_topolayer;
+
+/* checking the output GeoTable */
+    if (!check_output_geo_table (sqlite, out_table))
+	goto invalid_output;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_ExportTopoLayer (accessor, topolayer_name, out_table,
+				     with_spatial_index, create_only);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  invalid_output:
+    sqlite3_result_error (context,
+			  "TopoGeo_ExportTopoLayer: the output GeoTable already exists.",
+			  -1);
+    return;
+
+  err_topolayer:
+    sqlite3_result_error (context,
+			  "TopoGeo_ExportTopoLayer: not existing TopoLayer.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+SPATIALITE_PRIVATE void
+fnctaux_TopoGeo_InsertFeatureFromTopoLayer (const void *xcontext, int argc,
+					    const void *xargv)
+{
+/* SQL function:
+/ TopoGeo_InsertFeatureFromTopoLayer ( text topology-name, 
+/                                      text topolayer_name,
+/                                      text out_table, integer fid )
+/
+/ returns: 1 on success
+/ raises an exception on failure
+*/
+    int ret;
+    const char *topo_name;
+    const char *topolayer_name;
+    const char *out_table;
+    sqlite3_int64 fid;
+    GaiaTopologyAccessorPtr accessor;
+    sqlite3_context *context = (sqlite3_context *) xcontext;
+    sqlite3_value **argv = (sqlite3_value **) xargv;
+    sqlite3 *sqlite = sqlite3_context_db_handle (context);
+    struct splite_internal_cache *cache = sqlite3_user_data (context);
+    GAIA_UNUSED ();		/* LCOV_EXCL_LINE */
+    if (sqlite3_value_type (argv[0]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT)
+	topo_name = (const char *) sqlite3_value_text (argv[0]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[1]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[1]) == SQLITE_TEXT)
+	topolayer_name = (const char *) sqlite3_value_text (argv[1]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[2]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[2]) == SQLITE_TEXT)
+	out_table = (const char *) sqlite3_value_text (argv[2]);
+    else
+	goto invalid_arg;
+    if (sqlite3_value_type (argv[3]) == SQLITE_NULL)
+	goto null_arg;
+    else if (sqlite3_value_type (argv[3]) == SQLITE_INTEGER)
+	fid = sqlite3_value_int64 (argv[3]);
+    else
+	goto invalid_arg;
+
+/* attempting to get a Topology Accessor */
+    accessor = gaiaGetTopology (sqlite, cache, topo_name);
+    if (accessor == NULL)
+	goto no_topo;
+
+/* checking the input TopoLayer */
+    if (!topolayer_exists (accessor, topolayer_name))
+	goto err_topolayer;
+
+/* checking the output GeoTable */
+    if (check_output_geo_table (sqlite, out_table))
+	goto invalid_output;
+
+    gaiatopo_reset_last_error_msg (accessor);
+    start_topo_savepoint (sqlite, cache);
+    ret =
+	gaiaTopoGeo_InsertFeatureFromTopoLayer (accessor, topolayer_name,
+						out_table, fid);
+    if (!ret)
+	rollback_topo_savepoint (sqlite, cache);
+    else
+	release_topo_savepoint (sqlite, cache);
+    if (!ret)
+      {
+	  const char *msg = gaiaGetLwGeomErrorMsg ();
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_result_error (context, msg, -1);
+	  return;
+      }
+    sqlite3_result_int (context, 1);
+    return;
+
+  no_topo:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid topology name.",
+			  -1);
+    return;
+
+  invalid_output:
+    sqlite3_result_error (context,
+			  "TopoGeo_InsertFeatureFromTopoLayer: the output GeoTable does not exists.",
+			  -1);
+    return;
+
+  err_topolayer:
+    sqlite3_result_error (context,
+			  "TopoGeo_InsertFeatureFromTopoLayer: non-existing TopoLayer.",
+			  -1);
+    return;
+
+  null_arg:
+    sqlite3_result_error (context, "SQL/MM Spatial exception - null argument.",
+			  -1);
+    return;
+
+  invalid_arg:
+    sqlite3_result_error (context,
+			  "SQL/MM Spatial exception - invalid argument.", -1);
+    return;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/gaia_topostmts.c b/src/topology/gaia_topostmts.c
new file mode 100644
index 0000000..41eb7db
--- /dev/null
+++ b/src/topology/gaia_topostmts.c
@@ -0,0 +1,642 @@
+/*
+
+ gaia_topostmts.c -- implementation of Topology prepared statements
+    
+ version 4.3, 2015 July 18
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/*
+ 
+CREDITS:
+
+this module has been completely funded by:
+Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
+(Topology support) 
+
+CIG: 6038019AE5
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaiaaux.h>
+#include <spatialite/gaia_topology.h>
+
+#include <spatialite_private.h>
+
+#include <liblwgeom.h>
+#include <liblwgeom_topo.h>
+
+#include "topology_private.h"
+
+#define GAIA_UNUSED() if (argc || argv) argc = argc;
+
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getNodeWithinDistance2D (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getNodeWithinDistance2D prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT node_id FROM MAIN.\"%s\" "
+			 "WHERE ST_Distance(geom, MakePoint(?, ?)) <= ? AND ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geom' AND search_frame = BuildCircleMBR(?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getNodeWithinDistance2D error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getNodeWithinBox2D (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getNodeWithinBox2D prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT node_id FROM MAIN.\"%s\" WHERE ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geom' AND search_frame = BuildMBR(?, ?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getNodeWithinBox2D error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_insertNodes (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the insertNodes prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (node_id, containing_face, geom) "
+	 "VALUES (?, ?, ?)", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_insertNodes error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getEdgeWithinDistance2D (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getEdgeWithinDistance2D prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" "
+			 "WHERE ST_Distance(geom, MakePoint(?, ?)) <= ? AND ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geom' AND search_frame = BuildCircleMBR(?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getEdgeWithinDistance2D error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getEdgeWithinBox2D (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getEdgeWithinBox2D prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" WHERE ROWID IN ("
+			 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND "
+			 "f_geometry_column = 'geom' AND search_frame = BuildMBR(?, ?, ?, ?))",
+			 xtable, table);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getEdgeWithinBox2D error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getFaceContainingPoint_1 (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getFaceContainingPoint #1 prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *rtree;
+    char *xrtree;
+    if (topo == NULL)
+	return NULL;
+
+    rtree = sqlite3_mprintf ("idx_%s_face_mbr", topo->topology_name);
+    xrtree = gaiaDoubleQuotedSql (rtree);
+    sql =
+	sqlite3_mprintf
+	("SELECT pkid FROM MAIN.\"%s\" WHERE xmin <= ? AND xmax >= ? AND ymin <= ? AND ymax >= ?",
+	 xrtree);
+    free (xrtree);
+    sqlite3_free (rtree);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("Prepare_getFaceContainingPoint #1 error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getFaceContainingPoint_2 (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getFaceContainingPoint #2 prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    if (topo == NULL)
+	return NULL;
+
+    sql =
+	sqlite3_mprintf
+	("SELECT ST_Contains(ST_GetFaceGeometry(%Q, ?), MakePoint(?, ?))",
+	 topo->topology_name);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf
+	      ("Prepare_getFaceContainingPoint #2 error: \"%s\"",
+	       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_insertEdges (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the insertEdges prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (edge_id, start_node, end_node, left_face, "
+	 "right_face, next_left_edge, next_right_edge, geom) "
+	 "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_insertEdges error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getNextEdgeId (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getNextEdgeId prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    if (topo == NULL)
+	return NULL;
+
+    sql =
+	sqlite3_mprintf
+	("SELECT next_edge_id FROM MAIN.topologies WHERE Lower(topology_name) = Lower(%Q)",
+	 topo->topology_name);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getNextEdgeId error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_setNextEdgeId (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the setNextEdgeId prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    if (topo == NULL)
+	return NULL;
+
+    sql =
+	sqlite3_mprintf
+	("UPDATE MAIN.topologies SET next_edge_id = next_edge_id + 1 "
+	 "WHERE Lower(topology_name) = Lower(%Q)", topo->topology_name);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_setNextEdgeId error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getRingEdges (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getRingEdges prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_edge", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("WITH RECURSIVE edgering AS ("
+			 "SELECT ? as signed_edge_id, edge_id, next_left_edge, next_right_edge "
+			 "FROM MAIN.\"%s\" WHERE edge_id = ABS(?) UNION SELECT CASE WHEN "
+			 "p.signed_edge_id < 0 THEN p.next_right_edge ELSE p.next_left_edge END, "
+			 "e.edge_id, e.next_left_edge, e.next_right_edge "
+			 "FROM MAIN.\"%s\" AS e, edgering AS p WHERE "
+			 "e.edge_id = CASE WHEN p.signed_edge_id < 0 THEN "
+			 "ABS(p.next_right_edge) ELSE ABS(p.next_left_edge) END ) "
+			 "SELECT * FROM edgering", xtable, xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getRingEdges error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_insertFaces (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the insertFaces prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("INSERT INTO MAIN.\"%s\" (face_id, mbr) VALUES (?, BuildMBR(?, ?, ?, ?, %d))",
+	 xtable, topo->srid);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_insertFaces error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_updateFacesById (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the updateFacesById prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("UPDATE MAIN.\"%s\" SET mbr = BuildMBR(?, ?, ?, ?, %d) WHERE face_id = ?",
+	 xtable, topo->srid);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_updateFacesById error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_deleteFacesById (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the deleteFacesById prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_face", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE face_id = ?", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_deleteFacesById error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_deleteNodesById (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the deleteNodesById prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("%s_node", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE node_id = ?", xtable);
+    free (xtable);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_deleteNodesById error: \"%s\"",
+				       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+
+    return stmt;
+}
+
+TOPOLOGY_PRIVATE sqlite3_stmt *
+do_create_stmt_getFaceWithinBox2D (GaiaTopologyAccessorPtr accessor)
+{
+/* attempting to create the getFaceWithinBox2D prepared statement */
+    struct gaia_topology *topo = (struct gaia_topology *) accessor;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *table;
+    char *xtable;
+    if (topo == NULL)
+	return NULL;
+
+    table = sqlite3_mprintf ("idx_%s_face_mbr", topo->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sql =
+	sqlite3_mprintf
+	("SELECT pkid, xmin, ymin, xmax, ymax FROM MAIN.\"%s\" "
+	 "WHERE xmin <= ? AND xmax >= ? AND ymin <= ? AND ymax >= ?", xtable);
+    free (xtable);
+    sqlite3_free (table);
+    ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getFaceWithinBox2D error: \"%s\"",
+			       sqlite3_errmsg (topo->db_handle));
+	  gaiatopo_set_last_error_msg (accessor, msg);
+	  sqlite3_free (msg);
+	  return NULL;
+      }
+    return stmt;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/lwn_network.c b/src/topology/lwn_network.c
new file mode 100644
index 0000000..947127a
--- /dev/null
+++ b/src/topology/lwn_network.c
@@ -0,0 +1,1900 @@
+/*
+
+ lwn_network.c -- Topology-Network abstract multi-backend interface
+    
+ version 4.3, 2015 August 13
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include "lwn_network.h"
+#include "lwn_network_private.h"
+
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
+#include <geos_c.h>
+
+#include <liblwgeom.h>
+
+#include <spatialite_private.h>
+
+/*********************************************************************
+ *
+ * Backend iface
+ *
+ ********************************************************************/
+
+LWN_BE_IFACE *
+lwn_CreateBackendIface (const LWN_BE_DATA * data)
+{
+    LWN_BE_IFACE *iface = malloc (sizeof (LWN_BE_IFACE));
+    iface->data = data;
+    iface->cb = NULL;
+    iface->errorMsg = NULL;
+    return iface;
+}
+
+void
+lwn_BackendIfaceRegisterCallbacks (LWN_BE_IFACE * iface,
+				   const LWN_BE_CALLBACKS * cb)
+{
+    iface->cb = cb;
+}
+
+void
+lwn_FreeBackendIface (LWN_BE_IFACE * iface)
+{
+    if (iface == NULL)
+	return;
+    if (iface->errorMsg != NULL)
+	free (iface->errorMsg);
+    free (iface);
+}
+
+/*********************************************************************
+ *
+ * Backend wrappers
+ *
+ ********************************************************************/
+
+#define CHECKCB(be, method) do { \
+  if ( ! (be)->cb || ! (be)->cb->method ) \
+  lwn_SetErrorMsg(be, "Callback " # method " not registered by backend"); \
+} while (0)
+
+#define NETCB0(be, method) \
+  CHECKCB(be, method);\
+  return (be)->cb->method((be)->data)
+
+#define NETCB1(be, method, a1) \
+  CHECKCB(be, method);\
+  return (be)->cb->method((be)->data, a1)
+
+#define NETCBT0(to, method) \
+  CHECKCB((to)->be_iface, method);\
+  return (to)->be_iface->cb->method((to)->be_net)
+
+#define NETCBT1(to, method, a1) \
+  CHECKCB((to)->be_iface, method);\
+  return (to)->be_iface->cb->method((to)->be_net, a1)
+
+#define NETCBT2(to, method, a1, a2) \
+  CHECKCB((to)->be_iface, method);\
+  return (to)->be_iface->cb->method((to)->be_net, a1, a2)
+
+#define NETCBT3(to, method, a1, a2, a3) \
+  CHECKCB((to)->be_iface, method);\
+  return (to)->be_iface->cb->method((to)->be_net, a1, a2, a3)
+
+#define NETCBT4(to, method, a1, a2, a3, a4) \
+  CHECKCB((to)->be_iface, method);\
+  return (to)->be_iface->cb->method((to)->be_net, a1, a2, a3, a4)
+
+#define NETCBT5(to, method, a1, a2, a3, a4, a5) \
+  CHECKCB((to)->be_iface, method);\
+  return (to)->be_iface->cb->method((to)->be_net, a1, a2, a3, a4, a5)
+
+
+static LWN_BE_NETWORK *
+lwn_be_loadNetworkByName (LWN_BE_IFACE * be, const char *name)
+{
+    NETCB1 (be, loadNetworkByName, name);
+}
+
+static int
+lwn_be_netGetSRID (LWN_NETWORK * net)
+{
+    NETCBT0 (net, netGetSRID);
+}
+
+static int
+lwn_be_netHasZ (LWN_NETWORK * net)
+{
+    NETCBT0 (net, netHasZ);
+}
+
+static int
+lwn_be_netIsSpatial (LWN_NETWORK * net)
+{
+    NETCBT0 (net, netIsSpatial);
+}
+
+static int
+lwn_be_netAllowCoincident (LWN_NETWORK * net)
+{
+    NETCBT0 (net, netAllowCoincident);
+}
+
+static const void *
+lwn_be_netGetGEOS (LWN_NETWORK * net)
+{
+    NETCBT0 (net, netGetGEOS);
+}
+
+static int
+lwn_be_freeNetwork (LWN_NETWORK * net)
+{
+    NETCBT0 (net, freeNetwork);
+}
+
+static LWN_NET_NODE *
+lwn_be_getNetNodeWithinDistance2D (const LWN_NETWORK * net,
+				   const LWN_POINT * pt, double dist,
+				   int *numelems, int fields, int limit)
+{
+    NETCBT5 (net, getNetNodeWithinDistance2D, pt, dist, numelems, fields,
+	     limit);
+}
+
+static LWN_LINK *
+lwn_be_getLinkWithinDistance2D (const LWN_NETWORK * net, const LWN_POINT * pt,
+				double dist, int *numelems, int fields,
+				int limit)
+{
+    NETCBT5 (net, getLinkWithinDistance2D, pt, dist, numelems, fields, limit);
+}
+
+static int
+lwn_be_updateNetNodesById (const LWN_NETWORK * net,
+			   const LWN_NET_NODE * nodes, int numnodes,
+			   int upd_fields)
+{
+    NETCBT3 (net, updateNetNodesById, nodes, numnodes, upd_fields);
+}
+
+static int
+lwn_be_insertNetNodes (const LWN_NETWORK * net, LWN_NET_NODE * node,
+		       int numelems)
+{
+    NETCBT2 (net, insertNetNodes, node, numelems);
+}
+
+static LWN_NET_NODE *
+lwn_be_getNetNodeById (const LWN_NETWORK * net, const LWN_ELEMID * ids,
+		       int *numelems, int fields)
+{
+    NETCBT3 (net, getNetNodeById, ids, numelems, fields);
+}
+
+static LWN_LINK *
+lwn_be_getLinkByNetNode (const LWN_NETWORK * net, const LWN_ELEMID * ids,
+			 int *numelems, int fields)
+{
+    NETCBT3 (net, getLinkByNetNode, ids, numelems, fields);
+}
+
+static int
+lwn_be_deleteNetNodesById (const LWN_NETWORK * net, const LWN_ELEMID * ids,
+			   int numelems)
+{
+    NETCBT2 (net, deleteNetNodesById, ids, numelems);
+}
+
+static LWN_ELEMID
+lwn_be_getNextLinkId (const LWN_NETWORK * net)
+{
+    NETCBT0 (net, getNextLinkId);
+}
+
+static LWN_NET_NODE *
+lwn_be_getNetNodeWithinBox2D (const LWN_NETWORK * net,
+			      const LWN_BBOX * box, int *numelems, int fields,
+			      int limit)
+{
+    NETCBT4 (net, getNetNodeWithinBox2D, box, numelems, fields, limit);
+}
+
+static int
+lwn_be_insertLinks (const LWN_NETWORK * net, LWN_LINK * link, int numelems)
+{
+    NETCBT2 (net, insertLinks, link, numelems);
+}
+
+static int
+lwn_be_updateLinksById (const LWN_NETWORK * net, LWN_LINK * links, int numlinks,
+			int upd_fields)
+{
+    NETCBT3 (net, updateLinksById, links, numlinks, upd_fields);
+}
+
+static LWN_LINK *
+lwn_be_getLinkById (const LWN_NETWORK * net, const LWN_ELEMID * ids,
+		    int *numelems, int fields)
+{
+    NETCBT3 (net, getLinkById, ids, numelems, fields);
+}
+
+static int
+lwn_be_deleteLinksById (const LWN_NETWORK * net, const LWN_ELEMID * ids,
+			int numelems)
+{
+    NETCBT2 (net, deleteLinksById, ids, numelems);
+}
+
+
+/************************************************************************
+ *
+ * API implementation
+ *
+ ************************************************************************/
+
+LWN_NETWORK *
+lwn_LoadNetwork (LWN_BE_IFACE * iface, const char *name)
+{
+    LWN_BE_NETWORK *be_net;
+    LWN_NETWORK *net;
+
+    be_net = lwn_be_loadNetworkByName (iface, name);
+    if (!be_net)
+      {
+	  lwn_SetErrorMsg (iface, "Could not load network from backend");
+	  return NULL;
+      }
+    net = malloc (sizeof (LWN_NETWORK));
+    net->be_iface = iface;
+    net->be_net = be_net;
+    net->srid = lwn_be_netGetSRID (net);
+    net->hasZ = lwn_be_netHasZ (net);
+    net->spatial = lwn_be_netIsSpatial (net);
+    net->allowCoincident = lwn_be_netAllowCoincident (net);
+    net->geos_handle = lwn_be_netGetGEOS (net);
+    return net;
+}
+
+void
+lwn_FreeNetwork (LWN_NETWORK * net)
+{
+    if (!lwn_be_freeNetwork (net))
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "Could not release backend topology memory");
+      }
+    free (net);
+}
+
+LWN_POINT *
+lwn_create_point2d (int srid, double x, double y)
+{
+    LWN_POINT *point = malloc (sizeof (LWN_POINT));
+    point->srid = srid;
+    point->has_z = 0;
+    point->x = x;
+    point->y = y;
+    return point;
+}
+
+LWN_POINT *
+lwn_create_point3d (int srid, double x, double y, double z)
+{
+    LWN_POINT *point = malloc (sizeof (LWN_POINT));
+    point->srid = srid;
+    point->has_z = 1;
+    point->x = x;
+    point->y = y;
+    point->z = z;
+    return point;
+}
+
+void
+lwn_free_point (LWN_POINT * point)
+{
+    if (point == NULL)
+	return;
+    free (point);
+}
+
+LWN_LINE *
+lwn_alloc_line (int points, int srid, int hasz)
+{
+    LWN_LINE *line = malloc (sizeof (LWN_LINE));
+    line->points = points;
+    line->srid = srid;
+    line->has_z = hasz;
+    line->x = malloc (sizeof (double) * points);
+    line->y = malloc (sizeof (double) * points);
+    if (hasz)
+	line->z = malloc (sizeof (double) * points);
+    else
+	line->z = NULL;
+    return line;
+}
+
+void
+lwn_free_line (LWN_LINE * line)
+{
+    if (line == NULL)
+	return;
+    if (line->x != NULL)
+	free (line->x);
+    if (line->y != NULL)
+	free (line->y);
+    if (line->z != NULL && line->has_z)
+	free (line->z);
+    free (line);
+}
+
+void
+lwn_ResetErrorMsg (LWN_BE_IFACE * iface)
+{
+    if (iface == NULL)
+	return;
+    if (iface->errorMsg != NULL)
+	free (iface->errorMsg);
+    iface->errorMsg = NULL;
+}
+
+void
+lwn_SetErrorMsg (LWN_BE_IFACE * iface, const char *message)
+{
+    int len;
+    if (iface == NULL)
+	return;
+    if (iface->errorMsg != NULL)
+	free (iface->errorMsg);
+    iface->errorMsg = NULL;
+    if (message == NULL)
+	return;
+    len = strlen (message);
+    iface->errorMsg = malloc (len + 1);
+    strcpy (iface->errorMsg, message);
+}
+
+const char *
+lwn_GetErrorMsg (LWN_BE_IFACE * iface)
+{
+    if (iface == NULL)
+	return NULL;
+    return iface->errorMsg;
+}
+
+static void
+_lwn_release_nodes (LWN_NET_NODE * nodes, int num_nodes)
+{
+    int i;
+    for (i = 0; i < num_nodes; ++i)
+      {
+	  if (nodes[i].geom != NULL)
+	      lwn_free_point (nodes[i].geom);
+      }
+    free (nodes);
+}
+
+static void
+_lwn_release_links (LWN_LINK * links, int num_links)
+{
+    int i;
+    for (i = 0; i < num_links; ++i)
+      {
+	  if (links[i].geom != NULL)
+	      lwn_free_line (links[i].geom);
+      }
+    free (links);
+}
+
+LWN_ELEMID
+lwn_AddIsoNetNode (LWN_NETWORK * net, LWN_POINT * pt)
+{
+    LWN_NET_NODE node;
+
+    if (net->spatial && net->allowCoincident == 0)
+      {
+	  if (lwn_be_existsCoincidentNode (net, pt))
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - coincident node.");
+		return -1;
+	    }
+	  if (lwn_be_existsLinkIntersectingPoint (net, pt))
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - link crosses node.");
+		return -1;
+	    }
+      }
+
+    node.node_id = -1;
+    node.geom = pt;
+    if (!lwn_be_insertNetNodes (net, &node, 1))
+	return -1;
+
+    return node.node_id;
+}
+
+static LWN_NET_NODE *
+_lwn_GetIsoNetNode (LWN_NETWORK * net, LWN_ELEMID nid)
+{
+    LWN_NET_NODE *node;
+    int n = 1;
+    LWN_LINK *links;
+    int nlinks;
+
+    node = lwn_be_getNetNodeById (net, &nid, &n, LWN_COL_NODE_NODE_ID);
+    if (n < 0)
+	return 0;
+    if (n < 1)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - non-existent node.");
+	  return 0;
+      }
+
+    nlinks = 1;
+    links = lwn_be_getLinkByNetNode (net, &nid, &nlinks, LWN_COL_LINK_LINK_ID);
+    if (nlinks < 0)
+	return 0;
+    if (nlinks != 0)
+      {
+	  free (node);
+	  _lwn_release_links (links, nlinks);
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - not isolated node.");
+	  return 0;
+      }
+
+    return node;
+}
+
+static LWN_LINK *
+_lwn_GetLink (LWN_NETWORK * net, LWN_ELEMID link_id)
+{
+    LWN_LINK *link;
+    int n = 1;
+
+    link = lwn_be_getLinkById (net, &link_id, &n, LWN_COL_LINK_LINK_ID);
+    if (n < 0)
+	return 0;
+    if (n < 1)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - non-existent link.");
+	  return 0;
+      }
+    return link;
+}
+
+static int
+line2bbox (const LWN_LINE * line, LWN_BBOX * bbox)
+{
+    int iv;
+    if (line == NULL)
+	return 0;
+
+    bbox->min_x = DBL_MAX;
+    bbox->min_y = DBL_MAX;
+    bbox->max_x = -DBL_MAX;
+    bbox->max_y = -DBL_MAX;
+
+    for (iv = 0; iv < line->points; iv++)
+      {
+	  double x = line->x[iv];
+	  double y = line->y[iv];
+	  if (x < bbox->min_x)
+	      bbox->min_x = x;
+	  if (y < bbox->min_y)
+	      bbox->min_y = y;
+	  if (x > bbox->max_x)
+	      bbox->max_x = x;
+	  if (y > bbox->max_y)
+	      bbox->max_y = y;
+      }
+
+    return 1;
+}
+
+
+static GEOSGeometry *
+point2geos (GEOSContextHandle_t handle, const LWN_POINT * point)
+{
+    GEOSGeometry *geos = NULL;
+    GEOSCoordSequence *cs;
+    cs = GEOSCoordSeq_create_r (handle, 1, 2);
+    GEOSCoordSeq_setX_r (handle, cs, 0, point->x);
+    GEOSCoordSeq_setY_r (handle, cs, 0, point->y);
+    geos = GEOSGeom_createPoint_r (handle, cs);
+    return geos;
+}
+
+static GEOSGeometry *
+line2geos (GEOSContextHandle_t handle, const LWN_LINE * line)
+{
+    int iv;
+    GEOSGeometry *geos = NULL;
+    GEOSCoordSequence *cs;
+    cs = GEOSCoordSeq_create_r (handle, line->points, 2);
+    for (iv = 0; iv < line->points; iv++)
+      {
+	  GEOSCoordSeq_setX_r (handle, cs, iv, line->x[iv]);
+	  GEOSCoordSeq_setY_r (handle, cs, iv, line->y[iv]);
+      }
+    geos = GEOSGeom_createLineString_r (handle, cs);
+    return geos;
+}
+
+/* Check that a link does not cross an existing node
+ *
+ * Return -1 on cross or error, 0 if everything is fine.
+ * Note that before returning -1, lwerror is invoked...
+ */
+static int
+_lwn_CheckLinkCrossing (LWN_NETWORK * net,
+			LWN_ELEMID start_node, LWN_ELEMID end_node,
+			const LWN_LINE * geom)
+{
+    int i, num_nodes;
+    LWN_NET_NODE *nodes;
+    LWN_BBOX linkbbox;
+    GEOSContextHandle_t handle = (GEOSContextHandle_t) (net->geos_handle);
+    GEOSGeometry *linkgg;
+    const GEOSPreparedGeometry *prepared_link;
+
+    linkgg = line2geos (handle, geom);
+    if (!linkgg)
+	return -1;
+    prepared_link = GEOSPrepare_r (handle, linkgg);
+    if (!prepared_link)
+	return -1;
+    if (!line2bbox (geom, &linkbbox))
+      {
+	  GEOSPreparedGeom_destroy_r (handle, prepared_link);
+	  GEOSGeom_destroy_r (handle, linkgg);
+	  return -1;
+      }
+
+    /* loop over each node within the edge's gbox */
+    nodes = lwn_be_getNetNodeWithinBox2D (net, &linkbbox, &num_nodes,
+					  LWN_COL_NODE_ALL, 0);
+    if (num_nodes == -1)
+      {
+	  GEOSPreparedGeom_destroy_r (handle, prepared_link);
+	  GEOSGeom_destroy_r (handle, linkgg);
+	  return -1;
+      }
+    for (i = 0; i < num_nodes; ++i)
+      {
+	  LWN_NET_NODE *node = &(nodes[i]);
+	  GEOSGeometry *nodegg;
+	  int contains;
+	  if (node->node_id == start_node)
+	      continue;
+	  if (node->node_id == end_node)
+	      continue;
+	  /* check if the link contains this node (not on boundary) */
+	  nodegg = point2geos (handle, node->geom);
+	  /* ST_RelateMatch(rec.relate, 'T********') */
+	  contains = GEOSPreparedContains_r (handle, prepared_link, nodegg);
+	  GEOSGeom_destroy_r (handle, nodegg);
+	  if (contains == 2)
+	    {
+		GEOSPreparedGeom_destroy_r (handle, prepared_link);
+		GEOSGeom_destroy_r (handle, linkgg);
+		_lwn_release_nodes (nodes, num_nodes);
+		lwn_SetErrorMsg (net->be_iface,
+				 "GEOS exception on PreparedContains");
+		return -1;
+	    }
+	  if (contains)
+	    {
+		GEOSPreparedGeom_destroy_r (handle, prepared_link);
+		GEOSGeom_destroy_r (handle, linkgg);
+		_lwn_release_nodes (nodes, num_nodes);
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - geometry crosses a node.");
+		return -1;
+	    }
+      }
+    if (nodes)
+	_lwn_release_nodes (nodes, num_nodes);
+    GEOSPreparedGeom_destroy_r (handle, prepared_link);
+    GEOSGeom_destroy_r (handle, linkgg);
+
+    return 0;
+}
+
+int
+lwn_MoveIsoNetNode (LWN_NETWORK * net, LWN_ELEMID nid, const LWN_POINT * pt)
+{
+    LWN_NET_NODE *node;
+    int ret;
+
+    node = _lwn_GetIsoNetNode (net, nid);
+    if (!node)
+	return -1;
+
+    if (net->spatial && net->allowCoincident == 0)
+      {
+	  if (lwn_be_existsCoincidentNode (net, pt))
+	    {
+		_lwn_release_nodes (node, 1);
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - coincident node.");
+		return -1;
+	    }
+
+	  if (lwn_be_existsLinkIntersectingPoint (net, pt))
+	    {
+		_lwn_release_nodes (node, 1);
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - link crosses node.");
+		return -1;
+	    }
+      }
+
+    node->node_id = nid;
+    if (node->geom)
+	lwn_free_point (node->geom);
+    node->geom = (LWN_POINT *) pt;
+    ret = lwn_be_updateNetNodesById (net, node, 1, LWN_COL_NODE_GEOM);
+    node->geom = NULL;
+    _lwn_release_nodes (node, 1);
+    if (ret == -1)
+	return -1;
+
+    return 0;
+}
+
+int
+lwn_RemIsoNetNode (LWN_NETWORK * net, LWN_ELEMID nid)
+{
+    LWN_NET_NODE *node;
+    int n = 1;
+
+    node = _lwn_GetIsoNetNode (net, nid);
+    if (!node)
+	return -1;
+
+    n = lwn_be_deleteNetNodesById (net, &nid, n);
+    if (n == -1)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - not isolated node.");
+	  return -1;
+      }
+    if (n != 1)
+	return -1;
+
+    free (node);
+    return 0;
+}
+
+static int
+getLineFirstPoint (const LWN_LINE * geom, LWN_POINT * pt)
+{
+    if (geom == NULL)
+	return 0;
+    pt->srid = geom->srid;
+    pt->has_z = geom->has_z;
+    pt->x = geom->x[0];
+    pt->y = geom->y[0];
+    if (geom->has_z)
+	pt->z = geom->z[0];
+    return 1;
+}
+
+static int
+getLineLastPoint (const LWN_LINE * geom, LWN_POINT * pt)
+{
+    int iv;
+    if (geom == NULL)
+	return 0;
+    iv = geom->points - 1;
+    pt->srid = geom->srid;
+    pt->has_z = geom->has_z;
+    pt->x = geom->x[iv];
+    pt->y = geom->y[iv];
+    if (geom->has_z)
+	pt->z = geom->z[iv];
+    return 1;
+}
+
+static int
+point_same_2d (LWN_POINT * pt1, LWN_POINT * pt2)
+{
+    if (pt1->x == pt2->x && pt1->y == pt2->y)
+	return 1;
+    return 0;
+}
+
+LWN_ELEMID
+lwn_AddLink (LWN_NETWORK * net,
+	     LWN_ELEMID startNode, LWN_ELEMID endNode, LWN_LINE * geom)
+{
+    int num_nodes;
+    int i;
+    LWN_LINK newlink;
+    LWN_NET_NODE *endpoints;
+    LWN_ELEMID *node_ids;
+    LWN_POINT pt;
+
+    /* NOT IN THE SPECS:
+     * A closed link makes no sense and should always be forbidden
+     */
+    if (startNode == endNode)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - self-closed links are forbidden.");
+	  return -1;
+      }
+
+    /*
+     * Check for:
+     *    existence of nodes
+     * Extract:
+     *    nodes geoms
+     */
+    num_nodes = 2;
+    node_ids = malloc (sizeof (LWN_ELEMID) * num_nodes);
+    node_ids[0] = startNode;
+    node_ids[1] = endNode;
+    endpoints = lwn_be_getNetNodeById (net, node_ids, &num_nodes,
+				       LWN_COL_NODE_ALL);
+    if (num_nodes < 0)
+	return -1;
+    else if (num_nodes < 2)
+      {
+	  if (num_nodes)
+	      _lwn_release_nodes (endpoints, num_nodes);
+	  free (node_ids);
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - non-existent node.");
+	  return -1;
+      }
+    for (i = 0; i < num_nodes; ++i)
+      {
+	  const LWN_NET_NODE *n = &(endpoints[i]);
+	  if (net->spatial)
+	    {
+		if (n->geom == NULL)
+		    return -1;
+		if (n->node_id == startNode)
+		  {
+		      /* l) Check that start point of acurve match start node geoms. */
+		      if (!getLineFirstPoint (geom, &pt))
+			  return -1;
+		      if (!point_same_2d (&pt, n->geom))
+			{
+			    _lwn_release_nodes (endpoints, num_nodes);
+			    free (node_ids);
+			    lwn_SetErrorMsg (net->be_iface,
+					     "SQL/MM Spatial exception - "
+					     "start node not geometry start point.");
+			    return -1;
+			}
+		  }
+		else
+		  {
+		      /* m) Check that end point of acurve match end node geoms. */
+		      if (!getLineLastPoint (geom, &pt))
+			  return -1;
+		      if (!point_same_2d (&pt, n->geom))
+			{
+			    _lwn_release_nodes (endpoints, num_nodes);
+			    free (node_ids);
+			    lwn_SetErrorMsg (net->be_iface,
+					     "SQL/MM Spatial exception - "
+					     "end node not geometry end point.");
+			    return -1;
+			}
+		  }
+	    }
+      }
+    _lwn_release_nodes (endpoints, num_nodes);
+    free (node_ids);
+
+    if (net->spatial && net->allowCoincident == 0)
+      {
+	  if (_lwn_CheckLinkCrossing (net, startNode, endNode, geom))
+	      return -1;
+      }
+
+    /*
+     * All checks passed, time to prepare the new link
+     */
+
+    newlink.link_id = lwn_be_getNextLinkId (net);
+    if (newlink.link_id == -1)
+	return -1;
+
+    newlink.start_node = startNode;
+    newlink.end_node = endNode;
+    newlink.geom = geom;
+
+    if (!lwn_be_insertLinks (net, &newlink, 1))
+	return -1;
+
+    return newlink.link_id;
+}
+
+int
+lwn_ChangeLinkGeom (LWN_NETWORK * net, LWN_ELEMID link, const LWN_LINE * geom)
+{
+    int num_nodes;
+    int i;
+    LWN_LINK newlink;
+    LWN_LINK *oldlink;
+    LWN_NET_NODE *endpoints;
+    LWN_ELEMID *node_ids;
+    LWN_POINT pt;
+    LWN_ELEMID startNode;
+    LWN_ELEMID endNode;
+    int ret;
+
+    i = 1;
+    oldlink =
+	lwn_be_getLinkById (net, &link, &i,
+			    LWN_COL_LINK_START_NODE | LWN_COL_LINK_END_NODE);
+    if (!oldlink)
+      {
+	  if (i == -1)
+	      return -1;
+	  else if (i == 0)
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - non-existent link.");
+		return -1;
+	    }
+      }
+    startNode = oldlink->start_node;
+    endNode = oldlink->end_node;
+    _lwn_release_links (oldlink, 1);
+
+    /*
+     * Check for:
+     *    existence of nodes
+     * Extract:
+     *    nodes geoms
+     */
+    num_nodes = 2;
+    node_ids = malloc (sizeof (LWN_ELEMID) * num_nodes);
+    node_ids[0] = startNode;
+    node_ids[1] = endNode;
+    endpoints = lwn_be_getNetNodeById (net, node_ids, &num_nodes,
+				       LWN_COL_NODE_ALL);
+    if (num_nodes < 0)
+	return -1;
+    else if (num_nodes < 2)
+      {
+	  if (num_nodes)
+	      _lwn_release_nodes (endpoints, num_nodes);
+	  free (node_ids);
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - non-existent node.");
+	  return -1;
+      }
+    for (i = 0; i < num_nodes; ++i)
+      {
+	  const LWN_NET_NODE *n = &(endpoints[i]);
+	  if (net->spatial)
+	    {
+		if (n->geom == NULL)
+		    return -1;
+		if (n->node_id == startNode)
+		  {
+		      /* l) Check that start point of acurve match start node geoms. */
+		      if (!getLineFirstPoint (geom, &pt))
+			  return -1;
+		      if (!point_same_2d (&pt, n->geom))
+			{
+			    _lwn_release_nodes (endpoints, num_nodes);
+			    free (node_ids);
+			    lwn_SetErrorMsg (net->be_iface,
+					     "SQL/MM Spatial exception - "
+					     "start node not geometry start point.");
+			    return -1;
+			}
+		  }
+		else
+		  {
+		      /* m) Check that end point of acurve match end node geoms. */
+		      if (!getLineLastPoint (geom, &pt))
+			  return -1;
+		      if (!point_same_2d (&pt, n->geom))
+			{
+			    _lwn_release_nodes (endpoints, num_nodes);
+			    free (node_ids);
+			    lwn_SetErrorMsg (net->be_iface,
+					     "SQL/MM Spatial exception - "
+					     "end node not geometry end point.");
+			    return -1;
+			}
+		  }
+	    }
+      }
+    _lwn_release_nodes (endpoints, num_nodes);
+    free (node_ids);
+
+    if (net->spatial && net->allowCoincident == 0)
+      {
+	  if (_lwn_CheckLinkCrossing (net, startNode, endNode, geom))
+	      return -1;
+      }
+
+    /*
+     * All checks passed, time to prepare the new link
+     */
+
+    newlink.link_id = link;
+    newlink.start_node = startNode;
+    newlink.end_node = endNode;
+    newlink.geom = (LWN_LINE *) geom;
+
+    ret = lwn_be_updateLinksById (net, &newlink, 1, LWN_COL_LINK_GEOM);
+    if (ret == -1)
+	return -1;
+    else if (ret == 0)
+	return -1;
+
+    return 0;
+}
+
+int
+lwn_RemoveLink (LWN_NETWORK * net, LWN_ELEMID link_id)
+{
+    LWN_LINK *link;
+    int n = 1;
+
+    link = _lwn_GetLink (net, link_id);
+    if (!link)
+	return -1;
+
+    n = lwn_be_deleteLinksById (net, &link_id, n);
+    if (n != 1)
+	return -1;
+
+    free (link);
+    return 0;
+}
+
+LWN_INT64
+lwn_NewLogLinkSplit (LWN_NETWORK * net, LWN_ELEMID link)
+{
+    int i;
+    LWN_LINK *oldlink;
+    LWN_LINK newlink[2];
+    LWN_ELEMID startNode;
+    LWN_ELEMID endNode;
+    LWN_NET_NODE newnode;
+
+    i = 1;
+    oldlink =
+	lwn_be_getLinkById (net, &link, &i,
+			    LWN_COL_LINK_START_NODE | LWN_COL_LINK_END_NODE);
+    if (!oldlink)
+      {
+	  if (i == -1)
+	      return -1;
+	  else if (i == 0)
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - non-existent link.");
+		return -1;
+	    }
+      }
+    startNode = oldlink->start_node;
+    endNode = oldlink->end_node;
+    _lwn_release_links (oldlink, 1);
+
+/* inserting a new NetNode */
+    newnode.node_id = -1;
+    newnode.geom = NULL;
+    if (!lwn_be_insertNetNodes (net, &newnode, 1))
+	return -1;
+
+/* deleting the original Link */
+    i = lwn_be_deleteLinksById (net, &link, 1);
+    if (i != 1)
+	return -1;
+
+/* inserting two new Links */
+    newlink[0].link_id = lwn_be_getNextLinkId (net);
+    if (newlink[0].link_id == -1)
+	return -1;
+    newlink[1].link_id = lwn_be_getNextLinkId (net);
+    if (newlink[1].link_id == -1)
+	return -1;
+
+    newlink[0].start_node = startNode;
+    newlink[0].end_node = newnode.node_id;
+    newlink[0].geom = NULL;
+    newlink[1].start_node = newnode.node_id;
+    newlink[1].end_node = endNode;
+    newlink[1].geom = NULL;
+
+    if (!lwn_be_insertLinks (net, newlink, 2))
+	return -1;
+
+    return newnode.node_id;
+}
+
+LWN_INT64
+lwn_ModLogLinkSplit (LWN_NETWORK * net, LWN_ELEMID link)
+{
+    int i;
+    LWN_LINK *oldlink;
+    LWN_LINK newlink;
+    LWN_ELEMID startNode;
+    LWN_ELEMID endNode;
+    LWN_NET_NODE newnode;
+
+    i = 1;
+    oldlink =
+	lwn_be_getLinkById (net, &link, &i,
+			    LWN_COL_LINK_START_NODE | LWN_COL_LINK_END_NODE);
+    if (!oldlink)
+      {
+	  if (i == -1)
+	      return -1;
+	  else if (i == 0)
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - non-existent link.");
+		return -1;
+	    }
+      }
+    startNode = oldlink->start_node;
+    endNode = oldlink->end_node;
+    _lwn_release_links (oldlink, 1);
+
+/* inserting a new NetNode */
+    newnode.node_id = -1;
+    newnode.geom = NULL;
+    if (!lwn_be_insertNetNodes (net, &newnode, 1))
+	return -1;
+
+/* update the original Link */
+    newlink.link_id = link;
+    newlink.start_node = startNode;
+    newlink.end_node = newnode.node_id;
+    newlink.geom = NULL;
+    if (!lwn_be_updateLinksById (net, &newlink, 1, LWN_COL_LINK_END_NODE))
+	return -1;
+
+/* inserting a new Link */
+    newlink.link_id = lwn_be_getNextLinkId (net);
+    if (newlink.link_id == -1)
+	return -1;
+    newlink.start_node = newnode.node_id;
+    newlink.end_node = endNode;
+    newlink.geom = NULL;
+
+    if (!lwn_be_insertLinks (net, &newlink, 1))
+	return -1;
+
+    return newnode.node_id;
+}
+
+static int
+geo_link_split (LWN_NETWORK * net, const LWN_LINE * oldline,
+		const LWN_POINT * pt, LWN_LINE * newline1, LWN_LINE * newline2)
+{
+    POINTARRAY *pa;
+    POINT4D point;
+    int iv;
+    LWGEOM *lwg_ln;
+    LWGEOM *lwg_pt;
+    LWGEOM *split;
+    LWCOLLECTION *split_col;
+    LWGEOM *lwg = NULL;
+    LWLINE *lwl = NULL;
+    POINT4D pt4d;
+    int ret = 0;
+
+/* creating an LWGEOM Linestring from oldline */
+    pa = ptarray_construct (oldline->has_z, 0, oldline->points);
+    for (iv = 0; iv < oldline->points; iv++)
+      {
+	  /* copying vertices */
+	  point.x = oldline->x[iv];
+	  point.y = oldline->y[iv];
+	  if (oldline->has_z)
+	      point.z = oldline->z[iv];
+	  ptarray_set_point4d (pa, iv, &point);
+      }
+    lwg_ln = (LWGEOM *) lwline_construct (oldline->srid, NULL, pa);
+
+/* creating an LWGEOM Point from pt */
+    pa = ptarray_construct (pt->has_z, 0, 1);
+    point.x = pt->x;
+    point.y = pt->y;
+    if (pt->has_z)
+	point.z = pt->z;
+    ptarray_set_point4d (pa, 0, &point);
+    lwg_pt = (LWGEOM *) lwpoint_construct (oldline->srid, NULL, pa);
+
+/* locking the semaphore */
+    splite_lwgeom_semaphore_lock ();
+
+/* Split link */
+    split = lwgeom_split (lwg_ln, lwg_pt);
+    lwgeom_free (lwg_ln);
+    lwgeom_free (lwg_pt);
+    if (!split)
+      {
+	  lwn_SetErrorMsg (net->be_iface, "could not split link by point ?");
+	  goto end;
+      }
+    split_col = lwgeom_as_lwcollection (split);
+    if (!split_col)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "lwgeom_as_lwcollection returned NULL");
+	  goto end;
+      }
+    if (split_col->ngeoms != 2)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - point not on link.");
+	  goto end;
+      }
+
+/* retrieving the first half of the split link */
+    lwg = split_col->geoms[0];
+    if (lwg->type == LINETYPE)
+      {
+	  lwl = (LWLINE *) lwg;
+	  pa = lwl->points;
+	  newline1->points = pa->npoints;
+	  newline1->x = malloc (sizeof (double) * newline1->points);
+	  newline1->y = malloc (sizeof (double) * newline1->points);
+	  if (newline1->has_z)
+	      newline1->z = malloc (sizeof (double) * newline1->points);
+	  for (iv = 0; iv < newline1->points; iv++)
+	    {
+		/* copying LINESTRING vertices */
+		getPoint4d_p (pa, iv, &pt4d);
+		newline1->x[iv] = pt4d.x;
+		newline1->y[iv] = pt4d.y;
+		if (newline1->has_z)
+		    newline1->z[iv] = pt4d.z;
+	    }
+      }
+    else
+	goto end;
+
+/* retrieving the second half of the split link */
+    lwg = split_col->geoms[1];
+    if (lwg->type == LINETYPE)
+      {
+	  lwl = (LWLINE *) lwg;
+	  pa = lwl->points;
+	  newline2->points = pa->npoints;
+	  newline2->x = malloc (sizeof (double) * newline2->points);
+	  newline2->y = malloc (sizeof (double) * newline2->points);
+	  if (newline2->has_z)
+	      newline2->z = malloc (sizeof (double) * newline2->points);
+	  for (iv = 0; iv < newline2->points; iv++)
+	    {
+		/* copying LINESTRING vertices */
+		getPoint4d_p (pa, iv, &pt4d);
+		newline2->x[iv] = pt4d.x;
+		newline2->y[iv] = pt4d.y;
+		if (newline2->has_z)
+		    newline2->z[iv] = pt4d.z;
+	    }
+      }
+    else
+	goto end;
+
+    ret = 1;
+
+  end:
+    if (split != NULL)
+	lwgeom_free (split);
+/* unlocking the semaphore */
+    splite_lwgeom_semaphore_unlock ();
+    return ret;
+}
+
+static void
+cleanup_line (LWN_LINE * line)
+{
+    if (line->x != NULL)
+	free (line->x);
+    if (line->y != NULL)
+	free (line->y);
+    if (line->z != NULL)
+	free (line->z);
+}
+
+LWN_INT64
+lwn_NewGeoLinkSplit (LWN_NETWORK * net, LWN_ELEMID link, const LWN_POINT * pt)
+{
+    int i;
+    LWN_LINK *oldlink;
+    LWN_LINK newlink[2];
+    LWN_ELEMID startNode;
+    LWN_ELEMID endNode;
+    LWN_NET_NODE newnode;
+    LWN_LINE newline1;
+    LWN_LINE newline2;
+
+    i = 1;
+    oldlink = lwn_be_getLinkById (net, &link, &i, LWN_COL_LINK_ALL);
+    if (!oldlink)
+      {
+	  if (i == -1)
+	      return -1;
+	  else if (i == 0)
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - non-existent link.");
+		return -1;
+	    }
+      }
+    startNode = oldlink->start_node;
+    endNode = oldlink->end_node;
+
+    newline1.srid = oldlink->geom->srid;
+    newline1.has_z = oldlink->geom->has_z;
+    newline1.points = 0;
+    newline1.x = NULL;
+    newline1.y = NULL;
+    newline1.z = NULL;
+    newline2.srid = oldlink->geom->srid;
+    newline2.has_z = oldlink->geom->has_z;
+    newline2.points = 0;
+    newline2.x = NULL;
+    newline2.y = NULL;
+    newline2.z = NULL;
+    if (!geo_link_split (net, oldlink->geom, pt, &newline1, &newline2))
+      {
+	  _lwn_release_links (oldlink, 1);
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+    _lwn_release_links (oldlink, 1);
+
+    if (net->spatial && net->allowCoincident == 0)
+      {
+	  /* check if a coincident node already exists */
+	  if (lwn_be_existsCoincidentNode (net, pt))
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - coincident node");
+		cleanup_line (&newline1);
+		cleanup_line (&newline2);
+		return -1;
+	    }
+      }
+
+/* inserting a new NetNode */
+    newnode.node_id = -1;
+    newnode.geom = (LWN_POINT *) pt;
+    if (!lwn_be_insertNetNodes (net, &newnode, 1))
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+/* deleting the original Link */
+    i = lwn_be_deleteLinksById (net, &link, 1);
+    if (i != 1)
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+/* inserting two new Links */
+    newlink[0].link_id = lwn_be_getNextLinkId (net);
+    if (newlink[0].link_id == -1)
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+    newlink[1].link_id = lwn_be_getNextLinkId (net);
+    if (newlink[1].link_id == -1)
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+    newlink[0].start_node = startNode;
+    newlink[0].end_node = newnode.node_id;
+    newlink[0].geom = &newline1;
+    newlink[1].start_node = newnode.node_id;
+    newlink[1].end_node = endNode;
+    newlink[1].geom = &newline2;
+
+    if (!lwn_be_insertLinks (net, newlink, 2))
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+    cleanup_line (&newline1);
+    cleanup_line (&newline2);
+    return newnode.node_id;
+}
+
+LWN_INT64
+lwn_ModGeoLinkSplit (LWN_NETWORK * net, LWN_ELEMID link, const LWN_POINT * pt)
+{
+    int i;
+    LWN_LINK *oldlink;
+    LWN_LINK newlink;
+    LWN_ELEMID startNode;
+    LWN_ELEMID endNode;
+    LWN_NET_NODE newnode;
+    LWN_LINE newline1;
+    LWN_LINE newline2;
+
+    i = 1;
+    oldlink = lwn_be_getLinkById (net, &link, &i, LWN_COL_LINK_ALL);
+    if (!oldlink)
+      {
+	  if (i == -1)
+	      return -1;
+	  else if (i == 0)
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - non-existent link.");
+		return -1;
+	    }
+      }
+    startNode = oldlink->start_node;
+    endNode = oldlink->end_node;
+
+    newline1.srid = oldlink->geom->srid;
+    newline1.has_z = oldlink->geom->has_z;
+    newline1.points = 0;
+    newline1.x = NULL;
+    newline1.y = NULL;
+    newline1.z = NULL;
+    newline2.srid = oldlink->geom->srid;
+    newline2.has_z = oldlink->geom->has_z;
+    newline2.points = 0;
+    newline2.x = NULL;
+    newline2.y = NULL;
+    newline2.z = NULL;
+    if (!geo_link_split (net, oldlink->geom, pt, &newline1, &newline2))
+      {
+	  _lwn_release_links (oldlink, 1);
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+    _lwn_release_links (oldlink, 1);
+
+    if (net->spatial && net->allowCoincident == 0)
+      {
+	  /* check if a coincident node already exists */
+	  if (lwn_be_existsCoincidentNode (net, pt))
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - coincident node");
+		cleanup_line (&newline1);
+		cleanup_line (&newline2);
+		return -1;
+	    }
+      }
+
+/* inserting a new NetNode */
+    newnode.node_id = -1;
+    newnode.geom = (LWN_POINT *) pt;
+    if (!lwn_be_insertNetNodes (net, &newnode, 1))
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+/* update the original Link */
+    newlink.link_id = link;
+    newlink.start_node = startNode;
+    newlink.end_node = newnode.node_id;
+    newlink.geom = &newline1;
+    if (!lwn_be_updateLinksById
+	(net, &newlink, 1, LWN_COL_LINK_END_NODE | LWN_COL_LINK_GEOM))
+	return -1;
+
+/* inserting a new Link */
+    newlink.link_id = lwn_be_getNextLinkId (net);
+    if (newlink.link_id == -1)
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+    newlink.start_node = newnode.node_id;
+    newlink.end_node = endNode;
+    newlink.geom = &newline2;
+
+    if (!lwn_be_insertLinks (net, &newlink, 1))
+      {
+	  cleanup_line (&newline1);
+	  cleanup_line (&newline2);
+	  return -1;
+      }
+
+    cleanup_line (&newline1);
+    cleanup_line (&newline2);
+    return newnode.node_id;
+}
+
+static int
+_lwn_LinkHeal (LWN_NETWORK * net, LWN_ELEMID eid1, LWN_ELEMID eid2,
+	       LWN_ELEMID * node_id, LWN_ELEMID * start_node,
+	       LWN_ELEMID * end_node, LWN_LINE * newline)
+{
+    int caseno = 0;
+    LWN_ELEMID ids[2];
+    LWN_ELEMID commonnode = -1;
+    LWN_LINK *node_links;
+    int num_node_links;
+    LWN_LINK *links;
+    LWN_LINK *e1 = NULL;
+    LWN_LINK *e2 = NULL;
+    int nlinks, i;
+    int otherlinks = 0;
+
+    /* NOT IN THE SPECS: see if the same link is given twice.. */
+    if (eid1 == eid2)
+      {
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - Cannot heal link with itself.");
+	  return 0;
+      }
+    ids[0] = eid1;
+    ids[1] = eid2;
+    nlinks = 2;
+    links = lwn_be_getLinkById (net, ids, &nlinks, LWN_COL_LINK_ALL);
+    if (nlinks == -1)
+	return -0;
+    for (i = 0; i < nlinks; ++i)
+      {
+	  if (links[i].link_id == eid1)
+	      e1 = &(links[i]);
+	  else if (links[i].link_id == eid2)
+	      e2 = &(links[i]);
+      }
+    if (!e1)
+      {
+	  _lwn_release_links (links, nlinks);
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - non-existent first link.");
+	  return 0;
+      }
+    if (!e2)
+      {
+	  _lwn_release_links (links, nlinks);
+	  lwn_SetErrorMsg (net->be_iface,
+			   "SQL/MM Spatial exception - non-existent second link.");
+	  return 0;
+      }
+
+    /* Find common node */
+
+    if (e1->end_node == e2->start_node)
+      {
+	  commonnode = e1->end_node;
+	  *start_node = e1->start_node;
+	  *end_node = e2->end_node;
+	  caseno = 1;
+      }
+    else if (e1->end_node == e2->end_node)
+      {
+	  commonnode = e1->end_node;
+	  *start_node = e1->start_node;
+	  *end_node = e2->start_node;
+	  caseno = 2;
+      }
+    else if (e1->start_node == e2->start_node)
+      {
+	  commonnode = e1->start_node;
+	  *start_node = e2->end_node;
+	  *end_node = e1->end_node;
+	  caseno = 3;
+      }
+    else if (e1->start_node == e2->end_node)
+      {
+	  commonnode = e1->start_node;
+	  *start_node = e2->start_node;
+	  *end_node = e1->start_node;
+	  caseno = 4;
+      }
+
+    if (e1->geom != NULL && e2->geom != NULL)
+      {
+	  /* reassembling the healed Link geometry */
+	  int iv;
+	  int iv2 = 0;
+	  newline->srid = e1->geom->srid;
+	  newline->has_z = e1->geom->has_z;
+	  newline->points = e1->geom->points + e2->geom->points - 1;
+	  newline->x = malloc (sizeof (double) * newline->points);
+	  newline->y = malloc (sizeof (double) * newline->points);
+	  if (newline->has_z)
+	      newline->z = malloc (sizeof (double) * newline->points);
+	  switch (caseno)
+	    {
+	    case 1:
+		for (iv = 0; iv < e1->geom->points; iv++)
+		  {
+		      newline->x[iv2] = e1->geom->x[iv];
+		      newline->y[iv2] = e1->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e1->geom->z[iv];
+		      iv2++;
+		  }
+		for (iv = 1; iv < e2->geom->points; iv++)
+		  {
+		      newline->x[iv2] = e2->geom->x[iv];
+		      newline->y[iv2] = e2->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e2->geom->z[iv];
+		      iv2++;
+		  }
+		break;
+	    case 2:
+		for (iv = 0; iv < e1->geom->points - 1; iv++)
+		  {
+		      newline->x[iv2] = e1->geom->x[iv];
+		      newline->y[iv2] = e1->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e1->geom->z[iv];
+		      iv2++;
+		  }
+		for (iv = e2->geom->points - 1; iv >= 0; iv--)
+		  {
+		      newline->x[iv2] = e2->geom->x[iv];
+		      newline->y[iv2] = e2->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e2->geom->z[iv];
+		      iv2++;
+		  }
+		break;
+	    case 3:
+		for (iv = e2->geom->points - 1; iv >= 0; iv--)
+		  {
+		      newline->x[iv2] = e2->geom->x[iv];
+		      newline->y[iv2] = e2->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e2->geom->z[iv];
+		      iv2++;
+		  }
+		for (iv = 1; iv < e1->geom->points; iv++)
+		  {
+		      newline->x[iv2] = e1->geom->x[iv];
+		      newline->y[iv2] = e1->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e1->geom->z[iv];
+		      iv2++;
+		  }
+		break;
+	    case 4:
+		for (iv = 0; iv < e2->geom->points; iv++)
+		  {
+		      newline->x[iv2] = e2->geom->x[iv];
+		      newline->y[iv2] = e2->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e2->geom->z[iv];
+		      iv2++;
+		  }
+		for (iv = 1; iv < e1->geom->points; iv++)
+		  {
+		      newline->x[iv2] = e1->geom->x[iv];
+		      newline->y[iv2] = e1->geom->y[iv];
+		      if (newline->has_z)
+			  newline->z[iv2] = e1->geom->z[iv];
+		      iv2++;
+		  }
+		break;
+	    };
+      }
+
+
+    /* Check if any other link is connected to the common node, if found */
+    if (commonnode != -1)
+      {
+	  num_node_links = 1;
+	  node_links = lwn_be_getLinkByNetNode (net, &commonnode,
+						&num_node_links,
+						LWN_COL_LINK_LINK_ID);
+	  if (num_node_links == -1)
+	    {
+		_lwn_release_links (links, nlinks);
+		return 0;
+	    }
+	  for (i = 0; i < num_node_links; ++i)
+	    {
+		if (node_links[i].link_id == eid1)
+		    continue;
+		if (node_links[i].link_id == eid2)
+		    continue;
+		commonnode = -1;
+		otherlinks++;
+	    }
+	  free (node_links);
+      }
+
+    if (commonnode == -1)
+      {
+	  _lwn_release_links (links, nlinks);
+	  if (otherlinks)
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - other links connected.");
+	    }
+	  else
+	    {
+		lwn_SetErrorMsg (net->be_iface,
+				 "SQL/MM Spatial exception - non-connected links.");
+	    }
+	  return 0;
+      }
+    _lwn_release_links (links, nlinks);
+
+    *node_id = commonnode;
+    return 1;
+}
+
+LWN_INT64
+lwn_NewLinkHeal (LWN_NETWORK * net, LWN_ELEMID link, LWN_ELEMID anotherlink)
+{
+    LWN_ELEMID node_id;
+    LWN_ELEMID start_node;
+    LWN_ELEMID end_node;
+    LWN_ELEMID linkids[2];
+    LWN_LINK newlink;
+    LWN_LINE newline;
+    int n;
+
+    newline.points = 0;
+    newline.x = NULL;
+    newline.y = NULL;
+    newline.z = NULL;
+    if (!_lwn_LinkHeal
+	(net, link, anotherlink, &node_id, &start_node, &end_node, &newline))
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+/* removing both Links */
+    linkids[0] = link;
+    linkids[1] = anotherlink;
+    n = lwn_be_deleteLinksById (net, linkids, 2);
+    if (n != 2)
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+/* removing the common NetNode */
+    n = lwn_be_deleteNetNodesById (net, &node_id, 1);
+    if (n == -1)
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+/* inserting a new healed Link */
+    newlink.link_id = -1;
+    newlink.start_node = start_node;
+    newlink.end_node = end_node;
+    if (newline.points == 0)
+	newlink.geom = NULL;
+    else
+	newlink.geom = &newline;
+
+    if (!lwn_be_insertLinks (net, &newlink, 1))
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+    cleanup_line (&newline);
+    return node_id;
+}
+
+LWN_INT64
+lwn_ModLinkHeal (LWN_NETWORK * net, LWN_ELEMID link, LWN_ELEMID anotherlink)
+{
+    LWN_ELEMID node_id;
+    LWN_ELEMID start_node;
+    LWN_ELEMID end_node;
+    LWN_LINK newlink;
+    LWN_LINE newline;
+    int n;
+
+    newline.points = 0;
+    newline.x = NULL;
+    newline.y = NULL;
+    newline.z = NULL;
+    if (!_lwn_LinkHeal
+	(net, link, anotherlink, &node_id, &start_node, &end_node, &newline))
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+/* removing the second Link */
+    n = lwn_be_deleteLinksById (net, &anotherlink, 1);
+    if (n != 1)
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+/* updating the healed link */
+    newlink.link_id = link;
+    newlink.start_node = start_node;
+    newlink.end_node = end_node;
+    if (newline.points == 0)
+	newlink.geom = NULL;
+    else
+	newlink.geom = &newline;
+    if (!lwn_be_updateLinksById
+	(net, &newlink, 1,
+	 LWN_COL_LINK_START_NODE | LWN_COL_LINK_END_NODE | LWN_COL_LINK_GEOM))
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+/* removing the common NetNode */
+    n = lwn_be_deleteNetNodesById (net, &node_id, 1);
+    if (n == -1)
+      {
+	  cleanup_line (&newline);
+	  return -1;
+      }
+
+    cleanup_line (&newline);
+    return node_id;
+}
+
+LWN_ELEMID
+lwn_GetNetNodeByPoint (LWN_NETWORK * net, const LWN_POINT * pt, double tol)
+{
+    LWN_NET_NODE *elem;
+    int num;
+    int flds = LWN_COL_NODE_NODE_ID;
+    LWN_ELEMID id = 0;
+
+    elem = lwn_be_getNetNodeWithinDistance2D (net, pt, tol, &num, flds, 0);
+    if (num <= 0)
+	return -1;
+    else if (num > 1)
+      {
+	  _lwn_release_nodes (elem, num);
+	  lwn_SetErrorMsg (net->be_iface, "Two or more net-nodes found");
+	  return -1;
+      }
+    id = elem[0].node_id;
+    _lwn_release_nodes (elem, num);
+
+    return id;
+}
+
+LWN_ELEMID
+lwn_GetLinkByPoint (LWN_NETWORK * net, const LWN_POINT * pt, double tol)
+{
+    LWN_LINK *elem;
+    int num, i;
+    int flds = LWN_COL_LINK_LINK_ID;
+    LWN_ELEMID id = 0;
+
+    elem = lwn_be_getLinkWithinDistance2D (net, pt, tol, &num, flds, 0);
+    if (num <= 0)
+	return -1;
+    for (i = 0; i < num; ++i)
+      {
+	  LWN_LINK *e = &(elem[i]);
+
+	  if (id)
+	    {
+		_lwn_release_links (elem, num);
+		lwn_SetErrorMsg (net->be_iface, "Two or more links found");
+		return -1;
+	    }
+	  else
+	      id = e->link_id;
+      }
+    _lwn_release_links (elem, num);
+
+    return id;
+}
+
+/* wrappers of backend wrappers... */
+
+int
+lwn_be_existsCoincidentNode (const LWN_NETWORK * net, const LWN_POINT * pt)
+{
+    int exists = 0;
+    lwn_be_getNetNodeWithinDistance2D (net, pt, 0, &exists, 0, -1);
+    if (exists == -1)
+	return 0;
+    return exists;
+}
+
+int
+lwn_be_existsLinkIntersectingPoint (const LWN_NETWORK * net,
+				    const LWN_POINT * pt)
+{
+    int exists = 0;
+    lwn_be_getLinkWithinDistance2D (net, pt, 0, &exists, 0, -1);
+    if (exists == -1)
+	return 0;
+    return exists;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/lwn_network.h b/src/topology/lwn_network.h
new file mode 100644
index 0000000..50e5f8a
--- /dev/null
+++ b/src/topology/lwn_network.h
@@ -0,0 +1,872 @@
+/*
+ lwn_network.h -- Topology-Network abstract multi-backend interface
+  
+ version 4.3, 2015 August 12
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#ifndef LWN_NETWORK_H
+#define LWN_NETWORK_H 1
+
+#include <stdint.h>
+
+/* INT64 */
+typedef int64_t LWN_INT64;
+
+/** Identifier of network element */
+typedef LWN_INT64 LWN_ELEMID;
+
+/*
+ * Geometry elements
+ */
+
+typedef struct
+{
+    int srid;
+    double x;
+    double y;
+    double z;
+    int has_z;
+}
+LWN_POINT;
+
+typedef struct
+{
+    int srid;
+    int points;
+    double *x;
+    double *y;
+    double *z;
+    int has_z;
+}
+LWN_LINE;
+
+typedef struct
+{
+    double min_x;
+    double min_y;
+    double max_x;
+    double max_y;
+}
+LWN_BBOX;
+
+/*
+ * ISO primitive elements
+ */
+
+/** NODE */
+typedef struct
+{
+    LWN_ELEMID node_id;
+    LWN_POINT *geom;
+}
+LWN_NET_NODE;
+
+/** Node fields */
+#define LWN_COL_NODE_NODE_ID         1<<0
+#define LWN_COL_NODE_GEOM            1<<1
+#define LWN_COL_NODE_ALL            (1<<2)-1
+
+/** LINK */
+typedef struct
+{
+    LWN_ELEMID link_id;
+    LWN_ELEMID start_node;
+    LWN_ELEMID end_node;
+    LWN_LINE *geom;
+}
+LWN_LINK;
+
+/** Link fields */
+#define LWN_COL_LINK_LINK_ID         1<<0
+#define LWN_COL_LINK_START_NODE      1<<1
+#define LWN_COL_LINK_END_NODE        1<<2
+#define LWN_COL_LINK_GEOM            1<<3
+#define LWN_COL_LINK_ALL            (1<<4)-1
+
+/*
+ * Backend handling functions
+ */
+
+/* opaque pointers referencing native backend objects */
+
+/**
+ * Backend private data pointer
+ *
+ * Only the backend handler needs to know what it really is.
+ * It will be passed to all registered callback functions.
+ */
+typedef struct LWN_BE_DATA_T LWN_BE_DATA;
+
+/**
+ * Backend interface handler
+ *
+ * Embeds all registered backend callbacks and private data pointer.
+ * Will need to be passed (directly or indirectly) to al public facing
+ * APIs of this library.
+ */
+typedef struct LWN_BE_IFACE_T LWN_BE_IFACE;
+
+/**
+ * Network handler.
+ *
+ * Embeds backend interface handler.
+ * Will need to be passed to all network manipulation APIs
+ * of this library.
+ */
+typedef struct LWN_BE_NETWORK_T LWN_BE_NETWORK;
+
+/**
+ * Structure containing base backend callbacks
+ *
+ * Used for registering into the backend iface
+ */
+typedef struct LWN_BE_CALLBACKS_T
+{
+
+  /**
+   * Create a new network in the backend
+   *
+   * @param name the network name
+   * @param srid the network SRID
+   * @param hasZ non-zero if network primitives should have a Z ordinate
+   * @param spatial determines if this is a Logical or SpatialNetwork
+   * @param coincident_nodes determines if they should de tolerated or not.
+   * @param geos_handle handle to GEOS context.
+   * 
+   * @return a network handler, which embeds the backend data/params
+   *         or NULL on error (@see lastErrorMessage)
+   */
+    LWN_BE_NETWORK *(*createNetwork) (const LWN_BE_DATA * be,
+				      const char *name, int srid, int hasZ,
+				      int spatial, int coincident_nodes,
+				      const void *geos_handle);
+
+  /**
+   * Load a network from the backend
+   *
+   * @param name the network name
+   * @return a network handler, which embeds the backend data/params
+   *         or NULL on error (@see lastErrorMessage)
+   */
+    LWN_BE_NETWORK *(*loadNetworkByName) (const LWN_BE_DATA * be,
+					  const char *name);
+
+  /**
+   * Release memory associated to a backend network
+   *
+   * @param net the backend network handler
+   * @return 1 on success, 0 on error (@see lastErrorMessage)
+   */
+    int (*freeNetwork) (LWN_BE_NETWORK * net);
+
+  /**
+   * Get nodes within distance by point
+   *
+   * @param net the network to act upon
+   * @param pt the query point
+   * @param dist the distance
+   * @param numelems output parameter, gets number of elements found
+   *                 if the return is not null, otherwise see @return
+   *                 section for semantic.
+   * @param fields fields to be filled in the returned structure, see
+   *               LWN_COL_NODE_* macros
+   * @param limit max number of nodes to return, 0 for no limit, -1
+   *              to only check for existance if a matching row.
+   *
+   * @return an array of nodes or null in the following cases:
+   *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
+   *         - limit>0 and no records found ("numelems" is set to 0)
+   *         - error ("numelems" is set to -1)
+   *
+   */
+    LWN_NET_NODE *(*getNetNodeWithinDistance2D) (const LWN_BE_NETWORK * net,
+						 const LWN_POINT * pt,
+						 double dist, int *numelems,
+						 int fields, int limit);
+
+  /**
+   * Get links that start or end on any of the given node identifiers
+   *
+   * @param net the network to act upon
+   * @param ids an array of node identifiers
+   * @param numelems input/output parameter, pass number of node identifiers
+   *                 in the input array, gets number of edges in output array
+   *                 if the return is not null, otherwise see @return
+   *                 section for semantic.
+   * @param fields fields to be filled in the returned structure, see
+   *               LWN_COL_LINK_* macros
+   *
+   * @return an array of links that are incident to a node
+   *         or NULL in the following cases:
+   *         - no link found ("numelems" is set to 0)
+   *         - error ("numelems" is set to -1)
+   *           (@see lastErrorMessage)
+   */
+    LWN_LINK *(*getLinkByNetNode) (const LWN_BE_NETWORK * net,
+				   const LWN_ELEMID * ids, int *numelems,
+				   int fields);
+
+  /**
+   * Get links within distance by point
+   *
+   * @param net the network to act upon
+   * @param pt the query point
+   * @param dist the distance
+   * @param numelems output parameter, gets number of elements found
+   *                 if the return is not null, otherwise see @return
+   *                 section for semantic.
+   * @param fields fields to be filled in the returned structure, see
+   *               LWN_COL_LINK_* macros
+   * @param limit max number of links to return, 0 for no limit, -1
+   *              to only check for existance if a matching row.
+   *
+   * @return an array of links or null in the following cases:
+   *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
+   *         - limit>0 and no records found ("numelems" is set to 0)
+   *         - error ("numelems" is set to -1)
+   *
+   */
+    LWN_LINK *(*getLinkWithinDistance2D) (const LWN_BE_NETWORK * net,
+					  const LWN_POINT * pt, double dist,
+					  int *numelems, int fields, int limit);
+
+  /**
+   * Insert nodes
+   *
+   * Insert node primitives in the network
+   *
+   * @param net the network to act upon
+   * @param nodes the nodes to insert. Those with a node_id set to -1
+   *              it will be replaced to an automatically assigned identifier
+   * @param nelems number of elements in the nodes array
+   *
+   * @return 1 on success, 0 on error (@see lastErrorMessage)
+   */
+    int (*insertNetNodes) (const LWN_BE_NETWORK * net,
+			   LWN_NET_NODE * nodes, int numelems);
+
+  /**
+   * Get nodes by id
+   *
+   * @param net the network to act upon
+   * @param ids an array of element identifiers
+   * @param numelems input/output parameter, pass number of node identifiers
+   *                 in the input array, gets number of node in output array.
+   * @param fields fields to be filled in the returned structure, see
+   *               LWN_COL_NODE_* macros
+   *
+   * @return an array of nodes
+   *         or NULL in the following cases:
+   *         - no node found ("numelems" is set to 0)
+   *         - error ("numelems" is set to -1)
+   *           (@see lastErrorMessage)
+   *
+   */
+    LWN_NET_NODE *(*getNetNodeById) (const LWN_BE_NETWORK * topo,
+				     const LWN_ELEMID * ids, int *numelems,
+				     int fields);
+
+  /**
+   * Update nodes by id
+   *
+   * @param net the network to act upon
+   * @param nodes an array of LWN_NET_NODE objects with selecting id
+   *              and updating fields.
+   * @param numnodes number of nodes in the "nodes" array
+   * @param upd_fields fields to be updated for the selected edges,
+   *                   see LWN_COL_NODE_* macros
+   *
+   * @return number of nodes being updated or -1 on error
+   *         (@see lastErroMessage)
+   */
+    int (*updateNetNodesById) (const LWN_BE_NETWORK * net,
+			       const LWN_NET_NODE * nodes, int numnodes,
+			       int upd_fields);
+
+  /**
+   * Delete nodes by id
+   *
+   * @param net the network to act upon
+   * @param ids an array of node identifiers
+   * @param numelems number of node identifiers in the ids array
+   *
+   * @return number of nodes being deleted or -1 on error
+   *         (@see lastErroMessage)
+   */
+    int (*deleteNetNodesById) (const LWN_BE_NETWORK * net,
+			       const LWN_ELEMID * ids, int numelems);
+
+  /**
+   * Get next available link identifier
+   *
+   * Identifiers returned by this function should not be considered
+   * available anymore.
+   *
+   * @param net the network to act upon
+   *
+   * @return next available link identifier or -1 on error
+   */
+      LWN_ELEMID (*getNextLinkId) (const LWN_BE_NETWORK * net);
+
+  /**
+   * Get nodes within a 2D bounding box
+   *
+   * @param net the network to act upon
+   * @param box the query box
+   * @param numelems output parameter, gets number of elements found
+   *                 if the return is not null, otherwise see @return
+   *                 section for semantic.
+   * @param fields fields to be filled in the returned structure, see
+   *               LWN_COL_NODE_* macros
+   * @param limit max number of nodes to return, 0 for no limit, -1
+   *              to only check for existance if a matching row.
+   *
+   * @return an array of nodes or null in the following cases:
+   *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
+   *         - limit>0 and no records found ("numelems" is set to 0)
+   *         - error ("numelems" is set to -1)
+   *
+   */
+    LWN_NET_NODE *(*getNetNodeWithinBox2D) (const LWN_BE_NETWORK * net,
+					    const LWN_BBOX * box,
+					    int *numelems, int fields,
+					    int limit);
+
+  /**
+   * Get next available link identifier
+   *
+   * Identifiers returned by this function should not be considered
+   * available anymore.
+   *
+   * @param net the network to act upon
+   *
+   * @return next available link identifier or -1 on error
+   */
+      LWN_ELEMID (*getNexLinkId) (const LWN_BE_NETWORK * net);
+
+  /**
+   * Insert links
+   *
+   * Insert link primitives in the network
+   *
+   * @param net the network to act upon
+   * @param links the links to insert. Those with a link_id set to -1
+   *              it will be replaced to an automatically assigned identifier
+   * @param nelems number of elements in the links array
+   *
+   * @return number of inserted links, or -1 (@see lastErrorMessage)
+   */
+    int (*insertLinks) (const LWN_BE_NETWORK * net,
+			LWN_LINK * links, int numelems);
+
+  /**
+   * Update links by id
+   *
+   * @param net the network to act upon
+   * @param links an array of LWN_LINK object with selecting id
+   *              and updating fields.
+   * @param numedges number of links in the "links" array
+   * @param upd_fields fields to be updated for the selected links,
+   *                   see LWN_COL_LINK_* macros
+   *
+   * @return number of links being updated or -1 on error
+   *         (@see lastErroMessage)
+   */
+    int (*updateLinksById) (const LWN_BE_NETWORK * net,
+			    const LWN_LINK * links, int numlinks,
+			    int upd_fields);
+
+  /**
+   * Get link by id
+   *
+   * @param net the network to act upon
+   * @param ids an array of element identifiers
+   * @param numelems input/output parameter, pass number of link identifiers
+   *                 in the input array, gets number of links in output array
+   *                 if the return is not null, otherwise see @return
+   *                 section for semantic.
+   * @param fields fields to be filled in the returned structure, see
+   *               LWN_COL_LINK_* macros
+   *
+   * @return an array of links or NULL in the following cases:
+   *         - none found ("numelems" is set to 0)
+   *         - error ("numelems" is set to -1)
+   */
+    LWN_LINK *(*getLinkById) (const LWN_BE_NETWORK * net,
+			      const LWN_ELEMID * ids, int *numelems,
+			      int fields);
+
+  /**
+   * Delete links by id
+   *
+   * @param net the network to act upon
+   * @param ids an array of link identifiers
+   * @param numelems number of link identifiers in the ids array
+   *
+   * @return number of links being deleted or -1 on error
+   *         (@see lastErroMessage)
+   */
+    int (*deleteLinksById) (const LWN_BE_NETWORK * net,
+			    const LWN_ELEMID * ids, int numelems);
+
+
+  /**
+   * Get network SRID
+   * @return 0 for unknown
+   */
+    int (*netGetSRID) (const LWN_BE_NETWORK * net);
+
+  /**
+   * Get network Z flag
+   * @return 1 if network elements do have Z value, 0 otherwise
+   */
+    int (*netHasZ) (const LWN_BE_NETWORK * net);
+
+  /**
+   * Get network type flag
+   * @return 0 if network is of the Logical Type, 1 otherwise (Spatial)
+   */
+    int (*netIsSpatial) (const LWN_BE_NETWORK * net);
+
+  /**
+   * Get CoincidentNodes flag
+   * @return 1 if newtwork tolerates Coincident Nodes, 0 otherwise (Spatial)
+   */
+    int (*netAllowCoincident) (const LWN_BE_NETWORK * net);
+
+  /**
+   * Get GEOS Handle
+   * @return current GEOS Handle, NULL otherwise
+   */
+    const void *(*netGetGEOS) (const LWN_BE_NETWORK * net);
+
+
+} LWN_BE_CALLBACKS;
+
+
+/**
+ * Create a new backend interface
+ *
+ * Ownership to caller delete with lwn_FreeBackendIface
+ *
+ * @param data Backend data, passed as first parameter to all callback functions
+ */
+LWN_BE_IFACE *lwn_CreateBackendIface (const LWN_BE_DATA * data);
+
+/**
+ * Register backend callbacks into the opaque iface handler
+ *
+ * @param iface the backend interface handler (see lwn_CreateBackendIface)
+ * @param cb a pointer to the callbacks structure; ownership left to caller.
+ */
+void lwn_BackendIfaceRegisterCallbacks (LWN_BE_IFACE * iface,
+					const LWN_BE_CALLBACKS * cb);
+
+/** Release memory associated with an LWB_BE_IFACE */
+void lwn_FreeBackendIface (LWN_BE_IFACE * iface);
+
+/********************************************************************
+ *
+ * End of BE interface
+ *
+ *******************************************************************/
+
+
+/*
+ * Network functions
+ */
+
+/** Opaque network structure
+ *
+ * Embeds backend interface and network
+ */
+typedef struct LWN_NETWORK_T LWN_NETWORK;
+
+
+/********************************************************************
+ *
+ * Error handling functions
+ *
+ *******************************************************************/
+
+/**
+ * Reset the last backend error message
+ *
+ * @oaram iface the backend interface handler (see lwn_CreateBackendIface)
+ */
+void lwn_ResetErrorMsg (LWN_BE_IFACE * iface);
+
+/**
+ * Set the last backend error message
+ *
+ * @oaram iface the backend interface handler (see lwn_CreateBackendIface)
+ * 
+ * @return NULL-terminated error string
+ */
+void lwn_SetErrorMsg (LWN_BE_IFACE * iface, const char *message);
+
+/**
+ * Read last error message from backend
+ *
+ * @oaram iface the backend interface handler (see lwn_CreateBackendIface)
+ * 
+ * @return NULL-terminated error string
+ */
+const char *lwn_GetErrorMsg (LWN_BE_IFACE * iface);
+
+
+/*******************************************************************
+ *
+ * Backend independent Linestring auxiliary functions
+ *
+ *******************************************************************/
+
+/**
+ * Creates a backend independent 2D Point
+ * 
+ * @param srid the network SRID
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * 
+ * @return pointer to a new LWN_POINT
+ */
+LWN_POINT *lwn_create_point2d (int srid, double x, double y);
+
+/**
+ * Creates a backend independent 3D Point
+ * 
+ * @param srid the network SRID
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @param z the Z coordinate
+ * 
+ * @return pointer to a new LWN_POINT
+ */
+LWN_POINT *lwn_create_point3d (int srid, double x, double y, double z);
+
+/**
+ * Free a backend independent Point
+ *
+ * @param ptr pointer to the LWN_POINT to be freed
+ */
+void lwn_free_point (LWN_POINT * ptr);
+
+/**
+ * Initializes a backend independent Linestring
+ *
+ * @param points total number of points
+ * @param srid the network SRID
+ * @param hasz non-zero if network primitives should have a Z ordinate
+ *
+ * @return pointer to a new LWN_LINE
+ */
+LWN_LINE *lwn_alloc_line (int points, int srid, int hasz);
+
+/**
+ * Free a backend independent Linestring
+ *
+ * @param ptr pointer to the LWN_LINE to be freed
+ */
+void lwn_free_line (LWN_LINE * ptr);
+
+
+/*******************************************************************
+ *
+ * Non-ISO signatures here
+ *
+ *******************************************************************/
+
+/**
+ * Initializes a new network
+ *
+ * @param iface the backend interface handler (see lwn_CreateBackendIface)
+ * @param name name of the new network
+ * @param srid the network SRID
+ * @param hasz non-zero if network primitives should have a Z ordinate
+ * @param spatial determines if this is a Logical or SpatialNetwork
+ * @param coincident_nodes determines if they should de tolerated or not.
+ *
+ * @return the handler of the network, or NULL on error
+ *         (lwn error handler will be invoked with error message)
+ */
+LWN_NETWORK *lwn_CreateNetwork (LWN_BE_IFACE * iface, const char *name,
+				int srid, int hasz, int spatial,
+				int coincident_nodes);
+
+/**
+ * Loads an existing network by name from the database
+ *
+ * @param iface the backend interface handler (see lwt_CreateBackendIface)
+ * @param name name of the network to load
+ *
+ * @return the handler of the network, or NULL on error
+ *         (lwn error handler will be invoked with error message)
+ */
+LWN_NETWORK *lwn_LoadNetwork (LWN_BE_IFACE * iface, const char *name);
+
+/**
+ * Drop a network and all its associated objects from the database
+ *
+ * @param net the network to drop
+ */
+void lwn_DropNetwork (LWN_NETWORK * net);
+
+/** Release memory associated with an LWN_NETWORK
+ *
+ * @param net the network to release (it's not removed from db)
+ */
+void lwn_FreeNetwork (LWN_NETWORK * net);
+
+
+/*******************************************************************
+ *
+ * ISO signatures here
+ *
+ *******************************************************************/
+
+/**
+ * Add an isolated node
+ *
+ * For ST_AddIsoNetNode
+ *
+ * @param net the network to operate on
+ * @param pt the node position
+ *
+ * @return ID of the newly added node
+ *
+ */
+LWN_ELEMID lwn_AddIsoNetNode (LWN_NETWORK * net, LWN_POINT * pt);
+
+/**
+ * Move an isolated node
+ *
+ * For ST_MoveIsoNetNode
+ *
+ * @param net the network to operate on
+ * @param node the identifier of the nod to be moved
+ * @param pt the new node position
+ * @return 0 on success, -1 on error
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+int lwn_MoveIsoNetNode (LWN_NETWORK * net, LWN_ELEMID node,
+			const LWN_POINT * pt);
+
+/**
+ * Remove an isolated node
+ *
+ * For ST_RemIsoNetNode
+ *
+ * @param net the network to operate on
+ * @param node the identifier of the node to be moved
+ * @return 0 on success, -1 on error
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+int lwn_RemIsoNetNode (LWN_NETWORK * net, LWN_ELEMID node);
+
+/**
+ * Add a link connecting two existing nodes
+ *
+ * For ST_AddLink
+ *
+ * @param net the network to operate on
+ * @param start_node identifier of the starting node
+ * @param end_node identifier of the ending node
+ * @param geom the link geometry
+ * @return ID of the newly added link, or -1 on error
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_ELEMID lwn_AddLink (LWN_NETWORK * net,
+			LWN_ELEMID startNode, LWN_ELEMID endNode,
+			LWN_LINE * geom);
+
+/**
+ * Changes the shape of a link without affecting the network structure.
+ *
+ * For ST_ChangeLinkGeom
+ *
+ * @param net the network to operate on
+ * @param link the identifier of the link to be changed
+ * @param curve the link geometry
+ * @return 0 on success, -1 on error
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+int lwn_ChangeLinkGeom (LWN_NETWORK * net, LWN_ELEMID link,
+			const LWN_LINE * curve);
+
+/**
+ * Remove a link.
+ *
+ * For ST_RemoveLink
+ *
+ * @param net the network to operate on
+ * @param link the identifier of the link to be removed
+ * @return 0 on success, -1 on error
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+int lwn_RemoveLink (LWN_NETWORK * net, LWN_ELEMID link);
+
+/**
+ * Split a logical link, replacing it with two new links.
+ *
+ * For ST_NewLogLinkSplit
+ *
+ * @param net the network to operate on
+ * @param link the identifier of the link to be split.
+ * @return the ID of the inserted Node; a negative number on failure.
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_INT64 lwn_NewLogLinkSplit (LWN_NETWORK * net, LWN_ELEMID link);
+
+/**
+ * Split a logical link, modifying the original link and adding a new one.
+ * 
+ * For ST:ModLogLinkSplit
+ *
+ * @param net the network to operate on
+ * @param link the identifier of the link to be split.
+ * @return the ID of the inserted Node; a negative number on failure.
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_INT64 lwn_ModLogLinkSplit (LWN_NETWORK * net, LWN_ELEMID link);
+
+/**
+ * Split a spatial link by a node, replacing it with two new links.
+ *
+ * For ST_NewGeoLinkSplit
+ *
+ * @param net the network to operate on
+ * @param link the identifier of the link to be split.
+ * @param pt the point geometry
+ * @return the ID of the inserted Node; a negative number on failure.
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_INT64 lwn_NewGeoLinkSplit (LWN_NETWORK * net, LWN_ELEMID link,
+			       const LWN_POINT * pt);
+
+/**
+ * Split a spatial link by a node, modifying the original link and adding
+ * a new one.
+ *
+ * For ST_ModGeoLinkSplit
+ *
+ * @param net the network to operate on
+ * @param link the identifier of the link to be split.
+ * @param pt the point geometry
+ * @return the ID of the inserted Node; a negative number on failure.
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_INT64 lwn_ModGeoLinkSplit (LWN_NETWORK * net, LWN_ELEMID link,
+			       const LWN_POINT * pt);
+
+/**
+ * Heal two links by deleting the node connecting them, deleting both links,
+ * and replacing them with a new link whose direction is the same as the
+ * first link provided.
+ *
+ * For ST_NewLinkHeal
+ *
+ * @param net the network to operate on
+ * @param link the identifier of a first link.
+ * @param anotherlink the identifier of a second link.
+ * @return the ID of the rmove Node; a negative number on failure.
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_INT64 lwn_NewLinkHeal (LWN_NETWORK * net, LWN_ELEMID link,
+			   LWN_ELEMID anotherlink);
+
+/**
+ * Heal two links by deleting the node connecting them, modfying the first
+ * link provided, and deleting the second link.
+ *
+ * For ST_ModLinkHeal
+ *
+ * @param net the network to operate on
+ * @param link the identifier of a first link.
+ * @param anotherlink the identifier of a second link.
+ * @return the ID of the rmove Node; a negative number on failure.
+ *         (lwn error handler will be invoked with error message)
+ *
+ */
+LWN_INT64 lwn_ModLinkHeal (LWN_NETWORK * net, LWN_ELEMID link,
+			   LWN_ELEMID anotherlink);
+
+/**
+ * Retrieve the id of a net-node at a point location
+ *
+ * For GetNetNodeByNode
+ *
+ * @param net the network to operate on
+ * @param point the point to use for query
+ * @param tol max distance around the given point to look for a net-node
+ * @return a net-node identifier if one is found, 0 if none is found, -1
+ *         on error (multiple net-nodes within distance).
+ *         (lwn error handler will be invoked with error message)
+ */
+LWN_ELEMID lwn_GetNetNodeByPoint (LWN_NETWORK * net, const LWN_POINT * pt,
+				  double tol);
+
+/**
+ * Find the edge-id of a link that intersects a given point
+ *
+ * For GetLinkByPoint
+ *
+ * @param net the network to operate on
+ * @param point the point to use for query
+ * @param tol max distance around the given point to look for an
+ *            intersecting link
+ * @return a link identifier if one is found, 0 if none is found, -1
+ *         on error (multiple links within distance).
+ *         (lwn error handler will be invoked with error message)
+ */
+LWN_ELEMID lwn_GetLinkByPoint (LWN_NETWORK * net, const LWN_POINT * pt,
+			       double tol);
+
+#endif /* LWN_NETWORK_H */
diff --git a/src/headers/spatialite/spatialite.h b/src/topology/lwn_network_private.h
similarity index 58%
copy from src/headers/spatialite/spatialite.h
copy to src/topology/lwn_network_private.h
index 67b784f..069b3cf 100644
--- a/src/headers/spatialite/spatialite.h
+++ b/src/topology/lwn_network_private.h
@@ -1,7 +1,8 @@
-/* 
- spatialite.h -- Gaia support for SQLite extensions
+/*
+ lwn_network_private.h -- private members and methods
+ Topology-Network abstract multi-backend interface
   
- version 4.3, 2015 June 29
+ version 4.3, 2015 August 13
 
  Author: Sandro Furieri a.furieri at lqt.it
 
@@ -23,7 +24,7 @@ The Original Code is the SpatiaLite library
 
 The Initial Developer of the Original Code is Alessandro Furieri
  
-Portions created by the Initial Developer are Copyright (C) 2008-2015
+Portions created by the Initial Developer are Copyright (C) 2015
 the Initial Developer. All Rights Reserved.
 
 Contributor(s):
@@ -42,19 +43,44 @@ the terms of any one of the MPL, the GPL or the LGPL.
  
 */
 
-#include <spatialite_private.h>
-
-SPATIALITE_PRIVATE int virtualshape_extension_init (void *db);
-SPATIALITE_PRIVATE int virtualdbf_extension_init (void *db);
-SPATIALITE_PRIVATE int virtualtext_extension_init (void *db);
-SPATIALITE_PRIVATE int virtualXL_extension_init (void *db);
-SPATIALITE_PRIVATE int virtualnetwork_extension_init (void *db);
-SPATIALITE_PRIVATE int virtualfdo_extension_init (void *db);
-SPATIALITE_PRIVATE int virtualbbox_extension_init (void *db,
-						   const void *p_cache);
-SPATIALITE_PRIVATE int mbrcache_extension_init (void *db);
-SPATIALITE_PRIVATE int virtual_spatialindex_extension_init (void *db);
-SPATIALITE_PRIVATE int virtual_elementary_extension_init (void *db);
-SPATIALITE_PRIVATE int virtual_xpath_extension_init (void *db,
-						     const void *p_cache);
-SPATIALITE_PRIVATE int virtualgpkg_extension_init (void *db);
+#ifndef LWN_NETWORK_PRIVATE_H
+#define LWN_NETWORK_PRIVATE_H 1
+
+
+/************************************************************************
+ *
+ * Generic SQL handler
+ *
+ ************************************************************************/
+
+struct LWN_BE_IFACE_T
+{
+    const LWN_BE_DATA *data;
+    const LWN_BE_CALLBACKS *cb;
+    char *errorMsg;
+};
+
+/************************************************************************
+ *
+ * Internal objects
+ *
+ ************************************************************************/
+
+struct LWN_NETWORK_T
+{
+    LWN_BE_IFACE *be_iface;
+    LWN_BE_NETWORK *be_net;
+    int srid;
+    int hasZ;
+    int spatial;
+    int allowCoincident;
+    const void *geos_handle;
+};
+
+
+int lwn_be_existsCoincidentNode (const LWN_NETWORK * net, const LWN_POINT * pt);
+
+int lwn_be_existsLinkIntersectingPoint (const LWN_NETWORK * net,
+					const LWN_POINT * pt);
+
+#endif /* LWN_NETWORK_PRIVATE_H */
diff --git a/src/topology/net_callbacks.c b/src/topology/net_callbacks.c
new file mode 100644
index 0000000..3dac4d8
--- /dev/null
+++ b/src/topology/net_callbacks.c
@@ -0,0 +1,2333 @@
+/*
+
+ net_callbacks.c -- implementation of Topology-Network callback functions
+    
+ version 4.3, 2015 August 11
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaia_network.h>
+#include <spatialite/gaiaaux.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+
+#include <lwn_network.h>
+
+#include "network_private.h"
+
+struct net_node
+{
+/* a struct wrapping a Network Node */
+    sqlite3_int64 node_id;
+    double x;
+    double y;
+    double z;
+    int has_z;
+    int is_null;
+    struct net_node *next;
+};
+
+struct net_nodes_list
+{
+/* a struct wrapping a list of Network Nodes */
+    struct net_node *first;
+    struct net_node *last;
+    int count;
+};
+
+struct net_link
+{
+/* a struct wrapping a Network Link */
+    sqlite3_int64 link_id;
+    sqlite3_int64 start_node;
+    sqlite3_int64 end_node;
+    gaiaLinestringPtr geom;
+    struct net_link *next;
+};
+
+struct net_links_list
+{
+/* a struct wrapping a list of Network Links */
+    struct net_link *first;
+    struct net_link *last;
+    int count;
+};
+
+static struct net_node *
+create_net_node (sqlite3_int64 node_id, double x, double y, double z, int has_z)
+{
+/* creating a Network Node */
+    struct net_node *ptr = malloc (sizeof (struct net_node));
+    ptr->node_id = node_id;
+    ptr->x = x;
+    ptr->y = y;
+    ptr->z = z;
+    ptr->has_z = has_z;
+    ptr->is_null = 0;
+    ptr->next = NULL;
+    return ptr;
+}
+
+static struct net_node *
+create_net_node_null (sqlite3_int64 node_id)
+{
+/* creating a Network Node - NULL */
+    struct net_node *ptr = malloc (sizeof (struct net_node));
+    ptr->node_id = node_id;
+    ptr->is_null = 1;
+    ptr->next = NULL;
+    return ptr;
+}
+
+static void
+destroy_net_node (struct net_node *ptr)
+{
+/* destroying a Network Node */
+    if (ptr == NULL)
+	return;
+    free (ptr);
+}
+
+static struct net_link *
+create_net_link (sqlite3_int64 link_id, sqlite3_int64 start_node,
+		 sqlite3_int64 end_node, gaiaLinestringPtr ln)
+{
+/* creating a Network Link */
+    struct net_link *ptr = malloc (sizeof (struct net_link));
+    ptr->link_id = link_id;
+    ptr->start_node = start_node;
+    ptr->end_node = end_node;
+    ptr->geom = ln;
+    ptr->next = NULL;
+    return ptr;
+}
+
+static void
+destroy_net_link (struct net_link *ptr)
+{
+/* destroying a Network Link */
+    if (ptr == NULL)
+	return;
+    if (ptr->geom != NULL)
+	gaiaFreeLinestring (ptr->geom);
+    free (ptr);
+}
+
+static struct net_nodes_list *
+create_nodes_list (void)
+{
+/* creating an empty list of Network Nodes */
+    struct net_nodes_list *ptr = malloc (sizeof (struct net_nodes_list));
+    ptr->first = NULL;
+    ptr->last = NULL;
+    ptr->count = 0;
+    return ptr;
+}
+
+static void
+destroy_net_nodes_list (struct net_nodes_list *ptr)
+{
+/* destroying a list of Network Nodes */
+    struct net_node *p;
+    struct net_node *pn;
+    if (ptr == NULL)
+	return;
+
+    p = ptr->first;
+    while (p != NULL)
+      {
+	  pn = p->next;
+	  destroy_net_node (p);
+	  p = pn;
+      }
+    free (ptr);
+}
+
+static void
+add_node_2D (struct net_nodes_list *list, sqlite3_int64 node_id,
+	     double x, double y)
+{
+/* inserting a Network Node 2D into the list */
+    struct net_node *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_net_node (node_id, x, y, 0.0, 0);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static void
+add_node_3D (struct net_nodes_list *list, sqlite3_int64 node_id,
+	     double x, double y, double z)
+{
+/* inserting a Network Node 3D into the list */
+    struct net_node *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_net_node (node_id, x, y, z, 1);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static void
+add_node_null (struct net_nodes_list *list, sqlite3_int64 node_id)
+{
+/* inserting a Network Node (NULL) into the list */
+    struct net_node *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_net_node_null (node_id);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static struct net_links_list *
+create_links_list (void)
+{
+/* creating an empty list of Network Links */
+    struct net_links_list *ptr = malloc (sizeof (struct net_links_list));
+    ptr->first = NULL;
+    ptr->last = NULL;
+    ptr->count = 0;
+    return ptr;
+}
+
+static void
+destroy_links_list (struct net_links_list *ptr)
+{
+/* destroying a list of Network Links */
+    struct net_link *p;
+    struct net_link *pn;
+    if (ptr == NULL)
+	return;
+
+    p = ptr->first;
+    while (p != NULL)
+      {
+	  pn = p->next;
+	  destroy_net_link (p);
+	  p = pn;
+      }
+    free (ptr);
+}
+
+static void
+add_link (struct net_links_list *list, sqlite3_int64 link_id,
+	  sqlite3_int64 start_node, sqlite3_int64 end_node,
+	  gaiaLinestringPtr ln)
+{
+/* inserting a Network Link into the list */
+    struct net_link *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_net_link (link_id, start_node, end_node, ln);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static char *
+do_prepare_read_net_node (const char *network_name, int fields, int spatial,
+			  int has_z)
+{
+/* preparing the auxiliary "read_node" SQL statement */
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    if (fields & LWN_COL_NODE_NODE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, node_id", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s node_id", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_NODE_GEOM && spatial)
+      {
+	  if (comma)
+	      sql =
+		  sqlite3_mprintf ("%s, ST_X(geometry), ST_Y(geometry)", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s ST_X(geometry), ST_Y(geometry)", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+	  if (has_z)
+	    {
+		sql = sqlite3_mprintf ("%s, ST_Z(geometry)", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+      }
+    table = sqlite3_mprintf ("%s_node", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE node_id = ?", prev, xtable);
+    sqlite3_free (prev);
+    free (xtable);
+    return sql;
+}
+
+static int
+do_read_net_node (sqlite3_stmt * stmt, struct net_nodes_list *list,
+		  sqlite3_int64 id, int fields, int spatial, int has_z,
+		  const char *callback_name, char **errmsg)
+{
+/* reading Nodes out from the DBMS */
+    int icol = 0;
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_id = 0;
+		int ok_x = 0;
+		int ok_y = 0;
+		int ok_z = 0;
+		sqlite3_int64 node_id = -1;
+		double x = 0.0;
+		double y = 0.0;
+		double z = 0.0;
+		if (fields & LWN_COL_NODE_NODE_ID)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+			{
+			    node_id = sqlite3_column_int64 (stmt, icol);
+			    ok_id = 1;
+			}
+		      icol++;
+		  }
+		else
+		    ok_id = 1;
+		if (fields & LWN_COL_NODE_GEOM && spatial)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
+			{
+			    x = sqlite3_column_double (stmt, icol);
+			    ok_x = 1;
+			}
+		      icol++;
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
+			{
+			    y = sqlite3_column_double (stmt, icol);
+			    ok_y = 1;
+			}
+		      icol++;
+		      if (has_z)
+			{
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  z = sqlite3_column_double (stmt, icol);
+				  ok_z = 1;
+			      }
+			}
+		  }
+		else
+		  {
+		      ok_x = 1;
+		      ok_y = 1;
+		      ok_z = 1;
+		  }
+		if (!spatial)
+		  {
+		      add_node_null (list, node_id);
+		      *errmsg = NULL;
+		      sqlite3_reset (stmt);
+		      return 1;
+		  }
+		else
+		  {
+		      if (has_z)
+			{
+			    if (ok_id && ok_x && ok_y && ok_z)
+			      {
+				  add_node_3D (list, node_id, x, y, z);
+				  *errmsg = NULL;
+				  sqlite3_reset (stmt);
+				  return 1;
+			      }
+			}
+		      else
+			{
+			    if (ok_id && ok_x && ok_y)
+			      {
+				  add_node_2D (list, node_id, x, y);
+				  *errmsg = NULL;
+				  sqlite3_reset (stmt);
+				  return 1;
+			      }
+			}
+		  }
+		/* an invalid Node has been found */
+		*errmsg =
+		    sqlite3_mprintf
+		    ("%s: found an invalid Node \"%lld\"", callback_name,
+		     node_id);
+		sqlite3_reset (stmt);
+		return 0;
+	    }
+      }
+    *errmsg = NULL;
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static char *
+do_prepare_read_link (const char *network_name, int fields)
+{
+/* preparing the auxiliary "read_link" SQL statement */
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    if (fields & LWN_COL_LINK_LINK_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, link_id", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s link_id", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_LINK_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_LINK_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_LINK_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geometry", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geometry", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    table = sqlite3_mprintf ("%s_link", network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE link_id = ?", prev, xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    return sql;
+}
+
+static int
+do_read_link_row (sqlite3_stmt * stmt, struct net_links_list *list, int fields,
+		  const char *callback_name, char **errmsg)
+{
+/* reading a Link Row out from the resultset */
+    int icol = 0;
+
+    int ok_id = 0;
+    int ok_start = 0;
+    int ok_end = 0;
+    int ok_geom = 0;
+    sqlite3_int64 link_id = -1;
+    sqlite3_int64 start_node = -1;
+    sqlite3_int64 end_node = -1;
+    gaiaGeomCollPtr geom = NULL;
+    gaiaLinestringPtr ln = NULL;
+    if (fields & LWN_COL_LINK_LINK_ID)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		link_id = sqlite3_column_int64 (stmt, icol);
+		ok_id = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_id = 1;
+    if (fields & LWN_COL_LINK_START_NODE)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		start_node = sqlite3_column_int64 (stmt, icol);
+		ok_start = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_start = 1;
+    if (fields & LWN_COL_LINK_END_NODE)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		end_node = sqlite3_column_int64 (stmt, icol);
+		ok_end = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_end = 1;
+    if (fields & LWN_COL_LINK_GEOM)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
+	    {
+		ln = NULL;
+		ok_geom = 1;
+	    }
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_BLOB)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt, icol);
+		int blob_sz = sqlite3_column_bytes (stmt, icol);
+		geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      if (geom->FirstPoint == NULL
+			  && geom->FirstPolygon == NULL
+			  && geom->FirstLinestring ==
+			  geom->LastLinestring && geom->FirstLinestring != NULL)
+			{
+			    ln = geom->FirstLinestring;
+			    ok_geom = 1;
+			    /* releasing ownership on Linestring */
+			    geom->FirstLinestring = NULL;
+			    geom->LastLinestring = NULL;
+			}
+		      gaiaFreeGeomColl (geom);
+		  }
+	    }
+	  icol++;
+      }
+    else
+	ok_geom = 1;
+    if (ok_id && ok_start && ok_end && ok_geom)
+      {
+	  add_link (list, link_id, start_node, end_node, ln);
+	  *errmsg = NULL;
+	  return 1;
+      }
+/* an invalid Link has been found */
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    *errmsg =
+	sqlite3_mprintf
+	("%s: found an invalid Link \"%lld\"", callback_name, link_id);
+    return 0;
+}
+
+static int
+do_read_link (sqlite3_stmt * stmt, struct net_links_list *list,
+	      sqlite3_int64 link_id, int fields, const char *callback_name,
+	      char **errmsg)
+{
+/* reading a single Link out from the DBMS */
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, link_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (!do_read_link_row
+		    (stmt, list, fields, callback_name, errmsg))
+		  {
+		      sqlite3_reset (stmt);
+		      return 0;
+		  }
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static int
+do_read_link_by_net_node (sqlite3_stmt * stmt, struct net_links_list *list,
+			  sqlite3_int64 node_id, int fields,
+			  const char *callback_name, char **errmsg)
+{
+/* reading a single Link out from the DBMS */
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, node_id);
+    sqlite3_bind_int64 (stmt, 2, node_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (!do_read_link_row
+		    (stmt, list, fields, callback_name, errmsg))
+		  {
+		      sqlite3_reset (stmt);
+		      return 0;
+		  }
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+const char *
+netcallback_lastErrorMessage (const LWN_BE_DATA * be)
+{
+    return gaianet_get_last_exception ((GaiaNetworkAccessorPtr) be);
+}
+
+LWN_BE_NETWORK *
+netcallback_loadNetworkByName (const LWN_BE_DATA * be, const char *name)
+{
+/* callback function: loadNetworkByName */
+    struct gaia_network *ptr = (struct gaia_network *) be;
+    char *network_name;
+    int spatial;
+    int srid;
+    int has_z;
+    int allow_coincident;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) ptr->cache;
+
+    if (gaiaReadNetworkFromDBMS
+	(ptr->db_handle, name, &network_name, &spatial, &srid, &has_z,
+	 &allow_coincident))
+      {
+	  ptr->network_name = network_name;
+	  ptr->srid = srid;
+	  ptr->has_z = has_z;
+	  ptr->spatial = spatial;
+	  ptr->allow_coincident = allow_coincident;
+	  /* registering into the Internal Cache double linked list */
+	  if (cache->firstNetwork == NULL)
+	      cache->firstNetwork = ptr;
+	  if (cache->lastNetwork != NULL)
+	    {
+		struct gaia_network *p2 =
+		    (struct gaia_network *) (cache->lastNetwork);
+		p2->next = ptr;
+	    }
+	  cache->lastNetwork = ptr;
+	  return (LWN_BE_NETWORK *) ptr;
+      }
+    else
+	return NULL;
+}
+
+int
+netcallback_freeNetwork (LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: freeNetwork - does nothing */
+    if (lwn_net != NULL)
+	lwn_net = NULL;		/* silencing stupid compiler warnings on unuse args */
+    return 1;
+}
+
+static gaiaGeomCollPtr
+do_convert_lwnline_to_geom (LWN_LINE * line, int srid)
+{
+/* converting an LWN_LINE into a Linestring  */
+    int iv;
+    double ox;
+    double oy;
+    int normalized_points = 0;
+    gaiaLinestringPtr ln;
+    gaiaGeomCollPtr geom;
+    if (line->has_z)
+	geom = gaiaAllocGeomCollXYZ ();
+    else
+	geom = gaiaAllocGeomColl ();
+    for (iv = 0; iv < line->points; iv++)
+      {
+	  /* counting how many duplicate points are there */
+	  double x = line->x[iv];
+	  double y = line->y[iv];
+	  if (iv == 0)
+	      normalized_points++;
+	  else
+	    {
+		if (x == ox && y == oy)
+		    ;
+		else
+		    normalized_points++;
+	    }
+	  ox = x;
+	  oy = y;
+      }
+    ln = gaiaAddLinestringToGeomColl (geom, normalized_points);
+    normalized_points = 0;
+    for (iv = 0; iv < line->points; iv++)
+      {
+	  double x = line->x[iv];
+	  double y = line->y[iv];
+	  double z;
+	  if (iv == 0)
+	      ;
+	  else
+	    {
+		if (x == ox && y == oy)
+		    continue;	/* discarding duplicate points */
+	    }
+	  ox = x;
+	  oy = y;
+	  if (line->has_z)
+	      z = line->z[iv];
+	  if (line->has_z)
+	    {
+		gaiaSetPointXYZ (ln->Coords, normalized_points, x, y, z);
+	    }
+	  else
+	    {
+		gaiaSetPoint (ln->Coords, normalized_points, x, y);
+	    }
+	  normalized_points++;
+      }
+    geom->DeclaredType = GAIA_LINESTRING;
+    geom->Srid = srid;
+
+    return geom;
+}
+
+LWN_NET_NODE *
+netcallback_getNetNodeWithinDistance2D (const LWN_BE_NETWORK * lwn_net,
+					const LWN_POINT * pt, double dist,
+					int *numelems, int fields, int limit)
+{
+/* callback function: getNodeWithinDistance2D */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt;
+    int ret;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct net_nodes_list *list = NULL;
+    LWN_NET_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    if (pt == NULL)
+      {
+	  *numelems = 0;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getNetNodeWithinDistance2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql =
+	      do_prepare_read_net_node (accessor->network_name, fields,
+					accessor->spatial, accessor->has_z);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("Prepare_getNetNodeWithinDistance2D AUX error: \"%s\"",
+		     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		return NULL;
+	    }
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, pt->x);
+    sqlite3_bind_double (stmt, 2, pt->y);
+    sqlite3_bind_double (stmt, 3, dist);
+    sqlite3_bind_double (stmt, 4, pt->x);
+    sqlite3_bind_double (stmt, 5, pt->y);
+    sqlite3_bind_double (stmt, 6, dist);
+    list = create_nodes_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_net_node
+			  (stmt_aux, list, node_id, fields, accessor->spatial,
+			   accessor->has_z,
+			   "netcallback_getNetNodeWithinDistance2D", &msg))
+			{
+			    gaianet_set_last_error_msg (net, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_getNodeWithinDistance2D: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct net_node *p_nd;
+		result = malloc (sizeof (LWN_NET_NODE) * list->count);
+		p_nd = list->first;
+		while (p_nd != NULL)
+		  {
+		      LWN_NET_NODE *nd = result + i;
+		      nd->geom = NULL;
+		      if (fields & LWN_COL_NODE_NODE_ID)
+			  nd->node_id = p_nd->node_id;
+		      if (fields & LWN_COL_NODE_GEOM)
+			{
+			    if (p_nd->is_null)
+				;
+			    else
+			      {
+				  if (accessor->has_z)
+				      nd->geom =
+					  lwn_create_point3d (accessor->srid,
+							      p_nd->x, p_nd->y,
+							      p_nd->z);
+				  else
+				      nd->geom =
+					  lwn_create_point2d (accessor->srid,
+							      p_nd->x, p_nd->y);
+			      }
+			}
+		      i++;
+		      p_nd = p_nd->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_net_nodes_list (list);
+    sqlite3_reset (stmt);
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_net_nodes_list (list);
+    *numelems = -1;
+    sqlite3_reset (stmt);
+    return NULL;
+}
+
+LWN_NET_NODE *
+netcallback_getNetNodeById (const LWN_BE_NETWORK * lwn_net,
+			    const LWN_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getNetNodeById */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt_aux = NULL;
+    int ret;
+    int i;
+    char *sql;
+    struct net_nodes_list *list = NULL;
+    LWN_NET_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    /* preparing the SQL statement */
+    sql =
+	do_prepare_read_net_node (accessor->network_name, fields,
+				  accessor->spatial, accessor->has_z);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getNetNodeById AUX error: \"%s\"",
+			       sqlite3_errmsg (accessor->db_handle));
+	  gaianet_set_last_error_msg (net, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    list = create_nodes_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_net_node
+	      (stmt_aux, list, *(ids + i), fields, accessor->spatial,
+	       accessor->has_z, "netcallback_getNetNodeById", &msg))
+	    {
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no node was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct net_node *p_nd;
+	  result = malloc (sizeof (LWN_NET_NODE) * list->count);
+	  p_nd = list->first;
+	  i = 0;
+	  while (p_nd != NULL)
+	    {
+		LWN_NET_NODE *nd = result + i;
+		nd->geom = NULL;
+		if (fields & LWN_COL_NODE_NODE_ID)
+		    nd->node_id = p_nd->node_id;
+		if (fields & LWN_COL_NODE_GEOM)
+		  {
+		      if (p_nd->is_null)
+			  ;
+		      else
+			{
+			    if (accessor->has_z)
+				nd->geom =
+				    lwn_create_point3d (accessor->srid, p_nd->x,
+							p_nd->y, p_nd->z);
+			    else
+				nd->geom =
+				    lwn_create_point2d (accessor->srid, p_nd->x,
+							p_nd->y);
+			}
+		  }
+		i++;
+		p_nd = p_nd->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_net_nodes_list (list);
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_net_nodes_list (list);
+    *numelems = -1;
+    return NULL;
+}
+
+LWN_LINK *
+netcallback_getLinkWithinDistance2D (const LWN_BE_NETWORK * lwn_net,
+				     const LWN_POINT * pt, double dist,
+				     int *numelems, int fields, int limit)
+{
+/* callback function: getLinkWithinDistance2D */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt;
+    int ret;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct net_links_list *list = NULL;
+    LWN_LINK *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    if (pt == NULL)
+      {
+	  *numelems = 0;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getLinkWithinDistance2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql = do_prepare_read_link (accessor->network_name, fields);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf ("Prepare_getLinkById AUX error: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		return NULL;
+	    }
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, pt->x);
+    sqlite3_bind_double (stmt, 2, pt->y);
+    sqlite3_bind_double (stmt, 3, dist);
+    sqlite3_bind_double (stmt, 4, pt->x);
+    sqlite3_bind_double (stmt, 5, pt->y);
+    sqlite3_bind_double (stmt, 6, dist);
+    list = create_links_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 link_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_link
+			  (stmt_aux, list, link_id, fields,
+			   "netcallback_getLinkWithinDistance2D", &msg))
+			{
+			    gaianet_set_last_error_msg (net, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_getLinkWithinDistance2D: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct net_link *p_lnk;
+		result = malloc (sizeof (LWN_LINK) * list->count);
+		p_lnk = list->first;
+		while (p_lnk != NULL)
+		  {
+		      LWN_LINK *lnk = result + i;
+		      if (fields & LWN_COL_LINK_LINK_ID)
+			  lnk->link_id = p_lnk->link_id;
+		      if (fields & LWN_COL_LINK_START_NODE)
+			  lnk->start_node = p_lnk->start_node;
+		      if (fields & LWN_COL_LINK_END_NODE)
+			  lnk->end_node = p_lnk->end_node;
+		      if (fields & LWN_COL_LINK_GEOM)
+			  lnk->geom =
+			      gaianet_convert_linestring_to_lwnline
+			      (p_lnk->geom, accessor->srid, accessor->has_z);
+		      else
+			  lnk->geom = NULL;
+		      i++;
+		      p_lnk = p_lnk->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_links_list (list);
+    sqlite3_reset (stmt);
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_links_list (list);
+    *numelems = -1;
+    sqlite3_reset (stmt);
+    return NULL;
+}
+
+int
+netcallback_insertNetNodes (const LWN_BE_NETWORK * lwn_net,
+			    LWN_NET_NODE * nodes, int numelems)
+{
+/* callback function: insertNetNodes */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt;
+    int ret;
+    int i;
+    unsigned char *p_blob;
+    int n_bytes;
+    gaiaGeomCollPtr geom = NULL;
+    int gpkg_mode = 0;
+    if (accessor == NULL)
+	return 0;
+
+    stmt = accessor->stmt_insertNetNodes;
+    if (stmt == NULL)
+	return 0;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+    for (i = 0; i < numelems; i++)
+      {
+	  LWN_NET_NODE *nd = nodes + i;
+	  /* setting up the prepared statement */
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (nd->node_id <= 0)
+	      sqlite3_bind_null (stmt, 1);
+	  else
+	      sqlite3_bind_int64 (stmt, 1, nd->node_id);
+	  if (nd->geom == NULL)
+	      sqlite3_bind_null (stmt, 2);
+	  else
+	    {
+		if (accessor->has_z)
+		    geom = gaiaAllocGeomCollXYZ ();
+		else
+		    geom = gaiaAllocGeomColl ();
+		if (accessor->has_z)
+		    gaiaAddPointToGeomCollXYZ (geom, nd->geom->x, nd->geom->y,
+					       nd->geom->z);
+		else
+		    gaiaAddPointToGeomColl (geom, nd->geom->x, nd->geom->y);
+		geom->Srid = accessor->srid;
+		geom->DeclaredType = GAIA_POINT;
+		gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+		gaiaFreeGeomColl (geom);
+		sqlite3_bind_blob (stmt, 2, p_blob, n_bytes, free);
+	    }
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		/* retrieving the PK value */
+		nd->node_id = sqlite3_last_insert_rowid (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_insertNetNodes: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+
+  error:
+    sqlite3_reset (stmt);
+    return 0;
+}
+
+int
+netcallback_updateNetNodesById (const LWN_BE_NETWORK * lwn_net,
+				const LWN_NET_NODE * nodes, int numnodes,
+				int upd_fields)
+{
+/* callback function: updateNetNodesById */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int icol = 1;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_node", accessor->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
+    free (xtable);
+    prev = sql;
+    if (upd_fields & LWN_COL_NODE_NODE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, node_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s node_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWN_COL_NODE_GEOM)
+      {
+	  if (accessor->has_z)
+	    {
+		if (comma)
+		    sql =
+			sqlite3_mprintf
+			("%s, geometry = MakePointZ(?, ?. ?, %d)", prev,
+			 accessor->srid);
+		else
+		    sql =
+			sqlite3_mprintf
+			("%s geometry = MakePointZ(?, ?, ?, %d)", prev,
+			 accessor->srid);
+	    }
+	  else
+	    {
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, geometry = MakePoint(?, ?, %d)",
+					 prev, accessor->srid);
+		else
+		    sql =
+			sqlite3_mprintf ("%s geometry = MakePoint(?, ?, %d)",
+					 prev, accessor->srid);
+	    }
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    sql = sqlite3_mprintf ("%s WHERE node_id = ?", prev);
+    sqlite3_free (prev);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_updateNetNodesById error: \"%s\"",
+			       sqlite3_errmsg (accessor->db_handle));
+	  gaianet_set_last_error_msg (net, msg);
+	  sqlite3_free (msg);
+	  return -1;
+      }
+
+    for (i = 0; i < numnodes; i++)
+      {
+	  /* parameter binding */
+	  const LWN_NET_NODE *nd = nodes + i;
+	  icol = 1;
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (upd_fields & LWN_COL_NODE_NODE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, nd->node_id);
+		icol++;
+	    }
+	  if (upd_fields & LWN_COL_NODE_GEOM)
+	    {
+		if (accessor->spatial)
+		  {
+		      sqlite3_bind_double (stmt, icol, nd->geom->x);
+		      icol++;
+		      sqlite3_bind_double (stmt, icol, nd->geom->y);
+		      icol++;
+		      if (accessor->has_z)
+			{
+			    sqlite3_bind_double (stmt, icol, nd->geom->z);
+			    icol++;
+			}
+		  }
+		else
+		  {
+		      icol += 2;
+		      if (accessor->has_z)
+			  icol++;
+		  }
+	    }
+	  sqlite3_bind_int64 (stmt, icol, nd->node_id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      changed += sqlite3_changes (accessor->db_handle);
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_updateNetNodesById: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    return -1;
+}
+
+int
+netcallback_insertLinks (const LWN_BE_NETWORK * lwn_net, LWN_LINK * links,
+			 int numelems)
+{
+/* callback function: insertLinks */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt;
+    int ret;
+    int i;
+    gaiaGeomCollPtr geom;
+    unsigned char *p_blob;
+    int n_bytes;
+    int gpkg_mode = 0;
+    if (accessor == NULL)
+	return 0;
+
+    stmt = accessor->stmt_insertLinks;
+    if (stmt == NULL)
+	return 0;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+    for (i = 0; i < numelems; i++)
+      {
+	  LWN_LINK *lnk = links + i;
+	  /* setting up the prepared statement */
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (lnk->link_id <= 0)
+	      sqlite3_bind_null (stmt, 1);
+	  else
+	      sqlite3_bind_int64 (stmt, 1, lnk->link_id);
+	  sqlite3_bind_int64 (stmt, 2, lnk->start_node);
+	  sqlite3_bind_int64 (stmt, 3, lnk->end_node);
+	  if (lnk->geom == NULL)
+	      sqlite3_bind_null (stmt, 4);
+	  else
+	    {
+		/* transforming the LWN_LINE into a Geometry-Linestring */
+		geom = do_convert_lwnline_to_geom (lnk->geom, accessor->srid);
+		gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+		gaiaFreeGeomColl (geom);
+		sqlite3_bind_blob (stmt, 4, p_blob, n_bytes, free);
+	    }
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		/* retrieving the PK value */
+		lnk->link_id = sqlite3_last_insert_rowid (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("netcallback_inserLinks: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+
+  error:
+    sqlite3_reset (stmt);
+    return 0;
+}
+
+LWN_LINK *
+netcallback_getLinkByNetNode (const LWN_BE_NETWORK * lwn_net,
+			      const LWN_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getLinkByNetNode */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    int ret;
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+    int i;
+    sqlite3_stmt *stmt_aux = NULL;
+    struct net_links_list *list = NULL;
+    LWN_LINK *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    /* preparing the SQL statement */
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    if (fields & LWN_COL_LINK_LINK_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, link_id", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s link_id", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_LINK_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_LINK_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWN_COL_LINK_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geometry", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geometry", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    table = sqlite3_mprintf ("%s_link", accessor->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("%s FROM MAIN.\"%s\" WHERE start_node = ? OR end_node = ?", prev,
+	 xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+			    &stmt_aux, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getLinkByNetNode AUX error: \"%s\"",
+			       sqlite3_errmsg (accessor->db_handle));
+	  gaianet_set_last_error_msg (net, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    list = create_links_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_link_by_net_node
+	      (stmt_aux, list, *(ids + i), fields,
+	       "netcallback_getLinkByNetNode", &msg))
+	    {
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no link was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct net_link *p_lnk;
+	  result = malloc (sizeof (LWN_LINK) * list->count);
+	  p_lnk = list->first;
+	  i = 0;
+	  while (p_lnk != NULL)
+	    {
+		LWN_LINK *lnk = result + i;
+		lnk->geom = NULL;
+		if (fields & LWN_COL_LINK_LINK_ID)
+		    lnk->link_id = p_lnk->link_id;
+		if (fields & LWN_COL_LINK_START_NODE)
+		    lnk->start_node = p_lnk->start_node;
+		if (fields & LWN_COL_LINK_END_NODE)
+		    lnk->end_node = p_lnk->end_node;
+		if (fields & LWN_COL_LINK_GEOM)
+		    lnk->geom =
+			gaianet_convert_linestring_to_lwnline (p_lnk->geom,
+							       accessor->srid,
+							       accessor->has_z);
+		i++;
+		p_lnk = p_lnk->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_links_list (list);
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_links_list (list);
+    *numelems = -1;
+    return NULL;
+}
+
+int
+netcallback_deleteNetNodesById (const LWN_BE_NETWORK * lwn_net,
+				const LWN_ELEMID * ids, int numelems)
+{
+/* callback function: deleteNetNodesById */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+
+    stmt = accessor->stmt_deleteNetNodesById;
+    if (stmt == NULL)
+	return -1;
+
+    for (i = 0; i < numelems; i++)
+      {
+	  /* parameter binding */
+	  sqlite3_int64 id = *(ids + i);
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_int64 (stmt, 1, id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		changed += sqlite3_changes (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_deleteNetNodesById: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_reset (stmt);
+    return changed;
+
+  error:
+    sqlite3_reset (stmt);
+    return -1;
+}
+
+LWN_NET_NODE *
+netcallback_getNetNodeWithinBox2D (const LWN_BE_NETWORK * lwn_net,
+				   const LWN_BBOX * box, int *numelems,
+				   int fields, int limit)
+{
+/* callback function: getNetNodeWithinBox2D */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt;
+    int ret;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct net_nodes_list *list = NULL;
+    LWN_NET_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getNetNodeWithinBox2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql =
+	      do_prepare_read_net_node (accessor->network_name, fields,
+					accessor->spatial, accessor->has_z);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("Prepare_getNetNodeWithinBox2D AUX error: \"%s\"",
+		     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		return NULL;
+	    }
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, box->min_x);
+    sqlite3_bind_double (stmt, 2, box->min_y);
+    sqlite3_bind_double (stmt, 3, box->max_x);
+    sqlite3_bind_double (stmt, 4, box->max_y);
+    list = create_nodes_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_net_node
+			  (stmt_aux, list, node_id, fields, accessor->spatial,
+			   accessor->has_z, "netcallback_getNetNodeWithinBox2D",
+			   &msg))
+			{
+			    gaianet_set_last_error_msg (net, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_getNetNodeWithinBox2D: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct net_node *p_nd;
+		result = malloc (sizeof (LWN_NET_NODE) * list->count);
+		p_nd = list->first;
+		while (p_nd != NULL)
+		  {
+		      LWN_NET_NODE *nd = result + i;
+		      nd->geom = NULL;
+		      if (fields & LWN_COL_NODE_NODE_ID)
+			  nd->node_id = p_nd->node_id;
+		      if (fields & LWN_COL_NODE_GEOM)
+			{
+			    if (p_nd->is_null)
+				;
+			    else
+			      {
+				  if (accessor->has_z)
+				      nd->geom =
+					  lwn_create_point3d (accessor->srid,
+							      p_nd->x, p_nd->y,
+							      p_nd->z);
+				  else
+				      nd->geom =
+					  lwn_create_point2d (accessor->srid,
+							      p_nd->x, p_nd->y);
+			      }
+			}
+		      i++;
+		      p_nd = p_nd->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_net_nodes_list (list);
+    sqlite3_reset (stmt);
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_net_nodes_list (list);
+    *numelems = 1;
+    sqlite3_reset (stmt);
+    return NULL;
+}
+
+LWN_ELEMID
+netcallback_getNextLinkId (const LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: getNextLinkId */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt_in;
+    sqlite3_stmt *stmt_out;
+    int ret;
+    sqlite3_int64 link_id = -1;
+    if (accessor == NULL)
+	return -1;
+
+    stmt_in = accessor->stmt_getNextLinkId;
+    if (stmt_in == NULL)
+	return -1;
+    stmt_out = accessor->stmt_setNextLinkId;
+    if (stmt_out == NULL)
+	return -1;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	      link_id = sqlite3_column_int64 (stmt_in, 0);
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("netcallback_getNextLinkId: %s",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto stop;
+	    }
+      }
+
+/* updating next_link_id */
+    sqlite3_reset (stmt_out);
+    sqlite3_clear_bindings (stmt_out);
+    ret = sqlite3_step (stmt_out);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+      {
+	  sqlite3_reset (stmt_in);
+	  sqlite3_reset (stmt_out);
+	  return link_id;
+      }
+    else
+      {
+	  char *msg = sqlite3_mprintf ("netcallback_setNextLinkId: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaianet_set_last_error_msg (net, msg);
+	  sqlite3_free (msg);
+	  link_id = -1;
+      }
+  stop:
+    sqlite3_reset (stmt_in);
+    sqlite3_reset (stmt_out);
+    if (link_id >= 0)
+	link_id++;
+    return link_id;
+}
+
+int
+netcallback_updateLinksById (const LWN_BE_NETWORK * lwn_net,
+			     const LWN_LINK * links, int numlinks,
+			     int upd_fields)
+{
+/* callback function: updateLinksById */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt = NULL;
+    gaiaGeomCollPtr geom;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int i;
+    int changed = 0;
+    unsigned char *p_blob;
+    int n_bytes;
+    int gpkg_mode = 0;
+    if (accessor == NULL)
+	return -1;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_link", accessor->network_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
+    free (xtable);
+    prev = sql;
+    if (upd_fields & LWN_COL_LINK_LINK_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, link_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s link_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWN_COL_LINK_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWN_COL_LINK_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWN_COL_LINK_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geometry = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geometry = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    sql = sqlite3_mprintf ("%s WHERE link_id = ?", prev);
+    sqlite3_free (prev);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_updateLinksById error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaianet_set_last_error_msg (net, msg);
+	  sqlite3_free (msg);
+	  return -1;
+      }
+
+    for (i = 0; i < numlinks; i++)
+      {
+	  /* parameter binding */
+	  int icol = 1;
+	  const LWN_LINK *upd_link = links + i;
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (upd_fields & LWN_COL_LINK_LINK_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_link->link_id);
+		icol++;
+	    }
+	  if (upd_fields & LWN_COL_LINK_START_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_link->start_node);
+		icol++;
+	    }
+	  if (upd_fields & LWN_COL_LINK_END_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_link->end_node);
+		icol++;
+	    }
+	  if (upd_fields & LWN_COL_LINK_GEOM)
+	    {
+		if (upd_link->geom == NULL)
+		    sqlite3_bind_null (stmt, icol);
+		else
+		  {
+		      /* transforming the LWN_LINE into a Geometry-Linestring */
+		      geom =
+			  do_convert_lwnline_to_geom (upd_link->geom,
+						      accessor->srid);
+		      gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes,
+						 gpkg_mode);
+		      gaiaFreeGeomColl (geom);
+		      sqlite3_bind_blob (stmt, icol, p_blob, n_bytes, free);
+		  }
+		icol++;
+	    }
+	  sqlite3_bind_int64 (stmt, icol, upd_link->link_id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      changed += sqlite3_changes (accessor->db_handle);
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_updateLinksById: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    return -1;
+}
+
+LWN_LINK *
+netcallback_getLinkById (const LWN_BE_NETWORK * lwn_net,
+			 const LWN_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getLinkById */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt_aux = NULL;
+    int ret;
+    int i;
+    char *sql;
+    struct net_links_list *list = NULL;
+    LWN_LINK *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    /* preparing the SQL statement */
+    sql = do_prepare_read_link (accessor->network_name, fields);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getLinkById AUX error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaianet_set_last_error_msg (net, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    list = create_links_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_link
+	      (stmt_aux, list, *(ids + i), fields, "netcallback_getLinkById",
+	       &msg))
+	    {
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no link was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct net_link *p_lnk;
+	  result = malloc (sizeof (LWN_LINK) * list->count);
+	  p_lnk = list->first;
+	  i = 0;
+	  while (p_lnk != NULL)
+	    {
+		LWN_LINK *lnk = result + i;
+		lnk->geom = NULL;
+		if (fields & LWN_COL_LINK_LINK_ID)
+		    lnk->link_id = p_lnk->link_id;
+		if (fields & LWN_COL_LINK_START_NODE)
+		    lnk->start_node = p_lnk->start_node;
+		if (fields & LWN_COL_LINK_END_NODE)
+		    lnk->end_node = p_lnk->end_node;
+		if (fields & LWN_COL_LINK_GEOM)
+		  {
+		      if (p_lnk->geom == NULL)
+			  lnk->geom = NULL;
+		      else
+			  lnk->geom =
+			      gaianet_convert_linestring_to_lwnline
+			      (p_lnk->geom, accessor->srid, accessor->has_z);
+		  }
+		i++;
+		p_lnk = p_lnk->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_links_list (list);
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_links_list (list);
+    *numelems = -1;
+    return NULL;
+}
+
+int
+netcallback_deleteLinksById (const LWN_BE_NETWORK * lwn_net,
+			     const LWN_ELEMID * ids, int numelems)
+{
+/* callback function: deleteLinksById */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+
+    stmt = accessor->stmt_deleteLinksById;
+    if (stmt == NULL)
+	return -1;
+
+    for (i = 0; i < numelems; i++)
+      {
+	  /* parameter binding */
+	  sqlite3_int64 id = *(ids + i);
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_int64 (stmt, 1, id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		changed += sqlite3_changes (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("netcallback_deleteLinksById: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaianet_set_last_error_msg (net, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_reset (stmt);
+    return changed;
+
+  error:
+    sqlite3_reset (stmt);
+    return -1;
+}
+
+int
+netcallback_netGetSRID (const LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: netGetSRID */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    if (accessor == NULL)
+	return -1;
+
+    return accessor->srid;
+}
+
+int
+netcallback_netHasZ (const LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: netHasZ */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    if (accessor == NULL)
+	return 0;
+
+    return accessor->has_z;
+}
+
+int
+netcallback_netIsSpatial (const LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: netIsSpatial */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    if (accessor == NULL)
+	return 0;
+
+    return accessor->spatial;
+}
+
+int
+netcallback_netAllowCoincident (const LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: netAllowCoincident */
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    if (accessor == NULL)
+	return 0;
+
+    return accessor->allow_coincident;
+}
+
+const void *
+netcallback_netGetGEOS (const LWN_BE_NETWORK * lwn_net)
+{
+/* callback function: netGetGEOS */
+    const struct splite_internal_cache *cache;
+    GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
+    struct gaia_network *accessor = (struct gaia_network *) net;
+    if (accessor == NULL)
+	return NULL;
+    if (accessor->cache == NULL)
+	return NULL;
+
+    cache = (const struct splite_internal_cache *) (accessor->cache);
+    return cache->GEOS_handle;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/network_private.h b/src/topology/network_private.h
new file mode 100644
index 0000000..793fb8c
--- /dev/null
+++ b/src/topology/network_private.h
@@ -0,0 +1,214 @@
+/*
+ network_private.h -- Topology-Network opaque definitions
+  
+ version 4.3, 2015 August 11
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/**
+ \file network_private.h
+
+ SpatiaLite Topology-Network private header file
+ */
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+#ifdef _WIN32
+#ifdef DLL_EXPORT
+#define NETWORK_PRIVATE
+#else
+#define NETWORK_PRIVATE
+#endif
+#else
+#define NETWORK_PRIVATE __attribute__ ((visibility("hidden")))
+#endif
+#endif
+
+struct gaia_network
+{
+/* a struct wrapping a Topology-Network Accessor Object */
+    const void *cache;
+    sqlite3 *db_handle;
+    char *network_name;
+    int spatial;
+    int srid;
+    int has_z;
+    int allow_coincident;
+    char *last_error_message;
+    sqlite3_stmt *stmt_getNetNodeWithinDistance2D;
+    sqlite3_stmt *stmt_getLinkWithinDistance2D;
+    sqlite3_stmt *stmt_insertNetNodes;
+    sqlite3_stmt *stmt_deleteNetNodesById;
+    sqlite3_stmt *stmt_getNetNodeWithinBox2D;
+    sqlite3_stmt *stmt_getNextLinkId;
+    sqlite3_stmt *stmt_setNextLinkId;
+    sqlite3_stmt *stmt_insertLinks;
+    sqlite3_stmt *stmt_deleteLinksById;
+    void *callbacks;
+    void *lwn_iface;
+    void *lwn_network;
+    struct gaia_network *prev;
+    struct gaia_network *next;
+};
+
+/* prototypes for functions handling Topology errors */
+NETWORK_PRIVATE void gaianet_reset_last_error_msg (GaiaNetworkAccessorPtr
+						   accessor);
+
+NETWORK_PRIVATE void gaianet_set_last_error_msg (GaiaNetworkAccessorPtr
+						 accessor, const char *msg);
+
+NETWORK_PRIVATE const char
+    *gaianet_get_last_exception (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE int auxnet_insert_into_network (GaiaNetworkAccessorPtr accessor,
+						gaiaGeomCollPtr geom);
+
+
+/* prototypes for functions creating some SQL prepared statement */
+NETWORK_PRIVATE sqlite3_stmt
+    *
+do_create_stmt_getNetNodeWithinDistance2D (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_getLinkWithinDistance2D (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_insertNetNodes (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_deleteNetNodesById (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_getNetNodeWithinBox2D (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_getNextLinkId (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_setNextLinkId (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_insertLinks (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE sqlite3_stmt
+    * do_create_stmt_deleteLinksById (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE void
+finalize_toponet_prepared_stmts (GaiaNetworkAccessorPtr accessor);
+
+NETWORK_PRIVATE void
+create_toponet_prepared_stmts (GaiaNetworkAccessorPtr accessor);
+
+
+/* common utility */
+NETWORK_PRIVATE LWN_LINE
+    * gaianet_convert_linestring_to_lwnline (gaiaLinestringPtr ln, int srid,
+					     int has_z);
+
+
+/* callback function prototypes */
+const char *netcallback_lastErrorMessage (const LWN_BE_DATA * be);
+
+int netcallback_freeNetwork (LWN_BE_NETWORK * net);
+
+LWN_BE_NETWORK *netcallback_loadNetworkByName (const LWN_BE_DATA * be,
+					       const char *name);
+
+LWN_NET_NODE *netcallback_getNetNodeWithinDistance2D (const LWN_BE_NETWORK *
+						      lwn_net,
+						      const LWN_POINT * pt,
+						      double dist,
+						      int *numelems, int fields,
+						      int limit);
+
+LWN_LINK *netcallback_getLinkWithinDistance2D (const LWN_BE_NETWORK * net,
+					       const LWN_POINT * pt,
+					       double dist, int *numelems,
+					       int fields, int limit);
+
+int netcallback_updateNetNodesById (const LWN_BE_NETWORK * net,
+				    const LWN_NET_NODE * nodes, int numnodes,
+				    int upd_fields);
+
+int netcallback_deleteNetNodesById (const LWN_BE_NETWORK * net,
+				    const LWN_ELEMID * ids, int numnodes);
+
+int netcallback_insertNetNodes (const LWN_BE_NETWORK * net, LWN_NET_NODE * node,
+				int numelems);
+
+LWN_NET_NODE *netcallback_getNetNodeById (const LWN_BE_NETWORK * net,
+					  const LWN_ELEMID * ids, int *numelems,
+					  int fields);
+
+LWN_ELEMID netcallback_getNextLinkId (const LWN_BE_NETWORK * net);
+
+LWN_NET_NODE *netcallback_getNetNodeWithinBox2D (const LWN_BE_NETWORK * net,
+						 const LWN_BBOX * box,
+						 int *numelems, int fields,
+						 int limit);
+
+LWN_ELEMID netcallback_getNextLinkId (const LWN_BE_NETWORK * lwn_net);
+
+int netcallback_insertLinks (const LWN_BE_NETWORK * net,
+			     LWN_LINK * links, int numelems);
+
+int netcallback_updateLinksById (const LWN_BE_NETWORK * net,
+				 const LWN_LINK * links, int numlinks,
+				 int upd_fields);
+
+LWN_LINK *netcallback_getLinkByNetNode (const LWN_BE_NETWORK * net,
+					const LWN_ELEMID * ids, int *numelems,
+					int fields);
+
+LWN_LINK *netcallback_getLinkById (const LWN_BE_NETWORK * lwn_net,
+				   const LWN_ELEMID * ids, int *numelems,
+				   int fields);
+
+int netcallback_deleteLinksById (const LWN_BE_NETWORK * net,
+				 const LWN_ELEMID * ids, int numnodes);
+
+int netcallback_netGetSRID (const LWN_BE_NETWORK * net);
+
+int netcallback_netHasZ (const LWN_BE_NETWORK * net);
+
+int netcallback_netIsSpatial (const LWN_BE_NETWORK * net);
+
+int netcallback_netAllowCoincident (const LWN_BE_NETWORK * net);
+
+const void *netcallback_netGetGEOS (const LWN_BE_NETWORK * net);
diff --git a/src/topology/topo_callbacks.c b/src/topology/topo_callbacks.c
new file mode 100644
index 0000000..459930b
--- /dev/null
+++ b/src/topology/topo_callbacks.c
@@ -0,0 +1,5299 @@
+/*
+
+ topo_callbacks.c -- implementation of Topology callback functions 
+    
+ version 4.3, 2015 July 18
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ -----------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): 
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/*
+ 
+CREDITS:
+
+this module has been completely funded by:
+Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
+(Topology support) 
+
+CIG: 6038019AE5
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#include "config-msvc.h"
+#else
+#include "config.h"
+#endif
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+
+#include <spatialite/sqlite.h>
+#include <spatialite/debug.h>
+#include <spatialite/gaiageo.h>
+#include <spatialite/gaia_topology.h>
+#include <spatialite/gaiaaux.h>
+
+#include <spatialite.h>
+#include <spatialite_private.h>
+
+#include <liblwgeom.h>
+#include <liblwgeom_topo.h>
+
+#include "topology_private.h"
+
+struct topo_node
+{
+/* a struct wrapping a Topology Node */
+    sqlite3_int64 node_id;
+    sqlite3_int64 containing_face;
+    double x;
+    double y;
+    double z;
+    int has_z;
+    struct topo_node *next;
+};
+
+struct topo_nodes_list
+{
+/* a struct wrapping a list of Topology Nodes */
+    struct topo_node *first;
+    struct topo_node *last;
+    int count;
+};
+
+struct topo_edge
+{
+/* a struct wrapping a Topology Edge */
+    sqlite3_int64 edge_id;
+    sqlite3_int64 start_node;
+    sqlite3_int64 end_node;
+    sqlite3_int64 face_left;
+    sqlite3_int64 face_right;
+    sqlite3_int64 next_left;
+    sqlite3_int64 next_right;
+    gaiaLinestringPtr geom;
+    struct topo_edge *next;
+};
+
+struct topo_edges_list
+{
+/* a struct wrapping a list of Topology Edegs */
+    struct topo_edge *first;
+    struct topo_edge *last;
+    int count;
+};
+
+struct topo_face
+{
+/* a struct wrapping a Topology Face */
+    sqlite3_int64 id;
+    sqlite3_int64 face_id;
+    double minx;
+    double miny;
+    double maxx;
+    double maxy;
+    struct topo_face *next;
+};
+
+struct topo_faces_list
+{
+/* a struct wrapping a list of Topology Edegs */
+    struct topo_face *first;
+    struct topo_face *last;
+    int count;
+};
+
+static struct topo_node *
+create_topo_node (sqlite3_int64 node_id, sqlite3_int64 containing_face,
+		  double x, double y, double z, int has_z)
+{
+/* creating a Topology Node */
+    struct topo_node *ptr = malloc (sizeof (struct topo_node));
+    ptr->node_id = node_id;
+    ptr->containing_face = containing_face;
+    ptr->x = x;
+    ptr->y = y;
+    ptr->z = z;
+    ptr->has_z = has_z;
+    ptr->next = NULL;
+    return ptr;
+}
+
+static void
+destroy_topo_node (struct topo_node *ptr)
+{
+/* destroying a Topology Node */
+    if (ptr == NULL)
+	return;
+    free (ptr);
+}
+
+static struct topo_edge *
+create_topo_edge (sqlite3_int64 edge_id, sqlite3_int64 start_node,
+		  sqlite3_int64 end_node, sqlite3_int64 face_left,
+		  sqlite3_int64 face_right, sqlite3_int64 next_left,
+		  sqlite3_int64 next_right, gaiaLinestringPtr ln)
+{
+/* creating a Topology Edge */
+    struct topo_edge *ptr = malloc (sizeof (struct topo_edge));
+    ptr->edge_id = edge_id;
+    ptr->start_node = start_node;
+    ptr->end_node = end_node;
+    ptr->face_left = face_left;
+    ptr->face_right = face_right;
+    ptr->next_left = next_left;
+    ptr->next_right = next_right;
+    ptr->geom = ln;
+    ptr->next = NULL;
+    return ptr;
+}
+
+static void
+destroy_topo_edge (struct topo_edge *ptr)
+{
+/* destroying a Topology Edge */
+    if (ptr == NULL)
+	return;
+    if (ptr->geom != NULL)
+	gaiaFreeLinestring (ptr->geom);
+    free (ptr);
+}
+
+static struct topo_face *
+create_topo_face (sqlite3_int64 id, sqlite3_int64 face_id, double minx,
+		  double miny, double maxx, double maxy)
+{
+/* creating a Topology Face */
+    struct topo_face *ptr = malloc (sizeof (struct topo_face));
+    ptr->id = id;
+    ptr->face_id = face_id;
+    ptr->minx = minx;
+    ptr->miny = miny;
+    ptr->maxx = maxx;
+    ptr->maxy = maxy;
+    ptr->next = NULL;
+    return ptr;
+}
+
+static void
+destroy_topo_face (struct topo_face *ptr)
+{
+/* destroying a Topology Face */
+    if (ptr == NULL)
+	return;
+    free (ptr);
+}
+
+static struct topo_nodes_list *
+create_nodes_list (void)
+{
+/* creating an empty list of Topology Nodes */
+    struct topo_nodes_list *ptr = malloc (sizeof (struct topo_nodes_list));
+    ptr->first = NULL;
+    ptr->last = NULL;
+    ptr->count = 0;
+    return ptr;
+}
+
+static void
+destroy_nodes_list (struct topo_nodes_list *ptr)
+{
+/* destroying a list of Topology Nodes */
+    struct topo_node *p;
+    struct topo_node *pn;
+    if (ptr == NULL)
+	return;
+
+    p = ptr->first;
+    while (p != NULL)
+      {
+	  pn = p->next;
+	  destroy_topo_node (p);
+	  p = pn;
+      }
+    free (ptr);
+}
+
+static void
+add_node_2D (struct topo_nodes_list *list, sqlite3_int64 node_id,
+	     sqlite3_int64 containing_face, double x, double y)
+{
+/* inserting a Topology Node 2D into the list */
+    struct topo_node *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_topo_node (node_id, containing_face, x, y, 0.0, 0);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static void
+add_node_3D (struct topo_nodes_list *list, sqlite3_int64 node_id,
+	     sqlite3_int64 containing_face, double x, double y, double z)
+{
+/* inserting a Topology Node 3D into the list */
+    struct topo_node *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_topo_node (node_id, containing_face, x, y, z, 1);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static struct topo_edges_list *
+create_edges_list (void)
+{
+/* creating an empty list of Topology Edges */
+    struct topo_edges_list *ptr = malloc (sizeof (struct topo_edges_list));
+    ptr->first = NULL;
+    ptr->last = NULL;
+    ptr->count = 0;
+    return ptr;
+}
+
+static void
+destroy_edges_list (struct topo_edges_list *ptr)
+{
+/* destroying a list of Topology Edges */
+    struct topo_edge *p;
+    struct topo_edge *pn;
+    if (ptr == NULL)
+	return;
+
+    p = ptr->first;
+    while (p != NULL)
+      {
+	  pn = p->next;
+	  destroy_topo_edge (p);
+	  p = pn;
+      }
+    free (ptr);
+}
+
+static void
+add_edge (struct topo_edges_list *list, sqlite3_int64 edge_id,
+	  sqlite3_int64 start_node, sqlite3_int64 end_node,
+	  sqlite3_int64 face_left, sqlite3_int64 face_right,
+	  sqlite3_int64 next_left, sqlite3_int64 next_right,
+	  gaiaLinestringPtr ln)
+{
+/* inserting a Topology Edge into the list */
+    struct topo_edge *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = list->first;
+    while (ptr != NULL)
+      {
+	  /* avoiding to insert duplicate entries */
+	  if (ptr->edge_id == edge_id)
+	      return;
+	  ptr = ptr->next;
+      }
+
+    ptr =
+	create_topo_edge (edge_id, start_node, end_node, face_left, face_right,
+			  next_left, next_right, ln);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+static struct topo_faces_list *
+create_faces_list (void)
+{
+/* creating an empty list of Topology Faces */
+    struct topo_faces_list *ptr = malloc (sizeof (struct topo_faces_list));
+    ptr->first = NULL;
+    ptr->last = NULL;
+    ptr->count = 0;
+    return ptr;
+}
+
+static void
+destroy_faces_list (struct topo_faces_list *ptr)
+{
+/* destroying a list of Topology Faces */
+    struct topo_face *p;
+    struct topo_face *pn;
+    if (ptr == NULL)
+	return;
+
+    p = ptr->first;
+    while (p != NULL)
+      {
+	  pn = p->next;
+	  destroy_topo_face (p);
+	  p = pn;
+      }
+    free (ptr);
+}
+
+static void
+add_face (struct topo_faces_list *list, sqlite3_int64 id, sqlite3_int64 face_id,
+	  double minx, double miny, double maxx, double maxy)
+{
+/* inserting a Topology Face into the list */
+    struct topo_face *ptr;
+    if (list == NULL)
+	return;
+
+    ptr = create_topo_face (id, face_id, minx, miny, maxx, maxy);
+    if (list->first == NULL)
+	list->first = ptr;
+    if (list->last != NULL)
+	list->last->next = ptr;
+    list->last = ptr;
+    list->count++;
+}
+
+TOPOLOGY_PRIVATE LWLINE *
+gaia_convert_linestring_to_lwline (gaiaLinestringPtr ln, int srid, int has_z)
+{
+/* converting a Linestring into an LWLINE */
+    POINTARRAY *pa;
+    POINT4D point;
+    int iv;
+    double x;
+    double y;
+    double z;
+    double m;
+
+    pa = ptarray_construct (has_z, 0, ln->Points);
+    for (iv = 0; iv < ln->Points; iv++)
+      {
+	  /* copying vertices */
+	  if (ln->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
+	    }
+	  else if (ln->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (ln->Coords, iv, &x, &y);
+	    }
+	  point.x = x;
+	  point.y = y;
+	  if (has_z)
+	      point.z = z;
+	  ptarray_set_point4d (pa, iv, &point);
+      }
+    return lwline_construct (srid, NULL, pa);
+}
+
+static int
+check_unclosed_ring (gaiaRingPtr rng)
+{
+/* checks if a Ring is closed or not */
+    double x0;
+    double y0;
+    double z0 = 0.0;
+    double m0 = 0.0;
+    double x1;
+    double y1;
+    double z1 = 0.0;
+    double m1 = 0.0;
+    int last = rng->Points - 1;
+    if (rng->DimensionModel == GAIA_XY_Z)
+      {
+	  gaiaGetPointXYZ (rng->Coords, 0, &x0, &y0, &z0);
+      }
+    else if (rng->DimensionModel == GAIA_XY_M)
+      {
+	  gaiaGetPointXYM (rng->Coords, 0, &x0, &y0, &m0);
+      }
+    else if (rng->DimensionModel == GAIA_XY_Z_M)
+      {
+	  gaiaGetPointXYZM (rng->Coords, 0, &x0, &y0, &z0, &m0);
+      }
+    else
+      {
+	  gaiaGetPoint (rng->Coords, 0, &x0, &y0);
+      }
+    if (rng->DimensionModel == GAIA_XY_Z)
+      {
+	  gaiaGetPointXYZ (rng->Coords, last, &x1, &y1, &z1);
+      }
+    else if (rng->DimensionModel == GAIA_XY_M)
+      {
+	  gaiaGetPointXYM (rng->Coords, last, &x1, &y1, &m1);
+      }
+    else if (rng->DimensionModel == GAIA_XY_Z_M)
+      {
+	  gaiaGetPointXYZM (rng->Coords, last, &x1, &y1, &z1, &m1);
+      }
+    else
+      {
+	  gaiaGetPoint (rng->Coords, last, &x1, &y1);
+      }
+    if (x0 == x1 && y0 == y1 && z0 == z1 && m0 == m1)
+	return 0;
+    return 1;
+}
+
+TOPOLOGY_PRIVATE LWPOLY *
+gaia_convert_polygon_to_lwpoly (gaiaPolygonPtr pg, int srid, int has_z)
+{
+/* converting a Polygon into an LWPOLY */
+    int ngeoms;
+    POINTARRAY **ppaa;
+    POINT4D point;
+    gaiaRingPtr rng;
+    int close_ring;
+    int ib;
+    int iv;
+    double x;
+    double y;
+    double z;
+    double m;
+
+    ngeoms = pg->NumInteriors;
+    ppaa = lwalloc (sizeof (POINTARRAY *) * (ngeoms + 1));
+    rng = pg->Exterior;
+    close_ring = check_unclosed_ring (rng);
+    if (close_ring)
+	ppaa[0] = ptarray_construct (has_z, 0, rng->Points + 1);
+    else
+	ppaa[0] = ptarray_construct (has_z, 0, rng->Points);
+    for (iv = 0; iv < rng->Points; iv++)
+      {
+	  /* copying vertices */
+	  if (rng->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
+	    }
+	  else if (rng->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
+	    }
+	  else if (rng->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (rng->Coords, iv, &x, &y);
+	    }
+	  point.x = x;
+	  point.y = y;
+	  if (has_z)
+	      point.z = z;
+	  ptarray_set_point4d (ppaa[0], iv, &point);
+      }
+    if (close_ring)
+      {
+	  /* making an unclosed ring to be closed */
+	  if (rng->DimensionModel == GAIA_XY_Z)
+	    {
+		gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
+	    }
+	  else if (rng->DimensionModel == GAIA_XY_M)
+	    {
+		gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
+	    }
+	  else if (rng->DimensionModel == GAIA_XY_Z_M)
+	    {
+		gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
+	    }
+	  else
+	    {
+		gaiaGetPoint (rng->Coords, 0, &x, &y);
+	    }
+	  point.x = x;
+	  point.y = y;
+	  if (has_z)
+	      point.z = z;
+	  ptarray_set_point4d (ppaa[0], rng->Points, &point);
+      }
+    for (ib = 0; ib < pg->NumInteriors; ib++)
+      {
+	  /* copying vertices - Interior Rings */
+	  rng = pg->Interiors + ib;
+	  close_ring = check_unclosed_ring (rng);
+	  if (close_ring)
+	      ppaa[1 + ib] = ptarray_construct (has_z, 0, rng->Points + 1);
+	  else
+	      ppaa[1 + ib] = ptarray_construct (has_z, 0, rng->Points);
+	  for (iv = 0; iv < rng->Points; iv++)
+	    {
+		/* copying vertices */
+		if (rng->DimensionModel == GAIA_XY_Z)
+		  {
+		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
+		  }
+		else if (rng->DimensionModel == GAIA_XY_M)
+		  {
+		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
+		  }
+		else if (rng->DimensionModel == GAIA_XY_Z_M)
+		  {
+		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
+		  }
+		else
+		  {
+		      gaiaGetPoint (rng->Coords, iv, &x, &y);
+		  }
+		point.x = x;
+		point.y = y;
+		if (has_z)
+		    point.z = z;
+		ptarray_set_point4d (ppaa[1 + ib], iv, &point);
+	    }
+	  if (close_ring)
+	    {
+		/* making an unclosed ring to be closed */
+		if (rng->DimensionModel == GAIA_XY_Z)
+		  {
+		      gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
+		  }
+		else if (rng->DimensionModel == GAIA_XY_M)
+		  {
+		      gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
+		  }
+		else if (rng->DimensionModel == GAIA_XY_Z_M)
+		  {
+		      gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
+		  }
+		else
+		  {
+		      gaiaGetPoint (rng->Coords, 0, &x, &y);
+		  }
+		point.x = x;
+		point.y = y;
+		if (has_z)
+		    point.z = z;
+		ptarray_set_point4d (ppaa[1 + ib], rng->Points, &point);
+	    }
+      }
+    return lwpoly_construct (srid, NULL, ngeoms + 1, ppaa);
+}
+
+static gaiaGeomCollPtr
+do_lwline_to_geom (LWLINE * lwline, int srid)
+{
+/* converting a LWLINE into a Geometry (Linestring) */
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    int has_z = 0;
+    double x;
+    double y;
+    double z;
+    int iv;
+    gaiaGeomCollPtr geom;
+    gaiaLinestringPtr ln;
+
+    pa = lwline->points;
+    if (FLAGS_GET_Z (pa->flags))
+	has_z = 1;
+    if (has_z)
+	geom = gaiaAllocGeomCollXYZ ();
+    else
+	geom = gaiaAllocGeomColl ();
+    ln = gaiaAddLinestringToGeomColl (geom, pa->npoints);
+    for (iv = 0; iv < pa->npoints; iv++)
+      {
+	  /* copying LINESTRING vertices */
+	  getPoint4d_p (pa, iv, &pt4d);
+	  x = pt4d.x;
+	  y = pt4d.y;
+	  if (has_z)
+	      z = pt4d.z;
+	  if (has_z)
+	    {
+		gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
+	    }
+	  else
+	    {
+		gaiaSetPoint (ln->Coords, iv, x, y);
+	    }
+      }
+    geom->DeclaredType = GAIA_LINESTRING;
+    geom->Srid = srid;
+
+    return geom;
+}
+
+static char *
+do_prepare_read_node (const char *topology_name, int fields, int has_z)
+{
+/* preparing the auxiliary "read_node" SQL statement */
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    if (fields & LWT_COL_NODE_NODE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, node_id", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s node_id", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_NODE_CONTAINING_FACE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, containing_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s containing_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_NODE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, ST_X(geom), ST_Y(geom)", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s ST_X(geom), ST_Y(geom)", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+	  if (has_z)
+	    {
+		sql = sqlite3_mprintf ("%s, ST_Z(geom)", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+      }
+    table = sqlite3_mprintf ("%s_node", topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE node_id = ?", prev, xtable);
+    sqlite3_free (prev);
+    free (xtable);
+    return sql;
+}
+
+static int
+do_read_node (sqlite3_stmt * stmt, struct topo_nodes_list *list,
+	      sqlite3_int64 id, int fields, int has_z,
+	      const char *callback_name, char **errmsg)
+{
+/* reading Nodes out from the DBMS */
+    int icol = 0;
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_id = 0;
+		int ok_face = 0;
+		int ok_x = 0;
+		int ok_y = 0;
+		int ok_z = 0;
+		sqlite3_int64 node_id = -1;
+		sqlite3_int64 containing_face = -1;
+		double x = 0.0;
+		double y = 0.0;
+		double z = 0.0;
+		if (fields & LWT_COL_NODE_NODE_ID)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+			{
+			    node_id = sqlite3_column_int64 (stmt, icol);
+			    ok_id = 1;
+			}
+		      icol++;
+		  }
+		else
+		    ok_id = 1;
+		if (fields & LWT_COL_NODE_CONTAINING_FACE)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
+			{
+			    containing_face = -1;
+			    ok_face = 1;
+			}
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+			{
+			    containing_face = sqlite3_column_int64 (stmt, icol);
+			    ok_face = 1;
+			}
+		      icol++;
+		  }
+		else
+		    ok_face = 1;
+		if (fields & LWT_COL_NODE_GEOM)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
+			{
+			    x = sqlite3_column_double (stmt, icol);
+			    ok_x = 1;
+			}
+		      icol++;
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
+			{
+			    y = sqlite3_column_double (stmt, icol);
+			    ok_y = 1;
+			}
+		      icol++;
+		      if (has_z)
+			{
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  z = sqlite3_column_double (stmt, icol);
+				  ok_z = 1;
+			      }
+			}
+		  }
+		else
+		  {
+		      ok_x = 1;
+		      ok_y = 1;
+		      ok_z = 1;
+		  }
+		if (has_z)
+		  {
+		      if (ok_id && ok_face && ok_x && ok_y && ok_z)
+			{
+			    add_node_3D (list, node_id, containing_face, x, y,
+					 z);
+			    *errmsg = NULL;
+			    sqlite3_reset (stmt);
+			    return 1;
+			}
+		  }
+		else
+		  {
+		      if (ok_id && ok_face && ok_x && ok_y)
+			{
+			    add_node_2D (list, node_id, containing_face, x, y);
+			    *errmsg = NULL;
+			    sqlite3_reset (stmt);
+			    return 1;
+			}
+		  }
+		/* an invalid Node has been found */
+		*errmsg =
+		    sqlite3_mprintf
+		    ("%s: found an invalid Node \"%lld\"", callback_name,
+		     node_id);
+		return 0;
+	    }
+      }
+    *errmsg = NULL;
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static int
+do_read_node_by_face (sqlite3_stmt * stmt, struct topo_nodes_list *list,
+		      sqlite3_int64 id, int fields, const GBOX * box, int has_z,
+		      const char *callback_name, char **errmsg)
+{
+/* reading Nodes out from the DBMS */
+    int icol = 0;
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, id);
+    if (box != NULL)
+      {
+	  sqlite3_bind_double (stmt, 2, box->xmin);
+	  sqlite3_bind_double (stmt, 3, box->ymin);
+	  sqlite3_bind_double (stmt, 4, box->xmax);
+	  sqlite3_bind_double (stmt, 5, box->ymax);
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_id = 0;
+		int ok_face = 0;
+		int ok_x = 0;
+		int ok_y = 0;
+		int ok_z = 0;
+		sqlite3_int64 node_id = -1;
+		sqlite3_int64 containing_face = -1;
+		double x = 0.0;
+		double y = 0.0;
+		double z = 0.0;
+		if (fields & LWT_COL_NODE_NODE_ID)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+			{
+			    node_id = sqlite3_column_int64 (stmt, icol);
+			    ok_id = 1;
+			}
+		      icol++;
+		  }
+		else
+		    ok_id = 1;
+		if (fields & LWT_COL_NODE_CONTAINING_FACE)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
+			{
+			    containing_face = -1;
+			    ok_face = 1;
+			}
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+			{
+			    containing_face = sqlite3_column_int64 (stmt, icol);
+			    ok_face = 1;
+			}
+		      icol++;
+		  }
+		else
+		    ok_face = 1;
+		if (fields & LWT_COL_NODE_GEOM)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
+			{
+			    x = sqlite3_column_double (stmt, icol);
+			    ok_x = 1;
+			}
+		      icol++;
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
+			{
+			    y = sqlite3_column_double (stmt, icol);
+			    ok_y = 1;
+			}
+		      icol++;
+		      if (has_z)
+			{
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  z = sqlite3_column_double (stmt, icol);
+				  ok_z = 1;
+			      }
+			}
+		  }
+		else
+		  {
+		      ok_x = 1;
+		      ok_y = 1;
+		      ok_z = 1;
+		  }
+		if (has_z)
+		  {
+		      if (ok_id && ok_face && ok_x && ok_y && ok_z)
+			{
+			    add_node_3D (list, node_id, containing_face, x, y,
+					 z);
+			    *errmsg = NULL;
+			    sqlite3_reset (stmt);
+			    return 1;
+			}
+		  }
+		else
+		  {
+		      if (ok_id && ok_face && ok_x && ok_y)
+			{
+			    add_node_2D (list, node_id, containing_face, x, y);
+			    *errmsg = NULL;
+			    sqlite3_reset (stmt);
+			    return 1;
+			}
+		  }
+		/* an invalid Node has been found */
+		*errmsg =
+		    sqlite3_mprintf
+		    ("%s: found an invalid Node \"%lld\"", callback_name,
+		     node_id);
+		return 0;
+	    }
+      }
+    *errmsg = NULL;
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static char *
+do_prepare_read_edge (const char *topology_name, int fields)
+{
+/* preparing the auxiliary "read_edge" SQL statement */
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    /* unconditionally querying the Edge ID */
+    if (comma)
+	sql = sqlite3_mprintf ("%s, edge_id", prev);
+    else
+	sql = sqlite3_mprintf ("%s edge_id", prev);
+    comma = 1;
+    sqlite3_free (prev);
+    prev = sql;
+    if (fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, left_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s left_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, right_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s right_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_left_edge", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_left_edge", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_right_edge", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_right_edge", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geom", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geom", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    table = sqlite3_mprintf ("%s_edge", topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE edge_id = ?", prev, xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    return sql;
+}
+
+static int
+do_read_edge_row (sqlite3_stmt * stmt, struct topo_edges_list *list, int fields,
+		  const char *callback_name, char **errmsg)
+{
+/* reading an Edge Row out from the resultset */
+    int icol = 0;
+
+    int ok_id = 0;
+    int ok_start = 0;
+    int ok_end = 0;
+    int ok_left = 0;
+    int ok_right = 0;
+    int ok_next_left = 0;
+    int ok_next_right = 0;
+    int ok_geom = 0;
+    sqlite3_int64 edge_id;
+    sqlite3_int64 start_node;
+    sqlite3_int64 end_node;
+    sqlite3_int64 face_left;
+    sqlite3_int64 face_right;
+    sqlite3_int64 next_left_edge;
+    sqlite3_int64 next_right_edge;
+    gaiaGeomCollPtr geom = NULL;
+    gaiaLinestringPtr ln = NULL;
+    /* unconditionally querying the Edge ID */
+    if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+      {
+	  edge_id = sqlite3_column_int64 (stmt, icol);
+	  ok_id = 1;
+      }
+    icol++;
+    if (fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		start_node = sqlite3_column_int64 (stmt, icol);
+		ok_start = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_start = 1;
+    if (fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		end_node = sqlite3_column_int64 (stmt, icol);
+		ok_end = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_end = 1;
+    if (fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		face_left = sqlite3_column_int64 (stmt, icol);
+		ok_left = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_left = 1;
+    if (fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		face_right = sqlite3_column_int64 (stmt, icol);
+		ok_right = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_right = 1;
+    if (fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		next_left_edge = sqlite3_column_int64 (stmt, icol);
+		ok_next_left = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_next_left = 1;
+    if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+	    {
+		next_right_edge = sqlite3_column_int64 (stmt, icol);
+		ok_next_right = 1;
+	    }
+	  icol++;
+      }
+    else
+	ok_next_right = 1;
+    if (fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (sqlite3_column_type (stmt, icol) == SQLITE_BLOB)
+	    {
+		const unsigned char *blob = sqlite3_column_blob (stmt, icol);
+		int blob_sz = sqlite3_column_bytes (stmt, icol);
+		geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
+		if (geom != NULL)
+		  {
+		      if (geom->FirstPoint == NULL
+			  && geom->FirstPolygon == NULL
+			  && geom->FirstLinestring ==
+			  geom->LastLinestring && geom->FirstLinestring != NULL)
+			{
+			    ok_geom = 1;
+			    ln = geom->FirstLinestring;
+			}
+		  }
+	    }
+	  icol++;
+      }
+    else
+	ok_geom = 1;
+    if (ok_id && ok_start && ok_end && ok_left && ok_right
+	&& ok_next_left && ok_next_right && ok_geom)
+      {
+	  add_edge (list, edge_id, start_node, end_node,
+		    face_left, face_right, next_left_edge, next_right_edge, ln);
+	  if (geom != NULL)
+	    {
+		/* releasing ownership on Linestring */
+		geom->FirstLinestring = NULL;
+		geom->LastLinestring = NULL;
+		gaiaFreeGeomColl (geom);
+	    }
+	  *errmsg = NULL;
+	  return 1;
+      }
+/* an invalid Edge has been found */
+    if (geom != NULL)
+	gaiaFreeGeomColl (geom);
+    *errmsg =
+	sqlite3_mprintf
+	("%s: found an invalid Edge \"%lld\"", callback_name, edge_id);
+    return 0;
+}
+
+static int
+do_read_edge (sqlite3_stmt * stmt, struct topo_edges_list *list,
+	      sqlite3_int64 edge_id, int fields, const char *callback_name,
+	      char **errmsg)
+{
+/* reading a single Edge out from the DBMS */
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, edge_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (!do_read_edge_row
+		    (stmt, list, fields, callback_name, errmsg))
+		  {
+		      sqlite3_reset (stmt);
+		      return 0;
+		  }
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static int
+do_read_edge_by_node (sqlite3_stmt * stmt, struct topo_edges_list *list,
+		      sqlite3_int64 node_id, int fields,
+		      const char *callback_name, char **errmsg)
+{
+/* reading a single Edge out from the DBMS */
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, node_id);
+    sqlite3_bind_int64 (stmt, 2, node_id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (!do_read_edge_row
+		    (stmt, list, fields, callback_name, errmsg))
+		  {
+		      sqlite3_reset (stmt);
+		      return 0;
+		  }
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static int
+do_read_edge_by_face (sqlite3_stmt * stmt, struct topo_edges_list *list,
+		      sqlite3_int64 face_id, int fields, const GBOX * box,
+		      const char *callback_name, char **errmsg)
+{
+/* reading a single Edge out from the DBMS */
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_int64 (stmt, 1, face_id);
+    sqlite3_bind_int64 (stmt, 2, face_id);
+    if (box != NULL)
+      {
+	  sqlite3_bind_double (stmt, 3, box->xmin);
+	  sqlite3_bind_double (stmt, 4, box->ymin);
+	  sqlite3_bind_double (stmt, 5, box->xmax);
+	  sqlite3_bind_double (stmt, 6, box->ymax);
+      }
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (!do_read_edge_row
+		    (stmt, list, fields, callback_name, errmsg))
+		  {
+		      sqlite3_reset (stmt);
+		      return 0;
+		  }
+	    }
+      }
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+static int
+do_read_face (sqlite3_stmt * stmt, struct topo_faces_list *list,
+	      sqlite3_int64 id, int fields, const char *callback_name,
+	      char **errmsg)
+{
+/* reading Faces out from the DBMS */
+    int icol = 0;
+    int ret;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    if (id <= 0)
+	sqlite3_bind_int64 (stmt, 1, 0);
+    else
+	sqlite3_bind_int64 (stmt, 1, id);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		int ok_id = 0;
+		int ok_minx = 0;
+		int ok_miny = 0;
+		int ok_maxx = 0;
+		int ok_maxy = 0;
+		sqlite3_int64 face_id = -1;
+		double minx = 0.0;
+		double miny = 0.0;
+		double maxx = 0.0;
+		double maxy = 0.0;
+		if (fields & LWT_COL_FACE_FACE_ID)
+		  {
+		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
+			{
+			    face_id = sqlite3_column_int64 (stmt, icol);
+			    ok_id = 1;
+			}
+		      icol++;
+		  }
+		else
+		    ok_id = 1;
+		if (fields & LWT_COL_FACE_MBR)
+		  {
+		      if (id <= 0)
+			{
+			    ok_minx = 1;
+			    ok_miny = 1;
+			    ok_maxx = 1;
+			    ok_maxy = 1;
+			}
+		      else
+			{
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  minx = sqlite3_column_double (stmt, icol);
+				  ok_minx = 1;
+			      }
+			    icol++;
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  miny = sqlite3_column_double (stmt, icol);
+				  ok_miny = 1;
+			      }
+			    icol++;
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  maxx = sqlite3_column_double (stmt, icol);
+				  ok_maxx = 1;
+			      }
+			    icol++;
+			    if (sqlite3_column_type (stmt, icol) ==
+				SQLITE_FLOAT)
+			      {
+				  maxy = sqlite3_column_double (stmt, icol);
+				  ok_maxy = 1;
+			      }
+			    icol++;
+			}
+		  }
+		else
+		  {
+		      ok_minx = 1;
+		      ok_miny = 1;
+		      ok_maxx = 1;
+		      ok_maxy = 1;
+		  }
+		if (ok_id && ok_minx && ok_miny && ok_maxx && ok_maxy)
+		  {
+		      add_face (list, id, face_id, minx, miny, maxx, maxy);
+		      *errmsg = NULL;
+		      sqlite3_reset (stmt);
+		      return 1;
+		  }
+		/* an invalid Face has been found */
+		*errmsg =
+		    sqlite3_mprintf
+		    ("%s: found an invalid Face \"%lld\"", callback_name,
+		     face_id);
+		sqlite3_reset (stmt);
+		return 0;
+	    }
+      }
+    *errmsg = NULL;
+    sqlite3_reset (stmt);
+    return 1;
+}
+
+const char *
+callback_lastErrorMessage (const LWT_BE_DATA * be)
+{
+    return gaiatopo_get_last_exception ((GaiaTopologyAccessorPtr) be);
+}
+
+LWT_BE_TOPOLOGY *
+callback_loadTopologyByName (const LWT_BE_DATA * be, const char *name)
+{
+/* callback function: loadTopologyByName */
+    struct gaia_topology *ptr = (struct gaia_topology *) be;
+    char *topology_name;
+    int srid;
+    double tolerance;
+    int has_z;
+    struct splite_internal_cache *cache =
+	(struct splite_internal_cache *) ptr->cache;
+
+    if (gaiaReadTopologyFromDBMS
+	(ptr->db_handle, name, &topology_name, &srid, &tolerance, &has_z))
+      {
+	  ptr->topology_name = topology_name;
+	  ptr->srid = srid;
+	  ptr->tolerance = tolerance;
+	  ptr->has_z = has_z;
+	  /* registering into the Internal Cache double linked list */
+	  if (cache->firstTopology == NULL)
+	      cache->firstTopology = ptr;
+	  if (cache->lastTopology != NULL)
+	    {
+		struct gaia_topology *p2 =
+		    (struct gaia_topology *) (cache->lastTopology);
+		p2->next = ptr;
+	    }
+	  cache->lastTopology = ptr;
+	  return (LWT_BE_TOPOLOGY *) ptr;
+      }
+    else
+	return NULL;
+}
+
+int
+callback_freeTopology (LWT_BE_TOPOLOGY * lwt_topo)
+{
+/* callback function: freeTopology - does nothing */
+    if (lwt_topo != NULL)
+	lwt_topo = NULL;	/* silencing stupid compiler warnings on unuse args */
+    return 1;
+}
+
+LWT_ISO_NODE *
+callback_getNodeById (const LWT_BE_TOPOLOGY * lwt_topo,
+		      const LWT_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getNodeById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt_aux = NULL;
+    int ret;
+    int i;
+    char *sql;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    struct topo_nodes_list *list = NULL;
+    LWT_ISO_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    /* preparing the SQL statement */
+    sql =
+	do_prepare_read_node (accessor->topology_name, fields, accessor->has_z);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getNodeById AUX error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  accessor->inside_lwt_callback = 0;
+	  return NULL;
+      }
+
+    list = create_nodes_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_node
+	      (stmt_aux, list, *(ids + i), fields, accessor->has_z,
+	       "callback_getNodeById", &msg))
+	    {
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no node was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct topo_node *p_nd;
+	  result = lwalloc (sizeof (LWT_ISO_NODE) * list->count);
+	  p_nd = list->first;
+	  i = 0;
+	  while (p_nd != NULL)
+	    {
+		LWT_ISO_NODE *nd = result + i;
+		if (fields & LWT_COL_NODE_NODE_ID)
+		    nd->node_id = p_nd->node_id;
+		if (fields & LWT_COL_NODE_CONTAINING_FACE)
+		    nd->containing_face = p_nd->containing_face;
+		if (fields & LWT_COL_NODE_GEOM)
+		  {
+		      pa = ptarray_construct (accessor->has_z, 0, 1);
+		      pt4d.x = p_nd->x;
+		      pt4d.y = p_nd->y;
+		      if (accessor->has_z)
+			  pt4d.z = p_nd->z;
+		      ptarray_set_point4d (pa, 0, &pt4d);
+		      nd->geom = lwpoint_construct (accessor->srid, NULL, pa);
+		  }
+		i++;
+		p_nd = p_nd->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_nodes_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_nodes_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ISO_NODE *
+callback_getNodeWithinDistance2D (const LWT_BE_TOPOLOGY * lwt_topo,
+				  const LWPOINT * pt, double dist,
+				  int *numelems, int fields, int limit)
+{
+/* callback function: getNodeWithinDistance2D */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    double cx;
+    double cy;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct topo_nodes_list *list = NULL;
+    LWT_ISO_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getNodeWithinDistance2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql =
+	      do_prepare_read_node (accessor->topology_name, fields,
+				    accessor->has_z);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("Prepare_getNodeWithinDistance2D AUX error: \"%s\"",
+		     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		accessor->inside_lwt_callback = 0;
+		return NULL;
+	    }
+      }
+
+/* extracting X and Y from LWPOINT */
+    pa = pt->point;
+    getPoint4d_p (pa, 0, &pt4d);
+    cx = pt4d.x;
+    cy = pt4d.y;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, cx);
+    sqlite3_bind_double (stmt, 2, cy);
+    sqlite3_bind_double (stmt, 3, dist);
+    sqlite3_bind_double (stmt, 4, cx);
+    sqlite3_bind_double (stmt, 5, cy);
+    sqlite3_bind_double (stmt, 6, dist);
+    list = create_nodes_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_node
+			  (stmt_aux, list, node_id, fields, accessor->has_z,
+			   "callback_getNodeWithinDistance2D", &msg))
+			{
+			    gaiatopo_set_last_error_msg (topo, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("callback_getNodeWithinDistance2D: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct topo_node *p_nd;
+		result = lwalloc (sizeof (LWT_ISO_NODE) * list->count);
+		p_nd = list->first;
+		while (p_nd != NULL)
+		  {
+		      LWT_ISO_NODE *nd = result + i;
+		      if (fields & LWT_COL_NODE_NODE_ID)
+			  nd->node_id = p_nd->node_id;
+		      if (fields & LWT_COL_NODE_CONTAINING_FACE)
+			  nd->containing_face = p_nd->containing_face;
+		      if (fields & LWT_COL_NODE_GEOM)
+			{
+			    pa = ptarray_construct (accessor->has_z, 0, 1);
+			    pt4d.x = p_nd->x;
+			    pt4d.y = p_nd->y;
+			    if (accessor->has_z)
+				pt4d.z = p_nd->z;
+			    ptarray_set_point4d (pa, 0, &pt4d);
+			    nd->geom =
+				lwpoint_construct (accessor->srid, NULL, pa);
+			}
+		      i++;
+		      p_nd = p_nd->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_nodes_list (list);
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return result;
+
+  error:
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_nodes_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+int
+callback_insertNodes (const LWT_BE_TOPOLOGY * lwt_topo, LWT_ISO_NODE * nodes,
+		      int numelems)
+{
+/* callback function: insertNodes */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    int i;
+    double x;
+    double y;
+    double z;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    gaiaGeomCollPtr geom;
+    unsigned char *p_blob;
+    int n_bytes;
+    int gpkg_mode = 0;
+    if (accessor == NULL)
+	return 0;
+
+    stmt = accessor->stmt_insertNodes;
+    if (stmt == NULL)
+	return 0;
+    accessor->inside_lwt_callback = 1;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+    for (i = 0; i < numelems; i++)
+      {
+	  LWT_ISO_NODE *nd = nodes + i;
+	  /* setting up the prepared statement */
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (nd->node_id <= 0)
+	      sqlite3_bind_null (stmt, 1);
+	  else
+	      sqlite3_bind_int64 (stmt, 1, nd->node_id);
+	  if (nd->containing_face < 0)
+	      sqlite3_bind_null (stmt, 2);
+	  else
+	      sqlite3_bind_int64 (stmt, 2, nd->containing_face);
+	  if (accessor->has_z)
+	      geom = gaiaAllocGeomCollXYZ ();
+	  else
+	      geom = gaiaAllocGeomColl ();
+	  /* extracting X and Y from LWPOINT */
+	  pa = nd->geom->point;
+	  getPoint4d_p (pa, 0, &pt4d);
+	  x = pt4d.x;
+	  y = pt4d.y;
+	  if (accessor->has_z)
+	    {
+		z = pt4d.z;
+		gaiaAddPointToGeomCollXYZ (geom, x, y, z);
+	    }
+	  else
+	      gaiaAddPointToGeomColl (geom, x, y);
+	  geom->Srid = accessor->srid;
+	  geom->DeclaredType = GAIA_POINT;
+	  gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+	  gaiaFreeGeomColl (geom);
+	  sqlite3_bind_blob (stmt, 3, p_blob, n_bytes, free);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		/* retrieving the PK value */
+		nd->node_id = sqlite3_last_insert_rowid (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_insertNodes: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return 1;
+
+  error:
+    sqlite3_reset (stmt);
+    accessor->inside_lwt_callback = 0;
+    return 0;
+}
+
+LWT_ISO_EDGE *
+callback_getEdgeById (const LWT_BE_TOPOLOGY * lwt_topo,
+		      const LWT_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getEdgeById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    int ret;
+    int i;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct topo_edges_list *list = NULL;
+    LWT_ISO_EDGE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    /* preparing the SQL statement */
+    sql = do_prepare_read_edge (accessor->topology_name, fields);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+			    &stmt_aux, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getEdgeById AUX error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  accessor->inside_lwt_callback = 0;
+	  return NULL;
+      }
+
+    list = create_edges_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_edge
+	      (stmt_aux, list, *(ids + i), fields, "callback_getEdgeById",
+	       &msg))
+	    {
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no edge was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct topo_edge *p_ed;
+	  result = lwalloc (sizeof (LWT_ISO_EDGE) * list->count);
+	  p_ed = list->first;
+	  i = 0;
+	  while (p_ed != NULL)
+	    {
+		LWT_ISO_EDGE *ed = result + i;
+		if (fields & LWT_COL_EDGE_EDGE_ID)
+		    ed->edge_id = p_ed->edge_id;
+		if (fields & LWT_COL_EDGE_START_NODE)
+		    ed->start_node = p_ed->start_node;
+		if (fields & LWT_COL_EDGE_END_NODE)
+		    ed->end_node = p_ed->end_node;
+		if (fields & LWT_COL_EDGE_FACE_LEFT)
+		    ed->face_left = p_ed->face_left;
+		if (fields & LWT_COL_EDGE_FACE_RIGHT)
+		    ed->face_right = p_ed->face_right;
+		if (fields & LWT_COL_EDGE_NEXT_LEFT)
+		    ed->next_left = p_ed->next_left;
+		if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+		    ed->next_right = p_ed->next_right;
+		if (fields & LWT_COL_EDGE_GEOM)
+		    ed->geom =
+			gaia_convert_linestring_to_lwline (p_ed->geom,
+							   accessor->srid,
+							   accessor->has_z);
+		i++;
+		p_ed = p_ed->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_edges_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_edges_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ISO_EDGE *
+callback_getEdgeWithinDistance2D (const LWT_BE_TOPOLOGY * lwt_topo,
+				  const LWPOINT * pt, double dist,
+				  int *numelems, int fields, int limit)
+{
+/* callback function: getEdgeWithinDistance2D */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    double cx;
+    double cy;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct topo_edges_list *list = NULL;
+    LWT_ISO_EDGE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getEdgeWithinDistance2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql = do_prepare_read_edge (accessor->topology_name, fields);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf ("Prepare_getEdgeById AUX error: \"%s\"",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		accessor->inside_lwt_callback = 0;
+		return NULL;
+	    }
+      }
+
+/* extracting X and Y from LWPOINT */
+    pa = pt->point;
+    getPoint4d_p (pa, 0, &pt4d);
+    cx = pt4d.x;
+    cy = pt4d.y;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, cx);
+    sqlite3_bind_double (stmt, 2, cy);
+    sqlite3_bind_double (stmt, 3, dist);
+    sqlite3_bind_double (stmt, 4, cx);
+    sqlite3_bind_double (stmt, 5, cy);
+    sqlite3_bind_double (stmt, 6, dist);
+    list = create_edges_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_edge
+			  (stmt_aux, list, edge_id, fields,
+			   "callback_getEdgeWithinDistance2D", &msg))
+			{
+			    gaiatopo_set_last_error_msg (topo, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("callback_getEdgeWithinDistance2D: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct topo_edge *p_ed;
+		result = lwalloc (sizeof (LWT_ISO_EDGE) * list->count);
+		p_ed = list->first;
+		while (p_ed != NULL)
+		  {
+		      LWT_ISO_EDGE *ed = result + i;
+		      if (fields & LWT_COL_EDGE_EDGE_ID)
+			  ed->edge_id = p_ed->edge_id;
+		      if (fields & LWT_COL_EDGE_START_NODE)
+			  ed->start_node = p_ed->start_node;
+		      if (fields & LWT_COL_EDGE_END_NODE)
+			  ed->end_node = p_ed->end_node;
+		      if (fields & LWT_COL_EDGE_FACE_LEFT)
+			  ed->face_left = p_ed->face_left;
+		      if (fields & LWT_COL_EDGE_FACE_RIGHT)
+			  ed->face_right = p_ed->face_right;
+		      if (fields & LWT_COL_EDGE_NEXT_LEFT)
+			  ed->next_left = p_ed->next_left;
+		      if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+			  ed->next_right = p_ed->next_right;
+		      if (fields & LWT_COL_EDGE_GEOM)
+			  ed->geom =
+			      gaia_convert_linestring_to_lwline (p_ed->geom,
+								 accessor->srid,
+								 accessor->
+								 has_z);
+		      i++;
+		      p_ed = p_ed->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_edges_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_edges_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ELEMID
+callback_getNextEdgeId (const LWT_BE_TOPOLOGY * lwt_topo)
+{
+/* callback function: getNextEdgeId */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt_in;
+    sqlite3_stmt *stmt_out;
+    int ret;
+    sqlite3_int64 edge_id = -1;
+    if (accessor == NULL)
+	return -1;
+
+    stmt_in = accessor->stmt_getNextEdgeId;
+    if (stmt_in == NULL)
+	return -1;
+    stmt_out = accessor->stmt_setNextEdgeId;
+    if (stmt_out == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt_in);
+    sqlite3_clear_bindings (stmt_in);
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt_in);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		edge_id = sqlite3_column_int64 (stmt_in, 0);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_getNextEdgeId: %s",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto stop;
+	    }
+      }
+
+/* updating next_edge_id */
+    sqlite3_reset (stmt_out);
+    sqlite3_clear_bindings (stmt_out);
+    ret = sqlite3_step (stmt_out);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+      {
+	  accessor->inside_lwt_callback = 0;
+	  sqlite3_reset (stmt_in);
+	  sqlite3_reset (stmt_out);
+	  return edge_id;
+      }
+    else
+      {
+	  char *msg = sqlite3_mprintf ("callback_setNextEdgeId: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  edge_id = -1;
+      }
+  stop:
+    if (edge_id >= 0)
+	edge_id++;
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt_in);
+    sqlite3_reset (stmt_out);
+    return edge_id;
+}
+
+int
+callback_insertEdges (const LWT_BE_TOPOLOGY * lwt_topo, LWT_ISO_EDGE * edges,
+		      int numelems)
+{
+/* callback function: insertEdges */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    int i;
+    gaiaGeomCollPtr geom;
+    unsigned char *p_blob;
+    int n_bytes;
+    int gpkg_mode = 0;
+    if (accessor == NULL)
+	return 0;
+
+    stmt = accessor->stmt_insertEdges;
+    if (stmt == NULL)
+	return 0;
+    accessor->inside_lwt_callback = 1;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+    for (i = 0; i < numelems; i++)
+      {
+	  LWT_ISO_EDGE *eg = edges + i;
+	  /* setting up the prepared statement */
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (eg->edge_id <= 0)
+	      sqlite3_bind_null (stmt, 1);
+	  else
+	      sqlite3_bind_int64 (stmt, 1, eg->edge_id);
+	  sqlite3_bind_int64 (stmt, 2, eg->start_node);
+	  sqlite3_bind_int64 (stmt, 3, eg->end_node);
+	  if (eg->face_left <= 0)
+	      sqlite3_bind_int64 (stmt, 4, 0);
+	  else
+	      sqlite3_bind_int64 (stmt, 4, eg->face_left);
+	  if (eg->face_right <= 0)
+	      sqlite3_bind_int64 (stmt, 5, 0);
+	  else
+	      sqlite3_bind_int64 (stmt, 5, eg->face_right);
+	  sqlite3_bind_int64 (stmt, 6, eg->next_left);
+	  sqlite3_bind_int64 (stmt, 7, eg->next_right);
+	  /* transforming the LWLINE into a Geometry-Linestring */
+	  geom = do_lwline_to_geom (eg->geom, accessor->srid);
+	  gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+	  gaiaFreeGeomColl (geom);
+	  sqlite3_bind_blob (stmt, 8, p_blob, n_bytes, free);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		/* retrieving the PK value */
+		eg->edge_id = sqlite3_last_insert_rowid (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_insertEdges: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return 1;
+
+  error:
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return 0;
+}
+
+int
+callback_updateEdges (const LWT_BE_TOPOLOGY * lwt_topo,
+		      const LWT_ISO_EDGE * sel_edge, int sel_fields,
+		      const LWT_ISO_EDGE * upd_edge, int upd_fields,
+		      const LWT_ISO_EDGE * exc_edge, int exc_fields)
+{
+/* callback function: updateEdges */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int icol = 1;
+    unsigned char *p_blob;
+    int n_bytes;
+    int gpkg_mode = 0;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET ", xtable);
+    free (xtable);
+    prev = sql;
+    if (upd_fields & LWT_COL_EDGE_EDGE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, edge_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s edge_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, left_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s left_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, right_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s right_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_left_edge = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_right_edge = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_right_edge = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geom = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geom = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (exc_edge || sel_edge)
+      {
+	  sql = sqlite3_mprintf ("%s WHERE", prev);
+	  sqlite3_free (prev);
+	  prev = sql;
+	  if (sel_edge)
+	    {
+		comma = 0;
+		if (sel_fields & LWT_COL_EDGE_EDGE_ID)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND edge_id = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s edge_id = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_EDGE_START_NODE)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND start_node = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s start_node = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_EDGE_END_NODE)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND end_node = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s end_node = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_EDGE_FACE_LEFT)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND left_face = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s left_face = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_EDGE_FACE_RIGHT)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND right_face = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s right_face = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_EDGE_NEXT_LEFT)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf
+			      ("%s AND next_left_edge = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_EDGE_NEXT_RIGHT)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf
+			      ("%s AND next_right_edge = ?", prev);
+		      else
+			  sql =
+			      sqlite3_mprintf ("%s next_right_edge = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+	    }
+	  if (exc_edge)
+	    {
+		if (sel_edge)
+		  {
+		      sql = sqlite3_mprintf ("%s AND", prev);
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		comma = 0;
+		if (exc_fields & LWT_COL_EDGE_EDGE_ID)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND edge_id <> ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s edge_id <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_EDGE_START_NODE)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf ("%s AND start_node <> ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s start_node <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_EDGE_END_NODE)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND end_node <> ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s end_node <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_EDGE_FACE_LEFT)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND left_face <> ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s left_face <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_EDGE_FACE_RIGHT)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf ("%s AND right_face <> ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s right_face <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_EDGE_NEXT_LEFT)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf
+			      ("%s AND next_left_edge <> ?", prev);
+		      else
+			  sql =
+			      sqlite3_mprintf ("%s next_left_edge <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_EDGE_NEXT_RIGHT)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf
+			      ("%s AND next_right_edge <> ?", prev);
+		      else
+			  sql =
+			      sqlite3_mprintf ("%s next_right_edge <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+	    }
+      }
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_updateEdges error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  accessor->inside_lwt_callback = 0;
+	  return -1;
+      }
+
+/* parameter binding */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    if (upd_fields & LWT_COL_EDGE_EDGE_ID)
+      {
+	  sqlite3_bind_int64 (stmt, icol, upd_edge->edge_id);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_START_NODE)
+      {
+	  sqlite3_bind_int64 (stmt, icol, upd_edge->start_node);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_END_NODE)
+      {
+	  sqlite3_bind_int64 (stmt, icol, upd_edge->end_node);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (upd_edge->face_left <= 0)
+	      sqlite3_bind_int64 (stmt, icol, 0);
+	  else
+	      sqlite3_bind_int64 (stmt, icol, upd_edge->face_left);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (upd_edge->face_right <= 0)
+	      sqlite3_bind_int64 (stmt, icol, 0);
+	  else
+	      sqlite3_bind_int64 (stmt, icol, upd_edge->face_right);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  sqlite3_bind_int64 (stmt, icol, upd_edge->next_left);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  sqlite3_bind_int64 (stmt, icol, upd_edge->next_right);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_EDGE_GEOM)
+      {
+	  /* transforming the LWLINE into a Geometry-Linestring */
+	  gaiaGeomCollPtr geom =
+	      do_lwline_to_geom (upd_edge->geom, accessor->srid);
+	  gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+	  gaiaFreeGeomColl (geom);
+	  sqlite3_bind_blob (stmt, icol, p_blob, n_bytes, free);
+	  icol++;
+      }
+    if (sel_edge)
+      {
+	  if (sel_fields & LWT_COL_EDGE_EDGE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_edge->edge_id);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_EDGE_START_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_edge->start_node);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_EDGE_END_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_edge->end_node);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_EDGE_FACE_LEFT)
+	    {
+		if (sel_edge->face_left <= 0)
+		    sqlite3_bind_int64 (stmt, icol, 0);
+		else
+		    sqlite3_bind_int64 (stmt, icol, sel_edge->face_left);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_EDGE_FACE_RIGHT)
+	    {
+		if (sel_edge->face_right <= 0)
+		    sqlite3_bind_int64 (stmt, icol, 0);
+		else
+		    sqlite3_bind_int64 (stmt, icol, sel_edge->face_right);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_EDGE_NEXT_LEFT)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_edge->next_left);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_EDGE_NEXT_RIGHT)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_edge->next_right);
+		icol++;
+	    }
+      }
+    if (exc_edge)
+      {
+	  if (exc_fields & LWT_COL_EDGE_EDGE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_edge->edge_id);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_EDGE_START_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_edge->start_node);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_EDGE_END_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_edge->end_node);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_EDGE_FACE_LEFT)
+	    {
+		if (exc_edge->face_left <= 0)
+		    sqlite3_bind_int64 (stmt, icol, 0);
+		else
+		    sqlite3_bind_int64 (stmt, icol, exc_edge->face_left);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_EDGE_FACE_RIGHT)
+	    {
+		if (exc_edge->face_right <= 0)
+		    sqlite3_bind_int64 (stmt, icol, 0);
+		else
+		    sqlite3_bind_int64 (stmt, icol, exc_edge->face_right);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_EDGE_NEXT_LEFT)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_edge->next_left);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_EDGE_NEXT_RIGHT)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_edge->next_right);
+		icol++;
+	    }
+      }
+    ret = sqlite3_step (stmt);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	changed = sqlite3_changes (accessor->db_handle);
+    else
+      {
+	  char *msg = sqlite3_mprintf ("callback_updateEdges: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return -1;
+}
+
+LWT_ISO_FACE *
+callback_getFaceById (const LWT_BE_TOPOLOGY * lwt_topo,
+		      const LWT_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getFeceById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt_aux = NULL;
+    int ret;
+    int i;
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+    struct topo_faces_list *list = NULL;
+    LWT_ISO_FACE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    /* preparing the SQL statement */
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    if (fields & LWT_COL_FACE_FACE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, face_id", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s face_id", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_FACE_MBR)
+      {
+	  if (comma)
+	      sql =
+		  sqlite3_mprintf
+		  ("%s, MbrMinX(mbr), MbrMinY(mbr), MbrMaxX(mbr), MbrMaxY(mbr)",
+		   prev);
+	  else
+	      sql =
+		  sqlite3_mprintf
+		  ("%s MbrMinX(mbr), MbrMinY(mbr), MbrMaxX(mbr), MbrMaxY(mbr)",
+		   prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    table = sqlite3_mprintf ("%s_face", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE face_id = ?", prev, xtable);
+    sqlite3_free (prev);
+    free (xtable);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_getFaceById AUX error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  accessor->inside_lwt_callback = 0;
+	  return NULL;
+      }
+
+    list = create_faces_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_face
+	      (stmt_aux, list, *(ids + i), fields, "callback_getFaceById",
+	       &msg))
+	    {
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no face was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct topo_face *p_fc;
+	  result = lwalloc (sizeof (LWT_ISO_FACE) * list->count);
+	  p_fc = list->first;
+	  i = 0;
+	  while (p_fc != NULL)
+	    {
+		LWT_ISO_FACE *fc = result + i;
+		if (fields & LWT_COL_FACE_FACE_ID)
+		    fc->face_id = p_fc->face_id;
+		if (fields & LWT_COL_FACE_MBR)
+		  {
+		      if (p_fc->id == 0)
+			  fc->mbr = NULL;
+		      else
+			{
+			    fc->mbr = gbox_new (0);
+			    fc->mbr->xmin = p_fc->minx;
+			    fc->mbr->ymin = p_fc->miny;
+			    fc->mbr->xmax = p_fc->maxx;
+			    fc->mbr->ymax = p_fc->maxy;
+			}
+		  }
+		i++;
+		p_fc = p_fc->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_faces_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_faces_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ELEMID
+callback_getFaceContainingPoint (const LWT_BE_TOPOLOGY * lwt_topo,
+				 const LWPOINT * pt)
+{
+/* callback function: getFaceContainingPoint */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    sqlite3_stmt *stmt_aux;
+    int ret;
+    double cx;
+    double cy;
+    float fx;
+    float fy;
+    double tic;
+    double tic2;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    int count = 0;
+    sqlite3_int64 face_id;
+    if (accessor == NULL)
+	return -2;
+
+    stmt = accessor->stmt_getFaceContainingPoint_1;
+    if (stmt == NULL)
+	return -2;
+    stmt_aux = accessor->stmt_getFaceContainingPoint_2;
+    if (stmt_aux == NULL)
+	return -2;
+    accessor->inside_lwt_callback = 1;
+
+/* extracting X and Y from LWPOINT */
+    pa = pt->point;
+    getPoint4d_p (pa, 0, &pt4d);
+    cx = pt4d.x;
+    cy = pt4d.y;
+
+/* adjusting the MBR so to compensate for DOUBLE/FLOAT truncations */
+    fx = (float) cx;
+    fy = (float) cy;
+    tic = fabs (cx - fx);
+    tic2 = fabs (cy - fy);
+    if (tic2 > tic)
+	tic = tic2;
+    tic2 = fabs (cx - fx);
+    if (tic2 > tic)
+	tic = tic2;
+    tic2 = fabs (cy - fy);
+    if (tic2 > tic)
+	tic = tic2;
+    tic *= 2.0;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, cx + tic);
+    sqlite3_bind_double (stmt, 2, cx - tic);
+    sqlite3_bind_double (stmt, 3, cy + tic);
+    sqlite3_bind_double (stmt, 4, cy - tic);
+
+    while (1)
+      {
+	  /* scrolling the result set rows [R*Tree] */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 id = sqlite3_column_int64 (stmt, 0);
+		/* testing for real intersection */
+		sqlite3_reset (stmt_aux);
+		sqlite3_clear_bindings (stmt_aux);
+		sqlite3_bind_int64 (stmt_aux, 1, id);
+		sqlite3_bind_double (stmt_aux, 2, cx);
+		sqlite3_bind_double (stmt_aux, 3, cy);
+		while (1)
+		  {
+		      ret = sqlite3_step (stmt_aux);
+		      if (ret == SQLITE_DONE)
+			  break;	/* end of result set */
+		      if (ret == SQLITE_ROW)
+			{
+			    if (sqlite3_column_type (stmt_aux, 0) ==
+				SQLITE_INTEGER)
+			      {
+				  if (sqlite3_column_int (stmt_aux, 0) == 1)
+				    {
+					face_id = id;
+					count++;
+					break;
+				    }
+			      }
+			}
+		      else
+			{
+			    char *msg =
+				sqlite3_mprintf
+				("callback_getFaceContainingPoint #2: %s",
+				 sqlite3_errmsg (accessor->db_handle));
+			    gaiatopo_set_last_error_msg (topo, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		if (count > 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("callback_getFaceContainingPoint #1: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    sqlite3_reset (stmt);
+    accessor->inside_lwt_callback = 0;
+    if (count == 0)
+	return -1;		/* none found */
+    return face_id;
+
+  error:
+    sqlite3_reset (stmt);
+    accessor->inside_lwt_callback = 0;
+    return -2;
+}
+
+int
+callback_deleteEdges (const LWT_BE_TOPOLOGY * lwt_topo,
+		      const LWT_ISO_EDGE * sel_edge, int sel_fields)
+{
+/* callback function: deleteEdgest */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int icol = 1;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE", xtable);
+    free (xtable);
+    prev = sql;
+    if (sel_fields & LWT_COL_EDGE_EDGE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND edge_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s edge_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND start_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND end_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND left_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s left_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND right_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s right_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND next_left_edge = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND next_right_edge = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_right_edge = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (sel_fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s AND geom = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geom = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_deleteEdges error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  accessor->inside_lwt_callback = 0;
+	  return -1;
+      }
+
+/* parameter binding */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    if (sel_fields & LWT_COL_EDGE_EDGE_ID)
+      {
+	  sqlite3_bind_int64 (stmt, icol, sel_edge->edge_id);
+	  icol++;
+      }
+    if (sel_fields & LWT_COL_EDGE_START_NODE)
+      {
+	  sqlite3_bind_int64 (stmt, icol, sel_edge->start_node);
+	  icol++;
+      }
+    if (sel_fields & LWT_COL_EDGE_END_NODE)
+      {
+	  sqlite3_bind_int64 (stmt, icol, sel_edge->end_node);
+	  icol++;
+      }
+    if (sel_fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (sel_edge->face_left <= 0)
+	      sqlite3_bind_int64 (stmt, icol, 0);
+	  else
+	      sqlite3_bind_int64 (stmt, icol, sel_edge->face_left);
+	  icol++;
+      }
+    if (sel_fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (sel_edge->face_right <= 0)
+	      sqlite3_bind_int64 (stmt, icol, 0);
+	  else
+	      sqlite3_bind_int64 (stmt, icol, sel_edge->face_right);
+	  icol++;
+      }
+    if (sel_fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  sqlite3_bind_int64 (stmt, icol, sel_edge->next_left);
+	  icol++;
+      }
+    if (sel_fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  sqlite3_bind_int64 (stmt, icol, sel_edge->next_right);
+	  icol++;
+      }
+    ret = sqlite3_step (stmt);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	changed = sqlite3_changes (accessor->db_handle);
+    else
+      {
+	  char *msg = sqlite3_mprintf ("callback_deleteEdges: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return -1;
+}
+
+LWT_ISO_NODE *
+callback_getNodeWithinBox2D (const LWT_BE_TOPOLOGY * lwt_topo,
+			     const GBOX * box, int *numelems,
+			     int fields, int limit)
+{
+/* callback function: getNodeWithinBox2D */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct topo_nodes_list *list = NULL;
+    LWT_ISO_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getNodeWithinBox2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql =
+	      do_prepare_read_node (accessor->topology_name, fields,
+				    accessor->has_z);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("Prepare_getNodeWithinBox2D AUX error: \"%s\"",
+		     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		accessor->inside_lwt_callback = 0;
+		return NULL;
+	    }
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, box->xmin);
+    sqlite3_bind_double (stmt, 2, box->ymin);
+    sqlite3_bind_double (stmt, 3, box->xmax);
+    sqlite3_bind_double (stmt, 4, box->ymax);
+    list = create_nodes_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_node
+			  (stmt_aux, list, node_id, fields, accessor->has_z,
+			   "callback_getNodeWithinBox2D", &msg))
+			{
+			    gaiatopo_set_last_error_msg (topo, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_getNodeWithinBox2D: %s",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct topo_node *p_nd;
+		result = lwalloc (sizeof (LWT_ISO_NODE) * list->count);
+		p_nd = list->first;
+		while (p_nd != NULL)
+		  {
+		      LWT_ISO_NODE *nd = result + i;
+		      if (fields & LWT_COL_NODE_NODE_ID)
+			  nd->node_id = p_nd->node_id;
+		      if (fields & LWT_COL_NODE_CONTAINING_FACE)
+			  nd->containing_face = p_nd->containing_face;
+		      if (fields & LWT_COL_NODE_GEOM)
+			{
+			    pa = ptarray_construct (accessor->has_z, 0, 1);
+			    pt4d.x = p_nd->x;
+			    pt4d.y = p_nd->y;
+			    if (accessor->has_z)
+				pt4d.z = p_nd->z;
+			    ptarray_set_point4d (pa, 0, &pt4d);
+			    nd->geom =
+				lwpoint_construct (accessor->srid, NULL, pa);
+			}
+		      i++;
+		      p_nd = p_nd->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_nodes_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_nodes_list (list);
+    *numelems = 1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ISO_EDGE *
+callback_getEdgeWithinBox2D (const LWT_BE_TOPOLOGY * lwt_topo,
+			     const GBOX * box, int *numelems,
+			     int fields, int limit)
+{
+/* callback function: getEdgeWithinBox2D */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    int count = 0;
+    sqlite3_stmt *stmt_aux = NULL;
+    char *sql;
+    struct topo_edges_list *list = NULL;
+    LWT_ISO_EDGE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getEdgeWithinBox2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    if (limit >= 0)
+      {
+	  /* preparing the auxiliary SQL statement */
+	  sql = do_prepare_read_edge (accessor->topology_name, fields);
+	  ret =
+	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+				  &stmt_aux, NULL);
+	  sqlite3_free (sql);
+	  if (ret != SQLITE_OK)
+	    {
+		char *msg =
+		    sqlite3_mprintf
+		    ("Prepare_getEdgeWithinBox2D AUX error: \"%s\"",
+		     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		*numelems = -1;
+		accessor->inside_lwt_callback = 0;
+		return NULL;
+	    }
+      }
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, box->xmin);
+    sqlite3_bind_double (stmt, 2, box->ymin);
+    sqlite3_bind_double (stmt, 3, box->xmax);
+    sqlite3_bind_double (stmt, 4, box->ymax);
+    list = create_edges_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt, 0);
+		if (stmt_aux != NULL)
+		  {
+		      char *msg;
+		      if (!do_read_edge
+			  (stmt_aux, list, edge_id, fields,
+			   "callback_getEdgeWithinBox2D", &msg))
+			{
+			    gaiatopo_set_last_error_msg (topo, msg);
+			    sqlite3_free (msg);
+			    goto error;
+			}
+		  }
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_getEdgeWithinBox2D: %s",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct topo_edge *p_ed;
+		result = lwalloc (sizeof (LWT_ISO_EDGE) * list->count);
+		p_ed = list->first;
+		while (p_ed != NULL)
+		  {
+		      LWT_ISO_EDGE *ed = result + i;
+		      if (fields & LWT_COL_EDGE_EDGE_ID)
+			  ed->edge_id = p_ed->edge_id;
+		      if (fields & LWT_COL_EDGE_START_NODE)
+			  ed->start_node = p_ed->start_node;
+		      if (fields & LWT_COL_EDGE_END_NODE)
+			  ed->end_node = p_ed->end_node;
+		      if (fields & LWT_COL_EDGE_FACE_LEFT)
+			  ed->face_left = p_ed->face_left;
+		      if (fields & LWT_COL_EDGE_FACE_RIGHT)
+			  ed->face_right = p_ed->face_right;
+		      if (fields & LWT_COL_EDGE_NEXT_LEFT)
+			  ed->next_left = p_ed->next_left;
+		      if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+			  ed->next_right = p_ed->next_right;
+		      if (fields & LWT_COL_EDGE_GEOM)
+			  ed->geom =
+			      gaia_convert_linestring_to_lwline (p_ed->geom,
+								 accessor->srid,
+								 accessor->
+								 has_z);
+		      i++;
+		      p_ed = p_ed->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    destroy_edges_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    sqlite3_reset (stmt);
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_edges_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ISO_EDGE *
+callback_getEdgeByNode (const LWT_BE_TOPOLOGY * lwt_topo,
+			const LWT_ELEMID * ids, int *numelems, int fields)
+{
+/* callback function: getEdgeByNode */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    int ret;
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+    int i;
+    sqlite3_stmt *stmt_aux = NULL;
+    struct topo_edges_list *list = NULL;
+    LWT_ISO_EDGE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    /* preparing the SQL statement */
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    /* unconditionally querying the Edge ID */
+    if (comma)
+	sql = sqlite3_mprintf ("%s, edge_id", prev);
+    else
+	sql = sqlite3_mprintf ("%s edge_id", prev);
+    comma = 1;
+    sqlite3_free (prev);
+    prev = sql;
+    if (fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, left_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s left_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, right_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s right_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_left_edge", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_left_edge", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_right_edge", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_right_edge", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geom", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geom", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("%s FROM MAIN.\"%s\" WHERE start_node = ? OR end_node = ?", prev,
+	 xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+			    &stmt_aux, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getEdgeByNode AUX error: \"%s\"",
+			       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  accessor->inside_lwt_callback = 0;
+	  return NULL;
+      }
+
+    list = create_edges_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_edge_by_node
+	      (stmt_aux, list, *(ids + i), fields, "callback_getEdgeByNode",
+	       &msg))
+	    {
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no edge was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct topo_edge *p_ed;
+	  result = lwalloc (sizeof (LWT_ISO_EDGE) * list->count);
+	  p_ed = list->first;
+	  i = 0;
+	  while (p_ed != NULL)
+	    {
+		LWT_ISO_EDGE *ed = result + i;
+		if (fields & LWT_COL_EDGE_EDGE_ID)
+		    ed->edge_id = p_ed->edge_id;
+		if (fields & LWT_COL_EDGE_START_NODE)
+		    ed->start_node = p_ed->start_node;
+		if (fields & LWT_COL_EDGE_END_NODE)
+		    ed->end_node = p_ed->end_node;
+		if (fields & LWT_COL_EDGE_FACE_LEFT)
+		    ed->face_left = p_ed->face_left;
+		if (fields & LWT_COL_EDGE_FACE_RIGHT)
+		    ed->face_right = p_ed->face_right;
+		if (fields & LWT_COL_EDGE_NEXT_LEFT)
+		    ed->next_left = p_ed->next_left;
+		if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+		    ed->next_right = p_ed->next_right;
+		if (fields & LWT_COL_EDGE_GEOM)
+		    ed->geom =
+			gaia_convert_linestring_to_lwline (p_ed->geom,
+							   accessor->srid,
+							   accessor->has_z);
+		i++;
+		p_ed = p_ed->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_edges_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_edges_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+int
+callback_updateNodes (const LWT_BE_TOPOLOGY * lwt_topo,
+		      const LWT_ISO_NODE * sel_node, int sel_fields,
+		      const LWT_ISO_NODE * upd_node, int upd_fields,
+		      const LWT_ISO_NODE * exc_node, int exc_fields)
+{
+/* callback function: updateNodes */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int icol = 1;
+    int changed = 0;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    double x;
+    double y;
+    double z;
+    if (accessor == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_node", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET ", xtable);
+    free (xtable);
+    prev = sql;
+    if (upd_fields & LWT_COL_NODE_NODE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, node_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s node_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_NODE_CONTAINING_FACE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, containing_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s containing_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_NODE_GEOM)
+      {
+	  if (accessor->has_z)
+	    {
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, geom = MakePointZ(?, ?, ?, %d)",
+					 prev, accessor->srid);
+		else
+		    sql =
+			sqlite3_mprintf ("%s geom = MakePointZ(?, ?, ?, %d)",
+					 prev, accessor->srid);
+	    }
+	  else
+	    {
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, geom = MakePoint(?, ?, %d)", prev,
+					 accessor->srid);
+		else
+		    sql =
+			sqlite3_mprintf ("%s geom = MakePoint(?, ?, %d)", prev,
+					 accessor->srid);
+	    }
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (exc_node || sel_node)
+      {
+	  sql = sqlite3_mprintf ("%s WHERE", prev);
+	  sqlite3_free (prev);
+	  prev = sql;
+	  if (sel_node)
+	    {
+		comma = 0;
+		if (sel_fields & LWT_COL_NODE_NODE_ID)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND node_id = ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s node_id = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (sel_fields & LWT_COL_NODE_CONTAINING_FACE)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf ("%s AND containing_face = ?",
+					       prev);
+		      else
+			  sql =
+			      sqlite3_mprintf ("%s containing_face = ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+	    }
+	  if (exc_node)
+	    {
+		if (sel_node)
+		  {
+		      sql = sqlite3_mprintf ("%s AND", prev);
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		comma = 0;
+		if (exc_fields & LWT_COL_NODE_NODE_ID)
+		  {
+		      if (comma)
+			  sql = sqlite3_mprintf ("%s AND node_id <> ?", prev);
+		      else
+			  sql = sqlite3_mprintf ("%s node_id <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+		if (exc_fields & LWT_COL_NODE_CONTAINING_FACE)
+		  {
+		      if (comma)
+			  sql =
+			      sqlite3_mprintf ("%s AND containing_face <> ?",
+					       prev);
+		      else
+			  sql =
+			      sqlite3_mprintf ("%s containing_face <> ?", prev);
+		      comma = 1;
+		      sqlite3_free (prev);
+		      prev = sql;
+		  }
+	    }
+      }
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_updateNodes error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  accessor->inside_lwt_callback = 0;
+	  return -1;
+      }
+
+/* parameter binding */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    if (upd_fields & LWT_COL_NODE_NODE_ID)
+      {
+	  sqlite3_bind_int64 (stmt, icol, upd_node->node_id);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_NODE_CONTAINING_FACE)
+      {
+	  if (upd_node->containing_face < 0)
+	      sqlite3_bind_null (stmt, icol);
+	  else
+	      sqlite3_bind_int64 (stmt, icol, upd_node->containing_face);
+	  icol++;
+      }
+    if (upd_fields & LWT_COL_NODE_GEOM)
+      {
+	  /* extracting X and Y from LWPOINT */
+	  pa = upd_node->geom->point;
+	  getPoint4d_p (pa, 0, &pt4d);
+	  x = pt4d.x;
+	  y = pt4d.y;
+	  if (accessor->has_z)
+	      z = pt4d.z;
+	  sqlite3_bind_double (stmt, icol, x);
+	  icol++;
+	  sqlite3_bind_double (stmt, icol, y);
+	  icol++;
+	  if (accessor->has_z)
+	    {
+		sqlite3_bind_double (stmt, icol, z);
+		icol++;
+	    }
+      }
+    if (sel_node)
+      {
+	  if (sel_fields & LWT_COL_NODE_NODE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_node->node_id);
+		icol++;
+	    }
+	  if (sel_fields & LWT_COL_NODE_CONTAINING_FACE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, sel_node->containing_face);
+		icol++;
+	    }
+      }
+    if (exc_node)
+      {
+	  if (exc_fields & LWT_COL_NODE_NODE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_node->node_id);
+		icol++;
+	    }
+	  if (exc_fields & LWT_COL_NODE_CONTAINING_FACE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, exc_node->containing_face);
+		icol++;
+	    }
+      }
+    ret = sqlite3_step (stmt);
+    if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	changed = sqlite3_changes (accessor->db_handle);
+    else
+      {
+	  char *msg = sqlite3_mprintf ("callback_updateNodes: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  goto error;
+      }
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return -1;
+}
+
+int
+callback_insertFaces (const LWT_BE_TOPOLOGY * lwt_topo, LWT_ISO_FACE * faces,
+		      int numelems)
+{
+/* callback function: insertFaces */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    int ret;
+    int i;
+    int count = 0;
+    sqlite3_stmt *stmt;
+    if (accessor == NULL)
+	return -1;
+
+    stmt = accessor->stmt_insertFaces;
+    if (stmt == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+    for (i = 0; i < numelems; i++)
+      {
+	  LWT_ISO_FACE *fc = faces + i;
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (fc->face_id <= 0)
+	      sqlite3_bind_null (stmt, 1);
+	  else
+	      sqlite3_bind_int64 (stmt, 1, fc->face_id);
+	  sqlite3_bind_double (stmt, 2, fc->mbr->xmin);
+	  sqlite3_bind_double (stmt, 3, fc->mbr->ymin);
+	  sqlite3_bind_double (stmt, 4, fc->mbr->xmax);
+	  sqlite3_bind_double (stmt, 5, fc->mbr->ymax);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		if (fc->face_id <= 0)
+		    fc->face_id =
+			sqlite3_last_insert_rowid (accessor->db_handle);
+		count++;
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_insertFaces: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return count;
+
+  error:
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return -1;
+}
+
+int
+callback_updateFacesById (const LWT_BE_TOPOLOGY * lwt_topo,
+			  const LWT_ISO_FACE * faces, int numfaces)
+{
+/* callback function: updateFacesById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+
+    stmt = accessor->stmt_updateFacesById;
+    if (stmt == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+
+    for (i = 0; i < numfaces; i++)
+      {
+	  /* parameter binding */
+	  const LWT_ISO_FACE *fc = faces + i;
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_double (stmt, 1, fc->mbr->xmin);
+	  sqlite3_bind_double (stmt, 2, fc->mbr->ymin);
+	  sqlite3_bind_double (stmt, 3, fc->mbr->xmax);
+	  sqlite3_bind_double (stmt, 4, fc->mbr->ymax);
+	  sqlite3_bind_int64 (stmt, 5, fc->face_id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      changed += sqlite3_changes (accessor->db_handle);
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_updateFacesById: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    accessor->inside_lwt_callback = 0;
+    return changed;
+
+  error:
+    accessor->inside_lwt_callback = 0;
+    return -1;
+}
+
+int
+callback_deleteFacesById (const LWT_BE_TOPOLOGY * lwt_topo,
+			  const LWT_ELEMID * ids, int numelems)
+{
+/* callback function: deleteFacesById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+
+    stmt = accessor->stmt_deleteFacesById;
+    if (stmt == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+    for (i = 0; i < numelems; i++)
+      {
+	  /* parameter binding */
+	  sqlite3_int64 id = *(ids + i);
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_int64 (stmt, 1, id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		changed += sqlite3_changes (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_deleteFacesById: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return changed;
+
+  error:
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return -1;
+}
+
+int
+callback_deleteNodesById (const LWT_BE_TOPOLOGY * lwt_topo,
+			  const LWT_ELEMID * ids, int numelems)
+{
+/* callback function: deleteNodesById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+
+    stmt = accessor->stmt_deleteNodesById;
+    if (stmt == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+    for (i = 0; i < numelems; i++)
+      {
+	  /* parameter binding */
+	  sqlite3_int64 id = *(ids + i);
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  sqlite3_bind_int64 (stmt, 1, id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	    {
+		changed += sqlite3_changes (accessor->db_handle);
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_deleteNodesById: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return changed;
+
+  error:
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return -1;
+}
+
+LWT_ELEMID *
+callback_getRingEdges (const LWT_BE_TOPOLOGY * lwt_topo,
+		       LWT_ELEMID edge, int *numedges, int limit)
+{
+/* callback function: getRingEdges */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    int ret;
+    int i;
+    int count = 0;
+    sqlite3_stmt *stmt;
+
+    struct topo_edges_list *list = NULL;
+    LWT_ELEMID *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numedges = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getRingEdges;
+    if (stmt == NULL)
+      {
+	  *numedges = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, edge);
+    sqlite3_bind_double (stmt, 2, edge);
+    list = create_edges_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt, 0);
+		add_edge (list, edge_id, -1, -1, -1, -1, -1, -1, NULL);
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+	    }
+	  else
+	    {
+		char *msg =
+		    sqlite3_mprintf ("callback_getNodeWithinDistance2D: %s",
+				     sqlite3_errmsg (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numedges = count;
+      }
+    else
+      {
+	  if (list->count == 0)
+	    {
+		/* no edge was found */
+		*numedges = 0;
+	    }
+	  else
+	    {
+		struct topo_edge *p_ed;
+		result = lwalloc (sizeof (LWT_ELEMID) * list->count);
+		p_ed = list->first;
+		i = 0;
+		while (p_ed != NULL)
+		  {
+		      *(result + i) = p_ed->edge_id;
+		      i++;
+		      p_ed = p_ed->next;
+		  }
+		*numedges = list->count;
+	    }
+      }
+    destroy_edges_list (list);
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return result;
+
+  error:
+    if (list != NULL)
+	destroy_edges_list (list);
+    *numedges = -1;
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return NULL;
+}
+
+int
+callback_updateEdgesById (const LWT_BE_TOPOLOGY * lwt_topo,
+			  const LWT_ISO_EDGE * edges, int numedges,
+			  int upd_fields)
+{
+/* callback function: updateEdgesById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int i;
+    int changed = 0;
+    unsigned char *p_blob;
+    int n_bytes;
+    int gpkg_mode = 0;
+    if (accessor == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+    if (accessor->cache != NULL)
+      {
+	  struct splite_internal_cache *cache =
+	      (struct splite_internal_cache *) (accessor->cache);
+	  gpkg_mode = cache->gpkg_mode;
+      }
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
+    free (xtable);
+    prev = sql;
+    if (upd_fields & LWT_COL_EDGE_EDGE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, edge_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s edge_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, left_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s left_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, right_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s right_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_left_edge = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_right_edge = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_right_edge = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geom = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geom = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    sql = sqlite3_mprintf ("%s WHERE edge_id = ?", prev);
+    sqlite3_free (prev);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_updateEdgesById error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  accessor->inside_lwt_callback = 0;
+	  return -1;
+      }
+
+    for (i = 0; i < numedges; i++)
+      {
+	  /* parameter binding */
+	  int icol = 1;
+	  const LWT_ISO_EDGE *upd_edge = edges + i;
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (upd_fields & LWT_COL_EDGE_EDGE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_edge->edge_id);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_START_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_edge->start_node);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_END_NODE)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_edge->end_node);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_FACE_LEFT)
+	    {
+		if (upd_edge->face_left <= 0)
+		    sqlite3_bind_int64 (stmt, icol, 0);
+		else
+		    sqlite3_bind_int64 (stmt, icol, upd_edge->face_left);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_FACE_RIGHT)
+	    {
+		if (upd_edge->face_right <= 0)
+		    sqlite3_bind_int64 (stmt, icol, 0);
+		else
+		    sqlite3_bind_int64 (stmt, icol, upd_edge->face_right);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_NEXT_LEFT)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_edge->next_left);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_NEXT_RIGHT)
+	    {
+		sqlite3_bind_int64 (stmt, icol, upd_edge->next_right);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_EDGE_GEOM)
+	    {
+		/* transforming the LWLINE into a Geometry-Linestring */
+		gaiaGeomCollPtr geom =
+		    do_lwline_to_geom (upd_edge->geom, accessor->srid);
+		gaiaToSpatiaLiteBlobWkbEx (geom, &p_blob, &n_bytes, gpkg_mode);
+		gaiaFreeGeomColl (geom);
+		sqlite3_bind_blob (stmt, icol, p_blob, n_bytes, free);
+		icol++;
+	    }
+	  sqlite3_bind_int64 (stmt, icol, upd_edge->edge_id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      changed += sqlite3_changes (accessor->db_handle);
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_updateEdgesById: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return -1;
+}
+
+LWT_ISO_EDGE *
+callback_getEdgeByFace (const LWT_BE_TOPOLOGY * lwt_topo,
+			const LWT_ELEMID * ids, int *numelems, int fields,
+			const GBOX * box)
+{
+/* callback function: getEdgeByFace */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    int ret;
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+    int i;
+    sqlite3_stmt *stmt_aux = NULL;
+    struct topo_edges_list *list = NULL;
+    LWT_ISO_EDGE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    /* preparing the SQL statement */
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    /* unconditionally querying the Edge ID */
+    if (comma)
+	sql = sqlite3_mprintf ("%s, edge_id", prev);
+    else
+	sql = sqlite3_mprintf ("%s edge_id", prev);
+    comma = 1;
+    sqlite3_free (prev);
+    prev = sql;
+    if (fields & LWT_COL_EDGE_START_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, start_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s start_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_END_NODE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, end_node", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s end_node", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_FACE_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, left_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s left_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_FACE_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, right_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s right_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_NEXT_LEFT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_left_edge", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_left_edge", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, next_right_edge", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s next_right_edge", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_EDGE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, geom", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s geom", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf
+	("%s FROM MAIN.\"%s\" WHERE (left_face = ? OR right_face = ?)", prev,
+	 xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    if (box != NULL)
+      {
+	  table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
+	  prev = sql;
+	  sql =
+	      sqlite3_mprintf
+	      ("%s AND ROWID IN (SELECT ROWID FROM SpatialIndex WHERE "
+	       "f_table_name = %Q AND f_geometry_column = 'geom' AND search_frame = BuildMBR(?, ?, ?, ?))",
+	       sql, table);
+	  sqlite3_free (table);
+	  sqlite3_free (prev);
+      }
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
+			    &stmt_aux, NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getEdgeByFace AUX error: \"%s\"",
+			       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  accessor->inside_lwt_callback = 0;
+	  return NULL;
+      }
+
+    list = create_edges_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_edge_by_face
+	      (stmt_aux, list, *(ids + i), fields, box,
+	       "callback_getEdgeByFace", &msg))
+	    {
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no edge was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct topo_edge *p_ed;
+	  result = lwalloc (sizeof (LWT_ISO_EDGE) * list->count);
+	  p_ed = list->first;
+	  i = 0;
+	  while (p_ed != NULL)
+	    {
+		LWT_ISO_EDGE *ed = result + i;
+		if (fields & LWT_COL_EDGE_EDGE_ID)
+		    ed->edge_id = p_ed->edge_id;
+		if (fields & LWT_COL_EDGE_START_NODE)
+		    ed->start_node = p_ed->start_node;
+		if (fields & LWT_COL_EDGE_END_NODE)
+		    ed->end_node = p_ed->end_node;
+		if (fields & LWT_COL_EDGE_FACE_LEFT)
+		    ed->face_left = p_ed->face_left;
+		if (fields & LWT_COL_EDGE_FACE_RIGHT)
+		    ed->face_right = p_ed->face_right;
+		if (fields & LWT_COL_EDGE_NEXT_LEFT)
+		    ed->next_left = p_ed->next_left;
+		if (fields & LWT_COL_EDGE_NEXT_RIGHT)
+		    ed->next_right = p_ed->next_right;
+		if (fields & LWT_COL_EDGE_GEOM)
+		    ed->geom =
+			gaia_convert_linestring_to_lwline (p_ed->geom,
+							   accessor->srid,
+							   accessor->has_z);
+		i++;
+		p_ed = p_ed->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_edges_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_edges_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+LWT_ISO_NODE *
+callback_getNodeByFace (const LWT_BE_TOPOLOGY * lwt_topo,
+			const LWT_ELEMID * faces, int *numelems, int fields,
+			const GBOX * box)
+{
+/* callback function: getNodeByFace */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt_aux = NULL;
+    int ret;
+    int i;
+    char *sql;
+    char *prev;
+    char *table;
+    char *xtable;
+    int comma = 0;
+    POINTARRAY *pa;
+    POINT4D pt4d;
+    struct topo_nodes_list *list = NULL;
+    LWT_ISO_NODE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+    /* preparing the SQL statement */
+    sql = sqlite3_mprintf ("SELECT ");
+    prev = sql;
+    if (fields & LWT_COL_NODE_NODE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, node_id", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s node_id", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_NODE_CONTAINING_FACE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, containing_face", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s containing_face", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (fields & LWT_COL_NODE_GEOM)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, ST_X(geom), ST_Y(geom)", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s ST_X(geom), ST_Y(geom)", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+	  if (accessor->has_z)
+	    {
+		sql = sqlite3_mprintf ("%s, ST_Z(geom)", prev);
+		sqlite3_free (prev);
+		prev = sql;
+	    }
+      }
+    table = sqlite3_mprintf ("%s_node", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql =
+	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE containing_face = ?", prev,
+			 xtable);
+    free (xtable);
+    sqlite3_free (prev);
+    if (box != NULL)
+      {
+	  table = sqlite3_mprintf ("%s_node", accessor->topology_name);
+	  prev = sql;
+	  sql =
+	      sqlite3_mprintf
+	      ("%s AND ROWID IN (SELECT ROWID FROM SpatialIndex WHERE "
+	       "f_table_name = %Q AND f_geometry_column = 'geom' AND search_frame = BuildMBR(?, ?, ?, ?))",
+	       sql, table);
+	  sqlite3_free (table);
+	  sqlite3_free (prev);
+      }
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg =
+	      sqlite3_mprintf ("Prepare_getNodeByFace AUX error: \"%s\"",
+			       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  *numelems = -1;
+	  accessor->inside_lwt_callback = 0;
+	  return NULL;
+      }
+
+    list = create_nodes_list ();
+    for (i = 0; i < *numelems; i++)
+      {
+	  char *msg;
+	  if (!do_read_node_by_face
+	      (stmt_aux, list, *(faces + i), fields, box, accessor->has_z,
+	       "callback_getNodeByFace", &msg))
+	    {
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (list->count == 0)
+      {
+	  /* no node was found */
+	  *numelems = list->count;
+      }
+    else
+      {
+	  struct topo_node *p_nd;
+	  result = lwalloc (sizeof (LWT_ISO_NODE) * list->count);
+	  p_nd = list->first;
+	  i = 0;
+	  while (p_nd != NULL)
+	    {
+		LWT_ISO_NODE *nd = result + i;
+		if (fields & LWT_COL_NODE_NODE_ID)
+		    nd->node_id = p_nd->node_id;
+		if (fields & LWT_COL_NODE_CONTAINING_FACE)
+		    nd->containing_face = p_nd->containing_face;
+		if (fields & LWT_COL_NODE_GEOM)
+		  {
+		      pa = ptarray_construct (accessor->has_z, 0, 1);
+		      pt4d.x = p_nd->x;
+		      pt4d.y = p_nd->y;
+		      if (accessor->has_z)
+			  pt4d.z = p_nd->z;
+		      ptarray_set_point4d (pa, 0, &pt4d);
+		      nd->geom = lwpoint_construct (accessor->srid, NULL, pa);
+		  }
+		i++;
+		p_nd = p_nd->next;
+	    }
+	  *numelems = list->count;
+      }
+    sqlite3_finalize (stmt_aux);
+    destroy_nodes_list (list);
+    accessor->inside_lwt_callback = 0;
+    return result;
+
+  error:
+    if (stmt_aux != NULL)
+	sqlite3_finalize (stmt_aux);
+    if (list != NULL)
+	destroy_nodes_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    return NULL;
+}
+
+int
+callback_updateNodesById (const LWT_BE_TOPOLOGY * lwt_topo,
+			  const LWT_ISO_NODE * nodes, int numnodes,
+			  int upd_fields)
+{
+/* callback function: updateNodesById */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt = NULL;
+    int ret;
+    char *sql;
+    char *prev;
+    int comma = 0;
+    char *table;
+    char *xtable;
+    int icol = 1;
+    int i;
+    int changed = 0;
+    if (accessor == NULL)
+	return -1;
+    accessor->inside_lwt_callback = 1;
+
+/* composing the SQL prepared statement */
+    table = sqlite3_mprintf ("%s_node", accessor->topology_name);
+    xtable = gaiaDoubleQuotedSql (table);
+    sqlite3_free (table);
+    sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
+    free (xtable);
+    prev = sql;
+    if (upd_fields & LWT_COL_NODE_NODE_ID)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, node_id = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s node_id = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_NODE_CONTAINING_FACE)
+      {
+	  if (comma)
+	      sql = sqlite3_mprintf ("%s, containing_face = ?", prev);
+	  else
+	      sql = sqlite3_mprintf ("%s containing_face = ?", prev);
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    if (upd_fields & LWT_COL_NODE_GEOM)
+      {
+	  if (accessor->has_z)
+	    {
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, geom = MakePointZ(?, ?. ?, %d)",
+					 prev, accessor->srid);
+		else
+		    sql =
+			sqlite3_mprintf ("%s geom = MakePointZ(?, ?, ?, %d)",
+					 prev, accessor->srid);
+	    }
+	  else
+	    {
+		if (comma)
+		    sql =
+			sqlite3_mprintf ("%s, geom = MakePoint(?, ?, %d)", prev,
+					 accessor->srid);
+		else
+		    sql =
+			sqlite3_mprintf ("%s geom = MakePoint(?, ?, %d)", prev,
+					 accessor->srid);
+	    }
+	  comma = 1;
+	  sqlite3_free (prev);
+	  prev = sql;
+      }
+    sql = sqlite3_mprintf ("%s WHERE node_id = ?", prev);
+    sqlite3_free (prev);
+    ret =
+	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
+			    NULL);
+    sqlite3_free (sql);
+    if (ret != SQLITE_OK)
+      {
+	  char *msg = sqlite3_mprintf ("Prepare_updateNodesById error: \"%s\"",
+				       sqlite3_errmsg (accessor->db_handle));
+	  gaiatopo_set_last_error_msg (topo, msg);
+	  sqlite3_free (msg);
+	  accessor->inside_lwt_callback = 0;
+	  return -1;
+      }
+
+    for (i = 0; i < numnodes; i++)
+      {
+	  /* parameter binding */
+	  const LWT_ISO_NODE *nd = nodes + i;
+	  icol = 1;
+	  sqlite3_reset (stmt);
+	  sqlite3_clear_bindings (stmt);
+	  if (upd_fields & LWT_COL_NODE_NODE_ID)
+	    {
+		sqlite3_bind_int64 (stmt, icol, nd->node_id);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_NODE_CONTAINING_FACE)
+	    {
+		if (nd->containing_face < 0)
+		    sqlite3_bind_null (stmt, icol);
+		else
+		    sqlite3_bind_int64 (stmt, icol, nd->containing_face);
+		icol++;
+	    }
+	  if (upd_fields & LWT_COL_NODE_GEOM)
+	    {
+		POINTARRAY *pa;
+		POINT4D pt4d;
+		double x;
+		double y;
+		double z;
+		/* extracting X and Y from LWPOINT */
+		pa = nd->geom->point;
+		getPoint4d_p (pa, 0, &pt4d);
+		x = pt4d.x;
+		y = pt4d.y;
+		if (accessor->has_z)
+		    z = pt4d.z;
+		sqlite3_bind_double (stmt, icol, x);
+		icol++;
+		sqlite3_bind_double (stmt, icol, y);
+		icol++;
+		if (accessor->has_z)
+		  {
+		      sqlite3_bind_double (stmt, icol, z);
+		      icol++;
+		  }
+	    }
+	  sqlite3_bind_int64 (stmt, icol, nd->node_id);
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+	      changed += sqlite3_changes (accessor->db_handle);
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_updateNodesById: \"%s\"",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return changed;
+
+  error:
+    sqlite3_finalize (stmt);
+    accessor->inside_lwt_callback = 0;
+    return -1;
+}
+
+LWT_ISO_FACE *
+callback_getFaceWithinBox2D (const LWT_BE_TOPOLOGY * lwt_topo, const GBOX * box,
+			     int *numelems, int fields, int limit)
+{
+/* callback function: getFaceWithinBox2D */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    sqlite3_stmt *stmt;
+    int ret;
+    int count = 0;
+    struct topo_faces_list *list = NULL;
+    LWT_ISO_FACE *result = NULL;
+    if (accessor == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+
+    stmt = accessor->stmt_getFaceWithinBox2D;
+    if (stmt == NULL)
+      {
+	  *numelems = -1;
+	  return NULL;
+      }
+    accessor->inside_lwt_callback = 1;
+
+/* setting up the prepared statement */
+    sqlite3_reset (stmt);
+    sqlite3_clear_bindings (stmt);
+    sqlite3_bind_double (stmt, 1, box->xmax);
+    sqlite3_bind_double (stmt, 2, box->xmin);
+    sqlite3_bind_double (stmt, 3, box->ymax);
+    sqlite3_bind_double (stmt, 4, box->ymin);
+    list = create_faces_list ();
+
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		sqlite3_int64 face_id = sqlite3_column_int64 (stmt, 0);
+		double minx = sqlite3_column_double (stmt, 1);
+		double miny = sqlite3_column_double (stmt, 2);
+		double maxx = sqlite3_column_double (stmt, 3);
+		double maxy = sqlite3_column_double (stmt, 4);
+		add_face (list, face_id, face_id, minx, miny, maxx, maxy);
+		count++;
+		if (limit > 0)
+		  {
+		      if (count > limit)
+			  break;
+		  }
+		if (limit < 0)
+		    break;
+	    }
+	  else
+	    {
+		char *msg = sqlite3_mprintf ("callback_getFaceWithinBox2D: %s",
+					     sqlite3_errmsg
+					     (accessor->db_handle));
+		gaiatopo_set_last_error_msg (topo, msg);
+		sqlite3_free (msg);
+		goto error;
+	    }
+      }
+
+    if (limit < 0)
+      {
+	  result = NULL;
+	  *numelems = count;
+      }
+    else
+      {
+	  if (list->count <= 0)
+	    {
+		result = NULL;
+		*numelems = 0;
+	    }
+	  else
+	    {
+		int i = 0;
+		struct topo_face *p_fc;
+		result = lwalloc (sizeof (LWT_ISO_FACE) * list->count);
+		p_fc = list->first;
+		while (p_fc != NULL)
+		  {
+		      LWT_ISO_FACE *fc = result + i;
+		      if (fields & LWT_COL_FACE_FACE_ID)
+			  fc->face_id = p_fc->face_id;
+		      if (fields & LWT_COL_FACE_MBR)
+			{
+			    fc->mbr = gbox_new (0);
+			    fc->mbr->xmin = p_fc->minx;
+			    fc->mbr->ymin = p_fc->miny;
+			    fc->mbr->xmax = p_fc->maxx;
+			    fc->mbr->ymax = p_fc->maxy;
+			}
+		      i++;
+		      p_fc = p_fc->next;
+		  }
+		*numelems = list->count;
+	    }
+      }
+    destroy_faces_list (list);
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return result;
+
+  error:
+    if (list != NULL)
+	destroy_faces_list (list);
+    *numelems = -1;
+    accessor->inside_lwt_callback = 0;
+    sqlite3_reset (stmt);
+    return NULL;
+}
+
+int
+callback_updateTopoGeomEdgeSplit (const LWT_BE_TOPOLOGY * topo,
+				  LWT_ELEMID split_edge, LWT_ELEMID new_edge1,
+				  LWT_ELEMID new_edge2)
+{
+/* does nothing */
+    if (topo != NULL && split_edge == 0 && new_edge1 == 0 && new_edge2 == 0)
+	topo = NULL;		/* silencing stupid compiler warnings on unused args */
+    return 1;
+}
+
+int
+callback_updateTopoGeomFaceSplit (const LWT_BE_TOPOLOGY * topo,
+				  LWT_ELEMID split_face,
+				  LWT_ELEMID new_face1, LWT_ELEMID new_face2)
+{
+/* does nothing */
+    if (topo != NULL && split_face == 0 && new_face1 == 0 && new_face2 == 0)
+	topo = NULL;		/* silencing stupid compiler warnings on unused args */
+    return 1;
+}
+
+int
+callback_checkTopoGeomRemEdge (const LWT_BE_TOPOLOGY * topo,
+			       LWT_ELEMID rem_edge, LWT_ELEMID face_left,
+			       LWT_ELEMID face_right)
+{
+/* does nothing */
+    if (topo != NULL && rem_edge == 0 && face_left == 0 && face_right == 0)
+	topo = NULL;		/* silencing stupid compiler warnings on unused args */
+    return 1;
+}
+
+int
+callback_updateTopoGeomFaceHeal (const LWT_BE_TOPOLOGY * topo, LWT_ELEMID face1,
+				 LWT_ELEMID face2, LWT_ELEMID newface)
+{
+/* does nothing */
+    if (topo != NULL && face1 == 0 && face2 == 0 && newface == 0)
+	topo = NULL;		/* silencing stupid compiler warnings on unused args */
+    return 1;
+}
+
+int
+callback_checkTopoGeomRemNode (const LWT_BE_TOPOLOGY * topo,
+			       LWT_ELEMID rem_node, LWT_ELEMID e1,
+			       LWT_ELEMID e2)
+{
+/* does nothing */
+    if (topo != NULL && rem_node == 0 && e1 == 0 && e2 == 0)
+	topo = NULL;		/* silencing stupid compiler warnings on unused args */
+    return 1;
+}
+
+int
+callback_updateTopoGeomEdgeHeal (const LWT_BE_TOPOLOGY * topo, LWT_ELEMID edge1,
+				 LWT_ELEMID edge2, LWT_ELEMID newedge)
+{
+/* does nothing */
+    if (topo != NULL && edge1 == 0 && edge2 == 0 && newedge == 0)
+	topo = NULL;		/* silencing stupid compiler warnings on unused args */
+    return 1;
+}
+
+int
+callback_topoGetSRID (const LWT_BE_TOPOLOGY * lwt_topo)
+{
+/* callback function: topoGetSRID */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    if (accessor == NULL)
+	return -1;
+
+    return accessor->srid;
+}
+
+double
+callback_topoGetPrecision (const LWT_BE_TOPOLOGY * lwt_topo)
+{
+/* callback function: topoGetPrecision */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    if (accessor == NULL)
+	return 0.0;
+
+    return accessor->tolerance;
+}
+
+int
+callback_topoHasZ (const LWT_BE_TOPOLOGY * lwt_topo)
+{
+/* callback function: topoHasZ */
+    GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) lwt_topo;
+    struct gaia_topology *accessor = (struct gaia_topology *) topo;
+    if (accessor == NULL)
+	return 0;
+
+    return accessor->has_z;
+}
+
+#endif /* end TOPOLOGY conditionals */
diff --git a/src/topology/topology_private.h b/src/topology/topology_private.h
new file mode 100644
index 0000000..fd49580
--- /dev/null
+++ b/src/topology/topology_private.h
@@ -0,0 +1,406 @@
+/*
+ topology_private.h -- Topology opaque definitions
+  
+ version 4.3, 2015 July 15
+
+ Author: Sandro Furieri a.furieri at lqt.it
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+/**
+ \file topology_private.h
+
+ SpatiaLite Topology private header file
+ */
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+#ifdef _WIN32
+#ifdef DLL_EXPORT
+#define TOPOLOGY_PRIVATE
+#else
+#define TOPOLOGY_PRIVATE
+#endif
+#else
+#define TOPOLOGY_PRIVATE __attribute__ ((visibility("hidden")))
+#endif
+#endif
+
+struct gaia_topology
+{
+/* a struct wrapping a Topology Accessor Object */
+    const void *cache;
+    sqlite3 *db_handle;
+    char *topology_name;
+    int srid;
+    double tolerance;
+    int has_z;
+    char *last_error_message;
+    sqlite3_stmt *stmt_getNodeWithinDistance2D;
+    sqlite3_stmt *stmt_insertNodes;
+    sqlite3_stmt *stmt_getEdgeWithinDistance2D;
+    sqlite3_stmt *stmt_getNextEdgeId;
+    sqlite3_stmt *stmt_setNextEdgeId;
+    sqlite3_stmt *stmt_insertEdges;
+    sqlite3_stmt *stmt_getFaceContainingPoint_1;
+    sqlite3_stmt *stmt_getFaceContainingPoint_2;
+    sqlite3_stmt *stmt_deleteEdges;
+    sqlite3_stmt *stmt_getNodeWithinBox2D;
+    sqlite3_stmt *stmt_getEdgeWithinBox2D;
+    sqlite3_stmt *stmt_getFaceWithinBox2D;
+    sqlite3_stmt *stmt_updateNodes;
+    sqlite3_stmt *stmt_insertFaces;
+    sqlite3_stmt *stmt_updateFacesById;
+    sqlite3_stmt *stmt_getRingEdges;
+    sqlite3_stmt *stmt_deleteFacesById;
+    sqlite3_stmt *stmt_deleteNodesById;
+    void *callbacks;
+    void *lwt_iface;
+    void *lwt_topology;
+    struct gaia_topology *prev;
+    struct gaia_topology *next;
+    int inside_lwt_callback;
+};
+
+struct face_edge_item
+{
+/* a struct wrapping a Face-Edge item */
+    sqlite3_int64 edge_id;
+    sqlite3_int64 left_face;
+    sqlite3_int64 right_face;
+    gaiaGeomCollPtr geom;
+    int count;
+    struct face_edge_item *next;
+};
+
+struct face_item
+{
+/* a struct wrapping a Face item */
+    sqlite3_int64 face_id;
+    struct face_item *next;
+};
+
+struct face_edges
+{
+/* a struct containing Face-Edge items */
+    int has_z;
+    int srid;
+    struct face_edge_item *first_edge;
+    struct face_edge_item *last_edge;
+    struct face_item *first_face;
+    struct face_item *last_face;
+};
+
+/* common utilities */
+TOPOLOGY_PRIVATE LWLINE *gaia_convert_linestring_to_lwline (gaiaLinestringPtr
+							    ln, int srid,
+							    int has_z);
+TOPOLOGY_PRIVATE LWPOLY *gaia_convert_polygon_to_lwpoly (gaiaPolygonPtr pg,
+							 int srid, int has_z);
+
+/* prototypes for functions handling Topology errors */
+TOPOLOGY_PRIVATE void gaiatopo_reset_last_error_msg (GaiaTopologyAccessorPtr
+						     accessor);
+
+TOPOLOGY_PRIVATE void gaiatopo_set_last_error_msg (GaiaTopologyAccessorPtr
+						   accessor, const char *msg);
+
+TOPOLOGY_PRIVATE const char
+    *gaiatopo_get_last_exception (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE struct face_edges *auxtopo_create_face_edges (int has_z,
+							       int srid);
+
+TOPOLOGY_PRIVATE void auxtopo_free_face_edges (struct face_edges *list);
+
+TOPOLOGY_PRIVATE void auxtopo_add_face_edge (struct face_edges *list,
+					     sqlite3_int64 face_id,
+					     sqlite3_int64 edge_id,
+					     sqlite3_int64 left_face,
+					     sqlite3_int64 right_face,
+					     gaiaGeomCollPtr geom);
+
+TOPOLOGY_PRIVATE void auxtopo_select_valid_face_edges (struct face_edges *list);
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr auxtopo_polygonize_face_edges (struct
+								face_edges
+								*list,
+								const void
+								*cache);
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr
+auxtopo_polygonize_face_edges_generalize (struct face_edges *list,
+					  const void *cache);
+
+TOPOLOGY_PRIVATE int auxtopo_create_togeotable_sql (sqlite3 * db_handle,
+						    const char *db_prefix,
+						    const char *ref_table,
+						    const char *ref_column,
+						    const char *out_table,
+						    char **xcreate,
+						    char **xselect,
+						    char **xinsert,
+						    int *ref_geom_col);
+
+TOPOLOGY_PRIVATE int auxtopo_retrieve_geometry_type (sqlite3 * handle,
+						     const char *db_prefix,
+						     const char *table,
+						     const char *column,
+						     int *ref_type);
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr auxtopo_make_geom_from_point (int srid,
+							       int has_z,
+							       gaiaPointPtr pt);
+
+TOPOLOGY_PRIVATE gaiaGeomCollPtr auxtopo_make_geom_from_line (int srid,
+							      gaiaLinestringPtr
+							      line);
+
+TOPOLOGY_PRIVATE void auxtopo_destroy_geom_from (gaiaGeomCollPtr reference);
+
+TOPOLOGY_PRIVATE void auxtopo_copy_linestring (gaiaLinestringPtr line,
+					       gaiaGeomCollPtr geom);
+
+TOPOLOGY_PRIVATE void auxtopo_copy_linestring3d (gaiaLinestringPtr line,
+						 gaiaGeomCollPtr geom);
+
+TOPOLOGY_PRIVATE int auxtopo_insert_into_topology (GaiaTopologyAccessorPtr
+						   accessor,
+						   gaiaGeomCollPtr geom,
+						   double tolerance,
+						   int line_max_points,
+						   double max_length);
+
+
+/* prototypes for functions creating some SQL prepared statement */
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getNodeWithinDistance2D (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getNodeWithinBox2D (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getEdgeWithinDistance2D (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getEdgeWithinBox2D (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getFaceWithinBox2D (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    *
+do_create_stmt_getFaceContainingPoint_1 (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    *
+do_create_stmt_getFaceContainingPoint_2 (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_insertNodes (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_insertEdges (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_updateEdges (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getNextEdgeId (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_setNextEdgeId (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_getRingEdges (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_insertFaces (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_updateFacesById (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_deleteFacesById (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE sqlite3_stmt
+    * do_create_stmt_deleteNodesById (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE void
+finalize_topogeo_prepared_stmts (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE void
+create_topogeo_prepared_stmts (GaiaTopologyAccessorPtr accessor);
+
+TOPOLOGY_PRIVATE void finalize_all_topo_prepared_stmts (const void *cache);
+
+TOPOLOGY_PRIVATE void create_all_topo_prepared_stmts (const void *cache);
+
+
+/* callback function prototypes */
+const char *callback_lastErrorMessage (const LWT_BE_DATA * be);
+
+int callback_freeTopology (LWT_BE_TOPOLOGY * topo);
+
+LWT_BE_TOPOLOGY *callback_loadTopologyByName (const LWT_BE_DATA * be,
+					      const char *name);
+
+LWT_ISO_NODE *callback_getNodeById (const LWT_BE_TOPOLOGY * topo,
+				    const LWT_ELEMID * ids, int *numelems,
+				    int fields);
+
+LWT_ISO_NODE *callback_getNodeWithinDistance2D (const LWT_BE_TOPOLOGY *
+						topo, const LWPOINT * pt,
+						double dist, int *numelems,
+						int fields, int limit);
+
+int callback_insertNodes (const LWT_BE_TOPOLOGY * topo,
+			  LWT_ISO_NODE * nodes, int numelems);
+
+LWT_ISO_EDGE *callback_getEdgeById (const LWT_BE_TOPOLOGY * topo,
+				    const LWT_ELEMID * ids, int *numelems,
+				    int fields);
+
+LWT_ISO_EDGE *callback_getEdgeWithinDistance2D (const LWT_BE_TOPOLOGY *
+						topo, const LWPOINT * pt,
+						double dist, int *numelems,
+						int fields, int limit);
+
+LWT_ELEMID callback_getNextEdgeId (const LWT_BE_TOPOLOGY * topo);
+
+int callback_insertEdges (const LWT_BE_TOPOLOGY * topo,
+			  LWT_ISO_EDGE * edges, int numelems);
+
+int callback_updateEdges (const LWT_BE_TOPOLOGY * topo,
+			  const LWT_ISO_EDGE * sel_edge, int sel_fields,
+			  const LWT_ISO_EDGE * upd_edge, int upd_fields,
+			  const LWT_ISO_EDGE * exc_edge, int exc_fields);
+
+LWT_ISO_FACE *callback_getFaceById (const LWT_BE_TOPOLOGY * topo,
+				    const LWT_ELEMID * ids, int *numelems,
+				    int fields);
+
+LWT_ELEMID callback_getFaceContainingPoint (const LWT_BE_TOPOLOGY * topo,
+					    const LWPOINT * pt);
+
+int callback_deleteEdges (const LWT_BE_TOPOLOGY * topo,
+			  const LWT_ISO_EDGE * sel_edge, int sel_fields);
+
+LWT_ISO_NODE *callback_getNodeWithinBox2D (const LWT_BE_TOPOLOGY * topo,
+					   const GBOX * box, int *numelems,
+					   int fields, int limit);
+
+LWT_ISO_EDGE *callback_getEdgeWithinBox2D (const LWT_BE_TOPOLOGY * topo,
+					   const GBOX * box, int *numelems,
+					   int fields, int limit);
+
+LWT_ISO_EDGE *callback_getEdgeByNode (const LWT_BE_TOPOLOGY * topo,
+				      const LWT_ELEMID * ids,
+				      int *numelems, int fields);
+
+int callback_updateNodes (const LWT_BE_TOPOLOGY * topo,
+			  const LWT_ISO_NODE * sel_node, int sel_fields,
+			  const LWT_ISO_NODE * upd_node, int upd_fields,
+			  const LWT_ISO_NODE * exc_node, int exc_fields);
+
+int callback_updateTopoGeomFaceSplit (const LWT_BE_TOPOLOGY * topo,
+				      LWT_ELEMID split_face,
+				      LWT_ELEMID new_face1,
+				      LWT_ELEMID new_face2);
+
+int callback_insertFaces (const LWT_BE_TOPOLOGY * topo,
+			  LWT_ISO_FACE * faces, int numelems);
+
+int callback_updateFacesById (const LWT_BE_TOPOLOGY * topo,
+			      const LWT_ISO_FACE * faces, int numfaces);
+
+int callback_deleteFacesById (const LWT_BE_TOPOLOGY * topo,
+			      const LWT_ELEMID * ids, int numelems);
+
+LWT_ELEMID *callback_getRingEdges (const LWT_BE_TOPOLOGY * topo,
+				   LWT_ELEMID edge, int *numedges, int limit);
+
+int callback_updateEdgesById (const LWT_BE_TOPOLOGY * topo,
+			      const LWT_ISO_EDGE * edges, int numedges,
+			      int upd_fields);
+
+LWT_ISO_EDGE *callback_getEdgeByFace (const LWT_BE_TOPOLOGY * topo,
+				      const LWT_ELEMID * ids,
+				      int *numelems, int fields,
+				      const GBOX * box);
+
+LWT_ISO_NODE *callback_getNodeByFace (const LWT_BE_TOPOLOGY * topo,
+				      const LWT_ELEMID * faces,
+				      int *numelems, int fields,
+				      const GBOX * box);
+
+int callback_updateNodesById (const LWT_BE_TOPOLOGY * topo,
+			      const LWT_ISO_NODE * nodes, int numnodes,
+			      int upd_fields);
+
+int callback_deleteNodesById (const LWT_BE_TOPOLOGY * topo,
+			      const LWT_ELEMID * ids, int numelems);
+
+int callback_updateTopoGeomEdgeSplit (const LWT_BE_TOPOLOGY * topo,
+				      LWT_ELEMID split_edge,
+				      LWT_ELEMID new_edge1,
+				      LWT_ELEMID new_edge2);
+
+int callback_checkTopoGeomRemEdge (const LWT_BE_TOPOLOGY * topo,
+				   LWT_ELEMID rem_edge, LWT_ELEMID face_left,
+				   LWT_ELEMID face_right);
+
+int callback_updateTopoGeomFaceHeal (const LWT_BE_TOPOLOGY * topo,
+				     LWT_ELEMID face1, LWT_ELEMID face2,
+				     LWT_ELEMID newface);
+
+int callback_checkTopoGeomRemNode (const LWT_BE_TOPOLOGY * topo,
+				   LWT_ELEMID rem_node, LWT_ELEMID e1,
+				   LWT_ELEMID e2);
+
+int callback_updateTopoGeomEdgeHeal (const LWT_BE_TOPOLOGY * topo,
+				     LWT_ELEMID edge1, LWT_ELEMID edge2,
+				     LWT_ELEMID newedge);
+
+LWT_ISO_FACE *callback_getFaceWithinBox2D (const LWT_BE_TOPOLOGY * topo,
+					   const GBOX * box, int *numelems,
+					   int fields, int limit);
+
+int callback_topoGetSRID (const LWT_BE_TOPOLOGY * topo);
+
+double callback_topoGetPrecision (const LWT_BE_TOPOLOGY * topo);
+
+int callback_topoHasZ (const LWT_BE_TOPOLOGY * topo);
diff --git a/test/000323485.gpx b/test/000323485.gpx
new file mode 100644
index 0000000..d8c0c46
--- /dev/null
+++ b/test/000323485.gpx
@@ -0,0 +1,43 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gpx xmlns="http://www.topografix.com/GPX/1/0" version="1.0" creator="OSM gpx_dump.py">
+  <trk>
+    <name>Track 0</name>
+    <number>0</number>
+    <trkseg>
+      <trkpt lat="37.7709000" lon="-25.2021000" />
+      <trkpt lat="37.7710000" lon="-25.2002500" />
+      <trkpt lat="37.7696900" lon="-25.1987500" />
+      <trkpt lat="37.7699700" lon="-25.1971200" />
+      <trkpt lat="37.7710900" lon="-25.1959200" />
+      <trkpt lat="37.7724100" lon="-25.1965000" />
+      <trkpt lat="37.7732400" lon="-25.1979200" />
+      <trkpt lat="37.7742300" lon="-25.1977000" />
+      <trkpt lat="37.7753400" lon="-25.1970600" />
+      <trkpt lat="37.7767900" lon="-25.1965200" />
+      <trkpt lat="37.7764900" lon="-25.1947400" />
+      <trkpt lat="37.7780300" lon="-25.1951500" />
+      <trkpt lat="37.7788000" lon="-25.1962200" />
+      <trkpt lat="37.7796000" lon="-25.1974000" />
+      <trkpt lat="37.7803200" lon="-25.1982400" />
+      <trkpt lat="37.7815300" lon="-25.1986400" />
+      <trkpt lat="37.7816400" lon="-25.2000000" />
+      <trkpt lat="37.7833400" lon="-25.2002500" />
+      <trkpt lat="37.7845300" lon="-25.2007000" />
+      <trkpt lat="37.7860900" lon="-25.2016900" />
+      <trkpt lat="37.7867600" lon="-25.2007300" />
+      <trkpt lat="37.7858800" lon="-25.1993300" />
+      <trkpt lat="37.7859400" lon="-25.1976400" />
+      <trkpt lat="37.7854200" lon="-25.1959000" />
+      <trkpt lat="37.7856300" lon="-25.1953800" />
+      <trkpt lat="37.7863600" lon="-25.1947600" />
+      <trkpt lat="37.7868000" lon="-25.1937500" />
+      <trkpt lat="37.7874600" lon="-25.1929800" />
+      <trkpt lat="37.7877000" lon="-25.1914100" />
+      <trkpt lat="37.7887000" lon="-25.1899300" />
+      <trkpt lat="37.7897800" lon="-25.1885600" />
+      <trkpt lat="37.7913100" lon="-25.1864100" />
+      <trkpt lat="37.7936600" lon="-25.1853600" />
+      <trkpt lat="37.7961200" lon="-25.1847800" />
+    </trkseg>
+  </trk>
+</gpx>
diff --git a/test/Gpx-sample.gpx b/test/Gpx-sample.gpx
new file mode 100644
index 0000000..ed908fa
--- /dev/null
+++ b/test/Gpx-sample.gpx
@@ -0,0 +1,421 @@
+<?xml version="1.0"?>
+<gpx version="1.0" creator="maemo-mapper" xmlns="http://www.topografix.com/GPX/1/0">
+  <trk>
+    <trkseg>
+      <trkpt lat="55.753572" lon="37.808250">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:30Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753622" lon="37.808255">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:31Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753593" lon="37.808158">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:32Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753597" lon="37.808158">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:33Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753587" lon="37.808177">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:34Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753565" lon="37.808157">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:35Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753552" lon="37.808140">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:36Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753513" lon="37.808103">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:37Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753493" lon="37.808077">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:38Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753460" lon="37.808065">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:39Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753457" lon="37.808053">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:40Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753390" lon="37.808072">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:41Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.61</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753365" lon="37.808068">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:42Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753332" lon="37.808057">
+        <ele>135.00</ele>
+        <time>2009-05-19T04:00:43Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753290" lon="37.808067">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:44Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753275" lon="37.808043">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:45Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753243" lon="37.808033">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:46Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753228" lon="37.808028">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:47Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753200" lon="37.808005">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:48Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753193" lon="37.807987">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:49Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753193" lon="37.807950">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:50Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753185" lon="37.807892">
+        <ele>133.00</ele>
+        <time>2009-05-19T04:00:51Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753175" lon="37.807818">
+        <ele>133.00</ele>
+        <time>2009-05-19T04:00:52Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753180" lon="37.807740">
+        <ele>133.00</ele>
+        <time>2009-05-19T04:00:53Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753183" lon="37.807653">
+        <ele>133.00</ele>
+        <time>2009-05-19T04:00:54Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753185" lon="37.807547">
+        <ele>133.00</ele>
+        <time>2009-05-19T04:00:55Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753192" lon="37.807437">
+        <ele>133.00</ele>
+        <time>2009-05-19T04:00:56Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753203" lon="37.807312">
+        <ele>132.00</ele>
+        <time>2009-05-19T04:00:57Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753208" lon="37.807168">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:58Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753220" lon="37.807020">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:00:59Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753238" lon="37.806860">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:01:00Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.753267" lon="37.806703">
+        <ele>134.00</ele>
+        <time>2009-05-19T04:01:01Z</time>
+        <fix>2d</fix>
+        <sat>3</sat>
+        <hdop>2.60</hdop>
+        <vdop>1.00</vdop>
+        <pdop>2.79</pdop>
+      </trkpt>
+      <trkpt lat="55.758175" lon="37.677798">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:14Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758175" lon="37.677798">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:15Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758175" lon="37.677800">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:16Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677800">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:17Z</time>
+        <fix>3d</fix>
+        <sat>7</sat>
+        <hdop>1.17</hdop>
+        <vdop>0.94</vdop>
+        <pdop>1.50</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677800">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:18Z</time>
+        <fix>3d</fix>
+        <sat>7</sat>
+        <hdop>1.17</hdop>
+        <vdop>0.94</vdop>
+        <pdop>1.50</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677802">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:19Z</time>
+        <fix>3d</fix>
+        <sat>7</sat>
+        <hdop>1.17</hdop>
+        <vdop>0.94</vdop>
+        <pdop>1.50</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677802">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:20Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677800">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:21Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677802">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:22Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677802">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:23Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677803">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:24Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758178" lon="37.677803">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:25Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677803">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:26Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+      <trkpt lat="55.758177" lon="37.677802">
+        <ele>152.00</ele>
+        <time>2009-05-19T04:46:27Z</time>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.09</hdop>
+        <vdop>0.92</vdop>
+        <pdop>1.43</pdop>
+      </trkpt>
+    </trkseg>
+  </trk>
+</gpx>
diff --git a/test/Makefile.am b/test/Makefile.am
index 012a9a8..bad520c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -54,7 +54,15 @@ check_PROGRAMS = check_endian \
 		check_metacatalog \
 		check_virtualelem \
 		check_srid_fncts \
-		check_control_points
+		check_control_points \
+		check_cutter \
+		check_topology2d \
+		check_topology3d \
+		check_topoplus \
+		check_network2d \
+		check_network3d \
+		check_network_log \
+		check_virtualknn
 		
 if ENABLE_GEOPACKAGE
 check_PROGRAMS += \
@@ -100,8 +108,7 @@ TESTS = $(check_PROGRAMS)
 
 MOSTLYCLEANFILES = *.gcna *.gcno *.gcda
 
-EXTRA_DIST = asprintf4win.h \
-	fnmatch_impl4win.h \
+EXTRA_DIST = fnmatch_impl4win.h \
 	fnmatch4win.h \
 	scandir4win.h \
 	test_helpers.h \
@@ -184,12 +191,17 @@ EXTRA_DIST = asprintf4win.h \
 	22.dxf f06.dxf l02.dxf p05.dxf \
 	archaic.dxf linked.dxf hatch.dxf \
 	symbol.dxf gpkg_test.sqlite gpkg_test.gpkg \
-	gpkg_test_broken.gpkg gpkg_test_extrasrid.gpkg
+	gpkg_test_broken.gpkg gpkg_test_extrasrid.gpkg \
+	elba-pg.shp elba-pg.shx elba-pg.dbf \
+	elba-ln.shp elba-ln.shx elba-ln.dbf \
+	Gpx-sample.gpx 000323485.gpx
 
 SUBDIRS = sql_stmt_geosadvanced_tests sql_stmt_geos_tests \
 	sql_stmt_libxml2_tests sql_stmt_lwgeom_tests \
+	sql_stmt_lwgeom_20_tests sql_stmt_lwgeom_22_tests \
 	sql_stmt_mathsql_tests sql_stmt_proj_tests \
 	sql_stmt_security_tests sql_stmt_tests \
 	sql_stmt_xmlsec_tests sql_stmt_geopackage_tests \
 	sql_stmt_freexl_tests sql_stmt_cache_tests \
-	sql_stmt_nocache_tests
+	sql_stmt_nocache_tests sql_stmt_voronoj1_tests \
+	sql_stmt_voronoj2_tests
diff --git a/test/Makefile.in b/test/Makefile.in
index dff11c9..becaffa 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -114,7 +114,11 @@ check_PROGRAMS = check_endian$(EXEEXT) check_version$(EXEEXT) \
 	check_virtualbbox$(EXEEXT) check_wfsin$(EXEEXT) \
 	check_dxf$(EXEEXT) check_metacatalog$(EXEEXT) \
 	check_virtualelem$(EXEEXT) check_srid_fncts$(EXEEXT) \
-	check_control_points$(EXEEXT) $(am__EXEEXT_1)
+	check_control_points$(EXEEXT) check_cutter$(EXEEXT) \
+	check_topology2d$(EXEEXT) check_topology3d$(EXEEXT) \
+	check_topoplus$(EXEEXT) check_network2d$(EXEEXT) \
+	check_network3d$(EXEEXT) check_network_log$(EXEEXT) \
+	check_virtualknn$(EXEEXT) $(am__EXEEXT_1)
 @ENABLE_GEOPACKAGE_TRUE at am__append_1 = \
 @ENABLE_GEOPACKAGE_TRUE@		check_createBaseTables \
 @ENABLE_GEOPACKAGE_TRUE@		check_gpkgCreateTilesTable \
@@ -215,6 +219,9 @@ check_create_LDADD = $(LDADD)
 check_createBaseTables_SOURCES = check_createBaseTables.c
 check_createBaseTables_OBJECTS = check_createBaseTables.$(OBJEXT)
 check_createBaseTables_LDADD = $(LDADD)
+check_cutter_SOURCES = check_cutter.c
+check_cutter_OBJECTS = check_cutter.$(OBJEXT)
+check_cutter_LDADD = $(LDADD)
 check_dbf_load_SOURCES = check_dbf_load.c
 check_dbf_load_OBJECTS = check_dbf_load.$(OBJEXT)
 check_dbf_load_LDADD = $(LDADD)
@@ -400,6 +407,15 @@ check_metacatalog_LDADD = $(LDADD)
 check_multithread_SOURCES = check_multithread.c
 check_multithread_OBJECTS = check_multithread.$(OBJEXT)
 check_multithread_LDADD = $(LDADD)
+check_network2d_SOURCES = check_network2d.c
+check_network2d_OBJECTS = check_network2d.$(OBJEXT)
+check_network2d_LDADD = $(LDADD)
+check_network3d_SOURCES = check_network3d.c
+check_network3d_OBJECTS = check_network3d.$(OBJEXT)
+check_network3d_LDADD = $(LDADD)
+check_network_log_SOURCES = check_network_log.c
+check_network_log_OBJECTS = check_network_log.$(OBJEXT)
+check_network_log_LDADD = $(LDADD)
 check_recover_geom_SOURCES = check_recover_geom.c
 check_recover_geom_OBJECTS = check_recover_geom.$(OBJEXT)
 check_recover_geom_LDADD = $(LDADD)
@@ -424,6 +440,15 @@ check_srid_fncts_LDADD = $(LDADD)
 check_styling_SOURCES = check_styling.c
 check_styling_OBJECTS = check_styling.$(OBJEXT)
 check_styling_LDADD = $(LDADD)
+check_topology2d_SOURCES = check_topology2d.c
+check_topology2d_OBJECTS = check_topology2d.$(OBJEXT)
+check_topology2d_LDADD = $(LDADD)
+check_topology3d_SOURCES = check_topology3d.c
+check_topology3d_OBJECTS = check_topology3d.$(OBJEXT)
+check_topology3d_LDADD = $(LDADD)
+check_topoplus_SOURCES = check_topoplus.c
+check_topoplus_OBJECTS = check_topoplus.$(OBJEXT)
+check_topoplus_LDADD = $(LDADD)
 check_version_SOURCES = check_version.c
 check_version_OBJECTS = check_version.$(OBJEXT)
 check_version_LDADD = $(LDADD)
@@ -436,6 +461,9 @@ check_virtualbbox_LDADD = $(LDADD)
 check_virtualelem_SOURCES = check_virtualelem.c
 check_virtualelem_OBJECTS = check_virtualelem.$(OBJEXT)
 check_virtualelem_LDADD = $(LDADD)
+check_virtualknn_SOURCES = check_virtualknn.c
+check_virtualknn_OBJECTS = check_virtualknn.$(OBJEXT)
+check_virtualknn_LDADD = $(LDADD)
 check_virtualtable1_SOURCES = check_virtualtable1.c
 check_virtualtable1_OBJECTS = check_virtualtable1.$(OBJEXT)
 check_virtualtable1_LDADD = $(LDADD)
@@ -518,13 +546,13 @@ am__v_CCLD_1 =
 SOURCES = check_add_tile_triggers.c \
 	check_add_tile_triggers_bad_table_name.c check_bufovflw.c \
 	check_clone_table.c check_control_points.c check_create.c \
-	check_createBaseTables.c check_dbf_load.c check_dxf.c \
-	check_endian.c check_exif.c check_exif2.c check_extension.c \
-	check_extra_relations_fncts.c check_fdo1.c check_fdo2.c \
-	check_fdo3.c check_fdo_bufovflw.c check_gaia_utf8.c \
-	check_gaia_util.c check_geom_aux.c check_geometry_cols.c \
-	check_geoscvt_fncts.c check_get_normal_row.c \
-	check_get_normal_row_bad_geopackage.c \
+	check_createBaseTables.c check_cutter.c check_dbf_load.c \
+	check_dxf.c check_endian.c check_exif.c check_exif2.c \
+	check_extension.c check_extra_relations_fncts.c check_fdo1.c \
+	check_fdo2.c check_fdo3.c check_fdo_bufovflw.c \
+	check_gaia_utf8.c check_gaia_util.c check_geom_aux.c \
+	check_geometry_cols.c check_geoscvt_fncts.c \
+	check_get_normal_row.c check_get_normal_row_bad_geopackage.c \
 	check_get_normal_row_bad_geopackage2.c check_get_normal_zoom.c \
 	check_get_normal_zoom_bad_geopackage.c \
 	check_get_normal_zoom_bad_geopackage2.c \
@@ -544,26 +572,29 @@ SOURCES = check_add_tile_triggers.c \
 	check_gpkg_opt_extension_mechanism_extensions_data_table_def.c \
 	check_init.c check_init2.c check_libxml2.c check_math_funcs.c \
 	check_mbrcache.c check_md5.c check_metacatalog.c \
-	check_multithread.c check_recover_geom.c \
+	check_multithread.c check_network2d.c check_network3d.c \
+	check_network_log.c check_recover_geom.c \
 	check_relations_fncts.c check_shp_load.c check_shp_load_3d.c \
 	check_spatialindex.c check_sql_stmt.c check_srid_fncts.c \
-	check_styling.c check_version.c check_virtual_ovflw.c \
-	check_virtualbbox.c check_virtualelem.c check_virtualtable1.c \
-	check_virtualtable2.c check_virtualtable3.c \
-	check_virtualtable4.c check_virtualtable5.c \
-	check_virtualtable6.c check_virtualxpath.c check_wfsin.c \
-	check_xls_load.c shape_3d.c shape_cp1252.c shape_primitives.c \
-	shape_utf8_1.c shape_utf8_1ex.c shape_utf8_2.c
+	check_styling.c check_topology2d.c check_topology3d.c \
+	check_topoplus.c check_version.c check_virtual_ovflw.c \
+	check_virtualbbox.c check_virtualelem.c check_virtualknn.c \
+	check_virtualtable1.c check_virtualtable2.c \
+	check_virtualtable3.c check_virtualtable4.c \
+	check_virtualtable5.c check_virtualtable6.c \
+	check_virtualxpath.c check_wfsin.c check_xls_load.c shape_3d.c \
+	shape_cp1252.c shape_primitives.c shape_utf8_1.c \
+	shape_utf8_1ex.c shape_utf8_2.c
 DIST_SOURCES = check_add_tile_triggers.c \
 	check_add_tile_triggers_bad_table_name.c check_bufovflw.c \
 	check_clone_table.c check_control_points.c check_create.c \
-	check_createBaseTables.c check_dbf_load.c check_dxf.c \
-	check_endian.c check_exif.c check_exif2.c check_extension.c \
-	check_extra_relations_fncts.c check_fdo1.c check_fdo2.c \
-	check_fdo3.c check_fdo_bufovflw.c check_gaia_utf8.c \
-	check_gaia_util.c check_geom_aux.c check_geometry_cols.c \
-	check_geoscvt_fncts.c check_get_normal_row.c \
-	check_get_normal_row_bad_geopackage.c \
+	check_createBaseTables.c check_cutter.c check_dbf_load.c \
+	check_dxf.c check_endian.c check_exif.c check_exif2.c \
+	check_extension.c check_extra_relations_fncts.c check_fdo1.c \
+	check_fdo2.c check_fdo3.c check_fdo_bufovflw.c \
+	check_gaia_utf8.c check_gaia_util.c check_geom_aux.c \
+	check_geometry_cols.c check_geoscvt_fncts.c \
+	check_get_normal_row.c check_get_normal_row_bad_geopackage.c \
 	check_get_normal_row_bad_geopackage2.c check_get_normal_zoom.c \
 	check_get_normal_zoom_bad_geopackage.c \
 	check_get_normal_zoom_bad_geopackage2.c \
@@ -583,16 +614,19 @@ DIST_SOURCES = check_add_tile_triggers.c \
 	check_gpkg_opt_extension_mechanism_extensions_data_table_def.c \
 	check_init.c check_init2.c check_libxml2.c check_math_funcs.c \
 	check_mbrcache.c check_md5.c check_metacatalog.c \
-	check_multithread.c check_recover_geom.c \
+	check_multithread.c check_network2d.c check_network3d.c \
+	check_network_log.c check_recover_geom.c \
 	check_relations_fncts.c check_shp_load.c check_shp_load_3d.c \
 	check_spatialindex.c check_sql_stmt.c check_srid_fncts.c \
-	check_styling.c check_version.c check_virtual_ovflw.c \
-	check_virtualbbox.c check_virtualelem.c check_virtualtable1.c \
-	check_virtualtable2.c check_virtualtable3.c \
-	check_virtualtable4.c check_virtualtable5.c \
-	check_virtualtable6.c check_virtualxpath.c check_wfsin.c \
-	check_xls_load.c shape_3d.c shape_cp1252.c shape_primitives.c \
-	shape_utf8_1.c shape_utf8_1ex.c shape_utf8_2.c
+	check_styling.c check_topology2d.c check_topology3d.c \
+	check_topoplus.c check_version.c check_virtual_ovflw.c \
+	check_virtualbbox.c check_virtualelem.c check_virtualknn.c \
+	check_virtualtable1.c check_virtualtable2.c \
+	check_virtualtable3.c check_virtualtable4.c \
+	check_virtualtable5.c check_virtualtable6.c \
+	check_virtualxpath.c check_wfsin.c check_xls_load.c shape_3d.c \
+	shape_cp1252.c shape_primitives.c shape_utf8_1.c \
+	shape_utf8_1ex.c shape_utf8_2.c
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
 	ctags-recursive dvi-recursive html-recursive info-recursive \
 	install-data-recursive install-dvi-recursive \
@@ -1000,8 +1034,7 @@ AM_CFLAGS = -I at srcdir@/../src/headers -I at srcdir@
 @MINGW_TRUE at AM_LDFLAGS = -L../src -lspatialite -lm -lxml2 $(GCOV_FLAGS)
 TESTS = $(check_PROGRAMS)
 MOSTLYCLEANFILES = *.gcna *.gcno *.gcda
-EXTRA_DIST = asprintf4win.h \
-	fnmatch_impl4win.h \
+EXTRA_DIST = fnmatch_impl4win.h \
 	fnmatch4win.h \
 	scandir4win.h \
 	test_helpers.h \
@@ -1084,15 +1117,20 @@ EXTRA_DIST = asprintf4win.h \
 	22.dxf f06.dxf l02.dxf p05.dxf \
 	archaic.dxf linked.dxf hatch.dxf \
 	symbol.dxf gpkg_test.sqlite gpkg_test.gpkg \
-	gpkg_test_broken.gpkg gpkg_test_extrasrid.gpkg
+	gpkg_test_broken.gpkg gpkg_test_extrasrid.gpkg \
+	elba-pg.shp elba-pg.shx elba-pg.dbf \
+	elba-ln.shp elba-ln.shx elba-ln.dbf \
+	Gpx-sample.gpx 000323485.gpx
 
 SUBDIRS = sql_stmt_geosadvanced_tests sql_stmt_geos_tests \
 	sql_stmt_libxml2_tests sql_stmt_lwgeom_tests \
+	sql_stmt_lwgeom_20_tests sql_stmt_lwgeom_22_tests \
 	sql_stmt_mathsql_tests sql_stmt_proj_tests \
 	sql_stmt_security_tests sql_stmt_tests \
 	sql_stmt_xmlsec_tests sql_stmt_geopackage_tests \
 	sql_stmt_freexl_tests sql_stmt_cache_tests \
-	sql_stmt_nocache_tests
+	sql_stmt_nocache_tests sql_stmt_voronoj1_tests \
+	sql_stmt_voronoj2_tests
 
 all: all-recursive
 
@@ -1165,6 +1203,10 @@ check_createBaseTables$(EXEEXT): $(check_createBaseTables_OBJECTS) $(check_creat
 	@rm -f check_createBaseTables$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_createBaseTables_OBJECTS) $(check_createBaseTables_LDADD) $(LIBS)
 
+check_cutter$(EXEEXT): $(check_cutter_OBJECTS) $(check_cutter_DEPENDENCIES) $(EXTRA_check_cutter_DEPENDENCIES) 
+	@rm -f check_cutter$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_cutter_OBJECTS) $(check_cutter_LDADD) $(LIBS)
+
 check_dbf_load$(EXEEXT): $(check_dbf_load_OBJECTS) $(check_dbf_load_DEPENDENCIES) $(EXTRA_check_dbf_load_DEPENDENCIES) 
 	@rm -f check_dbf_load$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_dbf_load_OBJECTS) $(check_dbf_load_LDADD) $(LIBS)
@@ -1365,6 +1407,18 @@ check_multithread$(EXEEXT): $(check_multithread_OBJECTS) $(check_multithread_DEP
 	@rm -f check_multithread$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_multithread_OBJECTS) $(check_multithread_LDADD) $(LIBS)
 
+check_network2d$(EXEEXT): $(check_network2d_OBJECTS) $(check_network2d_DEPENDENCIES) $(EXTRA_check_network2d_DEPENDENCIES) 
+	@rm -f check_network2d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_network2d_OBJECTS) $(check_network2d_LDADD) $(LIBS)
+
+check_network3d$(EXEEXT): $(check_network3d_OBJECTS) $(check_network3d_DEPENDENCIES) $(EXTRA_check_network3d_DEPENDENCIES) 
+	@rm -f check_network3d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_network3d_OBJECTS) $(check_network3d_LDADD) $(LIBS)
+
+check_network_log$(EXEEXT): $(check_network_log_OBJECTS) $(check_network_log_DEPENDENCIES) $(EXTRA_check_network_log_DEPENDENCIES) 
+	@rm -f check_network_log$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_network_log_OBJECTS) $(check_network_log_LDADD) $(LIBS)
+
 check_recover_geom$(EXEEXT): $(check_recover_geom_OBJECTS) $(check_recover_geom_DEPENDENCIES) $(EXTRA_check_recover_geom_DEPENDENCIES) 
 	@rm -f check_recover_geom$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_recover_geom_OBJECTS) $(check_recover_geom_LDADD) $(LIBS)
@@ -1397,6 +1451,18 @@ check_styling$(EXEEXT): $(check_styling_OBJECTS) $(check_styling_DEPENDENCIES) $
 	@rm -f check_styling$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_styling_OBJECTS) $(check_styling_LDADD) $(LIBS)
 
+check_topology2d$(EXEEXT): $(check_topology2d_OBJECTS) $(check_topology2d_DEPENDENCIES) $(EXTRA_check_topology2d_DEPENDENCIES) 
+	@rm -f check_topology2d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_topology2d_OBJECTS) $(check_topology2d_LDADD) $(LIBS)
+
+check_topology3d$(EXEEXT): $(check_topology3d_OBJECTS) $(check_topology3d_DEPENDENCIES) $(EXTRA_check_topology3d_DEPENDENCIES) 
+	@rm -f check_topology3d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_topology3d_OBJECTS) $(check_topology3d_LDADD) $(LIBS)
+
+check_topoplus$(EXEEXT): $(check_topoplus_OBJECTS) $(check_topoplus_DEPENDENCIES) $(EXTRA_check_topoplus_DEPENDENCIES) 
+	@rm -f check_topoplus$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_topoplus_OBJECTS) $(check_topoplus_LDADD) $(LIBS)
+
 check_version$(EXEEXT): $(check_version_OBJECTS) $(check_version_DEPENDENCIES) $(EXTRA_check_version_DEPENDENCIES) 
 	@rm -f check_version$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_version_OBJECTS) $(check_version_LDADD) $(LIBS)
@@ -1413,6 +1479,10 @@ check_virtualelem$(EXEEXT): $(check_virtualelem_OBJECTS) $(check_virtualelem_DEP
 	@rm -f check_virtualelem$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_virtualelem_OBJECTS) $(check_virtualelem_LDADD) $(LIBS)
 
+check_virtualknn$(EXEEXT): $(check_virtualknn_OBJECTS) $(check_virtualknn_DEPENDENCIES) $(EXTRA_check_virtualknn_DEPENDENCIES) 
+	@rm -f check_virtualknn$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(check_virtualknn_OBJECTS) $(check_virtualknn_LDADD) $(LIBS)
+
 check_virtualtable1$(EXEEXT): $(check_virtualtable1_OBJECTS) $(check_virtualtable1_DEPENDENCIES) $(EXTRA_check_virtualtable1_DEPENDENCIES) 
 	@rm -f check_virtualtable1$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(check_virtualtable1_OBJECTS) $(check_virtualtable1_LDADD) $(LIBS)
@@ -1486,6 +1556,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_control_points.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_create.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_createBaseTables.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_cutter.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_dbf_load.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_dxf.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_endian.Po at am__quote@
@@ -1536,6 +1607,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_md5.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_metacatalog.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_multithread.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_network2d.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_network3d.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_network_log.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_recover_geom.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_relations_fncts.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_shp_load.Po at am__quote@
@@ -1544,10 +1618,14 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_sql_stmt.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_srid_fncts.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_styling.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_topology2d.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_topology3d.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_topoplus.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_version.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtual_ovflw.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtualbbox.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtualelem.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtualknn.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtualtable1.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtualtable2.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/check_virtualtable3.Po at am__quote@
@@ -2216,6 +2294,62 @@ check_control_points.log: check_control_points$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_cutter.log: check_cutter$(EXEEXT)
+	@p='check_cutter$(EXEEXT)'; \
+	b='check_cutter'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_topology2d.log: check_topology2d$(EXEEXT)
+	@p='check_topology2d$(EXEEXT)'; \
+	b='check_topology2d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_topology3d.log: check_topology3d$(EXEEXT)
+	@p='check_topology3d$(EXEEXT)'; \
+	b='check_topology3d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_topoplus.log: check_topoplus$(EXEEXT)
+	@p='check_topoplus$(EXEEXT)'; \
+	b='check_topoplus'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_network2d.log: check_network2d$(EXEEXT)
+	@p='check_network2d$(EXEEXT)'; \
+	b='check_network2d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_network3d.log: check_network3d$(EXEEXT)
+	@p='check_network3d$(EXEEXT)'; \
+	b='check_network3d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_network_log.log: check_network_log$(EXEEXT)
+	@p='check_network_log$(EXEEXT)'; \
+	b='check_network_log'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+check_virtualknn.log: check_virtualknn$(EXEEXT)
+	@p='check_virtualknn$(EXEEXT)'; \
+	b='check_virtualknn'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 check_createBaseTables.log: check_createBaseTables$(EXEEXT)
 	@p='check_createBaseTables$(EXEEXT)'; \
 	b='check_createBaseTables'; \
diff --git a/test/asprintf4win.h b/test/asprintf4win.h
deleted file mode 100644
index 3725072..0000000
--- a/test/asprintf4win.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2001 Federico Di Gregorio <fog at debian.org> 
- * Copyright (C) 1991, 1994-1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This code has been derived from an example in the glibc2 documentation.
- * This file is part of the psycopg module.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * asprintf.c -- asprintf() implementation for braindamaged operating systems
- * $Id: asprintf.c 554 2004-10-30 00:19:27Z fog $
- */
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-#include <stdarg.h>
-#include <stdio.h>
-#ifndef _WIN32
-#include <sys/time.h>
-#endif
-#include <stdlib.h>
-
-#ifdef _WIN32
-#define vsnprintf _vsnprintf
-#endif
-
-int
-asprintf (char **buffer, char *fmt, ...)
-{
-    /* Guess we need no more than 200 chars of space. */
-    int size = 200;
-    int nchars;
-    va_list ap;
-
-    *buffer = (char *) malloc (size);
-    if (*buffer == NULL)
-	return -1;
-
-    /* Try to print in the allocated space. */
-    va_start (ap, fmt);
-    nchars = vsnprintf (*buffer, size, fmt, ap);
-    va_end (ap);
-
-    if (nchars >= size)
-      {
-	  char *tmpbuff;
-	  /* Reallocate buffer now that we know how much space is needed. */
-	  size = nchars + 1;
-	  tmpbuff = (char *) realloc (*buffer, size);
-
-
-	  if (tmpbuff == NULL)
-	    {			/* we need to free it */
-		free (*buffer);
-		return -1;
-	    }
-
-	  *buffer = tmpbuff;
-	  /* Try again. */
-	  va_start (ap, fmt);
-	  nchars = vsnprintf (*buffer, size, fmt, ap);
-	  va_end (ap);
-      }
-
-    if (nchars < 0)
-	return nchars;
-    return size;
-}
diff --git a/test/check_bufovflw.c b/test/check_bufovflw.c
index 594dcfb..781ee94 100644
--- a/test/check_bufovflw.c
+++ b/test/check_bufovflw.c
@@ -88,7 +88,6 @@ main (int argc, char *argv[])
     char *dbf;
     char *table_a;
     char *table_b;
-    char *topology;
     char *auth;
 #ifndef OMIT_PROJ		/* including PROJ.4 */
     char *kml1;
@@ -151,7 +150,6 @@ main (int argc, char *argv[])
     pk = sqlite3_mprintf ("id_%s", suffix);
     name = sqlite3_mprintf ("name_%s", suffix);
     geom = sqlite3_mprintf ("geom_%s", suffix);
-    topology = sqlite3_mprintf ("topology_%s_", suffix);
 
 /* creating table "A" */
     sql = sqlite3_mprintf ("CREATE TABLE %s (\n"
@@ -836,41 +834,11 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-/* creating a topology */
-    sql =
-	sqlite3_mprintf ("SELECT CreateTopologyTables(%Q, 4326, 'XY')",
-			 topology);
-    ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &err_msg);
-    sqlite3_free (sql);
-    if (ret != SQLITE_OK)
-      {
-	  fprintf (stderr, "CreateTopologyTables error: %s\n", err_msg);
-	  sqlite3_free (err_msg);
-	  sqlite3_close (handle);
-	  return -61;
-      }
-    if (rows != 1 || columns != 1)
-      {
-	  fprintf (stderr,
-		   "Unexpected rows/columns (CreateTopologyTables): r=%d c=%d\n",
-		   rows, columns);
-	  return -62;
-      }
-    value = results[1];
-    if (strcmp ("1", value) != 0)
-      {
-	  fprintf (stderr, "Unexpected result (CreateTopologyTables): %s\n",
-		   results[1]);
-	  return -63;
-      }
-    sqlite3_free_table (results);
-
     sqlite3_free (table_a);
     sqlite3_free (table_b);
     sqlite3_free (pk);
     sqlite3_free (name);
     sqlite3_free (geom);
-    sqlite3_free (topology);
 
 /* inserting a CRS (very long auth) */
     auth = sqlite3_mprintf ("authority_%s", suffix);
@@ -889,7 +857,7 @@ main (int argc, char *argv[])
 	  return -64;
       }
 
-#ifndef OMIT_EPSG /* only if full EPSG support is enabled */
+#ifndef OMIT_EPSG		/* only if full EPSG support is enabled */
 /* checking for validity (SRID from Auth) */
     sql = sqlite3_mprintf ("SELECT SridFromAuthCrs(%Q, %d)", auth, 1122);
     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &err_msg);
diff --git a/test/check_control_points.c b/test/check_control_points.c
index 7e98f87..e2c62dc 100644
--- a/test/check_control_points.c
+++ b/test/check_control_points.c
@@ -822,7 +822,7 @@ main (int argc, char *argv[])
 /* resolving Control Points 2D  - 2nd order- AsText */
     sql = "SELECT GCP_IsValid(GCP_Compute(a.geometry, b.geometry, 2)) "
 	"FROM point_a_xy AS a, point_b_xy AS b WHERE a.id = b.id";
-    if (!test_query	(handle, sql,"1"))
+    if (!test_query (handle, sql, "1"))
 	return -44;
 
 /* resolving Control Points 2D - 2nd order - GCP2ATM */
diff --git a/test/check_create.c b/test/check_create.c
index 602eca5..9a06177 100644
--- a/test/check_create.c
+++ b/test/check_create.c
@@ -193,13 +193,31 @@ main (int argc, char *argv[])
 	  sqlite3_close (handle);
 	  return -5;
       }
+    ret =
+	sqlite3_exec (handle, "SELECT HasGeosReentrant()", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "HasGeosReentrant() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -6;
+      }
+    ret =
+	sqlite3_exec (handle, "SELECT HasGeosOnlyReentrant()", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "HasGeosOnlyReentrant() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -7;
+      }
     ret = sqlite3_exec (handle, "SELECT HasIconv()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "HasIconv() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -6;
+	  return -8;
       }
     ret = sqlite3_exec (handle, "SELECT HasMathSql()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
@@ -207,7 +225,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasMathSql() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -7;
+	  return -9;
       }
     ret =
 	sqlite3_exec (handle, "SELECT HasGeoCallbacks()", NULL, NULL, &err_msg);
@@ -216,7 +234,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasGeoCallbacks() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -8;
+	  return -10;
       }
     ret = sqlite3_exec (handle, "SELECT HasFreeXL()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
@@ -224,7 +242,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasFreeXL() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -9;
+	  return -11;
       }
     ret = sqlite3_exec (handle, "SELECT HasEpsg()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
@@ -232,7 +250,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasEpsg() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -10;
+	  return -12;
       }
     ret = sqlite3_exec (handle, "SELECT HasGeosTrunk()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
@@ -240,7 +258,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasGeoTrunk() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -11;
+	  return -13;
       }
     ret = sqlite3_exec (handle, "SELECT HasLwGeom()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
@@ -248,7 +266,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasLwGeom() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -12;
+	  return -14;
       }
     ret = sqlite3_exec (handle, "SELECT HasLibXml2()", NULL, NULL, &err_msg);
     if (ret != SQLITE_OK)
@@ -256,7 +274,7 @@ main (int argc, char *argv[])
 	  fprintf (stderr, "HasLibXml2() error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  sqlite3_close (handle);
-	  return -13;
+	  return -15;
       }
 
     gaiaInsertIntoSqlLog (handle, "test", "sql_statement_ok", &log_pk);
@@ -269,7 +287,7 @@ main (int argc, char *argv[])
       {
 	  fprintf (stderr, "sqlite3_close() error: %s\n",
 		   sqlite3_errmsg (handle));
-	  return -11;
+	  return -16;
       }
 
     spatialite_cleanup_ex (cache);
diff --git a/test/check_cutter.c b/test/check_cutter.c
new file mode 100644
index 0000000..9838222
--- /dev/null
+++ b/test/check_cutter.c
@@ -0,0 +1,2765 @@
+/*
+
+ check_cutter.c -- SpatiaLite Test Case
+
+ uthor: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static void
+do_get_cutter_message (sqlite3 * sqlite, const char *test_sql)
+{
+/* reporting the last Cutter Message */
+    int ret;
+    const char *sql = "SELECT GetCutterMessage()";
+    sqlite3_stmt *stmt = NULL;
+
+    fprintf (stderr,
+	     "Failed ST_Cutter() test: %s\nGetCutterMessage() reports: ",
+	     test_sql);
+
+    ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "\n");
+	  return;
+      }
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
+		  {
+		      const char *msg =
+			  (const char *) sqlite3_column_text (stmt, 0);
+		      fprintf (stderr, "%s", msg);
+		  }
+	    }
+      }
+    sqlite3_finalize (stmt);
+    fprintf (stderr, "\n");
+}
+
+static int
+test_query (sqlite3 * sqlite, const char *sql)
+{
+/* testing some SQL query returning an INT value */
+    int ret;
+    int ok = 0;
+    sqlite3_stmt *stmt = NULL;
+    fprintf (stderr, "\n\n%s\n", sql);
+
+    ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "%s\n: \"%s\"\n", sql, sqlite3_errmsg (sqlite));
+	  return 0;
+      }
+    while (1)
+      {
+	  /* scrolling the result set rows */
+	  ret = sqlite3_step (stmt);
+	  if (ret == SQLITE_DONE)
+	      break;		/* end of result set */
+	  if (ret == SQLITE_ROW)
+	    {
+		if (sqlite3_column_type (stmt, 0) == SQLITE_INTEGER)
+		  {
+		      if (sqlite3_column_int (stmt, 0) >= 1)
+			  ok = 1;
+		  }
+	    }
+	  else
+	      goto error;
+      }
+    sqlite3_finalize (stmt);
+    if (ok != 1)
+	do_get_cutter_message (sqlite, sql);
+    return ok;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+static int
+check_cutter_main (sqlite3 * handle, int *retcode)
+{
+/* testing ST_Cutter - MAIN DB */
+    const char *sql;
+    int ret;
+
+/* cutting Points XY - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xy', NULL, NULL, 'blades_xyzm', NULL, 'out_points_xy_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 1;
+	  return 0;
+      }
+
+/* cutting Points XY - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xy', NULL, NULL, 'blades_xyz', NULL, 'out_points_xy_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 2;
+	  return 0;
+      }
+
+/* cutting Points XY - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xy', NULL, NULL, 'blades_xym', NULL, 'out_points_xy_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 3;
+	  return 0;
+      }
+
+/* cutting Points XY - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'points_xy', 'geometry', 'main', 'blades_xy', 'geometry', 'out_points_xy_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 4;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xy', NULL, NULL, 'blades_xyzm', NULL, 'out_lines_xy_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 5;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xy', NULL, NULL, 'blades_xyz', NULL, 'out_lines_xy_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 6;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xy', NULL, NULL, 'blades_xym', NULL, 'out_lines_xy_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 7;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'lines_xy', 'geometry', 'main', 'blades_xy', 'geometry', 'out_lines_xy_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 8;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xy', NULL, NULL, 'blades_xyzm', NULL, 'out_polygs_xy_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 9;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xy', NULL, NULL, 'blades_xyz', NULL, 'out_polygs_xy_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 10;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xy', NULL, NULL, 'blades_xym', NULL, 'out_polygs_xy_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 11;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'polygs_xy', 'geometry', 'main', 'blades_xy', 'geometry', 'out_polygs_xy_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 12;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xyz', NULL, NULL, 'blades_xyzm', NULL, 'out_points_xyz_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 13;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xyz', NULL, NULL, 'blades_xyz', NULL, 'out_points_xyz_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 14;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xyz', NULL, NULL, 'blades_xym', NULL, 'out_points_xyz_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 15;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'points_xyz', 'geometry', 'main', 'blades_xy', 'geometry', 'out_points_xyz_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 16;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xyz', NULL, NULL, 'blades_xyzm', NULL, 'out_lines_xyz_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 17;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xyz', NULL, NULL, 'blades_xyz', NULL, 'out_lines_xyz_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 18;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xyz', NULL, NULL, 'blades_xym', NULL, 'out_lines_xyz_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 19;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'lines_xyz', 'geometry', 'main', 'blades_xy', 'geometry', 'out_lines_xyz_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 20;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xyz', NULL, NULL, 'blades_xyzm', NULL, 'out_polygs_xyz_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 21;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xyz', NULL, NULL, 'blades_xyz', NULL, 'out_polygs_xyz_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 22;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xyz', NULL, NULL, 'blades_xym', NULL, 'out_polygs_xyz_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 23;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'polygs_xyz', 'geometry', 'main', 'blades_xy', 'geometry', 'out_polygs_xyz_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 24;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xym', NULL, NULL, 'blades_xyzm', NULL, 'out_points_xym_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 25;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xym', NULL, NULL, 'blades_xyz', NULL, 'out_points_xym_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 26;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xym', NULL, NULL, 'blades_xym', NULL, 'out_points_xym_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 27;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'points_xym', 'geometry', 'main', 'blades_xy', 'geometry', 'out_points_xym_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 28;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xym', NULL, NULL, 'blades_xyzm', NULL, 'out_lines_xym_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 29;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xym', NULL, NULL, 'blades_xyz', NULL, 'out_lines_xym_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 30;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xym', NULL, NULL, 'blades_xym', NULL, 'out_lines_xym_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 31;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'lines_xym', 'geometry', 'main', 'blades_xy', 'geometry', 'out_lines_xym_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 32;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xym', NULL, NULL, 'blades_xyzm', NULL, 'out_polygs_xym_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 33;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xym', NULL, NULL, 'blades_xyz', NULL, 'out_polygs_xym_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 34;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xym', NULL, NULL, 'blades_xym', NULL, 'out_polygs_xym_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 35;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'polygs_xym', 'geometry', 'main', 'blades_xy', 'geometry', 'out_polygs_xym_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 36;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xyzm', NULL, NULL, 'blades_xyzm', NULL, 'out_points_xyzm_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 37;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xyzm', NULL, NULL, 'blades_xyz', NULL, 'out_points_xyzm_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 38;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'points_xyzm', NULL, NULL, 'blades_xym', NULL, 'out_points_xyzm_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 39;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'points_xyzm', 'geometry', 'main', 'blades_xy', 'geometry', 'out_points_xyzm_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 40;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xyzm', NULL, NULL, 'blades_xyzm', NULL, 'out_lines_xyzm_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 41;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xyzm', NULL, NULL, 'blades_xyz', NULL, 'out_lines_xyzm_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 42;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'lines_xyzm', NULL, NULL, 'blades_xym', NULL, 'out_lines_xyzm_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 43;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'lines_xyzm', 'geometry', 'main', 'blades_xy', 'geometry', 'out_lines_xyzm_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 44;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xyzm', 'geometry', NULL, 'blades_xyzm', NULL, 'out_polygs_xyzm_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 45;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xyzm', 'geometry', NULL, 'blades_xyz', NULL, 'out_polygs_xyzm_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 46;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter(NULL, 'polygs_xyzm', 'geometry', NULL, 'blades_xym', NULL, 'out_polygs_xyzm_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 47;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('MAIN', 'polygs_xyzm', 'geometry', 'main', 'blades_xy', 'geometry', 'out_polygs_xyzm_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 48;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+check_cutter_attach (sqlite3 * handle, int *retcode)
+{
+/* testing ST_Cutter - ATTACHed DB */
+    const char *sql;
+    int ret;
+
+/* cutting Points XY - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xy', NULL, 'blade', 'blades_xyzm', NULL, 'out_points_xy_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 1;
+	  return 0;
+      }
+
+/* cutting Points XY - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xy', NULL, 'blade', 'blades_xyz', NULL, 'out_points_xy_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 2;
+	  return 0;
+      }
+
+/* cutting Points XY - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xy', NULL, 'blade', 'blades_xym', NULL, 'out_points_xy_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 3;
+	  return 0;
+      }
+
+/* cutting Points XY - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xy', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_points_xy_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 4;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xy', NULL, 'blade', 'blades_xyzm', NULL, 'out_lines_xy_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 5;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xy', NULL, 'blade', 'blades_xyz', NULL, 'out_lines_xy_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 6;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xy', NULL, 'blade', 'blades_xym', NULL, 'out_lines_xy_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 7;
+	  return 0;
+      }
+
+/* cutting Linestrings XY - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xy', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_lines_xy_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 8;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xy', NULL, 'blade', 'blades_xyzm', NULL, 'out_polygs_xy_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 9;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xy', NULL, 'blade', 'blades_xyz', NULL, 'out_polygs_xy_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 10;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xy', NULL, 'blade', 'blades_xym', NULL, 'out_polygs_xy_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 11;
+	  return 0;
+      }
+
+/* cutting Polygons XY - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xy', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_polygs_xy_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 12;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyz', NULL, 'blade', 'blades_xyzm', NULL, 'out_points_xyz_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 13;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyz', NULL, 'blade', 'blades_xyz', NULL, 'out_points_xyz_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 14;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyz', NULL, 'blade', 'blades_xym', NULL, 'out_points_xyz_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 15;
+	  return 0;
+      }
+
+/* cutting Points XYZ - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyz', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_points_xyz_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 16;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyz', NULL, 'blade', 'blades_xyzm', NULL, 'out_lines_xyz_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 17;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyz', NULL, 'blade', 'blades_xyz', NULL, 'out_lines_xyz_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 18;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyz', NULL, 'blade', 'blades_xym', NULL, 'out_lines_xyz_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 19;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZ - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyz', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_lines_xyz_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 20;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyz', NULL, 'blade', 'blades_xyzm', NULL, 'out_polygs_xyz_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 21;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyz', NULL, 'blade', 'blades_xyz', NULL, 'out_polygs_xyz_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 22;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyz', NULL, 'blade', 'blades_xym', NULL, 'out_polygs_xyz_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 23;
+	  return 0;
+      }
+
+/* cutting Polygons XYZ - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyz', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_polygs_xyz_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 24;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xym', NULL, 'blade', 'blades_xyzm', NULL, 'out_points_xym_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 25;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xym', NULL, 'blade', 'blades_xyz', NULL, 'out_points_xym_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 26;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xym', NULL, 'blade', 'blades_xym', NULL, 'out_points_xym_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 27;
+	  return 0;
+      }
+
+/* cutting Points XYM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xym', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_points_xym_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 28;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xym', NULL, 'blade', 'blades_xyzm', NULL, 'out_lines_xym_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 29;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xym', NULL, 'blade', 'blades_xyz', NULL, 'out_lines_xym_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 30;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xym', NULL, 'blade', 'blades_xym', NULL, 'out_lines_xym_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 31;
+	  return 0;
+      }
+
+/* cutting Linestrings XYM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xym', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_lines_xym_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 32;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xym', NULL, 'blade', 'blades_xyzm', NULL, 'out_polygs_xym_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 33;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xym', NULL, 'blade', 'blades_xyz', NULL, 'out_polygs_xym_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 34;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xym', NULL, 'blade', 'blades_xym', NULL, 'out_polygs_xym_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 35;
+	  return 0;
+      }
+
+/* cutting Polygons XYM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xym', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_polygs_xym_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 36;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyzm', NULL, 'blade', 'blades_xyzm', NULL, 'out_points_xyzm_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 37;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyzm', NULL, 'blade', 'blades_xyz', NULL, 'out_points_xyzm_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 38;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyzm', NULL, 'blade', 'blades_xym', NULL, 'out_points_xyzm_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 39;
+	  return 0;
+      }
+
+/* cutting Points XYZM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'points_xyzm', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_points_xyzm_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 40;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyzm', NULL, 'blade', 'blades_xyzm', NULL, 'out_lines_xyzm_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 41;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyzm', NULL, 'blade', 'blades_xyz', NULL, 'out_lines_xyzm_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 42;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyzm', NULL, 'blade', 'blades_xym', NULL, 'out_lines_xyzm_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 43;
+	  return 0;
+      }
+
+/* cutting Linestrings XYZM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'lines_xyzm', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_lines_xyzm_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 44;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XYZM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyzm', 'geometry', 'blade', 'blades_xyzm', NULL, 'out_polygs_xyzm_xyzm', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 45;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XYZ */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyzm', 'geometry', 'blade', 'blades_xyz', NULL, 'out_polygs_xyzm_xyz', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 46;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XYM */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyzm', 'geometry', 'blade', 'blades_xym', NULL, 'out_polygs_xyzm_xym', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 47;
+	  return 0;
+      }
+
+/* cutting Polygons XYZM - Blade XY */
+    sql =
+	"SELECT ST_Cutter('input', 'polygs_xyzm', 'geometry', 'blade', 'blades_xy', 'geometry', 'out_polygs_xyzm_xy', 1, 1)";
+    ret = test_query (handle, sql);
+    if (!ret)
+      {
+	  *retcode -= 48;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+create_points_xyzm (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POINT XYZM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret = sqlite3_exec (handle, "CREATE TABLE points_xyzm ("
+			"pk_2 DOUBLE NOT NULL, pk_1 TEXT NOT NULL, pk_3 TEXT NOT NULL,"
+			"CONSTRAINT points_xyzm_pk PRIMARY KEY (pk_1, pk_2, pk_3))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xyzm error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'points_xyzm', 'geometry', 4326, 'POINT', 'XYZM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xyzm Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'a', 'a', "
+		      "GeomFromText('POINT ZM(-10 10 1 2)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'a', 'b', "
+		      "GeomFromText('POINT ZM(16 3 2 22)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 4;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'a', 'c', "
+		      "GeomFromText('POINT ZM(34 9 3 12)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 5;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'a', 'd', "
+		      "GeomFromText('POINT ZM(14 15 4 15)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 6;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'a', 'e', "
+		      "GeomFromText('POINT ZM(10 10 4.5 11)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 7;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'a', 'f', "
+		      "GeomFromText('POINT ZM(7 10 14.5 17)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 8;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'b', 'a', "
+		      "GeomFromText('POINT ZM(10 8 12.5 7)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 9;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'b', 'b', "
+		      "GeomFromText('POINT ZM(10 8 2.5 7.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 10;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'b', 'c', "
+		      "GeomFromText('POINT ZM(20 2 23.5 72.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 11;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'b', 'd', "
+		      "GeomFromText('POINT ZM(24 4.25 23 74)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 12;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'b', 'e', "
+		      "GeomFromText('POINT ZM(23 0 25 41)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 13;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'b', 'f', "
+		      "GeomFromText('POINT ZM(5.1 5.1 22 51)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 14;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'c', 'a', "
+		      "GeomFromText('POINT ZM(25.1 5.1 22 51)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 15;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'c', 'b', "
+		      "GeomFromText('POINT ZM(8 2 32 71)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 16;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'c', 'c', "
+		      "GeomFromText('POINT ZM(28 2 36 75)', 4326))", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 17;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'c', 'd', "
+		      "GeomFromText('POINT ZM(11 111 3.6 7.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 18;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'c', 'e', "
+		      "GeomFromText('POINT ZM(12 112 4.6 76.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 19;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (1.0, 'c', 'f', "
+		      "GeomFromText('POINT ZM(17 117 46 75)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 20;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (2.0, 'a', 'a', "
+		      "GeomFromText('POINT ZM(25 85 47 76)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 21;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (2.0, 'a', 'b', "
+		      "GeomFromText('POINT ZM(15 95 74 67)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 22;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (2.0, 'a', 'c', "
+		      "GeomFromText('POINT ZM(25 95 78 68)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 23;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (2.0, 'a', 'd', "
+		      "GeomFromText('POINT ZM(55 85 79 58)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 24;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (2.0, 'a', 'e', "
+		      "GeomFromText('POINT ZM(40 120 79.5 58.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 25;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (2.0, 'a', 'f', "
+		      "GeomFromText('POINT ZM(42 120 79.5 58.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 26;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyzm VALUES (6.0, 'e', 'd', "
+		      "GeomFromText('POINT ZM(45 120 9.5 8.5)', 4326))", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 27;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_points_xyz (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POINT XYZ */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE points_xyz (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xyz error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'points_xyz', 'geometry', 4326, 'POINT', 'XYZ')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xyz Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xyz SELECT NULL, CastToXYZ(geometry) FROM points_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xyz Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_points_xym (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POINT XYM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE points_xym (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xym error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'points_xym', 'geometry', 4326, 'POINT', 'XYM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xym Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xym SELECT NULL, CastToXYM(geometry) FROM points_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xym Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_points_xy (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POINT XY */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE points_xy (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xy error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'points_xy', 'geometry', 4326, 'POINT', 'XY')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE points_xy Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO points_xy SELECT NULL, CastToXY(geometry) FROM points_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO points_xy Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_lines_xyzm (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - LINESTRING XYZM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret = sqlite3_exec (handle, "CREATE TABLE lines_xyzm ("
+			"pk_1 DOUBLE NOT NULL, pk_2 TEXT NOT NULL, pk_3 TEXT NOT NULL,"
+			"CONSTRAINT lines_xyzm_pk PRIMARY KEY (pk_1, pk_2, pk_3))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xyzm error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'lines_xyzm', 'geometry', 4326, 'LINESTRING', 'XYZM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xyzm Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (1.0, 'a', 'a', "
+			"GeomFromText('LINESTRING ZM(-10 5.5 1 2, 35 5.5 3 4)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (1.0, 'a', 'b', "
+			"GeomFromText('LINESTRING ZM(2 9 4 4, 7 9 5 5)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 4;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (1.0, 'a', 'c', "
+			"GeomFromText('LINESTRING ZM(6 4 3 2, 10 4 2 3)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 5;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (1.0, 'a', 'd', "
+			"GeomFromText('LINESTRING ZM(3 4.5 1 2, 7 4.5 4 3)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 6;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (1.0, 'a', 'e', "
+			"GeomFromText('LINESTRING ZM(2 2 5 5, 8 8 5 5)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 7;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (1.0, 'a', 'f', "
+			"GeomFromText('LINESTRING ZM(-1 2 2 3, 0 2 3 2, 0 0 2 3, 5 0 3 2, 5 -1 2 3)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 8;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'a', 'a', "
+			"GeomFromText('LINESTRING ZM(30 11 1 2, 30 6 2 1, 31 5 1 2, 30 4 1 2, 30 0 2 1, "
+			"24 0 2 1, 24 4 2 3, 26 4 3 2, 27 5 3 2, 26 6 2 3, 24 6 1 3, 24 10 3 1, 20 10 2 3, 20 3 2 1)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 9;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'b', 'a', "
+			"GeomFromText('LINESTRING ZM(-2 52 3 4, 20 52 4 3, 20 45 3 2)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 10;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'c', 'a', "
+			"GeomFromText('LINESTRING ZM(0 100 4 5, 100 100 5 4)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 11;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'd', 'a', "
+			"GeomFromText('LINESTRING ZM(20 80 2 4, 70 80 4 2)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 12;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'e', 'a', "
+			"GeomFromText('LINESTRING ZM(20 90 1 4, 70 90 2 3)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 13;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'f', 'a', "
+			"GeomFromText('LINESTRING ZM(20 70 6 2, 70 70 6 4)', 4326))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 14;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "INSERT INTO lines_xyzm VALUES (2.0, 'f', 'f', "
+			"GeomFromText('LINESTRING ZM(40 140 2 3, 60 140 3 4, 100 100 5 6, "
+			"60 60 7 1, 50 60 4 2)', 4326))", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 15;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_lines_xyz (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - LINESTRING XYZ */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE lines_xyz (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xyz error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'lines_xyz', 'geometry', 4326, 'LINESTRING', 'XYZ')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xyz Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO lines_xyz SELECT NULL, CastToXYZ(geometry) FROM lines_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xyz Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_lines_xym (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - LINESTRING XYM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE lines_xym (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xym error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'lines_xym', 'geometry', 4326, 'LINESTRING', 'XYM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xym Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO lines_xym SELECT NULL, CastToXYM(geometry) FROM lines_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xym Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_lines_xy (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - LINESTRING XY */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE lines_xy (pk_id INTEGER PRIMARY KEY)", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xy error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'lines_xy', 'geometry', 4326, 'LINESTRING', 'XY')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE lines_xy Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO lines_xy SELECT NULL, CastToXY(geometry) FROM lines_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO lines_xy Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_polygs_xyzm (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POLYGON XYZM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret = sqlite3_exec (handle, "CREATE TABLE polygs_xyzm ("
+			"pk_3 DOUBLE NOT NULL, pk_1 TEXT NOT NULL, pk_2 TEXT NOT NULL,"
+			"CONSTRAINT polygs_xyzm_pk PRIMARY KEY (pk_1, pk_2, pk_3))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polygs_xyzm error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'polygs_xyzm', 'geometry', 4326, 'POLYGON', 'XYZM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polygs_xyzm Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (1.5, 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((-2 15 1 2, 35 15 2 3, 35 5 3 2, -2 5 2 2, -2 15 1 2))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (1.0, 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((-2 5 1 1, 10 5 2 2, 10 -5 1 2, -2 -5 2 1, -2 5 1 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 4;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (1.1, 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((10 5 3 4, 20 5 3 4, 20 -5 4 3, 10 -5 4 3, 10 5 3 4))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 5;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (2.0, 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((20 5 2 5, 35 5 3 5, 35 -5 2 3, 20 -5 3 3, 20 5 2 5))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 6;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (3.5, 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((0 100 1 1, 100 100 2 2, 100 150 2 1, 0 150 2 3, 0 100 1 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 7;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (0.5, 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((0 100 2 3, 100 100 3 1, 100 50 1 3, 0 50 2 1, 0 100 2 3))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 8;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES (2.4, 'b', 'a', "
+		      "GeomFromText('POLYGON ZM((70 10 1 2, 100 10 2 1, 100 40 2 3, 70 40 3 2, 70 10 1 2), "
+		      "(80 20 2 2, 90 20 3 3, 90 30 2 3, 80 30 3 2, 80 20 2 2))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 9;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyzm VALUES ('a', 'b', 'c', "
+		      "GeomFromText('POLYGON ZM((80 20 1 2, 90 20 2 3, 90 30 3 4, 80 30 3 2, 80 20 1 2))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 10;
+	  return 0;
+      }
+
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'polygs_xyzm', 'centroid', 4326, 'POINT', 'XY')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polygs_xyzm Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 11;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE polygs_xyzm SET centroid = CastToXY(ST_Centroid(geometry))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE polygs_xyzm SET Centroid error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 12;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_polygs_xyz (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POLYGON XYZ */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE polygs_xyz (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polys_xyz error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'polygs_xyz', 'geometry', 4326, 'POLYGON', 'XYZ')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polys_xyz Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xyz SELECT NULL, CastToXYZ(geometry) FROM polygs_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xyz Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_polygs_xym (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POLYGON XYM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE polygs_xym (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polys_xym error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'polygs_xym', 'geometry', 4326, 'POLYGON', 'XYM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polys_xym Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xym SELECT NULL, CastToXYM(geometry) FROM polygs_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xym Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_polygs_xy (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - POLYGON XY */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE polygs_xy (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polys_xy error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'polygs_xy', 'geometry', 4326, 'POLYGON', 'XY')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE polys_xy Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO polygs_xy SELECT NULL, CastToXY(geometry) FROM polygs_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO polygs_xy Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_blades_xyzm (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - BLADES XYZM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret = sqlite3_exec (handle, "CREATE TABLE blades_xyzm ("
+			"pk_1 TEXT NOT NULL, pk_2 TEXT NOT NULL, pk_3 TEXT NOT NULL,"
+			"CONSTRAINT blades_xyzm_pk PRIMARY KEY (pk_1, pk_2, pk_3))",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xyzm error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'blades_xyzm', 'geometry', 4326, 'POLYGON', 'XYZM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xyzm Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO blades_xyzm VALUES ('a', 'a', 'a', "
+		      "GeomFromText('POLYGON ZM((0 0 0 0, 10 0 0 1, 10 10 1 1, 0 10 1 2, 0 0 0 0), "
+		      "(4 4 1 2, 6 4 2 1, 6 6 3 2, 4 6 2 1, 4 4 1 2))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO blades_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO blades_xyzm VALUES ('b', 'c', 'd', "
+		      "GeomFromText('POLYGON ZM((20 0 1 2, 30 0 2 3, 30 4 3 2, 31 5 2 3, 30 6 2 1, 30 10 2 0, 20 10 0 2, 20 0 1 2), "
+		      "(24 4 1 1, 26 4 2 2, 27 5 2 1, 26 6 1 2, 24 6 2 1, 24 4 1 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO blades_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 4;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO blades_xyzm VALUES ('d', 'c', 'e', "
+		      "GeomFromText('POLYGON ZM((50 50 1 2, 100 100 2 3, 50 150 3 2, 0 100 2 1, 0 50 1 0, 50 50 1 2), "
+		      "(40 80 1 2, 60 80 2 3, 60 100 3 4, 40 80 1 2), "
+		      "(10 100 1 3, 30 80 3 2, 30 100 2 3, 10 100 1 3))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO blades_xyzm Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 5;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_blades_xyz (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - BLADES XYZ */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE blades_xyz (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xyz error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'blades_xyz', 'geometry', 4326, 'POLYGON', 'XYZ')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xyz Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO blades_xyz SELECT NULL, CastToXYZ(geometry) FROM blades_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO blades_xyz Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_blades_xym (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - BLADES XYM */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE blades_xym (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xym error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'blades_xym', 'geometry', 4326, 'POLYGON', 'XYM')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xym Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT CreateSpatialIndex('blades_xym', 'geometry')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xym Spatial Index error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO blades_xym SELECT NULL, CastToXYM(geometry) FROM blades_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO blades_xym Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 4;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+create_blades_xy (sqlite3 * handle, int *retcode)
+{
+/* creating and populating a test table - BLADES XY */
+    int ret;
+    char *err_msg = NULL;
+
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE TABLE blades_xy (pk_id INTEGER PRIMARY KEY)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xy error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+    ret = sqlite3_exec (handle, "SELECT AddGeometryColumn("
+			"'blades_xy', 'geometry', 4326, 'POLYGON', 'XY')",
+			NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE blades_xy Geometry error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO blades_xy SELECT NULL, CastToXY(geometry) FROM blades_xyzm",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO blades_xy Geometry error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+    return 1;
+}
+
+static int
+check_cutter_attached (int *retcode)
+{
+/* testing ST_Cutter on ATTACHed DBs */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" databse: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  *retcode -= 1;
+	  return 0;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 2;
+	  return 0;
+      }
+
+    ret =
+	sqlite3_exec (handle,
+		      "ATTACH DATABASE \"./test_cutter.sqlite\" AS input", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ATTACH DATABASE Input: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 3;
+	  return 0;
+      }
+
+    ret =
+	sqlite3_exec (handle,
+		      "ATTACH DATABASE \"./test_cutter.sqlite\" AS blade", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ATTACH DATABASE Blade: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 4;
+	  return 0;
+      }
+
+    if (!check_cutter_attach (handle, retcode))
+      {
+	  *retcode -= 5;
+	  sqlite3_close (handle);
+	  return 0;
+      }
+
+    ret = sqlite3_exec (handle, "DETACH DATABASE input", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DETACH DATABASE Input: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 6;
+	  return 0;
+      }
+
+    ret = sqlite3_exec (handle, "DETACH DATABASE blade", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DETACH DATABASE Blade: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  *retcode -= 7;
+	  return 0;
+      }
+
+    ret = sqlite3_close (handle);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "sqlite3_close() error: %s\n",
+		   sqlite3_errmsg (handle));
+	  *retcode -= 8;
+	  return 0;
+      }
+
+    return 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+#ifndef OMIT_GEOS		/* only if GEOS is enabled */
+    int ret;
+    int retcode;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    unlink ("./test_cutter.sqlite");
+
+    ret =
+	sqlite3_open_v2 ("./test_cutter.sqlite", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \"test_cutter.sqlite\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+    ret = sqlite3_exec (handle, "BEGIN", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "BEGIN TRANSACTION error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* creating and populating a test table - POINT XYZM */
+    retcode = -10;
+    if (!create_points_xyzm (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POINT XYZ */
+    retcode = -10;
+    if (!create_points_xyz (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POINT XYM */
+    retcode = -50;
+    if (!create_points_xym (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POINT XY */
+    retcode = -100;
+    if (!create_points_xy (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - LINESTRING XYZM */
+    retcode = -150;
+    if (!create_lines_xyzm (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - LINESTRING XYZ */
+    retcode = -200;
+    if (!create_lines_xyz (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - LINESTRING XYM */
+    retcode = -250;
+    if (!create_lines_xym (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - LINESTRING XY */
+    retcode = -300;
+    if (!create_lines_xy (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POLYGON XYZM */
+    retcode = -350;
+    if (!create_polygs_xyzm (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POLYGON XYZ */
+    retcode = -400;
+    if (!create_polygs_xyz (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POLYGON XYM */
+    retcode = -450;
+    if (!create_polygs_xym (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - POLYGON XY */
+    retcode = -500;
+    if (!create_polygs_xy (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - BLADES XYZM */
+    retcode = -550;
+    if (!create_blades_xyzm (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - BLADES XYZ */
+    retcode = -600;
+    if (!create_blades_xyz (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - BLADES XYM */
+    retcode = -650;
+    if (!create_blades_xym (handle, &retcode))
+	return retcode;
+
+/* creating and populating a test table - BLADES XY */
+    retcode = -700;
+    if (!create_blades_xy (handle, &retcode))
+	return retcode;
+
+    ret = sqlite3_exec (handle, "COMMIT", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "COMMIT TRANSACTION error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+/* testing ST_Cutter - MAIN DB */
+    retcode = -750;
+    if (!check_cutter_main (handle, &retcode))
+	return retcode;
+
+    ret = sqlite3_close (handle);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "sqlite3_close() error: %s\n",
+		   sqlite3_errmsg (handle));
+	  return -5;
+      }
+
+    spatialite_cleanup_ex (cache);
+
+/* testing ST_Cutter - ATTACHED DB */
+    retcode = -800;
+    if (!check_cutter_attached (&retcode))
+	return retcode;
+
+#endif /* end GEOS conditional */
+    unlink ("./test_cutter.sqlite");
+
+    spatialite_shutdown ();
+    return 0;
+}
diff --git a/test/check_dxf.c b/test/check_dxf.c
index 99592d6..e0c2751 100644
--- a/test/check_dxf.c
+++ b/test/check_dxf.c
@@ -51,6 +51,12 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "spatialite.h"
 #include "spatialite/gg_dxf.h"
 
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
+
 #ifndef OMIT_GEOS		/* only if GEOS is enabled */
 
 static int
@@ -1402,6 +1408,11 @@ main (int argc, char *argv[])
 
     for (cache_mode = 0; cache_mode <= 1; cache_mode++)
       {
+#ifdef GEOS_USE_ONLY_R_API	/* skipping legacy test */
+if (!cache_mode)
+continue;
+#endif
+
 	  fprintf (stderr, "\n******* Testing DXF in %s cache-mode\n\n",
 		   cache_mode ? "current" : "legacy");
 
diff --git a/test/check_extension.c b/test/check_extension.c
index 7b4a698..45c578c 100644
--- a/test/check_extension.c
+++ b/test/check_extension.c
@@ -51,10 +51,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "sqlite3.h"
 #include "spatialite.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 int
 main (int argc, char *argv[])
 {
@@ -83,10 +79,10 @@ main (int argc, char *argv[])
 
     sqlite3_enable_load_extension (db_handle, 1);
 
-    asprintf (&sql_statement, "SELECT load_extension('mod_spatialite')");
+    sql_statement = sqlite3_mprintf ("SELECT load_extension('mod_spatialite')");
 
     ret = sqlite3_exec (db_handle, sql_statement, NULL, NULL, &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "load_extension() error: %s\n", err_msg);
@@ -94,11 +90,11 @@ main (int argc, char *argv[])
 	  return -2;
       }
 
-    asprintf (&sql_statement, "SELECT spatialite_version()");
+    sql_statement = sqlite3_mprintf ("SELECT spatialite_version()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -121,11 +117,11 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement, "SELECT geos_version()");
+    sql_statement = sqlite3_mprintf ("SELECT geos_version()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error2: %s\n", err_msg);
@@ -157,11 +153,11 @@ main (int argc, char *argv[])
 #endif /* end GEOS conditional */
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement, "SELECT proj4_version()");
+    sql_statement = sqlite3_mprintf ("SELECT proj4_version()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error3: %s\n", err_msg);
@@ -193,11 +189,11 @@ main (int argc, char *argv[])
 #endif /* end PROJ conditional */
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement, "SELECT spatialite_target_cpu()");
+    sql_statement = sqlite3_mprintf ("SELECT spatialite_target_cpu()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error4: %s\n", err_msg);
@@ -213,11 +209,11 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement, "SELECT lwgeom_version()");
+    sql_statement = sqlite3_mprintf ("SELECT lwgeom_version()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error5: %s\n", err_msg);
@@ -249,11 +245,11 @@ main (int argc, char *argv[])
 #endif /* end LWGEOM conditional */
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement, "SELECT libxml2_version()");
+    sql_statement = sqlite3_mprintf ("SELECT libxml2_version()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error6: %s\n", err_msg);
@@ -285,11 +281,11 @@ main (int argc, char *argv[])
 #endif /* end LIBXML2 conditional */
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement, "SELECT freexl_version()");
+    sql_statement = sqlite3_mprintf ("SELECT freexl_version()");
     ret =
-	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
-			   &err_msg);
-    free (sql_statement);
+	sqlite3_get_table (db_handle, sql_statement, &results, &rows,
+			   &columns, &err_msg);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error2: %s\n", err_msg);
diff --git a/test/check_fdo1.c b/test/check_fdo1.c
index 9e7c0e8..00955fe 100644
--- a/test/check_fdo1.c
+++ b/test/check_fdo1.c
@@ -54,6 +54,11 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "spatialite/gaiageo.h"
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
@@ -577,10 +582,12 @@ main (int argc, char *argv[])
     if (ret != 0)
 	return ret;
 
+#ifndef GEOS_ONLY_REENTRANT	/* skipping legacy mode test (non-thread-safe GEOS API) */
     fprintf (stderr, "********* testing in legacy mode\n");
     ret = do_test (1);
     if (ret != 0)
 	return ret;
+#endif
 
     spatialite_shutdown ();
     return 0;
diff --git a/test/check_gaia_utf8.c b/test/check_gaia_utf8.c
index 5fda3b9..0464bd1 100644
--- a/test/check_gaia_utf8.c
+++ b/test/check_gaia_utf8.c
@@ -52,10 +52,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "spatialite.h"
 #include "spatialite/gaiaaux.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 int
 main (int argc, char *argv[])
 {
@@ -67,27 +63,27 @@ main (int argc, char *argv[])
     if (argc > 1 || argv[0] == NULL)
 	argc = 1;		/* silencing stupid compiler warnings */
 
-    asprintf (&test_str1, "Hello World");
+    test_str1 = sqlite3_mprintf ("Hello World");
     gaiaConvertCharset (&test_str1, "ASCII", "UTF-8");
     if (strcmp (test_str1, "Hello World") != 0)
       {
 	  fprintf (stderr, "bad ASCII to UTF-8 conversion: %s\n", test_str1);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -1;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 
 #if 0
     /* TODO: this will cause a buffer overflow */
-    asprintf (&test_str1, "Hello World");
+    test_str1 = sqlite_mprintf ("Hello World");
     gaiaConvertCharset (&test_str1, "ASCII", "UTF-16LE");
     if (memcmp (test_str1, "H\0e\0l\0l\0o\0 \0W\0o\0r\0l\0d\0\0\0", 24) != 0)
       {
 	  fprintf (stderr, "bad ASCII to UTF-16LE conversion\n");
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -2;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 #endif
 
     converter = gaiaCreateUTF8Converter ("CP1252");
diff --git a/test/check_gaia_util.c b/test/check_gaia_util.c
index 0609a74..070d77f 100644
--- a/test/check_gaia_util.c
+++ b/test/check_gaia_util.c
@@ -50,10 +50,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "spatialite.h"
 #include "spatialite/gaiaaux.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 int
 main (int argc, char *argv[])
 {
@@ -229,129 +225,129 @@ main (int argc, char *argv[])
 	  return -21;
       }
 
-    asprintf (&test_str1, "SELECT %s from %s;", "Foo", "Bar");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;", "Foo", "Bar");
     gaiaCleanSqlString (test_str1);
     if (strcmp (test_str1, "SELECT Foo from Bar;") != 0)
       {
 	  fprintf (stderr, "gaiaCleanSqlString failure: %s\n", test_str1);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -22;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 
-    asprintf (&test_str1, "SELECT %s from %s;           ", "Foo", "Bar");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;           ", "Foo", "Bar");
     gaiaCleanSqlString (test_str1);
     if (strcmp (test_str1, "SELECT Foo from Bar;") != 0)
       {
 	  fprintf (stderr, "gaiaCleanSqlString failure: %s\n", test_str1);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -23;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 
-    asprintf (&test_str1, "SELECT %s from %s;           ", "Foo", "'");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;           ", "Foo", "'");
     gaiaCleanSqlString (test_str1);
     if (strcmp (test_str1, "SELECT Foo from '';") != 0)
       {
 	  fprintf (stderr, "gaiaCleanSqlString failure: %s\n", test_str1);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -24;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 
 #if 0
     /* TODO: This will cause a buffer overflow */
-    asprintf (&test_str1, "SELECT %s from %s;", "Foo", "'");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;", "Foo", "'");
     gaiaCleanSqlString (test_str1);
     if (strcmp (test_str1, "SELECT Foo from '';") != 0)
       {
 	  fprintf (stderr, "gaiaCleanSqlString failure: %s\n", test_str1);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -25;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 #endif
 
-    asprintf (&test_str1, "           ");
+    test_str1 = sqlite3_mprintf ("           ");
     gaiaCleanSqlString (test_str1);
     if (strcmp (test_str1, "") != 0)
       {
 	  fprintf (stderr, "gaiaCleanSqlString failure: %s\n", test_str1);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  return -26;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
 
-    asprintf (&test_str1, "SELECT %s from %s;", "Foo", "Bar");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;", "Foo", "Bar");
     quoted_str = gaiaSingleQuotedSql (test_str1);
     if (strcmp (quoted_str, "SELECT Foo from Bar;") != 0)
       {
 	  fprintf (stderr, "gaiaSingleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -27;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "SELECT %s from %s;           ", "Foo", "Bar");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;           ", "Foo", "Bar");
     quoted_str = gaiaSingleQuotedSql (test_str1);
     if (strcmp (quoted_str, "SELECT Foo from Bar;") != 0)
       {
 	  fprintf (stderr, "gaiaSingleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -28;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "SELECT %s from %s;", "Foo", "'");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;", "Foo", "'");
     quoted_str = gaiaSingleQuotedSql (test_str1);
     if (strcmp (quoted_str, "SELECT Foo from '';") != 0)
       {
 	  fprintf (stderr, "gaiaSingleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -29;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "SELECT %s from %s   ;    ", "Foo", "Bar");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s   ;    ", "Foo", "Bar");
     quoted_str = gaiaSingleQuotedSql (test_str1);
     if (strcmp (quoted_str, "SELECT Foo from Bar   ;") != 0)
       {
 	  fprintf (stderr, "gaiaSingleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -30;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "SELECT %s from %s;", "'", "Bar");
+    test_str1 = sqlite3_mprintf ("SELECT %s from %s;", "'", "Bar");
     quoted_str = gaiaSingleQuotedSql (test_str1);
     if (strcmp (quoted_str, "SELECT '' from Bar;") != 0)
       {
 	  fprintf (stderr, "gaiaSingleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -31;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "My Name");
+    test_str1 = sqlite3_mprintf ("My Name");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "My Name") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -32;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
     quoted_str = gaiaDoubleQuotedSql (NULL);
@@ -400,88 +396,88 @@ main (int argc, char *argv[])
 	  return -37;
       }
 
-    asprintf (&test_str1, "My \"Name");
+    test_str1 = sqlite3_mprintf ("My \"Name");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "My \"\"Name") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -38;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "My \"Name                   ");
+    test_str1 = sqlite3_mprintf ("My \"Name                   ");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "My \"\"Name") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -39;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "%s", "");
+    test_str1 = sqlite3_mprintf ("%s", "");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -40;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "          ");
+    test_str1 = sqlite3_mprintf ("          ");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: |%s|\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -41;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "'          ");
+    test_str1 = sqlite3_mprintf ("'          ");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "'") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -42;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "'");
+    test_str1 = sqlite3_mprintf ("'");
     quoted_str = gaiaDoubleQuotedSql (test_str1);
     if (strcmp (quoted_str, "'") != 0)
       {
 	  fprintf (stderr, "gaiaDoubleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -43;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
-    asprintf (&test_str1, "\"");
+    test_str1 = sqlite3_mprintf ("\"");
     quoted_str = gaiaSingleQuotedSql (test_str1);
     if (strcmp (quoted_str, "\"") != 0)
       {
 	  fprintf (stderr, "gaiaSingleQuotedSql failure: %s\n", quoted_str);
-	  free (test_str1);
+	  sqlite3_free (test_str1);
 	  free (quoted_str);
 	  return -44;
       }
-    free (test_str1);
+    sqlite3_free (test_str1);
     free (quoted_str);
 
     spatialite_shutdown ();
diff --git a/test/check_gpkgInsertEpsgSRID.c b/test/check_gpkgInsertEpsgSRID.c
index 743b6ed..da28d90 100644
--- a/test/check_gpkgInsertEpsgSRID.c
+++ b/test/check_gpkgInsertEpsgSRID.c
@@ -59,7 +59,7 @@ main (int argc UNUSED, char *argv[]UNUSED)
     sqlite3 *db_handle = NULL;
     int ret;
     char *err_msg = NULL;
-#ifndef OMIT_EPSG /* only if full EPSG support is enabled */
+#ifndef OMIT_EPSG		/* only if full EPSG support is enabled */
     char *sql_statement;
     sqlite3_stmt *stmt;
 #endif
@@ -94,7 +94,7 @@ main (int argc UNUSED, char *argv[]UNUSED)
 	  return -100;
       }
 
-#ifndef OMIT_EPSG /* only if full EPSG support is enabled */
+#ifndef OMIT_EPSG		/* only if full EPSG support is enabled */
     ret =
 	sqlite3_exec (db_handle, "SELECT gpkgInsertEpsgSRID(3857)", NULL, NULL,
 		      &err_msg);
@@ -174,7 +174,7 @@ main (int argc UNUSED, char *argv[]UNUSED)
     ret = sqlite3_finalize (stmt);
 
     sqlite3_free (err_msg);
-    
+
     /* try no WKT, something of a hack here */
     ret =
 	sqlite3_exec (db_handle, "SELECT gpkgInsertEpsgSRID(40001)", NULL, NULL,
diff --git a/test/check_gpkgVirtual.c b/test/check_gpkgVirtual.c
index bfc5ab9..522ab12 100644
--- a/test/check_gpkgVirtual.c
+++ b/test/check_gpkgVirtual.c
@@ -76,7 +76,7 @@ test_table (sqlite3 * handle, const char *table)
 			   table);
 
     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
-    sqlite3_free(sql);
+    sqlite3_free (sql);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "SELECT FROM \"%s\" error: %s\n", table,
diff --git a/test/check_libxml2.c b/test/check_libxml2.c
index f67019e..aa4d736 100644
--- a/test/check_libxml2.c
+++ b/test/check_libxml2.c
@@ -544,10 +544,10 @@ check_parse (void *cache, const char *path)
 			 doc_sz);
 		return 0;
 	    }
-	  if (formatted_sz != 864)
+	  if (formatted_sz != 863)
 	    {
 		fprintf (stderr,
-			 "books.xml: unexpected formatted size %d (expected 864)\n",
+			 "books.xml: unexpected formatted size %d (expected 863)\n",
 			 formatted_sz);
 		return 0;
 	    }
@@ -582,10 +582,10 @@ check_parse (void *cache, const char *path)
 			 doc_sz);
 		return 0;
 	    }
-	  if (formatted_sz != 970)
+	  if (formatted_sz != 969)
 	    {
 		fprintf (stderr,
-			 "opera.xml: unexpected formatted size %d (expected 970)\n",
+			 "opera.xml: unexpected formatted size %d (expected 969)\n",
 			 formatted_sz);
 		return 0;
 	    }
@@ -620,10 +620,10 @@ check_parse (void *cache, const char *path)
 			 doc_sz);
 		return 0;
 	    }
-	  if (formatted_sz != 945)
+	  if (formatted_sz != 944)
 	    {
 		fprintf (stderr,
-			 "movies.xml: unexpected formatted size %d (expected 945)\n",
+			 "movies.xml: unexpected formatted size %d (expected 944)\n",
 			 formatted_sz);
 		return 0;
 	    }
@@ -640,6 +640,138 @@ check_parse (void *cache, const char *path)
     return 1;
 }
 
+static int
+check_mline_gpx (sqlite3 * handle, void *cache, const char *path)
+{
+/* parsing an XML Sample */
+    FILE *fl;
+    int sz = 0;
+    int rd;
+    unsigned char *xml = NULL;
+    int uncompressed_sz;
+    unsigned char *p_result = NULL;
+    gaiaGeomCollPtr geom;
+    gaiaLinestringPtr ln;
+    double x;
+    double y;
+    double z;
+    double m;
+
+/* loading the XMLDocument */
+    fl = fopen (path, "rb");
+    if (!fl)
+      {
+	  fprintf (stderr, "cannot open \"%s\"\n", path);
+	  return 0;
+      }
+    if (fseek (fl, 0, SEEK_END) == 0)
+	sz = ftell (fl);
+    xml = malloc (sz);
+    rewind (fl);
+    rd = fread (xml, 1, sz, fl);
+    if (rd != sz)
+      {
+	  fprintf (stderr, "read error \"%s\"\n", path);
+	  return 0;
+      }
+    fclose (fl);
+
+/* parsing the GPX document (no validation / not compressed) */
+    gaiaXmlToBlob (cache, xml, rd, 0, NULL, &p_result, &uncompressed_sz, NULL,
+		   NULL);
+    if (p_result == NULL)
+      {
+	  fprintf (stderr, "unable to parse(gpx)\"%s\"\n", path);
+	  return 0;
+      }
+
+    geom = gaiaXmlBlobMLineFromGPX (p_result, uncompressed_sz, handle);
+    if (geom == NULL)
+      {
+	  fprintf (stderr, "XB_MLineFromGPX: unexpected failure \"%s\"\n",
+		   path);
+	  return 0;
+      }
+
+    if (geom->Srid != 4326)
+      {
+	  fprintf (stderr, "XB_MLineFromGPX: invalid SRID (%d) \"%s\"\n",
+		   geom->Srid, path);
+	  return 0;
+      }
+    ln = geom->FirstLinestring;
+    if (ln == NULL)
+      {
+	  fprintf (stderr, "XB_MLineFromGPX: not a Linestring \"%s\"\n", path);
+	  return 0;
+      }
+    if (ln->Points < 5)
+      {
+	  fprintf (stderr, "XB_MLineFromGPX: too few points \"%s\"\n", path);
+	  return 0;
+      }
+    gaiaGetPointXYZM (ln->Coords, 4, &x, &y, &z, &m);
+    if (strcmp (path, "Gpx-sample.gpx") == 0)
+      {
+	  if (x != 37.808177)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected X=%f \"%s\"\n", x,
+			 path);
+		return 0;
+	    }
+	  if (y != 55.753587)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected Y=%f \"%s\"\n", y,
+			 path);
+		return 0;
+	    }
+	  if (z != 135.0)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected Z=%f \"%s\"\n", z,
+			 path);
+		return 0;
+	    }
+	  if (m < 2454970.667060 || m > 2454970.667061)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected M=%f \"%s\"\n", m,
+			 path);
+		return 0;
+	    }
+      }
+    else
+      {
+	  if (x != -25.1959200)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected X=%f \"%s\"\n", x,
+			 path);
+		return 0;
+	    }
+	  if (y != 37.7710900)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected Y=%f \"%s\"\n", y,
+			 path);
+		return 0;
+	    }
+	  if (z != 0.0)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected Z=%f \"%s\"\n", z,
+			 path);
+		return 0;
+	    }
+	  if (m != 1721059.50)
+	    {
+		fprintf (stderr, "XB_MLineFromGPX: unexpected M=%f \"%s\"\n", m,
+			 path);
+		return 0;
+	    }
+      }
+
+    gaiaFreeGeomColl (geom);
+    free (p_result);
+    free (xml);
+    return 1;
+}
+
 #endif
 
 int
@@ -725,6 +857,17 @@ main (int argc, char *argv[])
 	  return -12;
       }
 
+    if (!check_mline_gpx (handle, cache, "000323485.gpx"))
+      {
+	  fprintf (stderr, "unable to test \"000323485.gpx\"\n");
+	  return -13;
+      }
+    if (!check_mline_gpx (handle, cache, "Gpx-sample.gpx"))
+      {
+	  fprintf (stderr, "unable to test \"Gpx-sample.gpx\"\n");
+	  return -14;
+      }
+
 #endif
 
     ret = sqlite3_close (handle);
diff --git a/test/check_multithread.c b/test/check_multithread.c
index cfa2b68..5d9ab54 100644
--- a/test/check_multithread.c
+++ b/test/check_multithread.c
@@ -73,7 +73,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #ifdef _WIN32
 #include "fnmatch4win.h"
 #include "scandir4win.h"
-#include "asprintf4win.h"
 #include "fnmatch_impl4win.h"
 #endif
 
@@ -116,7 +115,7 @@ struct thread_params
     pthread_t thread_id;
     pthread_attr_t attr;
 #endif
-} mt_params[64];
+} mt_params[128];
 
 static struct db_conn *
 alloc_connection (void)
@@ -898,8 +897,8 @@ main (int argc, char *argv[])
 	  num_threads = atoi (env_var);
 	  if (num_threads < 1)
 	      num_threads = 1;
-	  if (num_threads > 64)
-	      num_threads = 64;
+	  if (num_threads > 128)
+	      num_threads = 128;
       }
     printf ("Testing %d concurrent threads\n", num_threads);
 
diff --git a/test/check_network2d.c b/test/check_network2d.c
new file mode 100644
index 0000000..85ebb8f
--- /dev/null
+++ b/test/check_network2d.c
@@ -0,0 +1,2277 @@
+/*
+
+ check_network2d.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+do_level2_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 2 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting three Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(-100, -100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -160;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(-100, -10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -161;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(-10, -10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -162;
+	  return 0;
+      }
+
+/* inserting two Links */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 4, GeomFromText('LINESTRING(-100 -10, -100 -100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -163;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 6, GeomFromText('LINESTRING(-100 -10, -10 -10)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -164;
+	  return 0;
+      }
+
+/* splitting a Link (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 3, MakePoint(-100, -50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -165;
+	  return 0;
+      }
+
+/* splitting a Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 4, MakePoint(-30, -10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -166;
+	  return 0;
+      }
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 333, MakePoint(0, 0, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #2: expected failure\n");
+	  *retcode = -167;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -168;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 333, MakePoint(0, 0, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #2: expected failure\n");
+	  *retcode = -169;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -170;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (point not on link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 6, MakePoint(-101, -60, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #3: expected failure\n");
+	  *retcode = -171;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on link.") != 0)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -172;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 6, MakePoint(-101, -60, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #3: expected failure\n");
+	  *retcode = -173;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on link.") != 0)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -174;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (same link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 4, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #1: expected failure\n");
+	  *retcode = -175;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Cannot heal link with itself.") != 0)
+      {
+	  fprintf (stderr, "ST_NewLinkSplit() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -176;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (same link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #1: expected failure\n");
+	  *retcode = -177;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Cannot heal link with itself.") != 0)
+      {
+	  fprintf (stderr, "ST_ModLinkSplit() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -178;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent first link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 333, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #2: expected failure\n");
+	  *retcode = -179;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent first link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -180;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent first link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 333, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #2: expected failure\n");
+	  *retcode = -181;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent first link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -182;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent second link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 4, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #3: expected failure\n");
+	  *retcode = -183;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent second link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -184;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent second link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #3: expected failure\n");
+	  *retcode = -185;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent second link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -186;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-connected links) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 7, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #4: expected failure\n");
+	  *retcode = -187;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected links.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -188;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-connected links) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #4: expected failure\n");
+	  *retcode = -189;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected links.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -190;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting one more Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 2, GeomFromText('LINESTRING(-100 -10, 0 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -191;
+	  return 0;
+      }
+
+/* attempting to heal links (other links connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 5, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #5: expected failure\n");
+	  *retcode = -192;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - other links connected.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -193;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (other links connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 5)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #5: expected failure\n");
+	  *retcode = -194;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - other links connected.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -195;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* deleting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 8)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -196;
+	  return 0;
+      }
+
+/* healing a Link (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 5, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -197;
+	  return 0;
+      }
+
+/* healing another Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 9)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -198;
+	  return 0;
+      }
+
+/* healing a third Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -199;
+	  return 0;
+      }
+
+/* deleting another Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 7)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -200;
+	  return 0;
+      }
+
+/* deleting two Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -201;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -202;
+	  return 0;
+      }
+
+/* inserting two Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(2, 100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -203;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(2, 90, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -204;
+	  return 0;
+      }
+
+/* inserting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 9, 10, GeometryFromText('LINESTRING(2 100, 2 90)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -205;
+	  return 0;
+      }
+
+/* retrieving a NetNode by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(0, 100), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -206;
+	  return 0;
+      }
+
+/* attempting to retrieve a NetNode by Point (two NetNodes found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(1, 100), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #2: expected failure\n");
+	  *retcode = -207;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more net-nodes found") != 0)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -208;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a NetNode by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #3: expected failure\n");
+	  sqlite3_free (err_msg);
+	  *retcode = -209;
+	  return 0;
+      }
+
+/* retrieving a Link by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(0, 50), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -210;
+	  return 0;
+      }
+
+/* attempting to retrieve a Link by Point (two Links found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(1, 95), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #2: expected failure\n");
+	  *retcode = -211;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more links found") != 0)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -212;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Link by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #3expected failure\n");
+	  sqlite3_free (err_msg);
+	  *retcode = -213;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level1_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 1 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(0, 0, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -110;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(0, 100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -111;
+	  return 0;
+      }
+
+/* inserting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeometryFromText('LINESTRING(0 0, 0 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -112;
+	  return 0;
+      }
+
+/* attempting to insert a Node (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(0, 100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #3: expected failure\n");
+	  *retcode = -113;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -114;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (coincident link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(0, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4: expected failure\n");
+	  *retcode = -115;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - link crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -116;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting a third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(99, 99, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -117;
+	  return 0;
+      }
+
+/* moving the third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePoint(100, 100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -118;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-existing node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 333, MakePoint(50, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #2: expected failure\n");
+	  *retcode = -119;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -120;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePoint(0, 100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #3: expected failure\n");
+	  *retcode = -121;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -122;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (coincident link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePoint(0, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #4: expected failure\n");
+	  *retcode = -123;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - link crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -124;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (bad StartNode) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRING(1 1, 100 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #2: expected failure\n");
+	  *retcode = -125;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddLink() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (bad EndNode) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRING(0 0, 99 99)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #3: expected failure\n");
+	  *retcode = -127;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -128;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (coincident Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRING(0 0, 0 100, 100 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #4: expected failure\n");
+	  *retcode = -129;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -130;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (self-closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 1, GeometryFromText('LINESTRING(0 0, 0 100, 100 100, 0 0)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5: expected failure\n");
+	  *retcode = -131;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - self-closed links are forbidden.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -132;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting a second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRING(0 0, 100 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -133;
+	  return 0;
+      }
+
+/* attempting to move a Link (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRING(0 0, 0 100, 100 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #1: expected failure\n");
+	  *retcode = -134;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -135;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (bad start node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRING(1 1, 100 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #2: expected failure\n");
+	  *retcode = -136;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -138;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (bad end node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRING(0 0, 101 101)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #3: expected failure\n");
+	  *retcode = -139;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -140;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* moving the second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRING(0 0, 0 50, 100 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -141;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePoint(0, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #5: expected failure\n");
+	  *retcode = -142;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -143;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #5: expected failure\n");
+	  *retcode = -144;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node.") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -145;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Link (not existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 33)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #1: expected failure\n");
+	  *retcode = -146;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -147;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing the second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 2)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -148;
+	  return 0;
+      }
+
+/* removing the third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -149;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level0_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 0 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to insert a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -10;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -11;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -12;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -13;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -14;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -15;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -16;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -17;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: expected failure\n");
+	  *retcode = -18;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -19;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: expected failure\n");
+	  *retcode = -20;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -21;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: expected failure\n");
+	  *retcode = -22;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -23;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: expected failure\n");
+	  *retcode = -24;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -25;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -26;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -27;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -28;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -29;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -30;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -31;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -32;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -33;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() INTEGER Geometry: expected failure\n");
+	  *retcode = -34;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -35;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() NULL Geometry: expected failure\n");
+	  *retcode = -36;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -37;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() LINESTRING Geometry: expected failure\n");
+	  *retcode = -38;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -39;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', GeomFromText('POLYGON((-40 -40, -40 -50, -50 -50, -50 -40, -40 -40))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() POLYGON Geometry: expected failure\n");
+	  *retcode = -40;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -41;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', GeomFromText('MULTIPOINT(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -42;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -43;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() INTEGER Geometry: expected failure\n");
+	  *retcode = -44;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -45;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() NULL Geometry: expected failure\n");
+	  *retcode = -46;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -47;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() LINESTRING Geometry: expected failure\n");
+	  *retcode = -48;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -49;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, GeomFromText('POLYGON((-40 -40, -40 -50, -50 -50, -50 -40, -40 -40))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() POLYGON Geometry: expected failure\n");
+	  *retcode = -50;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -51;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, GeomFromText('MULTIPOINT(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -52;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -53;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() INTEGER Geometry: expected failure\n");
+	  *retcode = -54;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -55;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() NULL Geometry: expected failure\n");
+	  *retcode = -56;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -57;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (Point geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, MakePoint(1, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() POINT Geometry: expected failure\n");
+	  *retcode = -58;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() POINT Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -59;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('POLYGON((-40 -40, -40 -50, -50 -50, -50 -40, -40 -40))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() POLYGON Geometry: expected failure\n");
+	  *retcode = -60;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -61;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (MultiLinestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('MULTILINESTRING((-40 -50,  -50 -40), (-20 -20, -30 -30))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddLink() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -62;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddLink() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -63;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() INTEGER Geometry: expected failure\n");
+	  *retcode = -64;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -65;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() NULL Geometry: expected failure\n");
+	  *retcode = -66;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -67;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (Point geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, MakePoint(1, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POINT Geometry: expected failure\n");
+	  *retcode = -68;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POINT Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -69;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('POLYGON((-40 -40, -40 -50, -50 -50, -50 -40, -40 -40))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POLYGON Geometry: expected failure\n");
+	  *retcode = -70;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -71;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (MultiLinestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('MULTILINESTRING((-40 -50,  -50 -40), (-20 -20, -30 -30))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -72;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -73;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() INTEGER Geometry: expected failure\n");
+	  *retcode = -74;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -75;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() NULL Geometry: expected failure\n");
+	  *retcode = -76;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -77;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() LINESTRING Geometry: expected failure\n");
+	  *retcode = -78;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -79;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, GeomFromText('POLYGON((-40 -40, -40 -50, -50 -50, -50 -40, -40 -40))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() POLYGON Geometry: expected failure\n");
+	  *retcode = -80;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -81;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, GeomFromText('MULTIPOINT(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -82;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -83;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() INTEGER Geometry: expected failure\n");
+	  *retcode = -84;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -85;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() NULL Geometry: expected failure\n");
+	  *retcode = -86;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -87;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() LINESTRING Geometry: expected failure\n");
+	  *retcode = -88;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -89;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, GeomFromText('POLYGON((-40 -40, -40 -50, -50 -50, -50 -40, -40 -40))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() POLYGON Geometry: expected failure\n");
+	  *retcode = -90;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -91;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, GeomFromText('MULTIPOINT(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -92;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -93;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLogLinkSplit('roads', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit(): expected failure\n");
+	  *retcode = -94;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - ST_NewLogLinkSplit can't support Spatial Network; try using ST_NewGeoLinkSplit.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit(): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -95;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLogLinkSplit('roads', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit(): expected failure\n");
+	  *retcode = -96;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - ST_ModLogLinkSplit can't support Spatial Network; try using ST_ModGeoLinkSplit.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit(): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -97;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    int retcode = 0;
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+/* creating a Network 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('roads', 1, 4326, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* basic tests: level 0 */
+    if (!do_level0_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 1 */
+    if (!do_level1_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 2 */
+    if (!do_level2_tests (handle, &retcode))
+	goto end;
+
+/* dropping the Network 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT DropNetwork('roads')", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DropNetwork() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+  end:
+    spatialite_finalize_topologies (cache);
+    sqlite3_close (handle);
+    spatialite_cleanup_ex (cache);
+
+#endif /* end TOPOLOGY conditional */
+
+    spatialite_shutdown ();
+    return retcode;
+}
diff --git a/test/check_network3d.c b/test/check_network3d.c
new file mode 100644
index 0000000..4c59590
--- /dev/null
+++ b/test/check_network3d.c
@@ -0,0 +1,2277 @@
+/*
+
+ check_network3d.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+do_level2_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 2 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting three Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(-100, -100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -160;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(-100, -10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -161;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(-10, -10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -162;
+	  return 0;
+      }
+
+/* inserting two Links */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 4, GeomFromText('LINESTRINGZ(-100 -10 1, -100 -100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -163;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 6, GeomFromText('LINESTRINGZ(-100 -10 1, -10 -10 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -164;
+	  return 0;
+      }
+
+/* splitting a Link (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 3, MakePointZ(-100, -50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -165;
+	  return 0;
+      }
+
+/* splitting a Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 4, MakePointZ(-30, -10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -166;
+	  return 0;
+      }
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 333, MakePointZ(0, 0, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #2: expected failure\n");
+	  *retcode = -167;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -168;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 333, MakePointZ(0, 0, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #2: expected failure\n");
+	  *retcode = -169;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -170;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (point not on link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 6, MakePointZ(-101, -60, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #3: expected failure\n");
+	  *retcode = -171;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on link.") != 0)
+      {
+	  fprintf (stderr, "ST_NewGeoLinkSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -172;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 6, MakePointZ(-101, -60, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #3: expected failure\n");
+	  *retcode = -173;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on link.") != 0)
+      {
+	  fprintf (stderr, "ST_ModGeoLinkSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -174;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (same link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 4, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #1: expected failure\n");
+	  *retcode = -175;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Cannot heal link with itself.") != 0)
+      {
+	  fprintf (stderr, "ST_NewLinkSplit() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -176;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (same link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #1: expected failure\n");
+	  *retcode = -177;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Cannot heal link with itself.") != 0)
+      {
+	  fprintf (stderr, "ST_ModLinkSplit() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -178;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent first link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 333, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #2: expected failure\n");
+	  *retcode = -179;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent first link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -180;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent first link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 333, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #2: expected failure\n");
+	  *retcode = -181;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent first link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -182;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent second link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 4, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #3: expected failure\n");
+	  *retcode = -183;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent second link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -184;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent second link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #3: expected failure\n");
+	  *retcode = -185;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent second link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -186;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-connected links) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 7, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #4: expected failure\n");
+	  *retcode = -187;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected links.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -188;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-connected links) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #4: expected failure\n");
+	  *retcode = -189;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected links.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -190;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting one more Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 2, GeomFromText('LINESTRINGZ(-100 -10 1, 0 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -191;
+	  return 0;
+      }
+
+/* attempting to heal links (other links connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 5, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #5: expected failure\n");
+	  *retcode = -192;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - other links connected.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -193;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (other links connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 5)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #5: expected failure\n");
+	  *retcode = -194;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - other links connected.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -195;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* deleting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 8)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -196;
+	  return 0;
+      }
+
+/* healing a Link (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 5, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -197;
+	  return 0;
+      }
+
+/* healing another Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 9)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -198;
+	  return 0;
+      }
+
+/* healing a third Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -199;
+	  return 0;
+      }
+
+/* deleting another Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 7)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -200;
+	  return 0;
+      }
+
+/* deleting two Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -201;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -202;
+	  return 0;
+      }
+
+/* inserting two Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(2, 100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -203;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(2, 90, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -204;
+	  return 0;
+      }
+
+/* inserting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 9, 10, GeometryFromText('LINESTRINGZ(2 100 1, 2 90 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -205;
+	  return 0;
+      }
+
+/* retrieving a NetNode by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(0, 100), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -206;
+	  return 0;
+      }
+
+/* attempting to retrieve a NetNode by Point (two NetNodes found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(1, 100), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #2: expected failure\n");
+	  *retcode = -207;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more net-nodes found") != 0)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -208;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a NetNode by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #3: expected failure\n");
+	  sqlite3_free (err_msg);
+	  *retcode = -209;
+	  return 0;
+      }
+
+/* retrieving a Link by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(0, 50), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -210;
+	  return 0;
+      }
+
+/* attempting to retrieve a Link by Point (two Links found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(1, 95), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #2: expected failure\n");
+	  *retcode = -211;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more links found") != 0)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -212;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Link by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #3: expected failure\n");
+	  sqlite3_free (err_msg);
+	  *retcode = -213;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level1_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 1 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 0, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -10;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -11;
+	  return 0;
+      }
+
+/* inserting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeometryFromText('LINESTRINGZ(0 0 1, 0 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -112;
+	  return 0;
+      }
+
+/* attempting to insert a Node (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #3: expected failure\n");
+	  *retcode = -113;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -114;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (coincident link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4: expected failure\n");
+	  *retcode = -115;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - link crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -116;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting a third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(99, 99, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -117;
+	  return 0;
+      }
+
+/* moving the third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePointZ(100, 100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -118;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-existing node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 333, MakePointZ(50, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #2: expected failure\n");
+	  *retcode = -119;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -120;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePointZ(0, 100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #3: expected failure\n");
+	  *retcode = -121;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -122;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (coincident link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePointZ(0, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #4: expected failure\n");
+	  *retcode = -123;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - link crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -124;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (bad StartNode) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRINGZ(1 1 1, 100 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #2: expected failure\n");
+	  *retcode = -125;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddLink() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (bad EndNode) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRINGZ(0 0 1, 99 99 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #3: expected failure\n");
+	  *retcode = -127;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -128;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (coincident Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRINGZ(0 0 1, 0 100 1, 100 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #4: expected failure\n");
+	  *retcode = -129;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -130;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (self-closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 1, GeometryFromText('LINESTRINGZ(0 0 1, 0 100 1, 100 100 1, 0 0 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5: expected failure\n");
+	  *retcode = -131;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - self-closed links are forbidden.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -132;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting a second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, GeometryFromText('LINESTRINGZ(0 0 1, 100 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -133;
+	  return 0;
+      }
+
+/* attempting to move a Link (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRINGZ(0 0 1, 0 100 1, 100 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #1: expected failure\n");
+	  *retcode = -134;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -135;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (bad start node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRINGZ(1 1 1, 100 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #2: expected failure\n");
+	  *retcode = -136;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -138;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (bad end node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRINGZ(0 0 1, 101 101 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #3: expected failure\n");
+	  *retcode = -139;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -140;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* moving the second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, GeometryFromText('LINESTRINGZ(0 0 1, 0 50 1, 100 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -141;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, MakePointZ(0, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #5: expected failure\n");
+	  *retcode = -142;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -143;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #5: expected failure\n");
+	  *retcode = -144;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node.") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -145;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Link (not existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 33)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #1: expected failure\n");
+	  *retcode = -146;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -147;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing the second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 2)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -148;
+	  return 0;
+      }
+
+/* removing the third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -149;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level0_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 0 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to insert a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -10;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -11;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -12;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -13;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -14;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -15;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: expected failure\n");
+	  *retcode = -16;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -17;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: expected failure\n");
+	  *retcode = -18;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -19;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: expected failure\n");
+	  *retcode = -20;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -21;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: expected failure\n");
+	  *retcode = -22;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -23;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: expected failure\n");
+	  *retcode = -24;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -25;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -26;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -27;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -28;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -29;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -30;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -31;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -32;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -33;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() INTEGER Geometry: expected failure\n");
+	  *retcode = -34;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -35;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() NULL Geometry: expected failure\n");
+	  *retcode = -36;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -37;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() LINESTRING Geometry: expected failure\n");
+	  *retcode = -38;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -39;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', GeomFromText('POLYGONZ((-40 -40 1, -40 -50 1, -50 -50 1, -50 -40 1, -40 -40 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() POLYGON Geometry: expected failure\n");
+	  *retcode = -40;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -41;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', GeomFromText('MULTIPOINTZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -42;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -43;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() INTEGER Geometry: expected failure\n");
+	  *retcode = -44;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -45;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() NULL Geometry: expected failure\n");
+	  *retcode = -46;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -47;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() LINESTRING Geometry: expected failure\n");
+	  *retcode = -48;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -49;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, GeomFromText('POLYGONZ((-40 -40 1, -40 -50 1, -50 -50 1, -50 -40 1, -40 -40 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() POLYGON Geometry: expected failure\n");
+	  *retcode = -50;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -51;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, GeomFromText('MULTIPOINTZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -52;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -53;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() INTEGER Geometry: expected failure\n");
+	  *retcode = -54;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -55;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() NULL Geometry: expected failure\n");
+	  *retcode = -56;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -57;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (Point geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, MakePointZ(1, 1, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() POINT Geometry: expected failure\n");
+	  *retcode = -58;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() POINT Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -59;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('POLYGONZ((-40 -40 1, -40 -50 1, -50 -50 1, -50 -40 1, -40 -40 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() POLYGON Geometry: expected failure\n");
+	  *retcode = -60;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -61;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (MultiLinestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('MULTILINESTRINGZ((-40 -50 1,  -50 -40 1), (-20 -20 1, -30 -30 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddLink() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -62;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddLink() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -63;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() INTEGER Geometry: expected failure\n");
+	  *retcode = -64;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -65;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() NULL Geometry: expected failure\n");
+	  *retcode = -66;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -67;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (Point geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, MakePointZ(1, 1, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POINT Geometry: expected failure\n");
+	  *retcode = -68;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POINT Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -69;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('POLYGONZ((-40 -40 1, -40 -50 1, -50 -50 1, -50 -40 1, -40 -40 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POLYGON Geometry: expected failure\n");
+	  *retcode = -70;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -71;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change a Link (MultiLinestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('MULTILINESTRINGZ((-40 -50 1,  -50 -40 1), (-20 -20 1, -30 -30 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -72;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -73;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() INTEGER Geometry: expected failure\n");
+	  *retcode = -74;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -75;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() NULL Geometry: expected failure\n");
+	  *retcode = -76;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -77;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() LINESTRING Geometry: expected failure\n");
+	  *retcode = -78;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -79;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, GeomFromText('POLYGONZ((-40 -40 1, -40 -50 1, -50 -50 1, -50 -40 1, -40 -40 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() POLYGON Geometry: expected failure\n");
+	  *retcode = -80;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -81;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, GeomFromText('MULTIPOINTZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -82;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -83;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (int geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() INTEGER Geometry: expected failure\n");
+	  *retcode = -84;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() INTEGER Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -85;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (NULL geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() NULL Geometry: expected failure\n");
+	  *retcode = -86;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Spatial Network can't accept null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() NULL Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -87;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Linestring geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() LINESTRING Geometry: expected failure\n");
+	  *retcode = -88;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() LINESTRING Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -89;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Polygon geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, GeomFromText('POLYGONZ((-40 -40 1, -40 -50 1, -50 -50 1, -50 -40 1, -40 -40 1))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() POLYGON Geometry: expected failure\n");
+	  *retcode = -90;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() POLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -91;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (MultiPoint geometry) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModGeoLinkSplit('roads', 1, GeomFromText('MULTIPOINTZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() MULTIPOLYGON Geometry: expected failure\n");
+	  *retcode = -92;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid argument.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() MULTIPOLYGON Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -93;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLogLinkSplit('roads', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit(): expected failure\n");
+	  *retcode = -94;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - ST_NewLogLinkSplit can't support Spatial Network; try using ST_NewGeoLinkSplit.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit(): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -95;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLogLinkSplit('roads', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit(): expected failure\n");
+	  *retcode = -96;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - ST_ModLogLinkSplit can't support Spatial Network; try using ST_ModGeoLinkSplit.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit(): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -97;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    int retcode = 0;
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+/* creating a Network 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('roads', 1, 4326, 1, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* basic tests: level 0 */
+    if (!do_level0_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 1 */
+    if (!do_level1_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 2 */
+    if (!do_level2_tests (handle, &retcode))
+	goto end;
+
+/* dropping the Network 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT DropNetwork('roads')", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DropNetwork() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+  end:
+    spatialite_finalize_topologies (cache);
+    sqlite3_close (handle);
+    spatialite_cleanup_ex (cache);
+
+#endif /* end TOPOLOGY conditional */
+
+    spatialite_shutdown ();
+    return retcode;
+}
diff --git a/test/check_network_log.c b/test/check_network_log.c
new file mode 100644
index 0000000..dee2524
--- /dev/null
+++ b/test/check_network_log.c
@@ -0,0 +1,1028 @@
+/*
+
+ check_network3d.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+do_level2_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 2 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting three Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -150;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -151;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -152;
+	  return 0;
+      }
+
+/* inserting two Links */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 4, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -153;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 6, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -154;
+	  return 0;
+      }
+
+/* splitting a Link (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLogLinkSplit('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -155;
+	  return 0;
+      }
+
+/* splitting a Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLogLinkSplit('roads', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -156;
+	  return 0;
+      }
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLogLinkSplit('roads', 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit() #2: expected failure\n");
+	  *retcode = -157;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_NewLogLinkSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -158;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a link (non-existing link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLogLinkSplit('roads', 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit() #2: expected failure\n");
+	  *retcode = -159;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_ModLogLinkSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -160;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (same link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 4, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #1: expected failure\n");
+	  *retcode = -161;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Cannot heal link with itself.") != 0)
+      {
+	  fprintf (stderr, "ST_NewLinkSplit() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -162;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (same link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #1: expected failure\n");
+	  *retcode = -163;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Cannot heal link with itself.") != 0)
+      {
+	  fprintf (stderr, "ST_ModLinkSplit() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -164;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent first link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 333, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #2: expected failure\n");
+	  *retcode = -165;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent first link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -166;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent first link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 333, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #2: expected failure\n");
+	  *retcode = -167;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent first link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -168;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent second link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 4, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #3: expected failure\n");
+	  *retcode = -169;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent second link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -170;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-existent second link) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #3: expected failure\n");
+	  *retcode = -171;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent second link.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -172;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-connected links) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 7, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #4: expected failure\n");
+	  *retcode = -173;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected links.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -174;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (non-connected links) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #4: expected failure\n");
+	  *retcode = -175;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected links.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -176;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting one more Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 5, 2, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -177;
+	  return 0;
+      }
+
+/* attempting to heal links (other links connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 5, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #5: expected failure\n");
+	  *retcode = -178;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - other links connected.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -179;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal links (other links connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 4, 5)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #5: expected failure\n");
+	  *retcode = -180;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - other links connected.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -181;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* deleting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 8)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -182;
+	  return 0;
+      }
+
+/* healing a Link (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewLinkHeal('roads', 5, 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewLinkHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -183;
+	  return 0;
+      }
+
+/* healing another Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 9)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -184;
+	  return 0;
+      }
+
+/* healing a third Link (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModLinkHeal('roads', 7, 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModLinkHeal() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -185;
+	  return 0;
+      }
+
+/* deleting another Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 7)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -186;
+	  return 0;
+      }
+
+/* deleting two Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -187;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -188;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level1_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 1 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -110;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -111;
+	  return 0;
+      }
+
+/* inserting a Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -112;
+	  return 0;
+      }
+
+/* inserting a third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNetNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -113;
+	  return 0;
+      }
+
+/* moving the third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -114;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-existing node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 333, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #2: expected failure\n");
+	  *retcode = -115;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -116;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (self-closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 1, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #2: expected failure\n");
+	  *retcode = -117;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - self-closed links are forbidden.") != 0)
+      {
+	  fprintf (stderr, "ST_AddLink() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -118;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting a second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 3, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -119;
+	  return 0;
+      }
+
+/* moving the second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 2, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeLinkGeom() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -120;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 3, NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #3: expected failure\n");
+	  *retcode = -121;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNetNode() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -122;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #1: expected failure\n");
+	  *retcode = -123;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node.") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -124;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Link (not existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 33)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #1: expected failure\n");
+	  *retcode = -125;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent link.") != 0)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing the second Link */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemoveLink('roads', 2)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemoveLink() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -127;
+	  return 0;
+      }
+
+/* removing the third Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNetNode('roads', 3)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNetNode() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -128;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level0_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 0 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to insert a Node (not null geom) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNetNode('roads', MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() NotNULL Geom: expected failure\n");
+	  *retcode = -10;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Logical Network can't accept not null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddIsoNetNode() NotNULL Geom: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -11;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (not null geom) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNetNode('roads', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() NotNULL Geom: expected failure\n");
+	  *retcode = -12;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Logical Network can't accept not null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_MoveIsoNetNode() NotNULL Geom: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -13;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Link (not null geom) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddLink('roads', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddLink() NotNULL Geom: expected failure\n");
+	  *retcode = -14;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Logical Network can't accept not null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddLink() NotNULL Geom: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -15;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Link (not null geom) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeLinkGeom('roads', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() NotNULL Geom: expected failure\n");
+	  *retcode = -16;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - Logical Network can't accept not null geometry.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeLinkGeom() NotNULL Geom: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -17;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (not null geom) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() NotNULL Geom: expected failure\n");
+	  *retcode = -18;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - ST_NewGeoLinkSplit can't support Logical Network; try using ST_NewLogLinkSplit.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewGeoLinkSplit() NotNULL Geom: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -19;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split a Link (Geom) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewGeoLinkSplit('roads', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: expected failure\n");
+	  *retcode = -20;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - ST_NewGeoLinkSplit can't support Logical Network; try using ST_NewLogLinkSplit.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModGeoLinkSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -21;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a NetNode by Point (Logical Network) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNetNodeByPoint('roads', MakePoint(1, 100), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #1: expected failure\n");
+	  *retcode = -22;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "GetNetNodekByPoint() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr, "GetNetNodeByPoint() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -23;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Link by Point (Logical Network) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetLinkByPoint('roads', MakePoint(1, 95), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #1: expected failure\n");
+	  *retcode = -24;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "GetLinkByPoint() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr, "GetLinkByPoint() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -25;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    int retcode = 0;
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+/* creating a Logical Network */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('roads', 0)", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* basic tests: level 0 */
+    if (!do_level0_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 1 */
+    if (!do_level1_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 2 */
+    if (!do_level2_tests (handle, &retcode))
+	goto end;
+
+/* dropping the Logical Network */
+    ret =
+	sqlite3_exec (handle, "SELECT DropNetwork('roads')", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DropNetwork() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+  end:
+    sqlite3_close (handle);
+    spatialite_cleanup_ex (cache);
+
+#endif /* end TOPOLOGY conditional */
+
+    spatialite_shutdown ();
+    return retcode;
+}
diff --git a/test/check_relations_fncts.c b/test/check_relations_fncts.c
index 90f1fde..12ed4f5 100644
--- a/test/check_relations_fncts.c
+++ b/test/check_relations_fncts.c
@@ -2100,6 +2100,8 @@ test_legacy_mode ()
     gaiaSetPoint (rng->Coords, 3, 4.5, 30.5);
     gaiaSetPoint (rng->Coords, 4, 4.5, 4.5);
 
+
+#ifndef GEOS_ONLY_REENTRANT /* skipping legacy mode test (non-thread-safe GEOS API) */
     /* Tests Polygons UnaryUnion [as in aggregate ST_Union] */
     g = gaiaUnaryUnion (geom);
     if (g == NULL)
@@ -2141,6 +2143,7 @@ test_legacy_mode ()
 	  goto exit;
       }
     gaiaFreeGeomColl (g);
+#endif
     gaiaFreeGeomColl (geom);
 
     /* Cleanup and exit */
diff --git a/test/check_sql_stmt.c b/test/check_sql_stmt.c
index 321af2e..86f196e 100644
--- a/test/check_sql_stmt.c
+++ b/test/check_sql_stmt.c
@@ -58,13 +58,17 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "spatialite.h"
 
 #ifndef OMIT_GEOS		/* including GEOS */
+#ifdef GEOS_REENTRANT
+#ifdef GEOS_ONLY_REENTRANT
+#define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+#endif
+#endif
 #include <geos_c.h>
 #endif
 
 #ifdef _WIN32
 #include "fnmatch4win.h"
 #include "scandir4win.h"
-#include "asprintf4win.h"
 #include "fnmatch_impl4win.h"
 #endif
 
@@ -277,6 +281,16 @@ do_one_case (struct db_conn *conn, const struct test_data *data,
       }
     if (ret != SQLITE_OK)
       {
+	  if (data->expected_rows == 1 && data->expected_columns == 1)
+	    {
+		/* checking for an expected exception */
+		if (strcmp (err_msg, data->expected_results[1]) == 0)
+		  {
+		      /* we expected this */
+		      sqlite3_free (err_msg);
+		      return 0;
+		  }
+	    }
 	  fprintf (stderr, "Error: %s\n", err_msg);
 	  sqlite3_free (err_msg);
 	  return -10;
@@ -484,13 +498,10 @@ run_subdir_test (const char *subdirname, struct db_conn *conn,
     for (i = 0; i < n; ++i)
       {
 	  struct test_data *data;
-	  char *path;
-	  if (asprintf (&path, "%s/%s", subdirname, namelist[i]->d_name) < 0)
-	    {
-		return -1;
-	    }
+	  char *path =
+	      sqlite3_mprintf ("%s/%s", subdirname, namelist[i]->d_name);
 	  data = read_one_case (path);
-	  free (path);
+	  sqlite3_free (path);
 
 	  result =
 	      do_one_case (conn, data, load_extension, gpkg_amphibious_mode);
@@ -565,6 +576,15 @@ run_all_testcases (struct db_conn *conn, int load_extension, int legacy)
 		   "WARNING: skipping GEOS testcases; obsolete version found !!!\n");
 	  goto skip_geos;
       }
+#ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+    if (legacy)
+      {
+	  /* skipping GEOS tests in legacy mode */
+	  fprintf (stderr,
+		   "WARNING: skipping GEOS testcases in legacy mode:  GEOS_USE_ONLY_R_API defined !!!\n");
+	  goto skip_geos;
+      }
+#endif
     ret = system ("cp test_geos.sqlite test_geos_x.sqlite");
     if (ret != 0)
       {
@@ -600,6 +620,15 @@ run_all_testcases (struct db_conn *conn, int load_extension, int legacy)
 		   "WARNING: skipping GEOS_ADVANCED testcases; obsolete version found !!!\n");
 	  goto skip_geos_advanced;
       }
+#ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+    if (legacy)
+      {
+	  /* skipping GEOS_ADVANCED tests in legacy mode */
+	  fprintf (stderr,
+		   "WARNING: skipping GEOS_ADVANCED testcases in legacy mode:  GEOS_USE_ONLY_R_API defined !!!\n");
+	  goto skip_geos_advanced;
+      }
+#endif
 
     result =
 	run_subdir_test ("sql_stmt_geosadvanced_tests", conn, load_extension,
@@ -608,17 +637,65 @@ run_all_testcases (struct db_conn *conn, int load_extension, int legacy)
       {
 	  return result;
       }
+      
+#ifdef GEOS_REENTRANT
+    result =
+	run_subdir_test ("sql_stmt_voronoj2_tests", conn, load_extension,
+			 0);
+    if (result != 0)
+      {
+	  return result;
+      }
+#else
+    result =
+	run_subdir_test ("sql_stmt_voronoj1_tests", conn, load_extension,
+			 0);
+    if (result != 0)
+      {
+	  return result;
+      }
+#endif
 
   skip_geos_advanced:
 #endif /* end GEOS_ADVANCED conditional */
 
 #ifdef ENABLE_LWGEOM		/* only if LWGEOM is supported */
+#ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
+    if (legacy)
+      {
+	  /* skipping LWGEOM tests in legacy mode */
+	  fprintf (stderr,
+		   "WARNING: skipping LWGEOM testcases in legacy mode:  GEOS_USE_ONLY_R_API defined !!!\n");
+	  goto skip_lwgeom;
+      }
+#endif
     result = run_subdir_test ("sql_stmt_lwgeom_tests", conn, load_extension, 0);
     if (result != 0)
       {
 	  return result;
       }
 
+#ifdef POSTGIS_2_2
+    if (sqlite3_libversion_number () >= 3008003)
+      {
+	  result =
+	      run_subdir_test ("sql_stmt_lwgeom_22_tests", conn, load_extension,
+			       0);
+	  if (result != 0)
+	    {
+		return result;
+	    }
+      }
+#else
+    result =
+	run_subdir_test ("sql_stmt_lwgeom_20_tests", conn, load_extension, 0);
+    if (result != 0)
+      {
+	  return result;
+      }
+#endif
+
+  skip_lwgeom:
 #endif /* end LWGEOM conditional */
 
 #ifdef ENABLE_LIBXML2		/* only if LIBXML2 is supported */
diff --git a/test/check_topology2d.c b/test/check_topology2d.c
new file mode 100644
index 0000000..2acea18
--- /dev/null
+++ b/test/check_topology2d.c
@@ -0,0 +1,3073 @@
+/*
+
+ check_topology2d.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+do_level6_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 6 */
+    int ret;
+    char *err_msg = NULL;
+
+/* retrieving a Node by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNodeByPoint('topo', MakePoint(152, 160), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -300;
+	  return 0;
+      }
+
+/* attempting to retrieve a Node by Point (two Nodes found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNodeByPoint('topo', MakePoint(152, 160), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #2: expected failure\n");
+	  *retcode = -301;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more nodes found") != 0)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -302;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Node by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNodeByPoint('topo', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -303;
+	  return 0;
+      }
+
+/* retrieving an Edge by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetEdgeByPoint('topo', MakePoint(154, 167), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -304;
+	  return 0;
+      }
+
+/* attempting to retrieve an Edge by Point (two Edges found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetEdgeByPoint('topo', MakePoint(151, 159), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #2: expected failure\n");
+	  *retcode = -305;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more edges found") != 0)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -306;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve an Edge by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetEdgeByPoint('topo', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -307;
+	  return 0;
+      }
+
+/* retrieving a Face by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetFaceByPoint('topo', MakePoint(153, 161), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -308;
+	  return 0;
+      }
+
+/* attempting to retrieve a Face by Point (two Faces found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetFaceByPoint('topo', MakePoint(149, 149), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #2: expected failure\n");
+	  *retcode = -309;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more faces found") != 0)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -310;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Face by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetFaceByPoint('topo', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -311;
+	  return 0;
+      }
+
+/* adding four Points */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(10, -10, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -312;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(25, -10, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -313;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(50, -10, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -314;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(100, -10, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -315;
+	  return 0;
+      }
+
+/* adding four Linestrings */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(10 -10, 100 -10)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -316;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(10 -25, 100 -25)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -317;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(10 -50, 100 -50)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -318;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(10 -100, 100 -100)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -319;
+	  return 0;
+      }
+
+/* adding four more Points */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(10, -100, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -320;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(25, -100, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -321;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(50, -100, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -322;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(100, -100, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -323;
+	  return 0;
+      }
+
+/* adding five more Linestrings */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(10 -10, 10 -100)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -324;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(25 -10, 25 -100)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -325;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(50 -10, 50 -100)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -326;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(100 -10, 100 -100)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -327;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRING(10 -10, 100 -100)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #9 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -328;
+	  return 0;
+      }
+
+/* adding two more Points (MultiPoint) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', GeomFromText('MULTIPOINT(130 -30, 90 -30)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -329;
+	  return 0;
+      }
+
+/* adding five more Linestrings (MultiLinestring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('MULTILINESTRING((90 -30, 130 -30), "
+		      "(90 -70, 130 -70), (90 -83, 130 -83), (90 -30, 90 -83), (130 -83, 130 -30))', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -330;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level5_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 5 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting four Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-50, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #20 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -250;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-50, 20, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #21 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -251;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-50, 40, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #22 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -252;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-50, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #23 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -253;
+	  return 0;
+      }
+
+/* inserting Edges */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 18, 19, GeomFromText('LINESTRING(-50 10,  -50 20)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #13 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -254;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 21, 20, GeomFromText('LINESTRING(-50 50,  -50 40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #14 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -255;
+	  return 0;
+      }
+
+/* adding more Edges (ModFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 20, 19, GeomFromText('LINESTRING(-50 40, -50 20)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -256;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 18, 21, GeomFromText('LINESTRING(-50 10, -100 10, -100 50, -50 50)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -257;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 19, 20, GeomFromText('LINESTRING(-50 20, -80 20, -80 40, -50 40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #13 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -258;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 19, 20, GeomFromText('LINESTRING(-50 20, -30 20, -30 40, -50 40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #14 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -259;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 21, 18, GeomFromText('LINESTRING(-50 50, -10 50, -10 10, -50 10)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #15 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -260;
+	  return 0;
+      }
+
+/* attempting to remove an Edge (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeModFace('topo', 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeModFace() #1: expected failure\n");
+	  *retcode = -261;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_RemEdgeModFace() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -262;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove an Edge (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #1: expected failure\n");
+	  *retcode = -263;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -264;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing an Edge (NewFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 17)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -265;
+	  return 0;
+      }
+
+/* removing an Edge (NewFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 18)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -266;
+	  return 0;
+      }
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 14, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #1: expected failure\n");
+	  *retcode = -267;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -268;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 333, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #2: expected failure\n");
+	  *retcode = -269;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -270;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 14, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #1: expected failure\n");
+	  *retcode = -271;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -272;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 333, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #2: expected failure\n");
+	  *retcode = -273;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -274;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (no common Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 14, 13)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #3: expected failure\n");
+	  *retcode = -275;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected edges") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -276;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (no common Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 13, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #3: expected failure\n");
+	  *retcode = -277;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected edges") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -278;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (other Edges connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 14, 16)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #4: expected failure\n");
+	  *retcode = -280;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - other edges connected (19)") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -281;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (other Edges connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NeWEdgeHeal('topo', 16, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #4: expected failure\n");
+	  *retcode = -282;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - other edges connected (19)") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -283;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* healing Edges (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 14, 15)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -284;
+	  return 0;
+      }
+
+/* healing Edges (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 13, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -285;
+	  return 0;
+      }
+
+/* removing an Edge (NewFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 20)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -286;
+	  return 0;
+      }
+
+/* healing Edges (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 16, 19)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -287;
+	  return 0;
+      }
+
+/* removing an Edge (ModFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeModFace('topo', 21)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeModFace() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -288;
+	  return 0;
+      }
+
+/* removing a Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 18)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -289;
+	  return 0;
+      }
+
+/* inserting two Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(99, 98, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #24 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -290;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(98, 99, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #25 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -291;
+	  return 0;
+      }
+
+/* inserting an Isolated Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 22, 23, GeomFromText('LINESTRING(99 98, 98 99)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #15 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -292;
+	  return 0;
+      }
+
+/* removing an Isolated Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoEdge('topo', 22)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoEdge() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -293;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level4_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 4 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting three Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-40, -50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #16 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -150;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-49, -49, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #17 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -151;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-50, -40, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #18 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -152;
+	  return 0;
+      }
+
+/* inserting an Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 14, 16, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -153;
+	  return 0;
+      }
+
+/* moving a Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 15, MakePoint(-50, -50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -154;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-existing node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 333, MakePoint(-51, -51, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #2: expected failure\n");
+	  *retcode = -155;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -156;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 15, MakePoint(-40, -50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #3: expected failure\n");
+	  *retcode = -157;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -158;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (edge crosses node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 15, MakePoint(-45, -45, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #4: expected failure\n");
+	  *retcode = -159;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - edge crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -160;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (non-isolated node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 14, MakePoint(-45, -45, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #5: expected failure\n");
+	  *retcode = -161;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -162;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* changing an Edge Geom */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRING(-40 -50, -40 -40, -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -163;
+	  return 0;
+      }
+
+/* attempting to change en Edge Geom (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRING(-40 -50, -50 -30, -40 -30, -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #2: expected failure\n");
+	  *retcode = -164;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -165;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (start geometry not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRING(-40 -51, -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #3: expected failure\n");
+	  *retcode = -166;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -167;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (end geometry not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRING(-40 -50, -51 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #4: expected failure\n");
+	  *retcode = -168;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -169;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (geometry crosses a node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRING(-40 -50, -50 -50, -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #5: expected failure\n");
+	  *retcode = -170;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -171;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (non existing edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 111, GeomFromText('LINESTRING(-40 -50, -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #6: expected failure\n");
+	  *retcode = -172;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 111") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #6: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -173;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting yet another Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-44, -44, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #19 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -174;
+	  return 0;
+      }
+
+/* inserting yet another Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 15, 17, GeomFromText('LINESTRING(-50 -50, -44 -44)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -175;
+	  return 0;
+      }
+
+/* attempting to change en Edge Geom (geometry intersects an edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRING(-40 -50, -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #7: expected failure\n");
+	  *retcode = -170;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 12")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #7: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -171;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 15)", NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #1: expected failure\n");
+	  *retcode = -172;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -173;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (not existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 155)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #2: expected failure\n");
+	  *retcode = -174;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -175;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing a Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 5)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -176;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level3_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 3 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(150, 150, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #9 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -70;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(180, 180, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #10 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -71;
+	  return 0;
+      }
+
+/* inserting an Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 8, 9, GeomFromText('LINESTRING(150 150,  180 150, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -72;
+	  return 0;
+      }
+
+/* adding an Edge (ModFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRING(150 150, 150 180, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -73;
+	  return 0;
+      }
+
+/* testing Face Geometry */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -74;
+	  return 0;
+      }
+
+/* attempting to test Face Geometry (non-existing face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 111)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #2: expected failure\n");
+	  *retcode = -75;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent face.") != 0)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -76;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to test Face Geometry (universe face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #3: expected failure\n");
+	  *retcode = -77;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - universal face has no geometry") != 0)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -78;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing Face Edges */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -79;
+	  return 0;
+      }
+
+/* attempting to test Face Edges (non-existing face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 111)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -80;
+	  return 0;
+      }
+
+/* attempting to test Face Edges (universe face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -80;
+	  return 0;
+      }
+
+/* attempting to add an invalid Edge (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRING(150 150, 170 150, 160 150, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #2: expected failure\n");
+	  *retcode = -84;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -81;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent start node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 18, 9, GeomFromText('LINESTRING(150 150, 150 180, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #3: expected failure\n");
+	  *retcode = -85;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -86;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent end node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 19, GeomFromText('LINESTRING(150 150, 150 180, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #4: expected failure\n");
+	  *retcode = -87;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -88;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (start node not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRING(151 150, 150 180, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #5: expected failure\n");
+	  *retcode = -89;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -90;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (end node not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRING(150 150, 150 180, 181 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #6: expected failure\n");
+	  *retcode = -91;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #6: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -92;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* adding an Edge (NewFaces) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 8, 9, GeomFromText('LINESTRING(150 150, 180 180)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -93;
+	  return 0;
+      }
+
+/* inserting three Nodes within a Face */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(152, 160, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -94;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(154, 160, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -95;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', 3, MakePoint(152, 170, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -96;
+	  return 0;
+      }
+
+/* inserting a Node within the other Face */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(178, 170, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #13 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -97;
+	  return 0;
+      }
+
+/* attempting to add an invalid Node (node crosses edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(178, 178, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #14: expected failure\n");
+	  *retcode = -98;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - edge crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #14: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -99;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Node (not within face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', 3, MakePoint(179, 160, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #15: expected failure\n");
+	  *retcode = -100;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not within face") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #15: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -101;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting an Edge within a Face */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 10, 11, GeomFromText('LINESTRING(152 160, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -102;
+	  return 0;
+      }
+
+/* attempting to add an invalid Edge (nodes in different faces) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 12, 13, GeomFromText('LINESTRING(152 170, 178 170)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #9: expected failure\n");
+	  *retcode = -103;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - nodes in different faces") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #9: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -104;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses a Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 10, 11, GeomFromText('LINESTRING(152 160, 152 170, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #7: expected failure\n");
+	  *retcode = -105;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #7: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -106;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses an Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 10, 11, GeomFromText('LINESTRING(152 160, 153 161, 153 159, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #8: expected failure\n");
+	  *retcode = -107;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 8")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #8: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -108;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (coincident Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 11, 10, GeomFromText('LINESTRING(154 160, 152 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #9: expected failure\n");
+	  *retcode = -109;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident edge 8") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #9: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -110;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRING(152 160, 154 162, 152 162, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #2: expected failure\n");
+	  *retcode = -111;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -112;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent start node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 18, 11, GeomFromText('LINESTRING(152 160, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #3: expected failure\n");
+	  *retcode = -113;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -114;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent end node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 19, GeomFromText('LINESTRING(152 160, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #4: expected failure\n");
+	  *retcode = -115;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -116;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (start node not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRING(52 160, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #5: expected failure\n");
+	  *retcode = -117;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -118;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (end node not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRING(152 160, 54 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #6: expected failure\n");
+	  *retcode = -119;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #6: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -120;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses a Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRING(152 160, 152 170, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #7: expected failure\n");
+	  *retcode = -121;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #7: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -122;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses an Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRING(152 160, 153 161, 153 159, 154 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #8: expected failure\n");
+	  *retcode = -123;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 8")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #8: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -124;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (coincident Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 11, 10, GeomFromText('LINESTRING(154 160, 152 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #9: expected failure\n");
+	  *retcode = -125;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident edge 8") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #9: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* creating new Faces (hole) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 11, 10, GeomFromText('LINESTRING(154 160, 154 167, 152 167, 152 160)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #10 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -127;
+	  return 0;
+      }
+
+/* attempting to add an invalid Edge (closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 13, 13, GeomFromText('LINESTRING(178 170, 178 161, 170 161, 178 170)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #10: expected failure\n");
+	  *retcode = -128;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "Closed edges would not be isolated, try lwt_AddEdgeNewFaces") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #10: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -129;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* adding an Edge/Face (closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 13, 13, GeomFromText('LINESTRING(178 170, 178 161, 170 161, 178 170)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #10 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -130;
+	  return 0;
+      }
+
+/* testing Face Geometry (Faces with internal hole) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -131;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -132;
+	  return 0;
+      }
+
+/* testing Face Edges (Faces with internal hole) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -133;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -134;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level2_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 2 */
+    int ret;
+    char *err_msg = NULL;
+
+/* splitting an Edge (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePoint(0, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -50;
+	  return 0;
+      }
+
+/* attempting to split an Edge (non-existent edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 100, MakePoint(0, 25, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #2: expected failure\n");
+	  *retcode = -51;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -52;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (point not on edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 2, MakePoint(0, 25, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #3: expected failure\n");
+	  *retcode = -53;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on edge") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -54;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePoint(0, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #4: expected failure\n");
+	  *retcode = -55;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -56;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* splitting an Edge (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 2, MakePoint(0, 75, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -57;
+	  return 0;
+      }
+
+/* attempting to split an Edge (non-existent edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 100, MakePoint(0, 25, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #2: expected failure\n");
+	  *retcode = -58;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -59;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (point not on edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 3, MakePoint(0, 25, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #3: expected failure\n");
+	  *retcode = -60;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on edge") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -61;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 1, MakePoint(0, 50, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #4: expected failure\n");
+	  *retcode = -62;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -62;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+static int
+do_level1_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 1 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(0, 0, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -10;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(0, 100, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -11;
+	  return 0;
+      }
+
+/* attempting to insert an invalid Edge (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRING(0 0, 0 90, 10 90, 10 80, 0 80, 0 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #1: expected failure\n");
+	  *retcode = -12;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -13;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Edge (start node not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRING(1 0, 0 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #2: expected failure\n");
+	  *retcode = -14;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -15;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Edge (end node not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRING(0 0, 1 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #3: expected failure\n");
+	  *retcode = -16;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -17;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting an Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRING(0 0, 0 100)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -18;
+	  return 0;
+      }
+
+/* attempting to insert an invalid Node (coincident) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(0, 0, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #3: expected failure\n");
+	  *retcode = -19;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -20;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Node (edge crosses node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #4: expected failure\n");
+	  *retcode = -21;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - edge crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -22;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Node (not within face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', 1, MakePoint(10, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #5: expected failure\n");
+	  *retcode = -23;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not within face") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -24;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting more Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(-1, 99, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -25;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(1, 101, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -26;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(1, 98, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -26;
+	  return 0;
+      }
+
+/* attempting to insert an invalid Edge (geometry crosses a node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 3, 4, GeomFromText('LINESTRING(-1 99, 1 101)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #5: expected failure\n");
+	  *retcode = -27;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -28;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Edge (geometry intersects an edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 3, 5, GeomFromText('LINESTRING(-1 99, 1 98)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #6: expected failure\n");
+	  *retcode = -29;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 1")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #6: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -30;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+static int
+do_level0_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 0 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to insert a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -190;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -191;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -192;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -193;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 1, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -194;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -195;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 1, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -196;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -197;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 14, 16, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: expected failure\n");
+	  *retcode = -198;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -199;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 14, 16, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: expected failure\n");
+	  *retcode = -200;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -201;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: expected failure\n");
+	  *retcode = -202;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -203;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: expected failure\n");
+	  *retcode = -204;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -205;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -206;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModEdgeSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -207;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -208;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModEdgeSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -209;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 1, MakePoint(0, 10, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: expected failure\n");
+	  *retcode = -210;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -211;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 1, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: expected failure\n");
+	  *retcode = -212;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -213;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 1, 2, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: expected failure\n");
+	  *retcode = -214;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -215;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: expected failure\n");
+	  *retcode = -216;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -217;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 1, 2, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: expected failure\n");
+	  *retcode = -218;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -221;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: expected failure\n");
+	  *retcode = -220;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -221;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Point (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(1, 1, 3003), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: expected failure\n");
+	  *retcode = -222;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -223;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Point (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(1, 1, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: expected failure\n");
+	  *retcode = -224;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -225;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Linestring (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLinestring('topo', GeomFromText('LINESTRING(-40 -50, -50 -40)', 3003), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: expected failure\n");
+	  *retcode = -226;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -227;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Linestring (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLinestring('topo', GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: expected failure\n");
+	  *retcode = -228;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -229;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    int retcode = 0;
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    if (sqlite3_libversion_number () < 3008003)
+      {
+	  fprintf (stderr,
+		   "*** check_topology2d skipped: libsqlite < 3.8.3 !!!\n");
+	  goto end;
+      }
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+/* creating a Topology 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('topo', 4326, 0, 0)", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* basic tests: level 0 */
+    if (!do_level0_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 1 */
+    if (!do_level1_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 2 */
+    if (!do_level2_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 3 */
+    if (!do_level3_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 4 */
+    if (!do_level4_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 5 */
+    if (!do_level5_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 6 */
+    if (!do_level6_tests (handle, &retcode))
+	goto end;
+
+/* dropping the Topology 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT DropTopology('topo')", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DropTopology() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+  end:
+    spatialite_finalize_topologies (cache);
+    sqlite3_close (handle);
+    spatialite_cleanup_ex (cache);
+
+#endif /* end TOPOLOGY conditional */
+
+    spatialite_shutdown ();
+    return retcode;
+}
diff --git a/test/check_topology3d.c b/test/check_topology3d.c
new file mode 100644
index 0000000..e9114b2
--- /dev/null
+++ b/test/check_topology3d.c
@@ -0,0 +1,2998 @@
+/*
+
+ check_topology3d.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+do_level6_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 6 */
+    int ret;
+    char *err_msg = NULL;
+
+/* retrieving a Node by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNodeByPoint('topo', MakePoint(152, 160), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -300;
+	  return 0;
+      }
+
+/* attempting to retrieve a Node by Point (two Nodes found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNodeByPoint('topo', MakePoint(152, 160), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #2: expected failure\n");
+	  *retcode = -301;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more nodes found") != 0)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -302;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Node by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetNodeByPoint('topo', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetNodeByPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -303;
+	  return 0;
+      }
+
+/* retrieving an Edge by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetEdgeByPoint('topo', MakePoint(154, 167), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -304;
+	  return 0;
+      }
+
+/* attempting to retrieve an Edge by Point (two Edges found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetEdgeByPoint('topo', MakePoint(151, 159), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #2: expected failure\n");
+	  *retcode = -305;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more edges found") != 0)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -306;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve an Edge by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetEdgeByPoint('topo', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetEdgeByPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -307;
+	  return 0;
+      }
+
+/* retrieving a Face by Point */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetFaceByPoint('topo', MakePoint(153, 161), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -308;
+	  return 0;
+      }
+
+/* attempting to retrieve a Face by Point (two Faces found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetFaceByPoint('topo', MakePoint(149, 149), 3.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #2: expected failure\n");
+	  *retcode = -309;
+	  return 0;
+      }
+    if (strcmp (err_msg, "Two or more faces found") != 0)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -310;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to retrieve a Face by Point (not found) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT GetFaceByPoint('topo', MakePoint(1, 1), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "GetFaceByPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -311;
+	  return 0;
+      }
+
+/* adding four Points */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(10, -10, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -312;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(25, -10, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -313;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(50, -10, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -314;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(100, -10, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -315;
+	  return 0;
+      }
+
+/* adding four Linestrings */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(10 -10 1, 100 -10 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -316;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(10 -25 1, 100 -25 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -317;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(10 -50 1, 100 -50 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -318;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(10 -100 1, 100 -100 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -319;
+	  return 0;
+      }
+
+/* adding four more Points */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(10, -100, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -320;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(25, -100, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -321;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(50, -100, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -322;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(100, -100, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -323;
+	  return 0;
+      }
+
+/* adding five more Linestrings */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(10 -10 1, 10 -100 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -324;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(25 -10 1, 25 -100 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -325;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(50 -10 1, 50 -100 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -326;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(100 -10 1, 100 -100 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -327;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('LINESTRINGZ(10 -10 1, 100 -100 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #9 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -328;
+	  return 0;
+      }
+
+/* adding two more Points (MultiPoint) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', GeomFromText('MULTIPOINTZ(130 -30 1, 90 -30 1)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddPoint() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -329;
+	  return 0;
+      }
+
+/* adding five more Linestrings (MultiLinestring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLineString('topo', GeomFromText('MULTILINESTRINGZ((90 -30 1, 130 -30 1), "
+		      "(90 -70 1, 130 -70 1), (90 -83 1, 130 -83 1), (90 -30 1, 90 -83 1), (130 -83 1, 130 -30 1))', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_AddLineString() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -330;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level5_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 5 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting four Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-50, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #20 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -250;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-50, 20, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #21 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -251;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-50, 40, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #22 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -252;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-50, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #23 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -253;
+	  return 0;
+      }
+
+/* inserting Edges */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 18, 19, GeomFromText('LINESTRINGZ(-50 10 1,  -50 20 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #13 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -254;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 21, 20, GeomFromText('LINESTRINGZ(-50 50 1,  -50 40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #14 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -255;
+	  return 0;
+      }
+
+/* adding more Edges (ModFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 20, 19, GeomFromText('LINESTRINGZ(-50 40 1, -50 20 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -256;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 18, 21, GeomFromText('LINESTRINGZ(-50 10 1, -100 10 1, -100 50 1, -50 50 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -257;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 19, 20, GeomFromText('LINESTRINGZ(-50 20 1, -80 20 1, -80 40 1, -50 40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #13 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -258;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 19, 20, GeomFromText('LINESTRINGZ(-50 20 1, -30 20 1, -30 40 1, -50 40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #14 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -259;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 21, 18, GeomFromText('LINESTRINGZ(-50 50 1, -10 50 1, -10 10 1, -50 10 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #15 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -260;
+	  return 0;
+      }
+
+/* attempting to remove an Edge (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeModFace('topo', 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeModFace() #1: expected failure\n");
+	  *retcode = -261;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_RemEdgeModFace() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -262;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove an Edge (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #1: expected failure\n");
+	  *retcode = -263;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #1: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -264;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing an Edge (NewFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 17)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -265;
+	  return 0;
+      }
+
+/* removing an Edge (NewFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 18)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -266;
+	  return 0;
+      }
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 14, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #1: expected failure\n");
+	  *retcode = -267;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -268;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 333, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #2: expected failure\n");
+	  *retcode = -269;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -270;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 14, 333)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #1: expected failure\n");
+	  *retcode = -271;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -272;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (non-existing Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 333, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #2: expected failure\n");
+	  *retcode = -273;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 333") !=
+	0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -274;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (no common Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 14, 13)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #3: expected failure\n");
+	  *retcode = -275;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected edges") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -276;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (no common Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 13, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #3: expected failure\n");
+	  *retcode = -277;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-connected edges") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -278;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (other Edges connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 14, 16)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #4: expected failure\n");
+	  *retcode = -280;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - other edges connected (19)") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -281;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to heal Edges (other Edges connected) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NeWEdgeHeal('topo', 16, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #4: expected failure\n");
+	  *retcode = -282;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - other edges connected (19)") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -283;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* healing Edges (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeHeal('topo', 14, 15)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeHeal() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -284;
+	  return 0;
+      }
+
+/* healing Edges (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 13, 14)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -285;
+	  return 0;
+      }
+
+/* removing an Edge (NewFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeNewFace('topo', 20)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeNewFace() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -286;
+	  return 0;
+      }
+
+/* healing Edges (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgeHeal('topo', 16, 19)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeHeal() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -287;
+	  return 0;
+      }
+
+/* removing an Edge (ModFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemEdgeModFace('topo', 21)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemEdgeModFace() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -288;
+	  return 0;
+      }
+
+/* removing a Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 18)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -289;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level4_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 4 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting three Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-40, -50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #16 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -150;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-49, -49, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #17 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -151;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-50, -40, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #18 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -152;
+	  return 0;
+      }
+
+/* inserting an Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 14, 16, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -153;
+	  return 0;
+      }
+
+/* moving a Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 15, MakePointZ(-50, -50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -154;
+	  return 0;
+      }
+
+/* attempting to move a Node (non-existing node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 333, MakePointZ(-51, -51, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #2: expected failure\n");
+	  *retcode = -155;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -156;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 15, MakePointZ(-40, -50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #3: expected failure\n");
+	  *retcode = -157;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -158;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (edge crosses node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 15, MakePointZ(-45, -45, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #4: expected failure\n");
+	  *retcode = -159;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - edge crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -160;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (non-isolated node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 14, MakePointZ(-45, -45, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #5: expected failure\n");
+	  *retcode = -161;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node") != 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -162;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* changing an Edge Geom */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRINGZ(-40 -50 1, -40 -40 1, -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -163;
+	  return 0;
+      }
+
+/* attempting to change en Edge Geom (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRINGZ(-40 -50 1, -50 -30 1, -40 -30 1, -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #2: expected failure\n");
+	  *retcode = -164;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -165;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (start geometry not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRINGZ(-40 -51 1, -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #3: expected failure\n");
+	  *retcode = -166;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -167;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (end geometry not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRINGZ(-40 -50 1, -51 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #4: expected failure\n");
+	  *retcode = -168;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -169;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (geometry crosses a node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRINGZ(-40 -50 1, -50 -50 1, -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #5: expected failure\n");
+	  *retcode = -170;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -171;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change en Edge Geom (non existing edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 111, GeomFromText('LINESTRINGZ(-40 -50 1, -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #6: expected failure\n");
+	  *retcode = -172;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge 111") !=
+	0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #6: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -173;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting yet another Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-44, -44, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #19 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -174;
+	  return 0;
+      }
+
+/* inserting yet another Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 15, 17, GeomFromText('LINESTRINGZ(-50 -50 1, -44 -44 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -175;
+	  return 0;
+      }
+
+/* attempting to change en Edge Geom (geometry intersects an edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 11, GeomFromText('LINESTRINGZ(-40 -50 1, -50 -40 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #7: expected failure\n");
+	  *retcode = -170;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 12")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_ChangeEdgeGeom() #7: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -171;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (non-isolated) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 15)", NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #1: expected failure\n");
+	  *retcode = -172;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not isolated node") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -173;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a Node (not existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 155)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #2: expected failure\n");
+	  *retcode = -174;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -175;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* removing a Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_RemIsoNode('topo', 5)", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_RemIsoNode() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -176;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level3_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 3 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(150, 150, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #9 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -70;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(180, 180, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #10 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -71;
+	  return 0;
+      }
+
+/* inserting an Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 8, 9, GeomFromText('LINESTRINGZ(150 150 1,  180 150 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -72;
+	  return 0;
+      }
+
+/* adding an Edge (ModFace) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRINGZ(150 150 1, 150 180 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -73;
+	  return 0;
+      }
+
+/* testing Face Geometry */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -74;
+	  return 0;
+      }
+
+/* attempting to test Face Geometry (non-existing face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 111)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #2: expected failure\n");
+	  *retcode = -75;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent face.") != 0)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -76;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to test Face Geometry (universe face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #3: expected failure\n");
+	  *retcode = -77;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - universal face has no geometry") != 0)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -78;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing Face Edges */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -79;
+	  return 0;
+      }
+
+/* attempting to add an invalid Edge (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRINGZ(150 150 1, 170 150 1, 160 150 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #2: expected failure\n");
+	  *retcode = -80;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -81;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent start node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 18, 9, GeomFromText('LINESTRINGZ(150 150 1, 150 180 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #3: expected failure\n");
+	  *retcode = -82;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -83;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent end node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 19, GeomFromText('LINESTRINGZ(150 150 1, 150 180 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #4: expected failure\n");
+	  *retcode = -84;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -85;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (start node not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRINGZ(151 150 1, 150 180 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #5: expected failure\n");
+	  *retcode = -86;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -87;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (end node not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 8, 9, GeomFromText('LINESTRINGZ(150 150 1, 150 180 1, 181 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #6: expected failure\n");
+	  *retcode = -88;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #6: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -89;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* adding an Edge (NewFaces) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 8, 9, GeomFromText('LINESTRINGZ(150 150 1, 180 180 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -90;
+	  return 0;
+      }
+
+/* inserting three Nodes within a Face */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(152, 160, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #11 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -91;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(154, 160, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -92;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', 3, MakePointZ(152, 170, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #12 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -93;
+	  return 0;
+      }
+
+/* inserting a Node within the other Face */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(178, 170, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #13 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -94;
+	  return 0;
+      }
+
+/* attempting to add an invalid Node (node crosses edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(178, 178, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #14: expected failure\n");
+	  *retcode = -95;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - edge crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #14: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -96;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Node (not within face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', 3, MakePointZ(179, 160, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #15: expected failure\n");
+	  *retcode = -97;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not within face") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #15: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -98;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting an Edge within a Face */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -99;
+	  return 0;
+      }
+
+/* attempting to add an invalid Edge (nodes in different faces) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 12, 13, GeomFromText('LINESTRINGZ(152 170 1, 178 170 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #9: expected failure\n");
+	  *retcode = -100;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - nodes in different faces") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #9: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -101;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses a Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 152 170 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #7: expected failure\n");
+	  *retcode = -102;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #7: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -103;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses an Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 153 161 1, 153 159 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #8: expected failure\n");
+	  *retcode = -104;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 8")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #8: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -105;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (coincident Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 11, 10, GeomFromText('LINESTRINGZ(154 160 1, 152 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #9: expected failure\n");
+	  *retcode = -106;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident edge 8") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #9: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -107;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 154 162 1, 152 162 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #2: expected failure\n");
+	  *retcode = -108;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -109;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent start node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 18, 11, GeomFromText('LINESTRINGZ(152 160 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #3: expected failure\n");
+	  *retcode = -110;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -111;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (non-existent end node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 19, GeomFromText('LINESTRINGZ(152 160 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #4: expected failure\n");
+	  *retcode = -112;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent node") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -113;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (start node not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRINGZ(52 160 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #5: expected failure\n");
+	  *retcode = -114;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #5: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -115;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (end node not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 54 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #6: expected failure\n");
+	  *retcode = -116;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #6: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -117;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses a Node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 152 170 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #7: expected failure\n");
+	  *retcode = -118;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #7: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -119;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (geometry crosses an Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 10, 11, GeomFromText('LINESTRINGZ(152 160 1, 153 161 1, 153 159 1, 154 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #8: expected failure\n");
+	  *retcode = -120;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 8")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #8: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -121;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an invalid Edge (coincident Edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 11, 10, GeomFromText('LINESTRINGZ(154 160 1, 152 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #9: expected failure\n");
+	  *retcode = -122;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident edge 8") != 0)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #9: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -123;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* creating new Faces (hole) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 11, 10, GeomFromText('LINESTRINGZ(154 160 1, 154 167 1, 152 167 1, 152 160 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeNewFaces() #10 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -124;
+	  return 0;
+      }
+
+/* attempting to add an invalid Edge (closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 13, 13, GeomFromText('LINESTRINGZ(178 170 1, 178 161 1, 170 161 1, 178 170 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #10: expected failure\n");
+	  *retcode = -125;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "Closed edges would not be isolated, try lwt_AddEdgeNewFaces") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #10: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* adding an Edge/Face (closed ring) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 13, 13, GeomFromText('LINESTRINGZ(178 170 1, 178 161 1, 170 161 1, 178 170 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddEdgeModFace() #10 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -127;
+	  return 0;
+      }
+
+/* testing Face Geometry (Faces with internal hole) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -128;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceGeometry('topo', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceGeometry() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -129;
+	  return 0;
+      }
+
+/* testing Face Edges (Faces with internal hole) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 4)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -130;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_GetFaceEdges('topo', 6)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_GetFaceEdges() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -131;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level2_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 2 */
+    int ret;
+    char *err_msg = NULL;
+
+/* splitting an Edge (Mod) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePointZ(0, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -50;
+	  return 0;
+      }
+
+/* attempting to split an Edge (non-existent edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 100, MakePointZ(0, 25, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #2: expected failure\n");
+	  *retcode = -51;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -52;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (point not on edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 2, MakePointZ(0, 25, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #3: expected failure\n");
+	  *retcode = -53;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on edge") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -54;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePointZ(0, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #4: expected failure\n");
+	  *retcode = -55;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -56;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* splitting an Edge (New) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 2, MakePointZ(0, 75, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgeSplit() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -57;
+	  return 0;
+      }
+
+/* attempting to split an Edge (non-existent edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 100, MakePointZ(0, 25, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #2: expected failure\n");
+	  *retcode = -58;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-existent edge") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #2: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -59;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (point not on edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 3, MakePointZ(0, 25, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #3: expected failure\n");
+	  *retcode = -60;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - point not on edge") != 0)
+      {
+	  fprintf (stderr, "ST_ModEdgeSplit() #3: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -61;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (coincident node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 1, MakePointZ(0, 50, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #4: expected failure\n");
+	  *retcode = -62;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_NewEdgesSplit() #4: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -62;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+static int
+do_level1_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 1 */
+    int ret;
+    char *err_msg = NULL;
+
+/* inserting a first Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(0, 0, 2, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -10;
+	  return 0;
+      }
+
+/* inserting a second Node */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(0, 100, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -11;
+	  return 0;
+      }
+
+/* attempting to insert an invalid Edge (curve not simple) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRINGZ(0 0 1, 0 90 1, 10 90 1, 10 80 1, 0 80 1, 0 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #1: expected failure\n");
+	  *retcode = -12;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - curve not simple") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #1: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -13;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Edge (start node not geometry start point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRINGZ(1 0 1, 0 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #2: expected failure\n");
+	  *retcode = -14;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - start node not geometry start point.") !=
+	0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -15;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Edge (end node not geometry end point) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRINGZ(0 0 1, 1 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #3: expected failure\n");
+	  *retcode = -16;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - end node not geometry end point.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -17;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting an Edge */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 1, 2, GeomFromText('LINESTRINGZ(0 0 1, 0 100 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -18;
+	  return 0;
+      }
+
+/* attempting to insert an invalid Node (coincident) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(0, 0, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #3: expected failure\n");
+	  *retcode = -19;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - coincident node") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #3: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -20;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Node (edge crosses node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(0, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #4: expected failure\n");
+	  *retcode = -21;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - edge crosses node.") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #4: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -22;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Node (not within face) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', 1, MakePointZ(10, 10, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #5: expected failure\n");
+	  *retcode = -23;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - not within face") != 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -24;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* inserting more Nodes */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(-1, 99, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -25;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(1, 101, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -26;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(1, 98, 1, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() #8 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -26;
+	  return 0;
+      }
+
+/* attempting to insert an invalid Edge (geometry crosses a node) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 3, 4, GeomFromText('LINESTRINGZ(-1 99 1, 1 101 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #5: expected failure\n");
+	  *retcode = -27;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses a node")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #5: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -28;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert an invalid Edge (geometry intersects an edge) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 3, 5, GeomFromText('LINESTRINGZ(-1 99 1, 1 98 1)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #6: expected failure\n");
+	  *retcode = -29;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - geometry crosses edge 1")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() #6: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -30;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+static int
+do_level0_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 0 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to insert a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -190;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -191;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to insert a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoNode('topo', NULL, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -192;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -193;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -194;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -195;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to move a Node (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_MoveIsoNode('topo', 1, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -196;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -197;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 14, 16, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: expected failure\n");
+	  *retcode = -198;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -199;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddIsoEdge('topo', 14, 16, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: expected failure\n");
+	  *retcode = -200;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr, "ST_AddIsoEdge() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -201;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 1, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: expected failure\n");
+	  *retcode = -202;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -203;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to change an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ChangeEdgeGeom('topo', 1, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: expected failure\n");
+	  *retcode = -204;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ChangeEdgeGeom() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -205;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -206;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModEdgeSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -207;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ModEdgeSplit('topo', 1, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_MoveIsoNode() invalid SRID: expected failure\n");
+	  *retcode = -208;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_ModEdgeSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -209;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 1, MakePointZ(0, 10, 1, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: expected failure\n");
+	  *retcode = -210;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -211;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to split an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_NewEdgesSplit('topo', 1, MakePoint(0, 10, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: expected failure\n");
+	  *retcode = -212;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_NewEdgesSplit() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -213;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: expected failure\n");
+	  *retcode = -214;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -215;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeModFace('topo', 1, 2, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: expected failure\n");
+	  *retcode = -216;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeModFace() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -217;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 1, 2, GeomFromText('LINESTRINGZ(-40 -50 1,  -50 -40 2)', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: expected failure\n");
+	  *retcode = -218;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -221;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add an Edge (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_AddEdgeNewFaces('topo', 1, 2, GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: expected failure\n");
+	  *retcode = -220;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_AddEdgeNewFaces() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -221;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Point (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePointZ(1, 1, 1, 3003), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: expected failure\n");
+	  *retcode = -222;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -223;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Point (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddPoint('topo', MakePoint(1, 1, 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: expected failure\n");
+	  *retcode = -224;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddPoint() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -225;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Linestring (invalid SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLinestring('topo', GeomFromText('LINESTRINGZ(-40 -50 1, -50 -40 1)', 3003), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: expected failure\n");
+	  *retcode = -226;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -227;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to add a Linestring (invalid DIMs) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_AddLinestring('topo', GeomFromText('LINESTRING(-40 -50,  -50 -40)', 4326), 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: expected failure\n");
+	  *retcode = -228;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_AddLinestring() invalid SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -229;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    int retcode = 0;
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    if (sqlite3_libversion_number () < 3008003)
+      {
+	  fprintf (stderr,
+		   "*** check_topology3d skipped: libsqlite < 3.8.3 !!!\n");
+	  goto end;
+      }
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+/* creating a Topology 3D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('topo', 4326, 0, 1)", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* basic tests: level 0 */
+    if (!do_level0_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 1 */
+    if (!do_level1_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 2 */
+    if (!do_level2_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 3 */
+    if (!do_level3_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 4 */
+    if (!do_level4_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 5 */
+    if (!do_level5_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 6 */
+    if (!do_level6_tests (handle, &retcode))
+	goto end;
+
+/* dropping the Topology 3D */
+    ret =
+	sqlite3_exec (handle, "SELECT DropTopology('topo')", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DropTopology() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+  end:
+    spatialite_finalize_topologies (cache);
+    sqlite3_close (handle);
+    spatialite_cleanup_ex (cache);
+
+#endif /* end TOPOLOGY conditional */
+
+    spatialite_shutdown ();
+    return retcode;
+}
diff --git a/test/check_topoplus.c b/test/check_topoplus.c
new file mode 100644
index 0000000..0029ffe
--- /dev/null
+++ b/test/check_topoplus.c
@@ -0,0 +1,3643 @@
+/*
+
+ check_topoplus.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2011
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+do_level7_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 7 */
+    int ret;
+    char *err_msg = NULL;
+
+/* creating a Topology 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('topocom', 23032, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -200;
+      }
+
+/* attaching an external DB */
+    ret =
+	sqlite3_exec (handle,
+		      "ATTACH DATABASE \"./test_geos.sqlite\" AS inputDB", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ATTACH DATABASE error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -201;
+      }
+
+/* loading a Polygon GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('topocom', 'inputDB', 'comuni', NULL, 0, 650, -1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -202;
+	  return 0;
+      }
+
+/* detaching the external DB */
+    ret =
+	sqlite3_exec (handle, "DETACH DATABASE inputDB", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DETACH DATABASE error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -203;
+      }
+
+/* creating a Topology 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('elbasplit', 32632, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -204;
+      }
+
+/* loading a Polygon GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elbasplit', 'main', 'elba_pg', 'geometry', 0, 256, 1000)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #6 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -205;
+	  return 0;
+      }
+
+/* creating a Topology 2D */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT CreateTopology('elbalnsplit', 32632, 0, 0)", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -206;
+      }
+
+/* loading a Polygon GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elbalnsplit', 'main', 'elba_ln', 'geometry', 0, 256, 500)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #7 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -207;
+	  return 0;
+      }
+
+/* loading a GeoTable into a TopoNet */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'roads', 'geometry')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_FromGeoTable() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -208;
+	  return 0;
+      }
+
+/* testing TopoGeo_GetEdgeSeed */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_GetEdgeSeed('elbasplit', edge_id) FROM MAIN.elbasplit_edge",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_GetEdgeSeed() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -209;
+	  return 0;
+      }
+
+/* testing TopoGeo_GetFaceSeed */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_GetFaceSeed('elbasplit', face_id) FROM MAIN.elbasplit_face WHERE face_id <> 0",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_GetFaceSeed() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -210;
+	  return 0;
+      }
+
+/* testing TopoNet_GetLinkSeed */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_GetLinkSeed('roads', link_id) FROM MAIN.roads_link",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_GetLinkSeed() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -211;
+	  return 0;
+      }
+
+/* testing TopoGeo_UpdateSeeds */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_UpdateSeeds('elbasplit')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_UpdateSeeds() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -212;
+	  return 0;
+      }
+
+/* testing TopoNet_UpdateSeeds */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_UpdateSeeds('roads')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_UpdateSeeds() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -213;
+	  return 0;
+      }
+
+/* sleeping for 2 secs, so to be sure that 'now' really changes */
+    sqlite3_sleep (2000);
+
+/* Edge's fake update */
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE MAIN.elbasplit_edge SET left_face = left_face",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE elbasplit error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -214;
+	  return 0;
+      }
+
+/* testing TopoGeo_UpdateSeeds */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_UpdateSeeds('elbasplit', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_UpdateSeeds() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -215;
+	  return 0;
+      }
+
+/* Link's fake update */
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE MAIN.roads_link SET start_node = start_node",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE roads error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -216;
+	  return 0;
+      }
+
+/* testing TopoNet_UpdateSeeds */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_UpdateSeeds('roads', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_UpdateSeeds() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -217;
+	  return 0;
+      }
+
+/* testing TopoGeo_ToGeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elbasplit', NULL, 'elba_ln', NULL, 'export_elba1')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_ToGeoTable() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -218;
+	  return 0;
+      }
+
+/* testing TopoGeo_ToGeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elbasplit', NULL, 'elba_pg', 'geometry', 'export_elba2', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_ToGeoTable() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -219;
+	  return 0;
+      }
+
+/* testing TopoNet_ToGeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'roads', 'geometry', 'export_roads')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_ToGeoTable() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -220;
+	  return 0;
+      }
+
+/* testing TopoGeo_ToGeoTableGeneralize */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elbasplit', NULL, 'elba_ln', NULL, 'export_elba1gen', 10)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_ToGeoTableGeneralize() #1 error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -221;
+	  return 0;
+      }
+
+/* testing TopoGeo_ToGeoTableGeneralize */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elbasplit', NULL, 'elba_pg', 'geometry', 'export_elba2gen', 10, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_ToGeoTableGeneralize() #2 error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -222;
+	  return 0;
+      }
+
+/* testing TopoNet_ToGeoTableGeneralize */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', 'geometry', 'export_roads1gen', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_ToGeoTableGeneralize() #1 error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -223;
+	  return 0;
+      }
+
+/* testing TopoNet_ToGeoTableGeneralize */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', 'geometry', 'export_roads2gen', 10, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_ToGeoTableGeneralize() #2 error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -224;
+	  return 0;
+      }
+
+/* testing TopoGeo_CreateTopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elbasplit', NULL, 'elba_pg', 'geometry', 'myelba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_CreateTopoLayer() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -225;
+	  return 0;
+      }
+
+/* testing TopoGeo_ExportTopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ExportTopoLayer('elbasplit', 'myelba', 'out_myelba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_ExportTopoLayer() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -226;
+	  return 0;
+      }
+
+/* testing TopoGeo_RemoveTopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_RemoveTopoLayer('elbasplit', 'myelba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_RemoveTopoLayer() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -227;
+	  return 0;
+      }
+
+/* testing TopoGeo_CreateTopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elbasplit', NULL, 'elba_pg', 'geometry', 'yourelba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_CreateTopoLayer() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -228;
+	  return 0;
+      }
+
+/* testing TopoGeo_ExportTopoLayer - create only */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ExportTopoLayer('elbasplit', 'yourelba', 'out_yourelba', 0, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_ExportTopoLayer() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -229;
+	  return 0;
+      }
+
+/* testing TopoGeo_InsertFeatureFromTopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InsertFeatureFromTopoLayer('elbasplit', 'yourelba', 'out_yourelba', 5)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InsertFeatureFromTopoLayer() #1 error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -230;
+	  return 0;
+      }
+
+/* testing CreateTopoGeo - ok */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_CreateTopoGeo('badelba1', GeomFromText('GEOMETRYCOLLECTION(POINT(1 2), LINESTRING(3 3, 4 4), POLYGON((10 10, 11 10, 11 11, 10 11, 10 10)))', 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_CreateTopoGeo() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -231;
+	  return 0;
+      }
+
+/* testing CreateTopoGeo - already populated Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_CreateTopoGeo('badelba1', MakePoint(1, 2, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_CreateTopoGeo() #2: expected failure\n");
+	  *retcode = -232;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-empty topology.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_CreateTopoGeo() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -233;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing SpatNetFromGeom - ok */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromGeom('badnet1', GeomFromText('GEOMETRYCOLLECTION(POINT(1 2), LINESTRING(3 3, 4 4), POLYGON((10 10, 11 10, 11 11, 10 11, 10 10)))', 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_SpatNetFromGeom() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -234;
+	  return 0;
+      }
+
+/* testing SpatNetFromGeom - already populated Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromGeom('badnet1', MakePoint(1, 2, 3003))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ST_SpatNetFromGeom() #2: expected failure\n");
+	  *retcode = -235;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-empty network.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() #2: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -236;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+static int
+do_level6_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 6 */
+    int ret;
+    char *err_msg = NULL;
+
+/* Validating a Topology - valid */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidateTopoGeo('elba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidateTopoGeo() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -180;
+	  return 0;
+      }
+
+/* dirtying the Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_node (node_id, containing_face, geom) "
+		      "SELECT NULL, NULL, ST_PointN(geom, 33) FROM elba_edge WHERE edge_id = 13",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Node #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -182;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE elba_edge SET geom = GeomFromText('LINESTRING(604477 4736752, 604483 4736751, 604480 4736755, 604483 4736751, 604840 4736648)', 32632) WHERE edge_id = 26",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE Edge error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -183;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_face (face_id, mbr) VALUES (NULL, BuildMBR(610000, 4700000, 610001, 4700001, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Face #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -184;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "DELETE FROM elba_face WHERE face_id = 0",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DELETE FROM Face #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -185;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_node (node_id, containing_face, geom) "
+		      "VALUES (NULL, NULL, MakePoint(612771, 4737829, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Node #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -186;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_face (face_id, mbr) VALUES (NULL, BuildMBR(612771, 4737329, 613771, 4737829, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Face #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -187;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_edge (edge_id, start_node, end_node, next_left_edge, next_right_edge, left_face, right_face, geom) "
+		      "VALUES (NULL, 49, 49, 46, -46, 28, 33, GeomFromText('LINESTRING(612771 4737829, 613771 4737829, 613771 4737329, 612771 4737329, 612771 4737829)', 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Edge #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -188;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_node (node_id, containing_face, geom) "
+		      "VALUES (NULL, NULL, MakePoint(613200, 4737700, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Node #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -189;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_face (face_id, mbr) VALUES (NULL, BuildMbr(611771, 4738329, 612771, 4738829, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Face #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -190;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "INSERT INTO elba_edge (edge_id, start_node, end_node, next_left_edge, next_right_edge, left_face, right_face, geom) "
+		      "VALUES (NULL, 50, 50, 47, -47, 29, 33, GeomFromText('LINESTRING(613200 4737700, 613400 4737700, 613400 4737400, 613200 4737400, 613200 4737700)', 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "INSERT INTO Edge #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -191;
+	  return 0;
+      }
+
+/* Validating yet again the dirtied Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidateTopoGeo('elba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidateTopoGeo() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -192;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level5_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 5 */
+    int ret;
+    char *err_msg = NULL;
+
+/* Validating a Spatial Network - valid */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidSpatialNet('spatnet')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidSpatialNet() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -160;
+	  return 0;
+      }
+
+/* dirtying the Spatial Network */
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE spatnet_link SET geometry = NULL WHERE link_id = 1",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE Spatial Link error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -162;
+	  return 0;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE spatnet_link SET geometry = GeomFromText('LINESTRING(604477 4736752, 604840 4736648)', 32632) WHERE link_id = 26",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE Spatial Link error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -163;
+	  return 0;
+      }
+
+/* Validating yet again the dirtied Spatial Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidSpatialNet('spatnet')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidSpatialNet() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -164;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level4_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 4 */
+    int ret;
+    char *err_msg = NULL;
+
+/* Validating a Logical Network - valid */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidLogicalNet('loginet')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidLogicalNet() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -150;
+	  return 0;
+      }
+
+/* dirtying the Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE loginet_link SET geometry = GeomFromText('LINESTRING(0 0, 1 1)', -1) WHERE link_id = 1",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE Logical Link error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -152;
+	  return 0;
+      }
+
+/* Validating yet again the dirtied Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidLogicalNet('loginet')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidLogicalNet() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -153;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level3_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 3 */
+    int ret;
+    char *err_msg = NULL;
+
+/* cloning a Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_Clone(NULL, 'elba', 'elba_clone')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_Clone() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -120;
+	  return 0;
+      }
+
+/* attempting to clone a Topology - already existing destination Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_Clone('MAIN', 'elba', 'elba_clone')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_Clone() already existing destination Topology: expected failure\n");
+	  *retcode = -121;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid topology name (destination).") !=
+	0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_Clone() already existing destination Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -122;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to transform a Topology into a Logical Network (non-existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_LogiNetFromTGeo('loginet', 'lollypop')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "LogiNetFromTGeo() non-existing Topology: expected failure\n");
+	  *retcode = -124;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid topology name.") !=
+	0)
+      {
+	  fprintf (stderr,
+		   "LogiNetFromTGeo() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -125;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* transforming a Topology into a Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_LogiNetFromTGeo('loginet', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "LogiNetFromTGeo() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+
+/* attempting to transform a Topology into a Spatial Network (non-existing) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromTGeo('spatnet', 'lollypop')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() non-existing Topology: expected failure\n");
+	  *retcode = -127;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - invalid topology name.") !=
+	0)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -128;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* transforming a Topology into a Spatial Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromTGeo('spatnet', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "SpatNetFromTGeo() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -129;
+	  return 0;
+      }
+
+/* attempting to transform a Topology into a Logical Network (non-empty) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_LogiNetFromTGeo('loginet', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "LogiNetFromTGeo() already populated Network: expected failure\n");
+	  *retcode = -130;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-empty network.") != 0)
+      {
+	  fprintf (stderr,
+		   "LogiNetFromTGeo() already populated Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -131;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to transform a Topology into a Spatial Network (non-empty) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromTGeo('spatnet', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() already populated Network: expected failure\n");
+	  *retcode = -132;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - non-empty network.") != 0)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() already populated Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -133;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* cloning a Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_Clone(NULL, 'loginet', 'loginet_clone')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_Clone() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -137;
+	  return 0;
+      }
+
+/* attempting to clone a Logical Network - already existing destination Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_Clone('MAIN', 'loginet', 'loginet_clone')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_Clone() already existing destination Logical Network: expected failure\n");
+	  *retcode = -138;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid network name (destination).") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_Clone() already existing destination Logical Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -139;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* cloning a Spatial Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_Clone('MAIN', 'spatnet', 'spatnet_clone')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoNet_Clone() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -140;
+	  return 0;
+      }
+
+/* attempting to clone a Spatial Network - already existing destination Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_Clone(NULL, 'spatnet', 'spatnet_clone')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_Clone() already existing destination Spatial Network: expected failure\n");
+	  *retcode = -141;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid network name (destination).") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_Clone() already existing destination Spatial Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -142;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+
+static int
+do_level2_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 2 */
+    int ret;
+    char *err_msg = NULL;
+
+/* loading a Point GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'elba_pg', 'centroid', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -100;
+	  return 0;
+      }
+
+/* loading a Polygon GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'elba_pg', 'geometry', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -101;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level1_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 1 */
+    int ret;
+    char *err_msg = NULL;
+
+/* loading a Linestring GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'elba_ln', NULL, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -90;
+	  return 0;
+      }
+
+/* loading a Point GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'elba_pg', 'centroid', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_FromGeoTable() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -91;
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+do_level00_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 00 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to load a Network - non-existing Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('wannebe', NULL, 'roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() non-existing Network: expected failure\n");
+	  *retcode = -220;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid network name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() non-existing Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -221;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Network - non-existing GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'wannabe', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() non-existing GeoTable: expected failure\n");
+	  *retcode = -222;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() non-existing GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -223;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Network - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', 'lollypop', 'roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() wrong DB-prefix: expected failure\n");
+	  *retcode = -224;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -225;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Network - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'roads', 'none')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() non-existing Geometry: expected failure\n");
+	  *retcode = -226;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -227;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Network - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'roads', 'wgs')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() mismatching SRID: expected failure\n");
+	  *retcode = -228;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID, dimensions or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -229;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - mismatching dims */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'roads', 'g3d')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() mismatching dims: expected failure\n");
+	  *retcode = -230;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID, dimensions or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() mismatching dims: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -231;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Network - mismatching class */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'elba_pg', 'geometry')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() mismatching class: expected failure\n");
+	  *retcode = -232;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID, dimensions or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() mismatching class: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -233;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Network - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('roads', NULL, 'roads', NULL)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() ambiguous Geometry: expected failure\n");
+	  *retcode = -235;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -235;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_FromGeoTable('loginet', NULL, 'roads', 'geometry')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() Logical Network: expected failure\n");
+	  *retcode = -236;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "FromGeoTable() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_FromGeoTable() Logical Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -237;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - non-existing Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('wannebe', NULL, 'roads', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing Network: expected failure\n");
+	  *retcode = -238;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid network name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -239;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - non-existing GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'wannabe', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing ref-GeoTable: expected failure\n");
+	  *retcode = -240;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoNet_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing ref-GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -241;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', 'lollypop', 'roads', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() wrong DB-prefix: expected failure\n");
+	  *retcode = -242;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoNet_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -243;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'roads', 'none', 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing Geometry: expected failure\n");
+	  *retcode = -244;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoNet_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -245;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'roads', 'wgs', 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() mismatching SRID: expected failure\n");
+	  *retcode = -246;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -247;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - mismatching class */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'elba_pg', 'geometry', 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() mismatching class: expected failure\n");
+	  *retcode = -248;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() mismatching class: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -249;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'roads', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() ambiguous Geometry: expected failure\n");
+	  *retcode = -250;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoNet_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -251;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('loginet', NULL, 'roads', 'geometry', 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() Logical Network: expected failure\n");
+	  *retcode = -252;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTable() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() Logical Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -253;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - already existing out-table */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'roads', 'geometry', 'elba_pg')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() already existing out-table: expected failure\n");
+	  *retcode = -254;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoNet_ToGeoTable: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() already existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -255;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Network - already existing out-table (non-geo) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTable('roads', NULL, 'roads', 'geometry', 'geometry_columns')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() already existing out-table (non-geo): expected failure\n");
+	  *retcode = -256;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoNet_ToGeoTable: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() already existing out-table (non-geo): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -257;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - non-existing Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('wannebe', NULL, 'roads', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() non-existing Network: expected failure\n");
+	  *retcode = -258;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid network name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() non-existing Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -259;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - non-existing GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'wannabe', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() non-existing ref-GeoTable: expected failure\n");
+	  *retcode = -260;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() non-existing ref-GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -261;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', 'lollypop', 'roads', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() wrong DB-prefix: expected failure\n");
+	  *retcode = -262;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -263;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', 'none', 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() non-existing Geometry: expected failure\n");
+	  *retcode = -264;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTable() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -265;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', 'wgs', 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() mismatching SRID: expected failure\n");
+	  *retcode = -266;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -267;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - mismatching class */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'elba_pg', 'geometry', 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() mismatching class: expected failure\n");
+	  *retcode = -268;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID or class).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() mismatching class: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -269;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() ambiguous Geometry: expected failure\n");
+	  *retcode = -270;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -271;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Logical Network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('loginet', NULL, 'roads', 'geometry', 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() Logical Network: expected failure\n");
+	  *retcode = -272;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize() cannot be applied to Logical Network.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() Logical Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -273;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - already existing out-table */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', 'geometry', 'elba_pg', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() already existing out-table: expected failure\n");
+	  *retcode = -274;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() already existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -275;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Network - already existing out-table (non-geo) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoNet_ToGeoTableGeneralize('roads', NULL, 'roads', 'geometry', 'geometry_columns', 10)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() already existing out-table (non-geo): expected failure\n");
+	  *retcode = -276;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoNet_ToGeoTableGeneralize: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoNet_ToGeoTableGeneralize() already existing out-table (non-geo): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -277;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+static int
+do_level0_tests (sqlite3 * handle, int *retcode)
+{
+/* performing basic tests: Level 0 */
+    int ret;
+    char *err_msg = NULL;
+
+/* attempting to load a Topology - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('wannebe', NULL, 'elba_ln', NULL, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() non-existing Topology: expected failure\n");
+	  *retcode = -50;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -51;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - non-existing GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'wannabe', NULL, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() non-existing GeoTable: expected failure\n");
+	  *retcode = -52;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() non-existing GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -53;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', 'lollypop', 'elba_ln', NULL, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() wrong DB-prefix: expected failure\n");
+	  *retcode = -54;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -55;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'elba_ln', 'none', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() non-existing Geometry: expected failure\n");
+	  *retcode = -56;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -57;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('badelba1', NULL, 'elba_ln', 'geometry', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() mismatching SRID: expected failure\n");
+	  *retcode = -58;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -59;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - mismatching dims */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('badelba2', NULL, 'elba_ln', 'GEOMETRY', 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() mismatching dims: expected failure\n");
+	  *retcode = -60;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid GeoTable (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() mismatching dims: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -61;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to load a Topology - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_FromGeoTable('elba', NULL, 'elba_pg', NULL, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() ambiguous Geometry: expected failure\n");
+	  *retcode = -62;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid input GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_FromGeoTable() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -63;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to transform a Topology into a Logical Network (Spatial Network indeed) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_LogiNetFromTGeo('spatnet', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "LogiNetFromTGeo() Spatial Network: expected failure\n");
+	  *retcode = -64;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "ST_LogiNetFromTGeo() cannot be applied to Spatial Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "LogiNetFromTGeo() Spatial Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -65;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to transform a Topology into a Spatial Network (Logical Network indeed) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromTGeo('loginet', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() Logical Network: expected failure\n");
+	  *retcode = -66;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "ST_SpatNetFromTGeo() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() Logical Network: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -67;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to transform a Topology into a Spatial Network (mismatching SRID) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromTGeo('badnet1', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() mismatching SRID: expected failure\n");
+	  *retcode = -68;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - mismatching SRID or dimensions.") != 0)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -69;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to transform a Topology into a Spatial Network (mismatching dims) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromTGeo('badnet2', 'elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() mismatching dims: expected failure\n");
+	  *retcode = -70;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - mismatching SRID or dimensions.") != 0)
+      {
+	  fprintf (stderr,
+		   "SpatNetFromTGeo() mismatching dims: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -71;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to validate a Logical Network (Spatial indeed) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidLogicalNet('spatnet')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ValidLogicalNet() mismatching type: expected failure\n");
+	  *retcode = -72;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "ST_ValidLogicalNet() cannot be applied to Spatial Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "ValidLogicalNet() mismatching type: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -73;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to validate a Logical Network (empty) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidLogicalNet('loginet')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidLogicalNet() empty: expected failure\n");
+	  *retcode = -74;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - empty network.") != 0)
+      {
+	  fprintf (stderr,
+		   "ValidLogicalNet() empty: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -75;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to validate a Spatial Network (Logical indeed) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidSpatialNet('loginet')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ValidSpatialNet() mismatching type: expected failure\n");
+	  *retcode = -76;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "ST_ValidSpatialNet() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "ValidSpatialNet() mismatching type: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -77;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to validate a Spatial Network (empty) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidSpatialNet('spatnet')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidSpatialNet() empty: expected failure\n");
+	  *retcode = -78;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - empty network.") != 0)
+      {
+	  fprintf (stderr,
+		   "ValidSpatialNet() empty: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -79;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to validate a TopoGeo (empty) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_ValidateTopoGeo('elba')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr, "ValidateTopoGeo() empty: expected failure\n");
+	  *retcode = -80;
+	  return 0;
+      }
+    if (strcmp (err_msg, "SQL/MM Spatial exception - empty topology.") != 0)
+      {
+	  fprintf (stderr,
+		   "ValidateTopoGeo() empty: unexpected \"%s\"\n", err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -81;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('wannebe', NULL, 'elba_ln', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing Topology: expected failure\n");
+	  *retcode = -82;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -83;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - non-existing ref-GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elba', NULL, 'wannabe', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing ref-GeoTable: expected failure\n");
+	  *retcode = -84;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -85;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elba', 'lollypop', 'elba_ln', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() wrong DB-prefix: expected failure\n");
+	  *retcode = -86;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -87;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elba', NULL, 'elba_ln', 'none', 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing Geometry: expected failure\n");
+	  *retcode = -88;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -89;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('badelba1', NULL, 'elba_ln', 'geometry', 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() mismatching SRID: expected failure\n");
+	  *retcode = -90;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -91;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elba', NULL, 'elba_pg', NULL, 'out-table')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() ambiguous Geometry: expected failure\n");
+	  *retcode = -92;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ToGeoTable: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -93;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - already existing out-table */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elba', NULL, 'elba_ln', NULL, 'elba_pg')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() already existing out-table: expected failure\n");
+	  *retcode = -94;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ToGeoTable: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() already existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -95;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Topology - already existing out-table (non-geo) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTable('elba', NULL, 'elba_ln', NULL, 'geometry_columns')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() already existing out-table (non-geo): expected failure\n");
+	  *retcode = -96;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ToGeoTable: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() already existing out-table (non-geo): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -97;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('wannebe', NULL, 'elba_ln', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() non-existing Topology: expected failure\n");
+	  *retcode = -82;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -98;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - non-existing ref-GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elba', NULL, 'wannabe', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() non-existing ref-GeoTable: expected failure\n");
+	  *retcode = -99;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() non-existing GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -100;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elba', 'lollypop', 'elba_ln', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() wrong DB-prefix: expected failure\n");
+	  *retcode = -101;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -102;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elba', NULL, 'elba_ln', 'none', 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() non-existing Geometry: expected failure\n");
+	  *retcode = -103;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -104;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('badelba1', NULL, 'elba_ln', 'geometry', 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() mismatching SRID: expected failure\n");
+	  *retcode = -105;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -106;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elba', NULL, 'elba_pg', NULL, 'out-table', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTable() ambiguous Geometry: expected failure\n");
+	  *retcode = -107;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ToGeoTableGeneralize: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -108;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - already existing out-table */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elba', NULL, 'elba_ln', NULL, 'elba_pg', 10.0)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() already existing out-table: expected failure\n");
+	  *retcode = -109;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ToGeoTableGeneralize: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() already existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -110;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a Generalized Topology - already existing out-table (non-geo) */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ToGeoTableGeneralize('elba', NULL, 'elba_ln', NULL, 'geometry_columns', 10)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() already existing out-table (non-geo): expected failure\n");
+	  *retcode = -111;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ToGeoTableGeneralize: output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ToGeoTableGeneralize() already existing out-table (non-geo): unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -112;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('wannebe', NULL, 'elba_ln', NULL, 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() non-existing Topology: expected failure\n");
+	  *retcode = -113;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -114;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - non-existing ref-GeoTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elba', NULL, 'wannabe', NULL, 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() non-existing ref-GeoTable: expected failure\n");
+	  *retcode = -115;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_CreateTopoLayer: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() non-existing GeoTable: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -116;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elba', 'lollypop', 'elba_ln', NULL, 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() wrong DB-prefix: expected failure\n");
+	  *retcode = -117;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_CreateTopoLayer: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -118;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - wrong geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elba', NULL, 'elba_ln', 'none', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() non-existing Geometry: expected failure\n");
+	  *retcode = -119;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_CreateTopoLayer: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() non-existing Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -120;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('badelba1', NULL, 'elba_ln', 'geometry', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() mismatching SRID: expected failure\n");
+	  *retcode = -121;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid reference GeoTable (mismatching SRID).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -122;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - mismatching View SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('badelba1', NULL, 'elba_ln', 'geometry', 'topolyr', 1)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() mismatching SRID: expected failure\n");
+	  *retcode = -123;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_CreateTopoLayer: invalid reference View (invalid Geometry).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -124;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to create a TopoLayer - ambiguous geometry column */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elba', NULL, 'elba_pg', NULL, 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() ambiguous Geometry: expected failure\n");
+	  *retcode = -125;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_CreateTopoLayer: invalid reference GeoTable.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() ambiguos Geometry: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -126;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* creating a TopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elba', NULL, 'elba_ln', NULL, 'elba_ln')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_CreateTopoLayer error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -127;
+      }
+
+/* attempting to create a TopoLayer - already existing  */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_CreateTopoLayer('elba', NULL, 'elba_ln', NULL, 'elba_ln')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() already existing out-table: expected failure\n");
+	  *retcode = -128;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_CreateTopoLayer: a TopoLayer of the same name already exists.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_CreateTopoLayer() already existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -129;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a TopoLayer - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_RemoveTopoLayer('wannebe', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_RemoveTopoLayer() non-existing Topology: expected failure\n");
+	  *retcode = -130;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_RemoveTopoLayer() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -131;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to remove a TopoLayer - non-existing Topolayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_RemoveTopoLayer('elba', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_RemoveTopoLayer() non-existing TopoLayer: expected failure\n");
+	  *retcode = -132;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_RemoveTopoLayer: not existing TopoLayer.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_RemoveTopoLayer() non-existing TopoLayer: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -133;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a TopoLayer - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ExportTopoLayer('wannebe', 'topolyr', 'outtable')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() non-existing Topology: expected failure\n");
+	  *retcode = -134;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -135;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a TopoLayer - non-existing Topolayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ExportTopoLayer('elba', 'topolyr', 'outtable')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() non-existing TopoLayer: expected failure\n");
+	  *retcode = -136;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_ExportTopoLayer: not existing TopoLayer.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() non-existing TopoLayer: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -137;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export a TopoLayer - already existing output table */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_ExportTopoLayer('elba', 'elba_ln', 'elba_pg')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() already-existing out-table: expected failure\n");
+	  *retcode = -138;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_ExportTopoLayer: the output GeoTable already exists.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() already-existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -139;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export TopoFeatures - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InsertFeatureFromTopoLayer('wannebe', 'topolyr', 'outtable', 100)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InsertFeatureFromTopoLayer() non-existing Topology: expected failure\n");
+	  *retcode = -140;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InsertFeatureFromTopoLayer() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -141;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export TopoFeatures - non-existing Topolayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InsertFeatureFromTopoLayer('elba', 'topolyr', 'outtable', 100)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InsertFeatureFromTopoLayer() non-existing TopoLayer: expected failure\n");
+	  *retcode = -142;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_InsertFeatureFromTopoLayer: non-existing TopoLayer.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InsertFeatureFromTopoLayer() non-existing TopoLayer: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -143;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to export TopoFeatures - already existing output table */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InsertFeatureFromTopoLayer('elba', 'elba_ln', 'outtable', 100)",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InsertFeatureFromTopoLayer() non-existing out-table: expected failure\n");
+	  *retcode = -144;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_InsertFeatureFromTopoLayer: the output GeoTable does not exists.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_ExportTopoLayer() non-existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -145;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing CreateTopoGeo - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_CreateTopoGeo('elba', MakePoint(1, 2, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_CreateTopoGeo() mismatching SRID: expected failure\n");
+	  *retcode = -146;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid Geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_CreateTopoGeo() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -147;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing CreateTopoGeo - mismatching DIMs */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_CreateTopoGeo('elba', MakePointZ(1, 2, 3, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_CreateTopoGeo() mismatching DIMs: expected failure\n");
+	  *retcode = -148;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid Geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_CreateTopoGeo() mismatching DIMs: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -149;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing SpatNetFromGeom - mismatching SRID */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromGeom('roads', MakePoint(1, 2, 4326))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() mismatching SRID: expected failure\n");
+	  *retcode = -150;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid Geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() mismatching SRID: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -151;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing SpatNetFromGeom - mismatching DIMs */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromGeom('roads', MakePointZ(1, 2, 3, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() mismatching DIMs: expected failure\n");
+	  *retcode = -152;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "SQL/MM Spatial exception - invalid Geometry (mismatching SRID or dimensions).")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() mismatching DIMs: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -153;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* testing SpatNetFromGeom - logical network */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ST_SpatNetFromGeom('loginet', MakePointZ(1, 2, 3, 32632))",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() mismatching DIMs: expected failure\n");
+	  *retcode = -154;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "ST_ValidSpatialNet() cannot be applied to Logical Network.") != 0)
+      {
+	  fprintf (stderr,
+		   "ST_SpatNetFromGeom() mismatching DIMs: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -155;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to initialize a TopoLayer - non-existing Topology */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InitTopoLayer('wannebe', NULL, 'elba_vw', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() non-existing Topology: expected failure\n");
+	  *retcode = -156;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "SQL/MM Spatial exception - invalid topology name.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() non-existing Topology: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -157;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to initialize a TopoLayer - non-existing ref-ìTable */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InitTopoLayer('elba', NULL, 'wannabe', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() non-existing ref-Table: expected failure\n");
+	  *retcode = -158;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_InitTopoLayer: invalid reference Table.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() non-existing Table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -159;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* attempting to initialize a TopoLayer - wrong DB-prefix */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InitTopoLayer('elba', 'lollypop', 'elba_vw', 'topolyr')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() wrong DB-prefix: expected failure\n");
+	  *retcode = -160;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg, "TopoGeo_InitTopoLayer: invalid reference Table.") != 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() wrong DB-prefix: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -161;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+/* initializing a TopoLayer */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InitTopoLayer('elba', NULL, 'elba_vw', 'elba_vw')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "TopoGeo_InitTopoLayer error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return -162;
+      }
+
+/* attempting to initialize a TopoLayer - already existing  */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT TopoGeo_InitTopoLayer('elba', NULL, 'elba_vw', 'elba_vw')",
+		      NULL, NULL, &err_msg);
+    if (ret == SQLITE_OK)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() already existing out-table: expected failure\n");
+	  *retcode = -163;
+	  return 0;
+      }
+    if (strcmp
+	(err_msg,
+	 "TopoGeo_InitTopoLayer: a TopoLayer of the same name already exists.")
+	!= 0)
+      {
+	  fprintf (stderr,
+		   "TopoGeo_InitTopoLayer() already existing out-table: unexpected \"%s\"\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  *retcode = -164;
+	  return 0;
+      }
+    sqlite3_free (err_msg);
+
+    return 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+    int retcode = 0;
+
+#ifdef POSTGIS_2_2		/* only if TOPOLOGY is enabled */
+    int ret;
+    sqlite3 *handle;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+    char *old_SPATIALITE_SECURITY_ENV = NULL;
+#ifdef _WIN32
+    char *env;
+#endif /* not WIN32 */
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    old_SPATIALITE_SECURITY_ENV = getenv ("SPATIALITE_SECURITY");
+#ifdef _WIN32
+    putenv ("SPATIALITE_SECURITY=relaxed");
+#else /* not WIN32 */
+    setenv ("SPATIALITE_SECURITY", "relaxed", 1);
+#endif
+
+    ret =
+	sqlite3_open_v2 (":memory:", &handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open \":memory:\" database: %s\n",
+		   sqlite3_errmsg (handle));
+	  sqlite3_close (handle);
+	  return -1;
+      }
+
+    spatialite_init_ex (handle, cache, 0);
+
+    if (sqlite3_libversion_number () < 3008003)
+      {
+	  fprintf (stderr,
+		   "*** check_topoplus skipped: libsqlite < 3.8.3 !!!\n");
+	  goto end;
+      }
+
+    ret =
+	sqlite3_exec (handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -2;
+      }
+
+/* importing Elba (polygons) from SHP */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ImportSHP('./elba-pg', 'elba_pg', 'CP1252', 32632)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ImportSHP() elba-pg error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -3;
+      }
+
+/* importing Elba (linestrings) from SHP */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ImportSHP('./elba-ln', 'elba_ln', 'CP1252', 32632)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ImportSHP() elba-ln error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -4;
+      }
+
+/* importing Merano Roads (linestrings) from SHP */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT ImportSHP('./shp/merano-3d/roads', 'roads', 'UTF-8', 32632)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "ImportSHP() elba-ln error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -5;
+      }
+
+    if (old_SPATIALITE_SECURITY_ENV)
+      {
+#ifdef _WIN32
+	  env =
+	      sqlite3_mprintf ("SPATIALITE_SECURITY=%s",
+			       old_SPATIALITE_SECURITY_ENV);
+	  putenv (env);
+	  sqlite3_free (env);
+#else /* not WIN32 */
+	  setenv ("SPATIALITE_SECURITY", old_SPATIALITE_SECURITY_ENV, 1);
+#endif
+      }
+    else
+      {
+#ifdef _WIN32
+	  putenv ("SPATIALITE_SECURITY=");
+#else /* not WIN32 */
+	  unsetenv ("SPATIALITE_SECURITY");
+#endif
+      }
+
+/* adding a second Geometry to Elba-polygons */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT AddGeometryColumn('elba_pg', 'centroid', 32632, 'POINT', 'XY')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "AddGeometryColumn elba-pg error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -6;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE elba_pg SET centroid = ST_Centroid(geometry)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "Update elba-pg centroids error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -7;
+      }
+
+/* adding a second Geometry to Roads */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT AddGeometryColumn('roads', 'wgs', 4326, 'LINESTRING', 'XY')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "AddGeometryColumn roads error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -8;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE roads SET wgs = ST_Transform(geometry, 4326)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "Update Roads WGS84 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -9;
+      }
+
+/* adding a thirdd Geometry to Roads */
+    ret =
+	sqlite3_exec (handle,
+		      "SELECT AddGeometryColumn('roads', 'g3d', 32632, 'LINESTRING', 'XYZ')",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "AddGeometryColumn roads error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -10;
+      }
+    ret =
+	sqlite3_exec (handle,
+		      "UPDATE roads SET g3d = CastToXYZ(geometry)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "Update Roads 3D error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -11;
+      }
+
+/* creating a Topology 2D (wrong SRID) */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('badelba1', 4326, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -12;
+      }
+
+/* creating a Topology 3D (wrong dims) */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('badelba2', 32632, 0, 1)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -13;
+      }
+
+/* creating a Topology 2D (ok) */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('elba', 32632, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -14;
+      }
+
+/* creating a Logical Network */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('loginet', 0)", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() #1 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -15;
+      }
+
+/* creating a Network 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('spatnet', 1, 32632, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() #2 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -16;
+      }
+
+/* creating a Network 2D - wrong SRID */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('badnet1', 1, 3003, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() #3 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -17;
+      }
+
+/* creating a Network 3D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('badnet2', 1, 32632, 1, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -18;
+      }
+
+/* creating a Network 2D */
+    ret =
+	sqlite3_exec (handle, "SELECT CreateNetwork('roads', 1, 32632, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateNetwork() #5 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -19;
+      }
+
+/* creating a View */
+    ret =
+	sqlite3_exec (handle,
+		      "CREATE VIEW elba_vw AS SELECT pk_uid, cod_istat, nome FROM elba_ln",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "Create View error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -20;
+      }
+
+/* basic tests: level 0 */
+    if (!do_level0_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 00 */
+    if (!do_level00_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 1 */
+    if (!do_level1_tests (handle, &retcode))
+	goto end;
+
+/* dropping and recreating again a Topology 2D (ok) */
+    ret =
+	sqlite3_exec (handle, "SELECT DropTopology('elba')", NULL,
+		      NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "DropTopology() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -15;
+      }
+    ret =
+	sqlite3_exec (handle, "SELECT CreateTopology('elba', 32632, 0, 0)",
+		      NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateTopology() #4 error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (handle);
+	  return -16;
+      }
+
+/* basic tests: level 2 */
+    if (!do_level2_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 3 */
+    if (!do_level3_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 4 */
+    if (!do_level4_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 5 */
+    if (!do_level5_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 6 */
+    if (!do_level6_tests (handle, &retcode))
+	goto end;
+
+/* basic tests: level 7 */
+    if (!do_level7_tests (handle, &retcode))
+	goto end;
+
+  end:
+    spatialite_finalize_topologies (cache);
+    sqlite3_close (handle);
+    spatialite_cleanup_ex (cache);
+
+#endif /* end TOPOLOGY conditional */
+
+    spatialite_shutdown ();
+    return retcode;
+}
diff --git a/test/check_virtualknn.c b/test/check_virtualknn.c
new file mode 100644
index 0000000..268c64f
--- /dev/null
+++ b/test/check_virtualknn.c
@@ -0,0 +1,620 @@
+/*
+
+ check_virtualknn.c -- SpatiaLite Test Case
+
+ Author: Sandro Furieri <a.furieri at lqt.it>
+
+ ------------------------------------------------------------------------------
+ 
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ 
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+ 
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is the SpatiaLite library
+
+The Initial Developer of the Original Code is Alessandro Furieri
+ 
+Portions created by the Initial Developer are Copyright (C) 2015
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms of
+either the GNU General Public License Version 2 or later (the "GPL"), or
+the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+in which case the provisions of the GPL or the LGPL are applicable instead
+of those above. If you wish to allow use of your version of this file only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of this file under the terms of the MPL, indicate your
+decision by deleting the provisions above and replace them with the notice
+and other provisions required by the GPL or the LGPL. If you do not delete
+the provisions above, a recipient may use your version of this file under
+the terms of any one of the MPL, the GPL or the LGPL.
+ 
+*/
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "sqlite3.h"
+#include "spatialite.h"
+
+static int
+create_table (sqlite3 * sqlite)
+{
+/* creating a test table */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+
+    sql = "CREATE TABLE points (id INTEGER PRIMARY KEY AUTOINCREMENT)";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE TABLE \"points\" error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    sql = "SELECT AddGeometryColumn('points', 'geom', 32632, 'POINT', 'XY')";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "AddGeometryColumn \"points.geom\" error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    sql = "SELECT CreateSpatialIndex('points', 'geom')";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateSpatialIndex \"points.geom\" error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+populate_table (sqlite3 * sqlite)
+{
+/* creating a test table */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+    sqlite3_stmt *stmt;
+    double x;
+    double y;
+
+    sql = "INSERT INTO points VALUES (NULL, MakePoint(?, ?, 32632))";
+    ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
+    if (ret != SQLITE_OK)
+	return 0;
+
+    ret = sqlite3_exec (sqlite, "BEGIN", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "BEGIN TRANSACTION error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    for (y = 4000000.0; y < 4001000.0; y += 20.0)
+      {
+	  for (x = 100000.0; x < 101000.0; x += 20.0)
+	    {
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_double (stmt, 1, x);
+		sqlite3_bind_double (stmt, 2, y);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      fprintf (stderr, "INSERT error: %s\n",
+			       sqlite3_errmsg (sqlite));
+		      goto end;
+		  }
+	    }
+      }
+    for (y = 4000501.0; y < 4001000.0; y += 10.0)
+      {
+	  for (x = 100501.0; x < 101000.0; x += 10.0)
+	    {
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_double (stmt, 1, x);
+		sqlite3_bind_double (stmt, 2, y);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      fprintf (stderr, "INSERT error: %s\n",
+			       sqlite3_errmsg (sqlite));
+		      goto end;
+		  }
+	    }
+      }
+    for (y = 4000750.5; y < 4001000.0; y += 1.0)
+      {
+	  for (x = 100750.5; x < 101000.0; x += 1.0)
+	    {
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_double (stmt, 1, x);
+		sqlite3_bind_double (stmt, 2, y);
+		ret = sqlite3_step (stmt);
+		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
+		    ;
+		else
+		  {
+		      fprintf (stderr, "INSERT error: %s\n",
+			       sqlite3_errmsg (sqlite));
+		      goto end;
+		  }
+	    }
+      }
+
+    ret = sqlite3_exec (sqlite, "COMMIT", NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "COMMIT TRANSACTION error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+  end:
+    sqlite3_finalize (stmt);
+    return 1;
+}
+
+static int
+add_second_geom (sqlite3 * sqlite)
+{
+/* adding a second geometry column */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+
+    sql = "SELECT AddGeometryColumn('points', 'geometry', 4326, 'POINT', 'XY')";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "AddGeometryColumn \"points.geometry\" error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    sql = "UPDATE points SET geometry = ST_Transform(geom, 4326)";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "UPDATE \"knn\" error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+add_second_rtree (sqlite3 * sqlite)
+{
+/* adding a second geometry Spatial Index */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+
+    sql = "SELECT CreateSpatialIndex('points', 'geometry')";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CreateSpatialIndex \"points.geometry\" error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+create_knn (sqlite3 * sqlite)
+{
+/* creating a test table */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+
+    sql = "CREATE VIRTUAL TABLE knn USING VirtualKNN ()";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE VIRTUAL TABLE \"knn\" error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+create_spatial_view_1 (sqlite3 * sqlite)
+{
+/* creating the first Spatial View */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+
+    sql = "CREATE VIEW view_1 AS SELECT id AS rowid, geom AS geom FROM points";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE VIEW \"view_1\" error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    sql =
+	"INSERT INTO views_geometry_columns VALUES('view_1', 'geom', 'rowid', 'points', 'geom', 1)";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "Register SpatialView \"view_1\" error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+create_spatial_view_2 (sqlite3 * sqlite)
+{
+/* creating the second Spatial View */
+    int ret;
+    char *err_msg = NULL;
+    const char *sql;
+
+    sql =
+	"CREATE VIEW view_2 AS SELECT id AS rowid, geometry AS geom FROM points";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "CREATE VIEW \"view_2\" error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    sql =
+	"INSERT INTO views_geometry_columns VALUES('view_2', 'geom', 'rowid', 'points', 'geometry', 1)";
+    ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "Register SpatialView \"view_2\" error: %s\n",
+		   err_msg);
+	  sqlite3_free (err_msg);
+	  return 0;
+      }
+
+    return 1;
+}
+
+static int
+test_knn (sqlite3 * sqlite, int mode)
+{
+/* testing a resultset */
+    int ret;
+    const char *sql;
+    sqlite3_stmt *stmt = NULL;
+    double x;
+    double y;
+    int rows = 0;
+
+    switch (mode)
+      {
+      case 0:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'DB=main.points' AND ref_geometry = MakePoint(?, ?)";
+	  break;
+      case 1:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'points' AND f_geometry_column = 'geom' "
+	      "AND ref_geometry = MakePoint(?, ?) AND max_items = 32632";
+	  break;
+      case 2:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'points' AND f_geometry_column = 'geomx' "
+	      "AND ref_geometry = MakePoint(?, ?)";
+	  break;
+      case 3:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'pointsx' AND ref_geometry = MakePoint(?, ?)";
+	  break;
+      case 4:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'points' AND f_geometry_column = 'geometry' "
+	      "AND ref_geometry = ST_Transform(MakePoint(?, ?, 32632), 4326) AND max_items = -10";
+	  break;
+      case 5:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'view_1' AND ref_geometry = MakePoint(?, ?)";
+	  break;
+      case 6:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'view_2' AND f_geometry_column = 'geom' "
+	      "AND ref_geometry = ST_Transform(MakePoint(?, ?, 32532), 4326)";
+	  break;
+      case 7:
+	  sql =
+	      "SELECT * FROM knn WHERE f_table_name = 'points' AND ref_geometry = MakePoint(?, ?) "
+	      "AND max_items = 10";
+	  break;
+      };
+    ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "SELECT FROM \"knn\": \"%s\"\n",
+		   sqlite3_errmsg (sqlite));
+	  return 0;
+      }
+
+    for (y = 3800000.25; y < 4002000.0; y += 12345.12345)
+      {
+	  for (x = 80000.25; x < 102000.0; x += 12345.12345)
+	    {
+		sqlite3_reset (stmt);
+		sqlite3_clear_bindings (stmt);
+		sqlite3_bind_double (stmt, 1, x);
+		sqlite3_bind_double (stmt, 2, y);
+		while (1)
+		  {
+		      /* scrolling the result set rows */
+		      ret = sqlite3_step (stmt);
+		      if (ret == SQLITE_DONE)
+			  break;	/* end of result set */
+		      if (ret == SQLITE_ROW)
+			{
+			    if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT
+				&& sqlite3_column_type (stmt, 1) == SQLITE_TEXT
+				&& sqlite3_column_type (stmt, 2) == SQLITE_BLOB
+				&& sqlite3_column_type (stmt,
+							3) == SQLITE_INTEGER
+				&& sqlite3_column_type (stmt,
+							4) == SQLITE_INTEGER
+				&& sqlite3_column_type (stmt,
+							5) == SQLITE_INTEGER
+				&& sqlite3_column_type (stmt,
+							6) == SQLITE_FLOAT)
+				;
+			    else
+				goto error;
+			    rows++;
+			}
+		      else
+			  goto error;
+		  }
+	    }
+      }
+    if (!rows)
+	goto error;
+    sqlite3_finalize (stmt);
+    return 1;
+
+  error:
+    if (stmt != NULL)
+	sqlite3_finalize (stmt);
+    return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+    sqlite3 *db_handle = NULL;
+    int ret;
+    char *err_msg = NULL;
+    void *cache = spatialite_alloc_connection ();
+
+    if (argc > 1 || argv[0] == NULL)
+	argc = 1;		/* silencing stupid compiler warnings */
+
+    ret =
+	sqlite3_open_v2 (":memory:", &db_handle,
+			 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "cannot open in-memory db: %s\n",
+		   sqlite3_errmsg (db_handle));
+	  sqlite3_close (db_handle);
+	  db_handle = NULL;
+	  return -1;
+      }
+
+    spatialite_init_ex (db_handle, cache, 0);
+
+    ret =
+	sqlite3_exec (db_handle, "SELECT InitSpatialMetadata(1)", NULL, NULL,
+		      &err_msg);
+    if (ret != SQLITE_OK)
+      {
+	  fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
+	  sqlite3_free (err_msg);
+	  sqlite3_close (db_handle);
+	  return -2;
+      }
+
+/* Creating and populating the test table */
+    ret = create_table (db_handle);
+    if (!ret)
+      {
+	  sqlite3_close (db_handle);
+	  return -3;
+      }
+    ret = populate_table (db_handle);
+    if (!ret)
+      {
+	  sqlite3_close (db_handle);
+	  return -4;
+      }
+
+/* Creating the VirtualKNN table */
+    ret = create_knn (db_handle);
+    if (ret)
+      {
+	  fprintf (stderr, "CREATE VIRTUAL TABLE knn: expected failure !!!\n");
+	  sqlite3_close (db_handle);
+	  return -5;
+      }
+
+/* Testing KNN - #1 */
+    ret = test_knn (db_handle, 0);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #1: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -6;
+      }
+
+/* Testing KNN - #2 */
+    ret = test_knn (db_handle, 1);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #2: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -7;
+      }
+
+/* Testing KNN - #3 */
+    ret = test_knn (db_handle, 2);
+    if (ret)
+      {
+	  fprintf (stderr, "Check KNN #3: unexpected success\n");
+	  sqlite3_close (db_handle);
+	  return -8;
+      }
+
+/* creating a first SpatialView */
+    ret = create_spatial_view_1 (db_handle);
+    if (!ret)
+      {
+	  fprintf (stderr, "Create Spatial View #1: unexpected failure !!!\n");
+	  sqlite3_close (db_handle);
+	  return -9;
+      }
+
+/* Testing KNN - #4 */
+    ret = test_knn (db_handle, 5);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #4: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -10;
+      }
+
+/* Testing KNN - #5 */
+    ret = test_knn (db_handle, 7);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #5: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -11;
+      }
+
+/* adding a second geometry column */
+    ret = add_second_geom (db_handle);
+    if (!ret)
+      {
+	  fprintf (stderr, "Add Second Geometry: unexpected failure !!!\n");
+	  sqlite3_close (db_handle);
+	  return -12;
+      }
+
+/* Testing KNN - #6 */
+    ret = test_knn (db_handle, 3);
+    if (ret)
+      {
+	  fprintf (stderr, "Check KNN #6: unexpected success\n");
+	  sqlite3_close (db_handle);
+	  return -13;
+      }
+
+/* Testing KNN - #7 */
+    ret = test_knn (db_handle, 1);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #7: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -14;
+      }
+
+/* Testing KNN - #8 */
+    ret = test_knn (db_handle, 4);
+    if (ret)
+      {
+	  fprintf (stderr, "Check KNN #8: unexpected success\n");
+	  sqlite3_close (db_handle);
+	  return -15;
+      }
+
+/* creating a second SpatialIndex */
+    ret = add_second_rtree (db_handle);
+    if (!ret)
+      {
+	  fprintf (stderr,
+		   "Add Second Spatial Index: unexpected failure !!!\n");
+	  sqlite3_close (db_handle);
+	  return -16;
+      }
+
+/* Testing KNN - #9 */
+    ret = test_knn (db_handle, 4);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #9: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -17;
+      }
+
+/* creating a second SpatialView */
+    ret = create_spatial_view_2 (db_handle);
+    if (!ret)
+      {
+	  fprintf (stderr, "Create Spatial View #2: unexpected failure !!!\n");
+	  sqlite3_close (db_handle);
+	  return -18;
+      }
+
+/* Testing KNN - #10 */
+    ret = test_knn (db_handle, 6);
+    if (!ret)
+      {
+	  fprintf (stderr, "Check KNN #10: unexpected failure\n");
+	  sqlite3_close (db_handle);
+	  return -19;
+      }
+
+    sqlite3_close (db_handle);
+    spatialite_cleanup_ex (cache);
+    spatialite_shutdown ();
+
+    return 0;
+}
diff --git a/test/check_virtualtable1.c b/test/check_virtualtable1.c
index b92e282..583e4ff 100644
--- a/test/check_virtualtable1.c
+++ b/test/check_virtualtable1.c
@@ -52,10 +52,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "sqlite3.h"
 #include "spatialite.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 int
 main (int argc, char *argv[])
 {
@@ -97,12 +93,13 @@ main (int argc, char *argv[])
 	  return -2;
       }
 
-    asprintf (&sql_statement,
-	      "select col003, col005, col006, col008 from places WHERE col003 = \"Canal Creek\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select col003, col005, col006, col008 from places WHERE col003 = \"Canal Creek\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
diff --git a/test/check_virtualtable2.c b/test/check_virtualtable2.c
index 6d6f312..8229dd3 100644
--- a/test/check_virtualtable2.c
+++ b/test/check_virtualtable2.c
@@ -53,10 +53,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "sqlite3.h"
 #include "spatialite.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 int
 do_test (sqlite3 * db_handle)
 {
@@ -105,12 +101,13 @@ do_test (sqlite3 * db_handle)
     sqlite3_free_table (results);
 
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 < 20;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 < 20;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -150,12 +147,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 <= 19;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 <= 19;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -195,12 +193,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 = 20;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 = 20;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -240,12 +239,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 > 2;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 > 2;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -285,12 +285,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 >= 20;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase2 >= 20;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -330,12 +331,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 < \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 < \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -375,12 +377,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 <= \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 <= \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -429,12 +432,13 @@ do_test (sqlite3 * db_handle)
 	  return -47;
       }
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 > \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 > \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -493,12 +497,13 @@ do_test (sqlite3 * db_handle)
 	  return -55;
       }
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 >= \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 >= \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -538,12 +543,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 = \"windward\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 = \"windward\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -583,12 +589,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID = 1;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID = 1;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -628,12 +635,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID < 2;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID < 2;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -673,12 +681,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID <= 1;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID <= 1;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -718,12 +727,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID > 1;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID > 1;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -763,12 +773,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID >= 2;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2, AsText(Geometry) from shapetest where PKUID >= 2;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -808,12 +819,13 @@ do_test (sqlite3 * db_handle)
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select PKUID, testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 LIKE \"wind%%\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select PKUID, testcase1, testcase2, AsText(Geometry) from shapetest where testcase1 LIKE \"wind%%\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
diff --git a/test/check_virtualtable3.c b/test/check_virtualtable3.c
index cf7e9da..2d7b5a1 100644
--- a/test/check_virtualtable3.c
+++ b/test/check_virtualtable3.c
@@ -52,10 +52,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "sqlite3.h"
 #include "spatialite.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 int
 main (int argc, char *argv[])
 {
@@ -97,12 +93,13 @@ main (int argc, char *argv[])
 	  return -2;
       }
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase2 < 20;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase2 < 20;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -136,12 +133,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase2 <= 19;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase2 <= 19;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -175,12 +173,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase2 = 20;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase2 = 20;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -214,12 +213,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase2 > 2;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase2 > 2;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -253,12 +253,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase2 >= 20;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase2 >= 20;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -292,12 +293,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase1 < \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase1 < \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -331,12 +333,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase1 <= \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase1 <= \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -378,12 +381,13 @@ main (int argc, char *argv[])
 	  return -46;
       }
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase1 > \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase1 > \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -436,12 +440,13 @@ main (int argc, char *argv[])
 	  return -47;
       }
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase1 >= \"p\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase1 >= \"p\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -475,12 +480,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where testcase1 = \"windward\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where testcase1 = \"windward\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -514,12 +520,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where PKUID = 1;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where PKUID = 1;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -553,12 +560,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where PKUID < 2;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where PKUID < 2;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -592,12 +600,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where PKUID <= 1;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where PKUID <= 1;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -631,12 +640,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where PKUID > 1;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where PKUID > 1;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -670,12 +680,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select testcase1, testcase2 from dbftest where PKUID >= 2;");
+    sql_statement =
+	sqlite3_mprintf
+	("select testcase1, testcase2 from dbftest where PKUID >= 2;");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -709,12 +720,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select PKUID, testcase1, testcase2 from dbftest where testcase1 LIKE \"wind%%\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select PKUID, testcase1, testcase2 from dbftest where testcase1 LIKE \"wind%%\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
diff --git a/test/check_virtualtable4.c b/test/check_virtualtable4.c
index 71340d2..1a55edd 100644
--- a/test/check_virtualtable4.c
+++ b/test/check_virtualtable4.c
@@ -51,10 +51,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
 #include "sqlite3.h"
 #include "spatialite.h"
 
-#ifdef _WIN32
-#include "asprintf4win.h"
-#endif
-
 struct test_step
 {
     const char *sql;
@@ -145,12 +141,13 @@ main (int argc, char *argv[])
 	  return -2;
       }
 
-    asprintf (&sql_statement,
-	      "select col_2, col_4, col_5, col_7, rowid from xltest WHERE col_2 = \"Canal Creek\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select col_2, col_4, col_5, col_7, rowid from xltest WHERE col_2 = \"Canal Creek\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -301,12 +298,13 @@ main (int argc, char *argv[])
 	  sqlite3_free (err_msg);
 	  return -30;
       }
-    asprintf (&sql_statement,
-	      "select row_no, place, lat, lon, rowid from sheet2 WHERE place = \"Canal Creek\";");
+    sql_statement =
+	sqlite3_mprintf
+	("select row_no, place, lat, lon, rowid from sheet2 WHERE place = \"Canal Creek\";");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
@@ -353,12 +351,13 @@ main (int argc, char *argv[])
       }
     sqlite3_free_table (results);
 
-    asprintf (&sql_statement,
-	      "select row_no, place, lat, lon, rowid from sheet2 WHERE row_no = 16");
+    sql_statement =
+	sqlite3_mprintf
+	("select row_no, place, lat, lon, rowid from sheet2 WHERE row_no = 16");
     ret =
 	sqlite3_get_table (db_handle, sql_statement, &results, &rows, &columns,
 			   &err_msg);
-    free (sql_statement);
+    sqlite3_free (sql_statement);
     if (ret != SQLITE_OK)
       {
 	  fprintf (stderr, "Error: %s\n", err_msg);
diff --git a/test/elba-ln.dbf b/test/elba-ln.dbf
new file mode 100644
index 0000000..000259b
Binary files /dev/null and b/test/elba-ln.dbf differ
diff --git a/test/elba-ln.shp b/test/elba-ln.shp
new file mode 100644
index 0000000..1971fa4
Binary files /dev/null and b/test/elba-ln.shp differ
diff --git a/test/elba-ln.shx b/test/elba-ln.shx
new file mode 100644
index 0000000..b2643cb
Binary files /dev/null and b/test/elba-ln.shx differ
diff --git a/test/elba-pg.dbf b/test/elba-pg.dbf
new file mode 100644
index 0000000..1c0a5c4
Binary files /dev/null and b/test/elba-pg.dbf differ
diff --git a/test/elba-pg.shp b/test/elba-pg.shp
new file mode 100644
index 0000000..3733233
Binary files /dev/null and b/test/elba-pg.shp differ
diff --git a/test/elba-pg.shx b/test/elba-pg.shx
new file mode 100644
index 0000000..3403ca2
Binary files /dev/null and b/test/elba-pg.shx differ
diff --git a/test/gpkg_test.sqlite b/test/gpkg_test.sqlite
index f06aa5c..dc5f56b 100644
Binary files a/test/gpkg_test.sqlite and b/test/gpkg_test.sqlite differ
diff --git a/test/sql_stmt_geos_tests/Makefile.am b/test/sql_stmt_geos_tests/Makefile.am
index dd83a08..4617c2c 100644
--- a/test/sql_stmt_geos_tests/Makefile.am
+++ b/test/sql_stmt_geos_tests/Makefile.am
@@ -108,6 +108,22 @@ EXTRA_DIST = bdmpolyfromtext10.testcase \
 	convexhull7.testcase \
 	convexhull8.testcase \
 	convexhull9.testcase \
+	acuttermessage.testcase \
+	cutter1.testcase \
+	cutter2.testcase \
+	cutter3.testcase \
+	cutter4.testcase \
+	cutter5.testcase \
+	cutter6.testcase \
+	cutter7.testcase \
+	cutter8.testcase \
+	cutter9.testcase \
+	cutter10.testcase \
+	cutter11.testcase \
+	cutter12.testcase \
+	cutter13.testcase \
+	cutter14.testcase \
+	cutter15.testcase \
 	difference10.testcase \
 	difference11.testcase \
 	difference12.testcase \
@@ -448,24 +464,6 @@ EXTRA_DIST = bdmpolyfromtext10.testcase \
 	covers_covered5.testcase \
 	covers_covered6.testcase \
 	covers_covered7.testcase \
-	createtopo10.testcase \
-	createtopo11.testcase \
-	createtopo12.testcase \
-	createtopo13.testcase \
-	createtopo14.testcase \
-	createtopo15.testcase \
-	createtopo16.testcase \
-	createtopo17.testcase \
-	createtopo18.testcase \
-	createtopo1.testcase \
-	createtopo2.testcase \
-	createtopo3.testcase \
-	createtopo4.testcase \
-	createtopo5.testcase \
-	createtopo6.testcase \
-	createtopo7.testcase \
-	createtopo8.testcase \
-	createtopo9.testcase \
 	distance_geogr10.testcase \
 	distance_geogr11.testcase \
 	distance_geogr12.testcase \
diff --git a/test/sql_stmt_geos_tests/Makefile.in b/test/sql_stmt_geos_tests/Makefile.in
index 29cfa81..c84615d 100644
--- a/test/sql_stmt_geos_tests/Makefile.in
+++ b/test/sql_stmt_geos_tests/Makefile.in
@@ -361,6 +361,22 @@ EXTRA_DIST = bdmpolyfromtext10.testcase \
 	convexhull7.testcase \
 	convexhull8.testcase \
 	convexhull9.testcase \
+	acuttermessage.testcase \
+	cutter1.testcase \
+	cutter2.testcase \
+	cutter3.testcase \
+	cutter4.testcase \
+	cutter5.testcase \
+	cutter6.testcase \
+	cutter7.testcase \
+	cutter8.testcase \
+	cutter9.testcase \
+	cutter10.testcase \
+	cutter11.testcase \
+	cutter12.testcase \
+	cutter13.testcase \
+	cutter14.testcase \
+	cutter15.testcase \
 	difference10.testcase \
 	difference11.testcase \
 	difference12.testcase \
@@ -701,24 +717,6 @@ EXTRA_DIST = bdmpolyfromtext10.testcase \
 	covers_covered5.testcase \
 	covers_covered6.testcase \
 	covers_covered7.testcase \
-	createtopo10.testcase \
-	createtopo11.testcase \
-	createtopo12.testcase \
-	createtopo13.testcase \
-	createtopo14.testcase \
-	createtopo15.testcase \
-	createtopo16.testcase \
-	createtopo17.testcase \
-	createtopo18.testcase \
-	createtopo1.testcase \
-	createtopo2.testcase \
-	createtopo3.testcase \
-	createtopo4.testcase \
-	createtopo5.testcase \
-	createtopo6.testcase \
-	createtopo7.testcase \
-	createtopo8.testcase \
-	createtopo9.testcase \
 	distance_geogr10.testcase \
 	distance_geogr11.testcase \
 	distance_geogr12.testcase \
diff --git a/test/sql_stmt_geos_tests/acuttermessage.testcase b/test/sql_stmt_geos_tests/acuttermessage.testcase
new file mode 100644
index 0000000..2ea826a
--- /dev/null
+++ b/test/sql_stmt_geos_tests/acuttermessage.testcase
@@ -0,0 +1,7 @@
+GetCutterMessage
+NEW:memory: #use in-memory database
+SELECT GetCutterMessage();
+1 # rows (not including the header row)
+1 # columns
+GetCutterMessage()
+(NULL)
diff --git a/test/sql_stmt_geos_tests/createtopo1.testcase b/test/sql_stmt_geos_tests/createtopo1.testcase
deleted file mode 100644
index dc6ca17..0000000
--- a/test/sql_stmt_geos_tests/createtopo1.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, 2D
-NEW:memory: #use in-memory database (empty)
-SELECT CreateTopologyTables(4326, "XY");
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(4326, "XY")
-1
diff --git a/test/sql_stmt_geos_tests/createtopo10.testcase b/test/sql_stmt_geos_tests/createtopo10.testcase
deleted file mode 100644
index 55cad2c..0000000
--- a/test/sql_stmt_geos_tests/createtopo10.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, integer prefix (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables(3, 4326, 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(3, 4326, 3)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/createtopo12.testcase b/test/sql_stmt_geos_tests/createtopo12.testcase
deleted file mode 100644
index 3eb09c3..0000000
--- a/test/sql_stmt_geos_tests/createtopo12.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, spaces in prefix
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables("hello world", 4326, 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("hello world", 4326, 3)
-1
diff --git a/test/sql_stmt_geos_tests/createtopo13.testcase b/test/sql_stmt_geos_tests/createtopo13.testcase
deleted file mode 100644
index dc78c9a..0000000
--- a/test/sql_stmt_geos_tests/createtopo13.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, quote in prefix
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables("hello'_world", 4326, 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("hello'_world", 4326, 3)
-1
diff --git a/test/sql_stmt_geos_tests/createtopo14.testcase b/test/sql_stmt_geos_tests/createtopo14.testcase
deleted file mode 100644
index 7ded789..0000000
--- a/test/sql_stmt_geos_tests/createtopo14.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, 2D int
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables(4326, 2);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(4326, 2)
-1
diff --git a/test/sql_stmt_geos_tests/createtopo15.testcase b/test/sql_stmt_geos_tests/createtopo15.testcase
deleted file mode 100644
index 7ec6147..0000000
--- a/test/sql_stmt_geos_tests/createtopo15.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, 3D int
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables(4326, 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(4326, 3)
-1
diff --git a/test/sql_stmt_geos_tests/createtopo16.testcase b/test/sql_stmt_geos_tests/createtopo16.testcase
deleted file mode 100644
index a32e31e..0000000
--- a/test/sql_stmt_geos_tests/createtopo16.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, 4D int (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables(4326, 4);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(4326, 4)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/createtopo17.testcase b/test/sql_stmt_geos_tests/createtopo17.testcase
deleted file mode 100644
index c2e9c50..0000000
--- a/test/sql_stmt_geos_tests/createtopo17.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, text SRID (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables("4326", 2);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("4326", 2)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/createtopo18.testcase b/test/sql_stmt_geos_tests/createtopo18.testcase
deleted file mode 100644
index 8ea52ed..0000000
--- a/test/sql_stmt_geos_tests/createtopo18.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, float dims (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables(4326, 2.0);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(4326, 2.0)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/createtopo2.testcase b/test/sql_stmt_geos_tests/createtopo2.testcase
deleted file mode 100644
index dbcf50e..0000000
--- a/test/sql_stmt_geos_tests/createtopo2.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 2 arguments, 3D
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables(4326, "XYZ");
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables(4326, "XYZ")
-1
diff --git a/test/sql_stmt_geos_tests/createtopo3.testcase b/test/sql_stmt_geos_tests/createtopo3.testcase
deleted file mode 100644
index d46f699..0000000
--- a/test/sql_stmt_geos_tests/createtopo3.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, 2D
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", 4326, "XY");
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", 4326, "XY")
-1
diff --git a/test/sql_stmt_geos_tests/createtopo4.testcase b/test/sql_stmt_geos_tests/createtopo4.testcase
deleted file mode 100644
index 9cc7604..0000000
--- a/test/sql_stmt_geos_tests/createtopo4.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, 3D
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", 4326, "XYZ");
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", 4326, "XYZ")
-1
diff --git a/test/sql_stmt_geos_tests/createtopo5.testcase b/test/sql_stmt_geos_tests/createtopo5.testcase
deleted file mode 100644
index e128fb2..0000000
--- a/test/sql_stmt_geos_tests/createtopo5.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, 3D int
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", 4326, 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", 4326, 3)
-1
diff --git a/test/sql_stmt_geos_tests/createtopo6.testcase b/test/sql_stmt_geos_tests/createtopo6.testcase
deleted file mode 100644
index e662c9b..0000000
--- a/test/sql_stmt_geos_tests/createtopo6.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, 2D int
-NEW:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", 4326, 2);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", 4326, 2)
-1
diff --git a/test/sql_stmt_geos_tests/createtopo7.testcase b/test/sql_stmt_geos_tests/createtopo7.testcase
deleted file mode 100644
index bffbf4e..0000000
--- a/test/sql_stmt_geos_tests/createtopo7.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, 4D (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", 4326, 4);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", 4326, 4)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/createtopo8.testcase b/test/sql_stmt_geos_tests/createtopo8.testcase
deleted file mode 100644
index fbb59d8..0000000
--- a/test/sql_stmt_geos_tests/createtopo8.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, text SRID (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", "WGS-84", 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", "WGS-84", 3)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/createtopo9.testcase b/test/sql_stmt_geos_tests/createtopo9.testcase
deleted file mode 100644
index b01f8b2..0000000
--- a/test/sql_stmt_geos_tests/createtopo9.testcase
+++ /dev/null
@@ -1,7 +0,0 @@
-CreateTopology - 3 arguments, 0 SRID (error)
-:memory: #use in-memory database
-SELECT CreateTopologyTables("my_prefix", 0, 3);
-1 # rows (not including the header row)
-1 # columns
-CreateTopologyTables("my_prefix", 0, 3)
-0
\ No newline at end of file
diff --git a/test/sql_stmt_geos_tests/cutter1.testcase b/test/sql_stmt_geos_tests/cutter1.testcase
new file mode 100644
index 0000000..9827436
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter1.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL input-DB-prefix
+:memory: #use in-memory database
+SELECT ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output')
+0
diff --git a/test/sql_stmt_geos_tests/cutter10.testcase b/test/sql_stmt_geos_tests/cutter10.testcase
new file mode 100644
index 0000000..f901a15
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter10.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - INT blade-geom
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', 'input_g', NULL, 'blade', 1, 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', 'input_g', NULL, 'blade', 1, 'output')
+-1
diff --git a/test/sql_stmt_geos_tests/cutter11.testcase b/test/sql_stmt_geos_tests/cutter11.testcase
new file mode 100644
index 0000000..4871bd2
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter11.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL output
+:memory: #use in-memory database
+SELECT ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', NULL)
+-1
diff --git a/test/sql_stmt_geos_tests/cutter12.testcase b/test/sql_stmt_geos_tests/cutter12.testcase
new file mode 100644
index 0000000..403f555
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter12.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL transaction
+:memory: #use in-memory database
+SELECT ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', NULL)
+-1
diff --git a/test/sql_stmt_geos_tests/cutter13.testcase b/test/sql_stmt_geos_tests/cutter13.testcase
new file mode 100644
index 0000000..ad886de
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter13.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - INT transaction
+:memory: #use in-memory database
+SELECT ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', 1);
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', 1)
+0
diff --git a/test/sql_stmt_geos_tests/cutter14.testcase b/test/sql_stmt_geos_tests/cutter14.testcase
new file mode 100644
index 0000000..172efe5
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter14.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL ram-temp-storage
+:memory: #use in-memory database
+SELECT ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', 1, NULL)
+-1
diff --git a/test/sql_stmt_geos_tests/cutter15.testcase b/test/sql_stmt_geos_tests/cutter15.testcase
new file mode 100644
index 0000000..de91635
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter15.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - INT ram-temp-storage
+:memory: #use in-memory database
+SELECT ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', 1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(NULL, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output', 1, 1)
+0
diff --git a/test/sql_stmt_geos_tests/cutter2.testcase b/test/sql_stmt_geos_tests/cutter2.testcase
new file mode 100644
index 0000000..aef5003
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter2.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - INT input-DB-prefix
+:memory: #use in-memory database
+SELECT ST_Cutter(1, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter(1, 'input', 'input_g', 'db-prefix', 'blade', 'blade_g', 'output')
+-1
diff --git a/test/sql_stmt_geos_tests/cutter3.testcase b/test/sql_stmt_geos_tests/cutter3.testcase
new file mode 100644
index 0000000..37cd680
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter3.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL input-table
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', NULL, 'input_g', 'db-prefix', 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', NULL, 'input_g', 'db-prefix', 'blade', 'blade_g', 'output')
+-1
diff --git a/test/sql_stmt_geos_tests/cutter4.testcase b/test/sql_stmt_geos_tests/cutter4.testcase
new file mode 100644
index 0000000..0c1994a
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter4.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL input-geom
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', NULL, 'db-prefix', 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', NULL, 'db-prefix', 'blade', 'blade_g', 'output')
+0
diff --git a/test/sql_stmt_geos_tests/cutter5.testcase b/test/sql_stmt_geos_tests/cutter5.testcase
new file mode 100644
index 0000000..53b1091
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter5.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - INT input-geom
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', 1, 'db-prefix', 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', 1, 'db-prefix', 'blade', 'blade_g', 'output')
+-1
diff --git a/test/sql_stmt_geos_tests/cutter6.testcase b/test/sql_stmt_geos_tests/cutter6.testcase
new file mode 100644
index 0000000..a9ebd98
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter6.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - INT blade-db-prefix
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', NULL, 1, 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', NULL, 1, 'blade', 'blade_g', 'output')
+-1
diff --git a/test/sql_stmt_geos_tests/cutter7.testcase b/test/sql_stmt_geos_tests/cutter7.testcase
new file mode 100644
index 0000000..01d7bf6
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter7.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL blade-db-prefix
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', 'input_g', NULL, 'blade', 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', 'input_g', NULL, 'blade', 'blade_g', 'output')
+0
diff --git a/test/sql_stmt_geos_tests/cutter8.testcase b/test/sql_stmt_geos_tests/cutter8.testcase
new file mode 100644
index 0000000..8a92af9
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter8.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL blade-table
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', 'input_g', NULL, NULL, 'blade_g', 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', 'input_g', NULL, NULL, 'blade_g', 'output')
+-1
diff --git a/test/sql_stmt_geos_tests/cutter9.testcase b/test/sql_stmt_geos_tests/cutter9.testcase
new file mode 100644
index 0000000..3f44c50
--- /dev/null
+++ b/test/sql_stmt_geos_tests/cutter9.testcase
@@ -0,0 +1,7 @@
+ST_Cutter - NULL blade-geom
+:memory: #use in-memory database
+SELECT ST_Cutter('db-prefix', 'input', 'input_g', NULL, 'blade', NULL, 'output');
+1 # rows (not including the header row)
+1 # columns
+ST_Cutter('db-prefix', 'input', 'input_g', NULL, 'blade', NULL, 'output')
+0
diff --git a/test/sql_stmt_geosadvanced_tests/Makefile.am b/test/sql_stmt_geosadvanced_tests/Makefile.am
index 1861ed4..fab6b17 100644
--- a/test/sql_stmt_geosadvanced_tests/Makefile.am
+++ b/test/sql_stmt_geosadvanced_tests/Makefile.am
@@ -36,23 +36,4 @@ EXTRA_DIST = concave_hull10.testcase \
 	delaunay6.testcase \
 	delaunay7.testcase \
 	delaunay8.testcase \
-	delaunay9.testcase \
-	voronoj10.testcase \
-	voronoj11.testcase \
-	voronoj12.testcase \
-	voronoj13.testcase \
-	voronoj14.testcase \
-	voronoj15.testcase \
-	voronoj16.testcase \
-	voronoj17.testcase \
-	voronoj18.testcase \
-	voronoj19.testcase \
-	voronoj1.testcase \
-	voronoj20.testcase \
-	voronoj2.testcase \
-	voronoj3.testcase \
-	voronoj4.testcase \
-	voronoj5.testcase \
-	voronoj6.testcase \
-	voronoj8.testcase \
-	voronoj9.testcase 
+	delaunay9.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/Makefile.in b/test/sql_stmt_geosadvanced_tests/Makefile.in
index f8fa487..d301197 100644
--- a/test/sql_stmt_geosadvanced_tests/Makefile.in
+++ b/test/sql_stmt_geosadvanced_tests/Makefile.in
@@ -288,26 +288,7 @@ EXTRA_DIST = concave_hull10.testcase \
 	delaunay6.testcase \
 	delaunay7.testcase \
 	delaunay8.testcase \
-	delaunay9.testcase \
-	voronoj10.testcase \
-	voronoj11.testcase \
-	voronoj12.testcase \
-	voronoj13.testcase \
-	voronoj14.testcase \
-	voronoj15.testcase \
-	voronoj16.testcase \
-	voronoj17.testcase \
-	voronoj18.testcase \
-	voronoj19.testcase \
-	voronoj1.testcase \
-	voronoj20.testcase \
-	voronoj2.testcase \
-	voronoj3.testcase \
-	voronoj4.testcase \
-	voronoj5.testcase \
-	voronoj6.testcase \
-	voronoj8.testcase \
-	voronoj9.testcase 
+	delaunay9.testcase
 
 all: all-am
 
diff --git a/test/sql_stmt_libxml2_tests/Makefile.am b/test/sql_stmt_libxml2_tests/Makefile.am
index 3789e2b..48c9bbf 100644
--- a/test/sql_stmt_libxml2_tests/Makefile.am
+++ b/test/sql_stmt_libxml2_tests/Makefile.am
@@ -69,6 +69,13 @@ EXTRA_DIST = addfileid1.testcase \
 	issldsestyle5.testcase \
 	issldsestyle6.testcase \
 	issldsestyle7.testcase \
+	isgpx1.testcase \
+	isgpx2.testcase \
+	isgpx3.testcase \
+	isgpx4.testcase \
+	isgpx5.testcase \
+	isgpx6.testcase \
+	isgpx7.testcase \
 	issvg1.testcase \
 	issvg2.testcase \
 	issvg3.testcase \
@@ -557,6 +564,12 @@ EXTRA_DIST = addfileid1.testcase \
 	xmlblobgettitle4.testcase \
 	xmlblobgettitle5.testcase \
 	xmlblobgettitle6.testcase \
+	xmlblobmlinegpx1.testcase \
+	xmlblobmlinegpx2.testcase \
+	xmlblobmlinegpx3.testcase \
+	xmlblobmlinegpx4.testcase \
+	xmlblobmlinegpx5.testcase \
+	xmlblobmlinegpx6.testcase \
 	xmlcompress1.testcase \
 	xmlcompress2.testcase \
 	xmlcompress3.testcase \
diff --git a/test/sql_stmt_libxml2_tests/Makefile.in b/test/sql_stmt_libxml2_tests/Makefile.in
index e811d72..9d99ad6 100644
--- a/test/sql_stmt_libxml2_tests/Makefile.in
+++ b/test/sql_stmt_libxml2_tests/Makefile.in
@@ -321,6 +321,13 @@ EXTRA_DIST = addfileid1.testcase \
 	issldsestyle5.testcase \
 	issldsestyle6.testcase \
 	issldsestyle7.testcase \
+	isgpx1.testcase \
+	isgpx2.testcase \
+	isgpx3.testcase \
+	isgpx4.testcase \
+	isgpx5.testcase \
+	isgpx6.testcase \
+	isgpx7.testcase \
 	issvg1.testcase \
 	issvg2.testcase \
 	issvg3.testcase \
@@ -809,6 +816,12 @@ EXTRA_DIST = addfileid1.testcase \
 	xmlblobgettitle4.testcase \
 	xmlblobgettitle5.testcase \
 	xmlblobgettitle6.testcase \
+	xmlblobmlinegpx1.testcase \
+	xmlblobmlinegpx2.testcase \
+	xmlblobmlinegpx3.testcase \
+	xmlblobmlinegpx4.testcase \
+	xmlblobmlinegpx5.testcase \
+	xmlblobmlinegpx6.testcase \
 	xmlcompress1.testcase \
 	xmlcompress2.testcase \
 	xmlcompress3.testcase \
diff --git a/test/sql_stmt_libxml2_tests/isgpx1.testcase b/test/sql_stmt_libxml2_tests/isgpx1.testcase
new file mode 100644
index 0000000..c4cf02e
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx1.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - NULL XmlBLOB
+:memory: #use in-memory database
+SELECT XB_IsGpx(NULL);
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx(NULL)
+-1
+
diff --git a/test/sql_stmt_libxml2_tests/isgpx2.testcase b/test/sql_stmt_libxml2_tests/isgpx2.testcase
new file mode 100644
index 0000000..b816248
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx2.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - INTEGER XmlBLOB
+:memory: #use in-memory database
+SELECT XB_IsGpx(1);
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx(1)
+-1
+
diff --git a/test/sql_stmt_libxml2_tests/isgpx3.testcase b/test/sql_stmt_libxml2_tests/isgpx3.testcase
new file mode 100644
index 0000000..029402e
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx3.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - DOUBLE XmlBLOB
+:memory: #use in-memory database
+SELECT XB_IsGpx(1.1);
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx(1.1)
+-1
+
diff --git a/test/sql_stmt_libxml2_tests/isgpx4.testcase b/test/sql_stmt_libxml2_tests/isgpx4.testcase
new file mode 100644
index 0000000..da4b95a
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx4.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - TEXT XmlBLOB
+:memory: #use in-memory database
+SELECT XB_IsGpx('alpha');
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx('alpha')
+-1
+
diff --git a/test/sql_stmt_libxml2_tests/isgpx5.testcase b/test/sql_stmt_libxml2_tests/isgpx5.testcase
new file mode 100644
index 0000000..8ce228e
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx5.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - invalid XmlBLOB
+:memory: #use in-memory database
+SELECT XB_IsGpx(zeroblob(100));
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx(zeroblob(100))
+-1
+
diff --git a/test/sql_stmt_libxml2_tests/isgpx6.testcase b/test/sql_stmt_libxml2_tests/isgpx6.testcase
new file mode 100644
index 0000000..251e3a0
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx6.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - valid XmlBLOB (TRUE)
+:memory: #use in-memory database
+SELECT XB_IsGpx(x'000BAC070000000F0000000000BA0000CA0000DA0000DE0000DB0000DC0000DDCB789CB3492FA850D0B7030009210219BC37382DE2DD');
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx(x'000BAC070000000F0000000000BA0000CA0000DA0000DE0000DB0000DC0000DDCB789CB3492FA850D0B7030009210219BC37382DE2DD')
+1
+
diff --git a/test/sql_stmt_libxml2_tests/isgpx7.testcase b/test/sql_stmt_libxml2_tests/isgpx7.testcase
new file mode 100644
index 0000000..91df3a1
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/isgpx7.testcase
@@ -0,0 +1,8 @@
+XB_IsGpx - valid XmlBLOB (FALSE)
+:memory: #use in-memory database
+SELECT XB_IsGpx(x'0001AB12000000120000000000BA0000CA0000DA0000DB0000DC0000DDCB3C613E3C623E746578743C2F623E3C2F613EBC49A10C93DD');
+1 # rows (not including the header row)
+1 # columns
+XB_IsGpx(x'0001AB12000000120000000000BA0000CA0000DA0000DB0000DC0000DDCB3C613E3C623E746578743C2F623E3C2F613EBC49A10C93DD')
+0
+
diff --git a/test/sql_stmt_libxml2_tests/xmlblobgetgeometry4.testcase b/test/sql_stmt_libxml2_tests/xmlblobgetgeometry4.testcase
index e956c9f..d44e963 100644
--- a/test/sql_stmt_libxml2_tests/xmlblobgetgeometry4.testcase
+++ b/test/sql_stmt_libxml2_tests/xmlblobgetgeometry4.testcase
@@ -1,8 +1,8 @@
-XB_GetGeometry - BLOB XmlDocument
+XB_GetGeometry - TEXT XmlDocument
 :memory: #use in-memory database
-SELECT XB_GetGeometry(zeroblob(100));
+SELECT XB_GetGeometry('alpha');
 1 # rows (not including the header row)
 1 # columns
-XB_GetGeometry(zeroblob(100))
+XB_GetGeometry('alpha')
 (NULL)
 
diff --git a/test/sql_stmt_libxml2_tests/xmlblobgetgeometry5.testcase b/test/sql_stmt_libxml2_tests/xmlblobgetgeometry5.testcase
index 43ab5bc..a9438e5 100644
--- a/test/sql_stmt_libxml2_tests/xmlblobgetgeometry5.testcase
+++ b/test/sql_stmt_libxml2_tests/xmlblobgetgeometry5.testcase
@@ -1,4 +1,4 @@
-XB_GetGeometry - invalid XmlBLOB
+XB_GetGeometry - invalid BLOB
 :memory: #use in-memory database
 SELECT XB_GetGeometry(zeroblob(100));
 1 # rows (not including the header row)
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx1.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_libxml2_tests/xmlblobmlinegpx1.testcase
index 29eb76c..7bb9f37 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx1.testcase
@@ -1,7 +1,8 @@
-ST_VoronojDiagram - integer input (error)
+XB_MLineFromGPX - NULL XmlDocument
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT XB_MLineFromGPX(NULL);
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+XB_MLineFromGPX(NULL)
 (NULL)
+
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx2.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_libxml2_tests/xmlblobmlinegpx2.testcase
index 29eb76c..326db41 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx2.testcase
@@ -1,7 +1,8 @@
-ST_VoronojDiagram - integer input (error)
+XB_MLineFromGPX - INTEGER XmlDocument
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT XB_MLineFromGPX(1);
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+XB_MLineFromGPX(1)
 (NULL)
+
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx3.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_libxml2_tests/xmlblobmlinegpx3.testcase
index 29eb76c..d42f053 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx3.testcase
@@ -1,7 +1,8 @@
-ST_VoronojDiagram - integer input (error)
+XB_MLineFromGPX - DOUBLE XmlDocument
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT XB_MLineFromGPX(1.1);
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+XB_MLineFromGPX(1.1)
 (NULL)
+
diff --git a/test/sql_stmt_libxml2_tests/xmlblobmlinegpx4.testcase b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx4.testcase
new file mode 100644
index 0000000..29e87a7
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx4.testcase
@@ -0,0 +1,8 @@
+XB_MLineFromGPX - invalid BLOB
+:memory: #use in-memory database
+SELECT XB_MLineFromGPX(zeroblob(100));
+1 # rows (not including the header row)
+1 # columns
+XB_MLineFromGPX(zeroblob(100))
+(NULL)
+
diff --git a/test/sql_stmt_libxml2_tests/xmlblobmlinegpx5.testcase b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx5.testcase
new file mode 100644
index 0000000..56b58ca
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx5.testcase
@@ -0,0 +1,8 @@
+XB_MLineFromGPX - valid XmlBLOB not a GPX
+:memory: #use in-memory database
+SELECT XB_MLineFromGPX(x'0001AB12000000120000000000BA0000CA0000DA0000DB0000DC0000DDCB3C613E3C623E746578743C2F623E3C2F613EBC49A10C93DD');
+1 # rows (not including the header row)
+1 # columns
+XB_MLineFromGPX(x'0001AB12000000120000000000BA0000CA0000DA0000DB0000DC0000DDCB3C613E3C623E746578743C2F623E3C2F613EBC49A10C93DD')
+(NULL)
+
diff --git a/test/sql_stmt_libxml2_tests/xmlblobmlinegpx6.testcase b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx6.testcase
new file mode 100644
index 0000000..6c0a213
--- /dev/null
+++ b/test/sql_stmt_libxml2_tests/xmlblobmlinegpx6.testcase
@@ -0,0 +1,8 @@
+XB_MLineFromGPX - TEXT XmlDocument
+:memory: #use in-memory database
+SELECT XB_MLineFromGPX('alpha');
+1 # rows (not including the header row)
+1 # columns
+XB_MLineFromGPX('alpha')
+(NULL)
+
diff --git a/test/sql_stmt_lwgeom_20_tests/Makefile.am b/test/sql_stmt_lwgeom_20_tests/Makefile.am
new file mode 100644
index 0000000..7e3dd1d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_20_tests/Makefile.am
@@ -0,0 +1,5 @@
+
+EXTRA_DIST = st_asx3d25.testcase \
+	st_asx3d26.testcase \
+	st_asx3d30.testcase \
+	st_split8.testcase
diff --git a/src/srsinit/epsg_update/Makefile.in b/test/sql_stmt_lwgeom_20_tests/Makefile.in
similarity index 97%
copy from src/srsinit/epsg_update/Makefile.in
copy to test/sql_stmt_lwgeom_20_tests/Makefile.in
index e0a1169..f3224a4 100644
--- a/src/srsinit/epsg_update/Makefile.in
+++ b/test/sql_stmt_lwgeom_20_tests/Makefile.in
@@ -87,7 +87,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/srsinit/epsg_update
+subdir = test/sql_stmt_lwgeom_20_tests
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -251,8 +251,10 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = README.txt README-obsolete.txt auto_epsg.c \
-	epsg_from_gdal.c auto_epsg_ext.c
+EXTRA_DIST = st_asx3d25.testcase \
+	st_asx3d26.testcase \
+	st_asx3d30.testcase \
+	st_split8.testcase
 
 all: all-am
 
@@ -266,9 +268,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/srsinit/epsg_update/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/sql_stmt_lwgeom_20_tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign src/srsinit/epsg_update/Makefile
+	  $(AUTOMAKE) --foreign test/sql_stmt_lwgeom_20_tests/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
diff --git a/test/sql_stmt_lwgeom_tests/st_asx3d25.testcase b/test/sql_stmt_lwgeom_20_tests/st_asx3d25.testcase
similarity index 100%
copy from test/sql_stmt_lwgeom_tests/st_asx3d25.testcase
copy to test/sql_stmt_lwgeom_20_tests/st_asx3d25.testcase
diff --git a/test/sql_stmt_lwgeom_tests/st_asx3d26.testcase b/test/sql_stmt_lwgeom_20_tests/st_asx3d26.testcase
similarity index 100%
copy from test/sql_stmt_lwgeom_tests/st_asx3d26.testcase
copy to test/sql_stmt_lwgeom_20_tests/st_asx3d26.testcase
diff --git a/test/sql_stmt_lwgeom_tests/st_asx3d30.testcase b/test/sql_stmt_lwgeom_20_tests/st_asx3d30.testcase
similarity index 100%
copy from test/sql_stmt_lwgeom_tests/st_asx3d30.testcase
copy to test/sql_stmt_lwgeom_20_tests/st_asx3d30.testcase
diff --git a/test/sql_stmt_lwgeom_tests/st_split8.testcase b/test/sql_stmt_lwgeom_20_tests/st_split8.testcase
similarity index 100%
rename from test/sql_stmt_lwgeom_tests/st_split8.testcase
rename to test/sql_stmt_lwgeom_20_tests/st_split8.testcase
diff --git a/test/sql_stmt_lwgeom_22_tests/Makefile.am b/test/sql_stmt_lwgeom_22_tests/Makefile.am
new file mode 100644
index 0000000..02711c8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/Makefile.am
@@ -0,0 +1,931 @@
+
+EXTRA_DIST = addedgemodface1.testcase \
+	addedgemodface2.testcase \
+	addedgemodface3.testcase \
+	addedgemodface4.testcase \
+	addedgemodface5.testcase \
+	addedgemodface6.testcase \
+	addedgemodface7.testcase \
+	addedgemodface8.testcase \
+	addedgemodface9.testcase \
+	addedgemodface10.testcase \
+	addedgemodface11.testcase \
+	addedgemodface12.testcase \
+	addedgemodface13.testcase \
+	addedgemodface14.testcase \
+	addedgemodface15.testcase \
+	addedgemodface16.testcase \
+	addedgemodface17.testcase \
+	addedgemodface18.testcase \
+	addedgemodface19.testcase \
+	addedgemodface20.testcase \
+	addedgenewfaces1.testcase \
+	addedgenewfaces2.testcase \
+	addedgenewfaces3.testcase \
+	addedgenewfaces4.testcase \
+	addedgenewfaces5.testcase \
+	addedgenewfaces6.testcase \
+	addedgenewfaces7.testcase \
+	addedgenewfaces8.testcase \
+	addedgenewfaces9.testcase \
+	addedgenewfaces10.testcase \
+	addedgenewfaces11.testcase \
+	addedgenewfaces12.testcase \
+	addedgenewfaces13.testcase \
+	addedgenewfaces14.testcase \
+	addedgenewfaces15.testcase \
+	addedgenewfaces16.testcase \
+	addedgenewfaces17.testcase \
+	addedgenewfaces18.testcase \
+	addedgenewfaces19.testcase \
+	addedgenewfaces20.testcase \
+	addisoedge1.testcase \
+	addisoedge2.testcase \
+	addisoedge3.testcase \
+	addisoedge4.testcase \
+	addisoedge5.testcase \
+	addisoedge6.testcase \
+	addisoedge7.testcase \
+	addisoedge8.testcase \
+	addisoedge9.testcase \
+	addisoedge10.testcase \
+	addisoedge11.testcase \
+	addisoedge12.testcase \
+	addisoedge13.testcase \
+	addisoedge14.testcase \
+	addisoedge15.testcase \
+	addisoedge16.testcase \
+	addisoedge17.testcase \
+	addisoedge18.testcase \
+	addisoedge19.testcase \
+	addisoedge20.testcase \
+	addisonetnode1.testcase \
+	addisonetnode2.testcase \
+	addisonetnode3.testcase \
+	addisonetnode4.testcase \
+	addisonetnode5.testcase \
+	addisonode1.testcase \
+	addisonode2.testcase \
+	addisonode3.testcase \
+	addisonode4.testcase \
+	addisonode5.testcase \
+	addisonode6.testcase \
+	addisonode7.testcase \
+	addisonode8.testcase \
+	addisonode9.testcase \
+	addisonode10.testcase \
+	addisonode11.testcase \
+	addisonode12.testcase \
+	addisonode13.testcase \
+	addisonode14.testcase \
+	addisonode15.testcase \
+	addisonode16.testcase \
+	addisonode17.testcase \
+	addisonode1.testcase \
+	addisonode2.testcase \
+	addisonode3.testcase \
+	addisonode4.testcase \
+	addisonode5.testcase \
+	addisonode6.testcase \
+	addisonode7.testcase \
+	addisonode8.testcase \
+	addisonode9.testcase \
+	addisonode10.testcase \
+	addisonode11.testcase \
+	addisonode12.testcase \
+	addisonode13.testcase \
+	addisonode14.testcase \
+	addisonode15.testcase \
+	addisonode16.testcase \
+	addisonode17.testcase \
+	addlink1.testcase \
+	addlink2.testcase \
+	addlink3.testcase \
+	addlink4.testcase \
+	addlink5.testcase \
+	addlink6.testcase \
+	addlink7.testcase \
+	addlink8.testcase \
+	addlink9.testcase \
+	addlink10.testcase \
+	addlink11.testcase \
+	addlink12.testcase \
+	addlink13.testcase \
+	changeedgegeom1.testcase \
+	changeedgegeom2.testcase \
+	changeedgegeom3.testcase \
+	changeedgegeom4.testcase \
+	changeedgegeom5.testcase \
+	changeedgegeom6.testcase \
+	changeedgegeom7.testcase \
+	changeedgegeom8.testcase \
+	changeedgegeom9.testcase \
+	changeedgegeom10.testcase \
+	changeedgegeom11.testcase \
+	changeedgegeom12.testcase \
+	changeedgegeom13.testcase \
+	changeedgegeom14.testcase \
+	changeedgegeom15.testcase \
+	changeedgegeom16.testcase \
+	changeedgegeom17.testcase \
+	changelinkgeom1.testcase \
+	changelinkgeom2.testcase \
+	changelinkgeom3.testcase \
+	changelinkgeom4.testcase \
+	changelinkgeom5.testcase \
+	changelinkgeom6.testcase \
+	changelinkgeom7.testcase \
+	changelinkgeom8.testcase \
+	createtopogeo1.testcase \
+	createtopogeo2.testcase \
+	createtopogeo3.testcase \
+	createtopogeo4.testcase \
+	createtopogeo5.testcase \
+	createtopogeo6.testcase \
+	createtopogeo7.testcase \
+	createtopogeo8.testcase \
+	createtopogeo9.testcase \
+	createtopogeo10.testcase \
+	createtopolayer1.testcase \
+	createtopolayer2.testcase \
+	createtopolayer3.testcase \
+	createtopolayer4.testcase \
+	createtopolayer5.testcase \
+	createtopolayer6.testcase \
+	createtopolayer7.testcase \
+	createtopolayer8.testcase \
+	createtopolayer9.testcase \
+	createtopolayer10.testcase \
+	createtopolayer11.testcase \
+	createtopolayer12.testcase \
+	createtopolayer13.testcase \
+	createtopolayer14.testcase \
+	createtopolayer15.testcase \
+	createtopolayer16.testcase \
+	createtopolayer17.testcase \
+	createtopolayer18.testcase \
+	createtopolayer19.testcase \
+	createtopolayer20.testcase \
+	createtopolayer21.testcase \
+	createtopolayer22.testcase \
+	createtopolayer23.testcase \
+	createtopolayer24.testcase \
+	createtopolayer25.testcase \
+	createtopolayer26.testcase \
+	createtopology1.testcase \
+	createtopology2.testcase \
+	createtopology3.testcase \
+	createtopology4.testcase \
+	createtopology5.testcase \
+	createtopology6.testcase \
+	createtopology7.testcase \
+	createtopology8.testcase \
+	createtopology9.testcase \
+	createtopology10.testcase \
+	createtopology11.testcase \
+	createtopology12.testcase \
+	createtopology13.testcase \
+	createtopology14.testcase \
+	createtopology15.testcase \
+	createtopology16.testcase \
+	createtopology17.testcase \
+	createtopology18.testcase \
+	createtopology19.testcase \
+	createtopology20.testcase \
+	createnetwork1.testcase \
+	createnetwork2.testcase \
+	createnetwork3.testcase \
+	createnetwork4.testcase \
+	createnetwork5.testcase \
+	createnetwork6.testcase \
+	createnetwork7.testcase \
+	createnetwork8.testcase \
+	createnetwork9.testcase \
+	createnetwork10.testcase \
+	createnetwork11.testcase \
+	createnetwork12.testcase \
+	createnetwork13.testcase \
+	createnetwork14.testcase \
+	createnetwork15.testcase \
+	createnetwork16.testcase \
+	createnetwork17.testcase \
+	createnetwork18.testcase \
+	createnetwork19.testcase \
+	createnetwork20.testcase \
+	createnetwork21.testcase \
+	createnetwork22.testcase \
+	createnetwork23.testcase \
+	createnetwork24.testcase \
+	createnetwork25.testcase \
+	droptopology1.testcase \
+	droptopology2.testcase \
+	droptopology3.testcase \
+	droptopology4.testcase \
+	droptopology5.testcase \
+	dropnetwork1.testcase \
+	dropnetwork2.testcase \
+	dropnetwork3.testcase \
+	dropnetwork4.testcase \
+	dropnetwork5.testcase \
+	exporttopolayer1.testcase \
+	exporttopolayer2.testcase \
+	exporttopolayer3.testcase \
+	exporttopolayer4.testcase \
+	exporttopolayer5.testcase \
+	exporttopolayer6.testcase \
+	exporttopolayer7.testcase \
+	exporttopolayer8.testcase \
+	exporttopolayer9.testcase \
+	exporttopolayer10.testcase \
+	exporttopolayer11.testcase \
+	exporttopolayer12.testcase \
+	exporttopolayer13.testcase \
+	exporttopolayer14.testcase \
+	exporttopolayer15.testcase \
+	exporttopolayer16.testcase \
+	exporttopolayer17.testcase \
+	exporttopolayer18.testcase \
+	exporttopolayer19.testcase \
+	exporttopolayer20.testcase \
+	exporttopolayer21.testcase \
+	exporttopolayer22.testcase \
+	exporttopolayer23.testcase \
+	featuretopolayer1.testcase \
+	featuretopolayer2.testcase \
+	featuretopolayer3.testcase \
+	featuretopolayer4.testcase \
+	featuretopolayer5.testcase \
+	featuretopolayer6.testcase \
+	featuretopolayer7.testcase \
+	featuretopolayer8.testcase \
+	featuretopolayer9.testcase \
+	featuretopolayer10.testcase \
+	featuretopolayer11.testcase \
+	featuretopolayer12.testcase \
+	featuretopolayer13.testcase \
+	featuretopolayer14.testcase \
+	featuretopolayer15.testcase \
+	featuretopolayer16.testcase \
+	featuretopolayer17.testcase \
+	getedgeseed1.testcase \
+	getedgeseed2.testcase \
+	getedgeseed3.testcase \
+	getedgeseed4.testcase \
+	getedgeseed5.testcase \
+	getedgeseed6.testcase \
+	getedgeseed7.testcase \
+	getedgeseed8.testcase \
+	getedgeseed9.testcase \
+	getlinkseed1.testcase \
+	getlinkseed2.testcase \
+	getlinkseed3.testcase \
+	getlinkseed4.testcase \
+	getlinkseed5.testcase \
+	getlinkseed6.testcase \
+	getlinkseed7.testcase \
+	getlinkseed8.testcase \
+	getlinkseed9.testcase \
+	getfaceedges1.testcase \
+	getfaceedges2.testcase \
+	getfaceedges3.testcase \
+	getfaceedges4.testcase \
+	getfaceedges5.testcase \
+	getfaceedges6.testcase \
+	getfaceedges7.testcase \
+	getfaceedges8.testcase \
+	getfaceedges9.testcase \
+	getfacegeometry1.testcase \
+	getfacegeometry2.testcase \
+	getfacegeometry3.testcase \
+	getfacegeometry4.testcase \
+	getfacegeometry5.testcase \
+	getfacegeometry6.testcase \
+	getfacegeometry7.testcase \
+	getfacegeometry8.testcase \
+	getfacegeometry9.testcase \
+	getedgebypoint1.testcase \
+	getedgebypoint2.testcase \
+	getedgebypoint3.testcase \
+	getedgebypoint4.testcase \
+	getedgebypoint5.testcase \
+	getedgebypoint6.testcase \
+	getedgebypoint7.testcase \
+	getedgebypoint8.testcase \
+	getedgebypoint9.testcase \
+	getedgebypoint10.testcase \
+	getedgebypoint11.testcase \
+	getedgebypoint12.testcase \
+	getedgebypoint13.testcase \
+	getedgebypoint14.testcase \
+	getedgebypoint15.testcase \
+	getedgebypoint16.testcase \
+	getedgebypoint17.testcase \
+	getfacegeometry1.testcase \
+	getfacegeometry2.testcase \
+	getfacegeometry3.testcase \
+	getfacegeometry4.testcase \
+	getfacegeometry5.testcase \
+	getfacegeometry6.testcase \
+	getfacegeometry7.testcase \
+	getfacegeometry8.testcase \
+	getfacegeometry9.testcase \
+	getfacebypoint1.testcase \
+	getfacebypoint2.testcase \
+	getfacebypoint3.testcase \
+	getfacebypoint4.testcase \
+	getfacebypoint5.testcase \
+	getfacebypoint6.testcase \
+	getfacebypoint7.testcase \
+	getfacebypoint8.testcase \
+	getfacebypoint9.testcase \
+	getfacebypoint10.testcase \
+	getfacebypoint11.testcase \
+	getfacebypoint12.testcase \
+	getfacebypoint13.testcase \
+	getfacebypoint14.testcase \
+	getfacebypoint15.testcase \
+	getfacebypoint16.testcase \
+	getfacebypoint17.testcase \
+	getfaceseed1.testcase \
+	getfaceseed2.testcase \
+	getfaceseed3.testcase \
+	getfaceseed4.testcase \
+	getfaceseed5.testcase \
+	getfaceseed6.testcase \
+	getfaceseed7.testcase \
+	getfaceseed8.testcase \
+	getfaceseed9.testcase \
+	getlinkbypoint1.testcase \
+	getlinkbypoint2.testcase \
+	getlinkbypoint3.testcase \
+	getlinkbypoint4.testcase \
+	getlinkbypoint5.testcase \
+	getlinkbypoint6.testcase \
+	getlinkbypoint7.testcase \
+	getlinkbypoint8.testcase \
+	getlinkbypoint9.testcase \
+	getlinkbypoint10.testcase \
+	getlinkbypoint11.testcase \
+	getlinkbypoint12.testcase \
+	getlinkbypoint13.testcase \
+	getlinkbypoint14.testcase \
+	getlinkbypoint15.testcase \
+	getlinkbypoint16.testcase \
+	getlinkbypoint17.testcase \
+	getnetnodebypoint1.testcase \
+	getnetnodebypoint2.testcase \
+	getnetnodebypoint3.testcase \
+	getnetnodebypoint4.testcase \
+	getnetnodebypoint5.testcase \
+	getnetnodebypoint6.testcase \
+	getnetnodebypoint7.testcase \
+	getnetnodebypoint8.testcase \
+	getnetnodebypoint9.testcase \
+	getnetnodebypoint10.testcase \
+	getnetnodebypoint11.testcase \
+	getnetnodebypoint12.testcase \
+	getnetnodebypoint13.testcase \
+	getnetnodebypoint14.testcase \
+	getnetnodebypoint15.testcase \
+	getnetnodebypoint16.testcase \
+	getnetnodebypoint17.testcase \
+	getnodebypoint1.testcase \
+	getnodebypoint2.testcase \
+	getnodebypoint3.testcase \
+	getnodebypoint4.testcase \
+	getnodebypoint5.testcase \
+	getnodebypoint6.testcase \
+	getnodebypoint7.testcase \
+	getnodebypoint8.testcase \
+	getnodebypoint9.testcase \
+	getnodebypoint10.testcase \
+	getnodebypoint11.testcase \
+	getnodebypoint12.testcase \
+	getnodebypoint13.testcase \
+	getnodebypoint14.testcase \
+	getnodebypoint15.testcase \
+	getnodebypoint16.testcase \
+	getnodebypoint17.testcase \
+	inittopolayer1.testcase \
+	inittopolayer2.testcase \
+	inittopolayer3.testcase \
+	inittopolayer4.testcase \
+	inittopolayer5.testcase \
+	inittopolayer6.testcase \
+	inittopolayer7.testcase \
+	inittopolayer8.testcase \
+	inittopolayer9.testcase \
+	inittopolayer10.testcase \
+	inittopolayer11.testcase \
+	inittopolayer12.testcase \
+	inittopolayer13.testcase \
+	inittopolayer14.testcase \
+	inittopolayer15.testcase \
+	inittopolayer16.testcase \
+	inittopolayer17.testcase \
+	loginetfromtgeo1.testcase \
+	loginetfromtgeo2.testcase \
+	loginetfromtgeo3.testcase \
+	loginetfromtgeo4.testcase \
+	loginetfromtgeo5.testcase \
+	loginetfromtgeo6.testcase \
+	loginetfromtgeo7.testcase \
+	loginetfromtgeo8.testcase \
+	loginetfromtgeo9.testcase \
+	modedgeheal1.testcase \
+	modedgeheal2.testcase \
+	modedgeheal3.testcase \
+	modedgeheal4.testcase \
+	modedgeheal5.testcase \
+	modedgeheal6.testcase \
+	modedgeheal7.testcase \
+	modedgeheal8.testcase \
+	modedgeheal9.testcase \
+	modedgeheal10.testcase \
+	modedgeheal11.testcase \
+	modedgeheal12.testcase \
+	modedgeheal13.testcase \
+	modedgesplit1.testcase \
+	modedgesplit2.testcase \
+	modedgesplit3.testcase \
+	modedgesplit4.testcase \
+	modedgesplit5.testcase \
+	modedgesplit6.testcase \
+	modedgesplit7.testcase \
+	modedgesplit8.testcase \
+	modedgesplit9.testcase \
+	modedgesplit10.testcase \
+	modedgesplit11.testcase \
+	modedgesplit12.testcase \
+	modedgesplit13.testcase \
+	modedgesplit14.testcase \
+	modedgesplit15.testcase \
+	modedgesplit16.testcase \
+	modgeolinksplit1.testcase \
+	modgeolinksplit2.testcase \
+	modgeolinksplit3.testcase \
+	modgeolinksplit4.testcase \
+	modgeolinksplit5.testcase \
+	modgeolinksplit6.testcase \
+	modgeolinksplit7.testcase \
+	modgeolinksplit8.testcase \
+	modgeolinksplit9.testcase \
+	modlinkheal1.testcase \
+	modlinkheal2.testcase \
+	modlinkheal3.testcase \
+	modlinkheal4.testcase \
+	modlinkheal5.testcase \
+	modlinkheal6.testcase \
+	modlinkheal7.testcase \
+	modlinkheal8.testcase \
+	modlinkheal9.testcase \
+	modlinkheal10.testcase \
+	modlinkheal11.testcase \
+	modlinkheal12.testcase \
+	modlinkheal13.testcase \
+	modloglinksplit1.testcase \
+	modloglinksplit2.testcase \
+	modloglinksplit3.testcase \
+	modloglinksplit4.testcase \
+	modloglinksplit5.testcase \
+	modloglinksplit6.testcase \
+	modloglinksplit7.testcase \
+	modloglinksplit8.testcase \
+	modloglinksplit9.testcase \
+	moveisonetnode1.testcase \
+	moveisonetnode2.testcase \
+	moveisonetnode3.testcase \
+	moveisonetnode4.testcase \
+	moveisonetnode5.testcase \
+	moveisonetnode6.testcase \
+	moveisonetnode7.testcase \
+	moveisonetnode8.testcase \
+	moveisonetnode9.testcase \
+	moveisonode1.testcase \
+	moveisonode2.testcase \
+	moveisonode3.testcase \
+	moveisonode4.testcase \
+	moveisonode5.testcase \
+	moveisonode6.testcase \
+	moveisonode7.testcase \
+	moveisonode8.testcase \
+	moveisonode9.testcase \
+	moveisonode10.testcase \
+	moveisonode11.testcase \
+	moveisonode12.testcase \
+	moveisonode13.testcase \
+	moveisonode14.testcase \
+	moveisonode15.testcase \
+	moveisonode16.testcase \
+	moveisonode17.testcase \
+	netexception1.testcase \
+	netexception2.testcase \
+	newedgeheal1.testcase \
+	newedgeheal2.testcase \
+	newedgeheal3.testcase \
+	newedgeheal4.testcase \
+	newedgeheal5.testcase \
+	newedgeheal6.testcase \
+	newedgeheal7.testcase \
+	newedgeheal8.testcase \
+	newedgeheal9.testcase \
+	newedgeheal10.testcase \
+	newedgeheal11.testcase \
+	newedgeheal12.testcase \
+	newedgeheal13.testcase \
+	newedgessplit1.testcase \
+	newedgessplit2.testcase \
+	newedgessplit3.testcase \
+	newedgessplit4.testcase \
+	newedgessplit5.testcase \
+	newedgessplit6.testcase \
+	newedgessplit7.testcase \
+	newedgessplit8.testcase \
+	newedgessplit9.testcase \
+	newedgessplit10.testcase \
+	newedgessplit11.testcase \
+	newedgessplit12.testcase \
+	newedgessplit13.testcase \
+	newedgessplit14.testcase \
+	newedgessplit15.testcase \
+	newedgessplit16.testcase \
+	newgeolinksplit1.testcase \
+	newgeolinksplit2.testcase \
+	newgeolinksplit3.testcase \
+	newgeolinksplit4.testcase \
+	newgeolinksplit5.testcase \
+	newgeolinksplit6.testcase \
+	newgeolinksplit7.testcase \
+	newgeolinksplit8.testcase \
+	newgeolinksplit9.testcase \
+	newlinkheal1.testcase \
+	newlinkheal2.testcase \
+	newlinkheal3.testcase \
+	newlinkheal4.testcase \
+	newlinkheal5.testcase \
+	newlinkheal6.testcase \
+	newlinkheal7.testcase \
+	newlinkheal8.testcase \
+	newlinkheal9.testcase \
+	newlinkheal10.testcase \
+	newlinkheal11.testcase \
+	newlinkheal12.testcase \
+	newlinkheal13.testcase \
+	newloglinksplit1.testcase \
+	newloglinksplit2.testcase \
+	newloglinksplit3.testcase \
+	newloglinksplit4.testcase \
+	newloglinksplit5.testcase \
+	newloglinksplit6.testcase \
+	newloglinksplit7.testcase \
+	newloglinksplit8.testcase \
+	newloglinksplit9.testcase \
+	remedgemodface1.testcase \
+	remedgemodface2.testcase \
+	remedgemodface3.testcase \
+	remedgemodface4.testcase \
+	remedgemodface5.testcase \
+	remedgemodface6.testcase \
+	remedgemodface7.testcase \
+	remedgemodface8.testcase \
+	remedgemodface9.testcase \
+	remedgenewface1.testcase \
+	remedgenewface2.testcase \
+	remedgenewface3.testcase \
+	remedgenewface4.testcase \
+	remedgenewface5.testcase \
+	remedgenewface6.testcase \
+	remedgenewface7.testcase \
+	remedgenewface8.testcase \
+	remedgenewface9.testcase \
+	remisoedge1.testcase \
+	remisoedge2.testcase \
+	remisoedge3.testcase \
+	remisoedge4.testcase \
+	remisoedge5.testcase \
+	remisoedge6.testcase \
+	remisoedge7.testcase \
+	remisoedge8.testcase \
+	remisoedge9.testcase \
+	remisonode1.testcase \
+	remisonode2.testcase \
+	remisonode3.testcase \
+	remisonode4.testcase \
+	remisonode5.testcase \
+	remisonode6.testcase \
+	remisonode7.testcase \
+	remisonode8.testcase \
+	remisonode9.testcase \
+	remisonetnode1.testcase \
+	remisonetnode2.testcase \
+	remisonetnode3.testcase \
+	remisonetnode4.testcase \
+	remisonetnode5.testcase \
+	remisonetnode6.testcase \
+	remisonetnode7.testcase \
+	remisonetnode8.testcase \
+	remisonetnode9.testcase \
+	remlink1.testcase \
+	remlink2.testcase \
+	remlink3.testcase \
+	remlink4.testcase \
+	remlink5.testcase \
+	remlink6.testcase \
+	remlink7.testcase \
+	remlink8.testcase \
+	remlink9.testcase \
+	removetopolayer1.testcase \
+	removetopolayer2.testcase \
+	removetopolayer3.testcase \
+	removetopolayer4.testcase \
+	removetopolayer5.testcase \
+	removetopolayer6.testcase \
+	removetopolayer7.testcase \
+	removetopolayer8.testcase \
+	removetopolayer9.testcase \
+	spatnetfromtgeo1.testcase \
+	spatnetfromtgeo2.testcase \
+	spatnetfromtgeo3.testcase \
+	spatnetfromtgeo4.testcase \
+	spatnetfromtgeo5.testcase \
+	spatnetfromtgeo6.testcase \
+	spatnetfromtgeo7.testcase \
+	spatnetfromtgeo8.testcase \
+	spatnetfromtgeo9.testcase \
+	spatnetfromgeom1.testcase \
+	spatnetfromgeom2.testcase \
+	spatnetfromgeom3.testcase \
+	spatnetfromgeom4.testcase \
+	spatnetfromgeom5.testcase \
+	spatnetfromgeom6.testcase \
+	spatnetfromgeom7.testcase \
+	spatnetfromgeom8.testcase \
+	spatnetfromgeom9.testcase \
+	spatnetfromgeom10.testcase \
+	st_asx3d25.testcase \
+	st_asx3d26.testcase \
+	st_asx3d30.testcase \
+	st_split8.testcase \
+	topoexception1.testcase \
+	topoexception2.testcase \
+	topogeoaddpoint1.testcase \
+	topogeoaddpoint2.testcase \
+	topogeoaddpoint3.testcase \
+	topogeoaddpoint4.testcase \
+	topogeoaddpoint5.testcase \
+	topogeoaddpoint6.testcase \
+	topogeoaddpoint7.testcase \
+	topogeoaddpoint8.testcase \
+	topogeoaddpoint9.testcase \
+	topogeoaddpoint10.testcase \
+	topogeoaddpoint11.testcase \
+	topogeoaddpoint12.testcase \
+	topogeoaddpoint13.testcase \
+	topogeoaddpoint14.testcase \
+	topogeoaddpoint15.testcase \
+	topogeoaddpoint16.testcase \
+	topogeoaddpoint17.testcase \
+	topogeoaddline1.testcase \
+	topogeoaddline2.testcase \
+	topogeoaddline3.testcase \
+	topogeoaddline4.testcase \
+	topogeoaddline5.testcase \
+	topogeoaddline6.testcase \
+	topogeoaddline7.testcase \
+	topogeoaddline8.testcase \
+	topogeoaddline9.testcase \
+	topogeoaddline10.testcase \
+	topogeoaddline11.testcase \
+	topogeoaddline12.testcase \
+	topogeoaddline13.testcase \
+	topogeoaddline14.testcase \
+	topogeoaddline15.testcase \
+	topogeoaddline16.testcase \
+	topogeoaddline17.testcase \
+	topogeoclone1.testcase \
+	topogeoclone2.testcase \
+	topogeoclone3.testcase \
+	topogeoclone4.testcase \
+	topogeoclone5.testcase \
+	topogeoclone6.testcase \
+	topogeoclone7.testcase \
+	topogeoclone8.testcase \
+	topogeoclone9.testcase \
+	topogeoclone10.testcase \
+	topogeoclone11.testcase \
+	topogeoclone12.testcase \
+	topogeofromtable1.testcase \
+	topogeofromtable2.testcase \
+	topogeofromtable3.testcase \
+	topogeofromtable4.testcase \
+	topogeofromtable5.testcase \
+	topogeofromtable6.testcase \
+	topogeofromtable7.testcase \
+	topogeofromtable8.testcase \
+	topogeofromtable9.testcase \
+	topogeofromtable10.testcase \
+	topogeofromtable11.testcase \
+	topogeofromtable12.testcase \
+	topogeofromtable13.testcase \
+	topogeofromtable14.testcase \
+	topogeofromtable15.testcase \
+	topogeofromtable16.testcase \
+	topogeofromtable17.testcase \
+	topogeofromtable18.testcase \
+	topogeofromtable19.testcase \
+	topogeofromtable20.testcase \
+	topogeofromtable21.testcase \
+	topogeofromtable22.testcase \
+	topogeofromtable23.testcase \
+	topogeofromtable24.testcase \
+	topogeofromtable25.testcase \
+	topogeofromtable26.testcase \
+	topogeofromtable27.testcase \
+	topogeofromtable28.testcase \
+	topogeofromtable29.testcase \
+	topogeofromtable30.testcase \
+	topogeosplitline1.testcase \
+	topogeosplitline2.testcase \
+	topogeosplitline3.testcase \
+	topogeosplitline4.testcase \
+	topogeosplitline5.testcase \
+	topogeosplitline6.testcase \
+	topogeosplitline7.testcase \
+	topogeosplitline8.testcase \
+	topogeosplitline9.testcase \
+	topogeosplitline10.testcase \
+	topogeosplitline11.testcase \
+	topogeosplitline12.testcase \
+	topogeosplitline13.testcase \
+	topogeosplitline14.testcase \
+	topogeosplitline15.testcase \
+	topogeosplitline16.testcase \
+	topogeototable1.testcase \
+	topogeototable2.testcase \
+	topogeototable3.testcase \
+	topogeototable4.testcase \
+	topogeototable5.testcase \
+	topogeototable6.testcase \
+	topogeototable7.testcase \
+	topogeototable8.testcase \
+	topogeototable9.testcase \
+	topogeototable10.testcase \
+	topogeototable11.testcase \
+	topogeototable12.testcase \
+	topogeototable13.testcase \
+	topogeototable14.testcase \
+	topogeototable15.testcase \
+	topogeototable16.testcase \
+	topogeototable17.testcase \
+	topogeototable18.testcase \
+	topogeototable19.testcase \
+	topogeototable20.testcase \
+	topogeototable21.testcase \
+	topogeototable22.testcase \
+	topogeototable23.testcase \
+	topogeototable24.testcase \
+	topogeototable25.testcase \
+	topogeototable26.testcase \
+	topogeototablegen1.testcase \
+	topogeototablegen2.testcase \
+	topogeototablegen3.testcase \
+	topogeototablegen4.testcase \
+	topogeototablegen5.testcase \
+	topogeototablegen6.testcase \
+	topogeototablegen7.testcase \
+	topogeototablegen8.testcase \
+	topogeototablegen9.testcase \
+	topogeototablegen10.testcase \
+	topogeototablegen11.testcase \
+	topogeototablegen12.testcase \
+	topogeototablegen13.testcase \
+	topogeototablegen14.testcase \
+	topogeototablegen15.testcase \
+	topogeototablegen16.testcase \
+	topogeototablegen17.testcase \
+	topogeototablegen18.testcase \
+	topogeototablegen19.testcase \
+	topogeototablegen20.testcase \
+	topogeototablegen21.testcase \
+	topogeototablegen22.testcase \
+	topogeototablegen23.testcase \
+	topogeototablegen24.testcase \
+	topogeototablegen25.testcase \
+	topogeototablegen26.testcase \
+	topogeototablegen27.testcase \
+	topogeototablegen28.testcase \
+	topogeototablegen29.testcase \
+	topogeototablegen30.testcase \
+	topogeototablegen31.testcase \
+	topogeoupdateseeds1.testcase \
+	topogeoupdateseeds2.testcase \
+	topogeoupdateseeds3.testcase \
+	topogeoupdateseeds4.testcase \
+	topogeoupdateseeds5.testcase \
+	topogeoupdateseeds6.testcase \
+	topogeoupdateseeds7.testcase \
+	topogeoupdateseeds8.testcase \
+	topogeoupdateseeds9.testcase \
+	topogeoupdateseeds10.testcase \
+	toponetclone1.testcase \
+	toponetclone2.testcase \
+	toponetclone3.testcase \
+	toponetclone4.testcase \
+	toponetclone5.testcase \
+	toponetclone6.testcase \
+	toponetclone7.testcase \
+	toponetclone8.testcase \
+	toponetclone9.testcase \
+	toponetclone10.testcase \
+	toponetclone11.testcase \
+	toponetclone12.testcase \
+	toponetfromtable1.testcase \
+	toponetfromtable2.testcase \
+	toponetfromtable3.testcase \
+	toponetfromtable4.testcase \
+	toponetfromtable5.testcase \
+	toponetfromtable6.testcase \
+	toponetfromtable7.testcase \
+	toponetfromtable8.testcase \
+	toponetfromtable9.testcase \
+	toponetfromtable10.testcase \
+	toponetfromtable11.testcase \
+	toponetfromtable12.testcase \
+	toponetfromtable13.testcase \
+	toponetfromtable14.testcase \
+	toponetfromtable15.testcase \
+	toponetfromtable16.testcase \
+	toponetfromtable17.testcase \
+	toponettotable1.testcase \
+	toponettotable2.testcase \
+	toponettotable3.testcase \
+	toponettotable4.testcase \
+	toponettotable5.testcase \
+	toponettotable6.testcase \
+	toponettotable7.testcase \
+	toponettotable8.testcase \
+	toponettotable9.testcase \
+	toponettotable10.testcase \
+	toponettotable11.testcase \
+	toponettotable12.testcase \
+	toponettotable13.testcase \
+	toponettotable14.testcase \
+	toponettotable15.testcase \
+	toponettotable16.testcase \
+	toponettotable17.testcase \
+	toponettotable18.testcase \
+	toponettotable19.testcase \
+	toponettotable20.testcase \
+	toponettotable21.testcase \
+	toponettotable22.testcase \
+	toponettotable23.testcase \
+	toponettotable24.testcase \
+	toponettotable25.testcase \
+	toponettotable26.testcase \
+	toponettotablegen1.testcase \
+	toponettotablegen2.testcase \
+	toponettotablegen3.testcase \
+	toponettotablegen4.testcase \
+	toponettotablegen5.testcase \
+	toponettotablegen6.testcase \
+	toponettotablegen7.testcase \
+	toponettotablegen8.testcase \
+	toponettotablegen9.testcase \
+	toponettotablegen10.testcase \
+	toponettotablegen11.testcase \
+	toponettotablegen12.testcase \
+	toponettotablegen13.testcase \
+	toponettotablegen14.testcase \
+	toponettotablegen15.testcase \
+	toponettotablegen16.testcase \
+	toponettotablegen17.testcase \
+	toponettotablegen18.testcase \
+	toponettotablegen19.testcase \
+	toponettotablegen20.testcase \
+	toponettotablegen21.testcase \
+	toponettotablegen22.testcase \
+	toponettotablegen23.testcase \
+	toponettotablegen24.testcase \
+	toponettotablegen25.testcase \
+	toponettotablegen26.testcase \
+	toponettotablegen27.testcase \
+	toponettotablegen28.testcase \
+	toponettotablegen29.testcase \
+	toponettotablegen30.testcase \
+	toponettotablegen31.testcase \
+	validatetopogeo1.testcase \
+	validatetopogeo2.testcase \
+	validatetopogeo3.testcase \
+	validatetopogeo4.testcase \
+	validatetopogeo5.testcase \
+	validlogicalnet1.testcase \
+	validlogicalnet2.testcase \
+	validlogicalnet3.testcase \
+	validlogicalnet4.testcase \
+	validlogicalnet5.testcase \
+	validspatialnet1.testcase \
+	validspatialnet2.testcase \
+	validspatialnet3.testcase \
+	validspatialnet4.testcase \
+	validspatialnet5.testcase
+	
diff --git a/test/sql_stmt_lwgeom_22_tests/Makefile.in b/test/sql_stmt_lwgeom_22_tests/Makefile.in
new file mode 100644
index 0000000..e51260c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/Makefile.in
@@ -0,0 +1,1378 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/sql_stmt_lwgeom_22_tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOSCONFIG = @GEOSCONFIG@
+GEOS_CFLAGS = @GEOS_CFLAGS@
+GEOS_LDFLAGS = @GEOS_LDFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = addedgemodface1.testcase \
+	addedgemodface2.testcase \
+	addedgemodface3.testcase \
+	addedgemodface4.testcase \
+	addedgemodface5.testcase \
+	addedgemodface6.testcase \
+	addedgemodface7.testcase \
+	addedgemodface8.testcase \
+	addedgemodface9.testcase \
+	addedgemodface10.testcase \
+	addedgemodface11.testcase \
+	addedgemodface12.testcase \
+	addedgemodface13.testcase \
+	addedgemodface14.testcase \
+	addedgemodface15.testcase \
+	addedgemodface16.testcase \
+	addedgemodface17.testcase \
+	addedgemodface18.testcase \
+	addedgemodface19.testcase \
+	addedgemodface20.testcase \
+	addedgenewfaces1.testcase \
+	addedgenewfaces2.testcase \
+	addedgenewfaces3.testcase \
+	addedgenewfaces4.testcase \
+	addedgenewfaces5.testcase \
+	addedgenewfaces6.testcase \
+	addedgenewfaces7.testcase \
+	addedgenewfaces8.testcase \
+	addedgenewfaces9.testcase \
+	addedgenewfaces10.testcase \
+	addedgenewfaces11.testcase \
+	addedgenewfaces12.testcase \
+	addedgenewfaces13.testcase \
+	addedgenewfaces14.testcase \
+	addedgenewfaces15.testcase \
+	addedgenewfaces16.testcase \
+	addedgenewfaces17.testcase \
+	addedgenewfaces18.testcase \
+	addedgenewfaces19.testcase \
+	addedgenewfaces20.testcase \
+	addisoedge1.testcase \
+	addisoedge2.testcase \
+	addisoedge3.testcase \
+	addisoedge4.testcase \
+	addisoedge5.testcase \
+	addisoedge6.testcase \
+	addisoedge7.testcase \
+	addisoedge8.testcase \
+	addisoedge9.testcase \
+	addisoedge10.testcase \
+	addisoedge11.testcase \
+	addisoedge12.testcase \
+	addisoedge13.testcase \
+	addisoedge14.testcase \
+	addisoedge15.testcase \
+	addisoedge16.testcase \
+	addisoedge17.testcase \
+	addisoedge18.testcase \
+	addisoedge19.testcase \
+	addisoedge20.testcase \
+	addisonetnode1.testcase \
+	addisonetnode2.testcase \
+	addisonetnode3.testcase \
+	addisonetnode4.testcase \
+	addisonetnode5.testcase \
+	addisonode1.testcase \
+	addisonode2.testcase \
+	addisonode3.testcase \
+	addisonode4.testcase \
+	addisonode5.testcase \
+	addisonode6.testcase \
+	addisonode7.testcase \
+	addisonode8.testcase \
+	addisonode9.testcase \
+	addisonode10.testcase \
+	addisonode11.testcase \
+	addisonode12.testcase \
+	addisonode13.testcase \
+	addisonode14.testcase \
+	addisonode15.testcase \
+	addisonode16.testcase \
+	addisonode17.testcase \
+	addisonode1.testcase \
+	addisonode2.testcase \
+	addisonode3.testcase \
+	addisonode4.testcase \
+	addisonode5.testcase \
+	addisonode6.testcase \
+	addisonode7.testcase \
+	addisonode8.testcase \
+	addisonode9.testcase \
+	addisonode10.testcase \
+	addisonode11.testcase \
+	addisonode12.testcase \
+	addisonode13.testcase \
+	addisonode14.testcase \
+	addisonode15.testcase \
+	addisonode16.testcase \
+	addisonode17.testcase \
+	addlink1.testcase \
+	addlink2.testcase \
+	addlink3.testcase \
+	addlink4.testcase \
+	addlink5.testcase \
+	addlink6.testcase \
+	addlink7.testcase \
+	addlink8.testcase \
+	addlink9.testcase \
+	addlink10.testcase \
+	addlink11.testcase \
+	addlink12.testcase \
+	addlink13.testcase \
+	changeedgegeom1.testcase \
+	changeedgegeom2.testcase \
+	changeedgegeom3.testcase \
+	changeedgegeom4.testcase \
+	changeedgegeom5.testcase \
+	changeedgegeom6.testcase \
+	changeedgegeom7.testcase \
+	changeedgegeom8.testcase \
+	changeedgegeom9.testcase \
+	changeedgegeom10.testcase \
+	changeedgegeom11.testcase \
+	changeedgegeom12.testcase \
+	changeedgegeom13.testcase \
+	changeedgegeom14.testcase \
+	changeedgegeom15.testcase \
+	changeedgegeom16.testcase \
+	changeedgegeom17.testcase \
+	changelinkgeom1.testcase \
+	changelinkgeom2.testcase \
+	changelinkgeom3.testcase \
+	changelinkgeom4.testcase \
+	changelinkgeom5.testcase \
+	changelinkgeom6.testcase \
+	changelinkgeom7.testcase \
+	changelinkgeom8.testcase \
+	createtopogeo1.testcase \
+	createtopogeo2.testcase \
+	createtopogeo3.testcase \
+	createtopogeo4.testcase \
+	createtopogeo5.testcase \
+	createtopogeo6.testcase \
+	createtopogeo7.testcase \
+	createtopogeo8.testcase \
+	createtopogeo9.testcase \
+	createtopogeo10.testcase \
+	createtopolayer1.testcase \
+	createtopolayer2.testcase \
+	createtopolayer3.testcase \
+	createtopolayer4.testcase \
+	createtopolayer5.testcase \
+	createtopolayer6.testcase \
+	createtopolayer7.testcase \
+	createtopolayer8.testcase \
+	createtopolayer9.testcase \
+	createtopolayer10.testcase \
+	createtopolayer11.testcase \
+	createtopolayer12.testcase \
+	createtopolayer13.testcase \
+	createtopolayer14.testcase \
+	createtopolayer15.testcase \
+	createtopolayer16.testcase \
+	createtopolayer17.testcase \
+	createtopolayer18.testcase \
+	createtopolayer19.testcase \
+	createtopolayer20.testcase \
+	createtopolayer21.testcase \
+	createtopolayer22.testcase \
+	createtopolayer23.testcase \
+	createtopolayer24.testcase \
+	createtopolayer25.testcase \
+	createtopolayer26.testcase \
+	createtopology1.testcase \
+	createtopology2.testcase \
+	createtopology3.testcase \
+	createtopology4.testcase \
+	createtopology5.testcase \
+	createtopology6.testcase \
+	createtopology7.testcase \
+	createtopology8.testcase \
+	createtopology9.testcase \
+	createtopology10.testcase \
+	createtopology11.testcase \
+	createtopology12.testcase \
+	createtopology13.testcase \
+	createtopology14.testcase \
+	createtopology15.testcase \
+	createtopology16.testcase \
+	createtopology17.testcase \
+	createtopology18.testcase \
+	createtopology19.testcase \
+	createtopology20.testcase \
+	createnetwork1.testcase \
+	createnetwork2.testcase \
+	createnetwork3.testcase \
+	createnetwork4.testcase \
+	createnetwork5.testcase \
+	createnetwork6.testcase \
+	createnetwork7.testcase \
+	createnetwork8.testcase \
+	createnetwork9.testcase \
+	createnetwork10.testcase \
+	createnetwork11.testcase \
+	createnetwork12.testcase \
+	createnetwork13.testcase \
+	createnetwork14.testcase \
+	createnetwork15.testcase \
+	createnetwork16.testcase \
+	createnetwork17.testcase \
+	createnetwork18.testcase \
+	createnetwork19.testcase \
+	createnetwork20.testcase \
+	createnetwork21.testcase \
+	createnetwork22.testcase \
+	createnetwork23.testcase \
+	createnetwork24.testcase \
+	createnetwork25.testcase \
+	droptopology1.testcase \
+	droptopology2.testcase \
+	droptopology3.testcase \
+	droptopology4.testcase \
+	droptopology5.testcase \
+	dropnetwork1.testcase \
+	dropnetwork2.testcase \
+	dropnetwork3.testcase \
+	dropnetwork4.testcase \
+	dropnetwork5.testcase \
+	exporttopolayer1.testcase \
+	exporttopolayer2.testcase \
+	exporttopolayer3.testcase \
+	exporttopolayer4.testcase \
+	exporttopolayer5.testcase \
+	exporttopolayer6.testcase \
+	exporttopolayer7.testcase \
+	exporttopolayer8.testcase \
+	exporttopolayer9.testcase \
+	exporttopolayer10.testcase \
+	exporttopolayer11.testcase \
+	exporttopolayer12.testcase \
+	exporttopolayer13.testcase \
+	exporttopolayer14.testcase \
+	exporttopolayer15.testcase \
+	exporttopolayer16.testcase \
+	exporttopolayer17.testcase \
+	exporttopolayer18.testcase \
+	exporttopolayer19.testcase \
+	exporttopolayer20.testcase \
+	exporttopolayer21.testcase \
+	exporttopolayer22.testcase \
+	exporttopolayer23.testcase \
+	featuretopolayer1.testcase \
+	featuretopolayer2.testcase \
+	featuretopolayer3.testcase \
+	featuretopolayer4.testcase \
+	featuretopolayer5.testcase \
+	featuretopolayer6.testcase \
+	featuretopolayer7.testcase \
+	featuretopolayer8.testcase \
+	featuretopolayer9.testcase \
+	featuretopolayer10.testcase \
+	featuretopolayer11.testcase \
+	featuretopolayer12.testcase \
+	featuretopolayer13.testcase \
+	featuretopolayer14.testcase \
+	featuretopolayer15.testcase \
+	featuretopolayer16.testcase \
+	featuretopolayer17.testcase \
+	getedgeseed1.testcase \
+	getedgeseed2.testcase \
+	getedgeseed3.testcase \
+	getedgeseed4.testcase \
+	getedgeseed5.testcase \
+	getedgeseed6.testcase \
+	getedgeseed7.testcase \
+	getedgeseed8.testcase \
+	getedgeseed9.testcase \
+	getlinkseed1.testcase \
+	getlinkseed2.testcase \
+	getlinkseed3.testcase \
+	getlinkseed4.testcase \
+	getlinkseed5.testcase \
+	getlinkseed6.testcase \
+	getlinkseed7.testcase \
+	getlinkseed8.testcase \
+	getlinkseed9.testcase \
+	getfaceedges1.testcase \
+	getfaceedges2.testcase \
+	getfaceedges3.testcase \
+	getfaceedges4.testcase \
+	getfaceedges5.testcase \
+	getfaceedges6.testcase \
+	getfaceedges7.testcase \
+	getfaceedges8.testcase \
+	getfaceedges9.testcase \
+	getfacegeometry1.testcase \
+	getfacegeometry2.testcase \
+	getfacegeometry3.testcase \
+	getfacegeometry4.testcase \
+	getfacegeometry5.testcase \
+	getfacegeometry6.testcase \
+	getfacegeometry7.testcase \
+	getfacegeometry8.testcase \
+	getfacegeometry9.testcase \
+	getedgebypoint1.testcase \
+	getedgebypoint2.testcase \
+	getedgebypoint3.testcase \
+	getedgebypoint4.testcase \
+	getedgebypoint5.testcase \
+	getedgebypoint6.testcase \
+	getedgebypoint7.testcase \
+	getedgebypoint8.testcase \
+	getedgebypoint9.testcase \
+	getedgebypoint10.testcase \
+	getedgebypoint11.testcase \
+	getedgebypoint12.testcase \
+	getedgebypoint13.testcase \
+	getedgebypoint14.testcase \
+	getedgebypoint15.testcase \
+	getedgebypoint16.testcase \
+	getedgebypoint17.testcase \
+	getfacegeometry1.testcase \
+	getfacegeometry2.testcase \
+	getfacegeometry3.testcase \
+	getfacegeometry4.testcase \
+	getfacegeometry5.testcase \
+	getfacegeometry6.testcase \
+	getfacegeometry7.testcase \
+	getfacegeometry8.testcase \
+	getfacegeometry9.testcase \
+	getfacebypoint1.testcase \
+	getfacebypoint2.testcase \
+	getfacebypoint3.testcase \
+	getfacebypoint4.testcase \
+	getfacebypoint5.testcase \
+	getfacebypoint6.testcase \
+	getfacebypoint7.testcase \
+	getfacebypoint8.testcase \
+	getfacebypoint9.testcase \
+	getfacebypoint10.testcase \
+	getfacebypoint11.testcase \
+	getfacebypoint12.testcase \
+	getfacebypoint13.testcase \
+	getfacebypoint14.testcase \
+	getfacebypoint15.testcase \
+	getfacebypoint16.testcase \
+	getfacebypoint17.testcase \
+	getfaceseed1.testcase \
+	getfaceseed2.testcase \
+	getfaceseed3.testcase \
+	getfaceseed4.testcase \
+	getfaceseed5.testcase \
+	getfaceseed6.testcase \
+	getfaceseed7.testcase \
+	getfaceseed8.testcase \
+	getfaceseed9.testcase \
+	getlinkbypoint1.testcase \
+	getlinkbypoint2.testcase \
+	getlinkbypoint3.testcase \
+	getlinkbypoint4.testcase \
+	getlinkbypoint5.testcase \
+	getlinkbypoint6.testcase \
+	getlinkbypoint7.testcase \
+	getlinkbypoint8.testcase \
+	getlinkbypoint9.testcase \
+	getlinkbypoint10.testcase \
+	getlinkbypoint11.testcase \
+	getlinkbypoint12.testcase \
+	getlinkbypoint13.testcase \
+	getlinkbypoint14.testcase \
+	getlinkbypoint15.testcase \
+	getlinkbypoint16.testcase \
+	getlinkbypoint17.testcase \
+	getnetnodebypoint1.testcase \
+	getnetnodebypoint2.testcase \
+	getnetnodebypoint3.testcase \
+	getnetnodebypoint4.testcase \
+	getnetnodebypoint5.testcase \
+	getnetnodebypoint6.testcase \
+	getnetnodebypoint7.testcase \
+	getnetnodebypoint8.testcase \
+	getnetnodebypoint9.testcase \
+	getnetnodebypoint10.testcase \
+	getnetnodebypoint11.testcase \
+	getnetnodebypoint12.testcase \
+	getnetnodebypoint13.testcase \
+	getnetnodebypoint14.testcase \
+	getnetnodebypoint15.testcase \
+	getnetnodebypoint16.testcase \
+	getnetnodebypoint17.testcase \
+	getnodebypoint1.testcase \
+	getnodebypoint2.testcase \
+	getnodebypoint3.testcase \
+	getnodebypoint4.testcase \
+	getnodebypoint5.testcase \
+	getnodebypoint6.testcase \
+	getnodebypoint7.testcase \
+	getnodebypoint8.testcase \
+	getnodebypoint9.testcase \
+	getnodebypoint10.testcase \
+	getnodebypoint11.testcase \
+	getnodebypoint12.testcase \
+	getnodebypoint13.testcase \
+	getnodebypoint14.testcase \
+	getnodebypoint15.testcase \
+	getnodebypoint16.testcase \
+	getnodebypoint17.testcase \
+	inittopolayer1.testcase \
+	inittopolayer2.testcase \
+	inittopolayer3.testcase \
+	inittopolayer4.testcase \
+	inittopolayer5.testcase \
+	inittopolayer6.testcase \
+	inittopolayer7.testcase \
+	inittopolayer8.testcase \
+	inittopolayer9.testcase \
+	inittopolayer10.testcase \
+	inittopolayer11.testcase \
+	inittopolayer12.testcase \
+	inittopolayer13.testcase \
+	inittopolayer14.testcase \
+	inittopolayer15.testcase \
+	inittopolayer16.testcase \
+	inittopolayer17.testcase \
+	loginetfromtgeo1.testcase \
+	loginetfromtgeo2.testcase \
+	loginetfromtgeo3.testcase \
+	loginetfromtgeo4.testcase \
+	loginetfromtgeo5.testcase \
+	loginetfromtgeo6.testcase \
+	loginetfromtgeo7.testcase \
+	loginetfromtgeo8.testcase \
+	loginetfromtgeo9.testcase \
+	modedgeheal1.testcase \
+	modedgeheal2.testcase \
+	modedgeheal3.testcase \
+	modedgeheal4.testcase \
+	modedgeheal5.testcase \
+	modedgeheal6.testcase \
+	modedgeheal7.testcase \
+	modedgeheal8.testcase \
+	modedgeheal9.testcase \
+	modedgeheal10.testcase \
+	modedgeheal11.testcase \
+	modedgeheal12.testcase \
+	modedgeheal13.testcase \
+	modedgesplit1.testcase \
+	modedgesplit2.testcase \
+	modedgesplit3.testcase \
+	modedgesplit4.testcase \
+	modedgesplit5.testcase \
+	modedgesplit6.testcase \
+	modedgesplit7.testcase \
+	modedgesplit8.testcase \
+	modedgesplit9.testcase \
+	modedgesplit10.testcase \
+	modedgesplit11.testcase \
+	modedgesplit12.testcase \
+	modedgesplit13.testcase \
+	modedgesplit14.testcase \
+	modedgesplit15.testcase \
+	modedgesplit16.testcase \
+	modgeolinksplit1.testcase \
+	modgeolinksplit2.testcase \
+	modgeolinksplit3.testcase \
+	modgeolinksplit4.testcase \
+	modgeolinksplit5.testcase \
+	modgeolinksplit6.testcase \
+	modgeolinksplit7.testcase \
+	modgeolinksplit8.testcase \
+	modgeolinksplit9.testcase \
+	modlinkheal1.testcase \
+	modlinkheal2.testcase \
+	modlinkheal3.testcase \
+	modlinkheal4.testcase \
+	modlinkheal5.testcase \
+	modlinkheal6.testcase \
+	modlinkheal7.testcase \
+	modlinkheal8.testcase \
+	modlinkheal9.testcase \
+	modlinkheal10.testcase \
+	modlinkheal11.testcase \
+	modlinkheal12.testcase \
+	modlinkheal13.testcase \
+	modloglinksplit1.testcase \
+	modloglinksplit2.testcase \
+	modloglinksplit3.testcase \
+	modloglinksplit4.testcase \
+	modloglinksplit5.testcase \
+	modloglinksplit6.testcase \
+	modloglinksplit7.testcase \
+	modloglinksplit8.testcase \
+	modloglinksplit9.testcase \
+	moveisonetnode1.testcase \
+	moveisonetnode2.testcase \
+	moveisonetnode3.testcase \
+	moveisonetnode4.testcase \
+	moveisonetnode5.testcase \
+	moveisonetnode6.testcase \
+	moveisonetnode7.testcase \
+	moveisonetnode8.testcase \
+	moveisonetnode9.testcase \
+	moveisonode1.testcase \
+	moveisonode2.testcase \
+	moveisonode3.testcase \
+	moveisonode4.testcase \
+	moveisonode5.testcase \
+	moveisonode6.testcase \
+	moveisonode7.testcase \
+	moveisonode8.testcase \
+	moveisonode9.testcase \
+	moveisonode10.testcase \
+	moveisonode11.testcase \
+	moveisonode12.testcase \
+	moveisonode13.testcase \
+	moveisonode14.testcase \
+	moveisonode15.testcase \
+	moveisonode16.testcase \
+	moveisonode17.testcase \
+	netexception1.testcase \
+	netexception2.testcase \
+	newedgeheal1.testcase \
+	newedgeheal2.testcase \
+	newedgeheal3.testcase \
+	newedgeheal4.testcase \
+	newedgeheal5.testcase \
+	newedgeheal6.testcase \
+	newedgeheal7.testcase \
+	newedgeheal8.testcase \
+	newedgeheal9.testcase \
+	newedgeheal10.testcase \
+	newedgeheal11.testcase \
+	newedgeheal12.testcase \
+	newedgeheal13.testcase \
+	newedgessplit1.testcase \
+	newedgessplit2.testcase \
+	newedgessplit3.testcase \
+	newedgessplit4.testcase \
+	newedgessplit5.testcase \
+	newedgessplit6.testcase \
+	newedgessplit7.testcase \
+	newedgessplit8.testcase \
+	newedgessplit9.testcase \
+	newedgessplit10.testcase \
+	newedgessplit11.testcase \
+	newedgessplit12.testcase \
+	newedgessplit13.testcase \
+	newedgessplit14.testcase \
+	newedgessplit15.testcase \
+	newedgessplit16.testcase \
+	newgeolinksplit1.testcase \
+	newgeolinksplit2.testcase \
+	newgeolinksplit3.testcase \
+	newgeolinksplit4.testcase \
+	newgeolinksplit5.testcase \
+	newgeolinksplit6.testcase \
+	newgeolinksplit7.testcase \
+	newgeolinksplit8.testcase \
+	newgeolinksplit9.testcase \
+	newlinkheal1.testcase \
+	newlinkheal2.testcase \
+	newlinkheal3.testcase \
+	newlinkheal4.testcase \
+	newlinkheal5.testcase \
+	newlinkheal6.testcase \
+	newlinkheal7.testcase \
+	newlinkheal8.testcase \
+	newlinkheal9.testcase \
+	newlinkheal10.testcase \
+	newlinkheal11.testcase \
+	newlinkheal12.testcase \
+	newlinkheal13.testcase \
+	newloglinksplit1.testcase \
+	newloglinksplit2.testcase \
+	newloglinksplit3.testcase \
+	newloglinksplit4.testcase \
+	newloglinksplit5.testcase \
+	newloglinksplit6.testcase \
+	newloglinksplit7.testcase \
+	newloglinksplit8.testcase \
+	newloglinksplit9.testcase \
+	remedgemodface1.testcase \
+	remedgemodface2.testcase \
+	remedgemodface3.testcase \
+	remedgemodface4.testcase \
+	remedgemodface5.testcase \
+	remedgemodface6.testcase \
+	remedgemodface7.testcase \
+	remedgemodface8.testcase \
+	remedgemodface9.testcase \
+	remedgenewface1.testcase \
+	remedgenewface2.testcase \
+	remedgenewface3.testcase \
+	remedgenewface4.testcase \
+	remedgenewface5.testcase \
+	remedgenewface6.testcase \
+	remedgenewface7.testcase \
+	remedgenewface8.testcase \
+	remedgenewface9.testcase \
+	remisoedge1.testcase \
+	remisoedge2.testcase \
+	remisoedge3.testcase \
+	remisoedge4.testcase \
+	remisoedge5.testcase \
+	remisoedge6.testcase \
+	remisoedge7.testcase \
+	remisoedge8.testcase \
+	remisoedge9.testcase \
+	remisonode1.testcase \
+	remisonode2.testcase \
+	remisonode3.testcase \
+	remisonode4.testcase \
+	remisonode5.testcase \
+	remisonode6.testcase \
+	remisonode7.testcase \
+	remisonode8.testcase \
+	remisonode9.testcase \
+	remisonetnode1.testcase \
+	remisonetnode2.testcase \
+	remisonetnode3.testcase \
+	remisonetnode4.testcase \
+	remisonetnode5.testcase \
+	remisonetnode6.testcase \
+	remisonetnode7.testcase \
+	remisonetnode8.testcase \
+	remisonetnode9.testcase \
+	remlink1.testcase \
+	remlink2.testcase \
+	remlink3.testcase \
+	remlink4.testcase \
+	remlink5.testcase \
+	remlink6.testcase \
+	remlink7.testcase \
+	remlink8.testcase \
+	remlink9.testcase \
+	removetopolayer1.testcase \
+	removetopolayer2.testcase \
+	removetopolayer3.testcase \
+	removetopolayer4.testcase \
+	removetopolayer5.testcase \
+	removetopolayer6.testcase \
+	removetopolayer7.testcase \
+	removetopolayer8.testcase \
+	removetopolayer9.testcase \
+	spatnetfromtgeo1.testcase \
+	spatnetfromtgeo2.testcase \
+	spatnetfromtgeo3.testcase \
+	spatnetfromtgeo4.testcase \
+	spatnetfromtgeo5.testcase \
+	spatnetfromtgeo6.testcase \
+	spatnetfromtgeo7.testcase \
+	spatnetfromtgeo8.testcase \
+	spatnetfromtgeo9.testcase \
+	spatnetfromgeom1.testcase \
+	spatnetfromgeom2.testcase \
+	spatnetfromgeom3.testcase \
+	spatnetfromgeom4.testcase \
+	spatnetfromgeom5.testcase \
+	spatnetfromgeom6.testcase \
+	spatnetfromgeom7.testcase \
+	spatnetfromgeom8.testcase \
+	spatnetfromgeom9.testcase \
+	spatnetfromgeom10.testcase \
+	st_asx3d25.testcase \
+	st_asx3d26.testcase \
+	st_asx3d30.testcase \
+	st_split8.testcase \
+	topoexception1.testcase \
+	topoexception2.testcase \
+	topogeoaddpoint1.testcase \
+	topogeoaddpoint2.testcase \
+	topogeoaddpoint3.testcase \
+	topogeoaddpoint4.testcase \
+	topogeoaddpoint5.testcase \
+	topogeoaddpoint6.testcase \
+	topogeoaddpoint7.testcase \
+	topogeoaddpoint8.testcase \
+	topogeoaddpoint9.testcase \
+	topogeoaddpoint10.testcase \
+	topogeoaddpoint11.testcase \
+	topogeoaddpoint12.testcase \
+	topogeoaddpoint13.testcase \
+	topogeoaddpoint14.testcase \
+	topogeoaddpoint15.testcase \
+	topogeoaddpoint16.testcase \
+	topogeoaddpoint17.testcase \
+	topogeoaddline1.testcase \
+	topogeoaddline2.testcase \
+	topogeoaddline3.testcase \
+	topogeoaddline4.testcase \
+	topogeoaddline5.testcase \
+	topogeoaddline6.testcase \
+	topogeoaddline7.testcase \
+	topogeoaddline8.testcase \
+	topogeoaddline9.testcase \
+	topogeoaddline10.testcase \
+	topogeoaddline11.testcase \
+	topogeoaddline12.testcase \
+	topogeoaddline13.testcase \
+	topogeoaddline14.testcase \
+	topogeoaddline15.testcase \
+	topogeoaddline16.testcase \
+	topogeoaddline17.testcase \
+	topogeoclone1.testcase \
+	topogeoclone2.testcase \
+	topogeoclone3.testcase \
+	topogeoclone4.testcase \
+	topogeoclone5.testcase \
+	topogeoclone6.testcase \
+	topogeoclone7.testcase \
+	topogeoclone8.testcase \
+	topogeoclone9.testcase \
+	topogeoclone10.testcase \
+	topogeoclone11.testcase \
+	topogeoclone12.testcase \
+	topogeofromtable1.testcase \
+	topogeofromtable2.testcase \
+	topogeofromtable3.testcase \
+	topogeofromtable4.testcase \
+	topogeofromtable5.testcase \
+	topogeofromtable6.testcase \
+	topogeofromtable7.testcase \
+	topogeofromtable8.testcase \
+	topogeofromtable9.testcase \
+	topogeofromtable10.testcase \
+	topogeofromtable11.testcase \
+	topogeofromtable12.testcase \
+	topogeofromtable13.testcase \
+	topogeofromtable14.testcase \
+	topogeofromtable15.testcase \
+	topogeofromtable16.testcase \
+	topogeofromtable17.testcase \
+	topogeofromtable18.testcase \
+	topogeofromtable19.testcase \
+	topogeofromtable20.testcase \
+	topogeofromtable21.testcase \
+	topogeofromtable22.testcase \
+	topogeofromtable23.testcase \
+	topogeofromtable24.testcase \
+	topogeofromtable25.testcase \
+	topogeofromtable26.testcase \
+	topogeofromtable27.testcase \
+	topogeofromtable28.testcase \
+	topogeofromtable29.testcase \
+	topogeofromtable30.testcase \
+	topogeosplitline1.testcase \
+	topogeosplitline2.testcase \
+	topogeosplitline3.testcase \
+	topogeosplitline4.testcase \
+	topogeosplitline5.testcase \
+	topogeosplitline6.testcase \
+	topogeosplitline7.testcase \
+	topogeosplitline8.testcase \
+	topogeosplitline9.testcase \
+	topogeosplitline10.testcase \
+	topogeosplitline11.testcase \
+	topogeosplitline12.testcase \
+	topogeosplitline13.testcase \
+	topogeosplitline14.testcase \
+	topogeosplitline15.testcase \
+	topogeosplitline16.testcase \
+	topogeototable1.testcase \
+	topogeototable2.testcase \
+	topogeototable3.testcase \
+	topogeototable4.testcase \
+	topogeototable5.testcase \
+	topogeototable6.testcase \
+	topogeototable7.testcase \
+	topogeototable8.testcase \
+	topogeototable9.testcase \
+	topogeototable10.testcase \
+	topogeototable11.testcase \
+	topogeototable12.testcase \
+	topogeototable13.testcase \
+	topogeototable14.testcase \
+	topogeototable15.testcase \
+	topogeototable16.testcase \
+	topogeototable17.testcase \
+	topogeototable18.testcase \
+	topogeototable19.testcase \
+	topogeototable20.testcase \
+	topogeototable21.testcase \
+	topogeototable22.testcase \
+	topogeototable23.testcase \
+	topogeototable24.testcase \
+	topogeototable25.testcase \
+	topogeototable26.testcase \
+	topogeototablegen1.testcase \
+	topogeototablegen2.testcase \
+	topogeototablegen3.testcase \
+	topogeototablegen4.testcase \
+	topogeototablegen5.testcase \
+	topogeototablegen6.testcase \
+	topogeototablegen7.testcase \
+	topogeototablegen8.testcase \
+	topogeototablegen9.testcase \
+	topogeototablegen10.testcase \
+	topogeototablegen11.testcase \
+	topogeototablegen12.testcase \
+	topogeototablegen13.testcase \
+	topogeototablegen14.testcase \
+	topogeototablegen15.testcase \
+	topogeototablegen16.testcase \
+	topogeototablegen17.testcase \
+	topogeototablegen18.testcase \
+	topogeototablegen19.testcase \
+	topogeototablegen20.testcase \
+	topogeototablegen21.testcase \
+	topogeototablegen22.testcase \
+	topogeototablegen23.testcase \
+	topogeototablegen24.testcase \
+	topogeototablegen25.testcase \
+	topogeototablegen26.testcase \
+	topogeototablegen27.testcase \
+	topogeototablegen28.testcase \
+	topogeototablegen29.testcase \
+	topogeototablegen30.testcase \
+	topogeototablegen31.testcase \
+	topogeoupdateseeds1.testcase \
+	topogeoupdateseeds2.testcase \
+	topogeoupdateseeds3.testcase \
+	topogeoupdateseeds4.testcase \
+	topogeoupdateseeds5.testcase \
+	topogeoupdateseeds6.testcase \
+	topogeoupdateseeds7.testcase \
+	topogeoupdateseeds8.testcase \
+	topogeoupdateseeds9.testcase \
+	topogeoupdateseeds10.testcase \
+	toponetclone1.testcase \
+	toponetclone2.testcase \
+	toponetclone3.testcase \
+	toponetclone4.testcase \
+	toponetclone5.testcase \
+	toponetclone6.testcase \
+	toponetclone7.testcase \
+	toponetclone8.testcase \
+	toponetclone9.testcase \
+	toponetclone10.testcase \
+	toponetclone11.testcase \
+	toponetclone12.testcase \
+	toponetfromtable1.testcase \
+	toponetfromtable2.testcase \
+	toponetfromtable3.testcase \
+	toponetfromtable4.testcase \
+	toponetfromtable5.testcase \
+	toponetfromtable6.testcase \
+	toponetfromtable7.testcase \
+	toponetfromtable8.testcase \
+	toponetfromtable9.testcase \
+	toponetfromtable10.testcase \
+	toponetfromtable11.testcase \
+	toponetfromtable12.testcase \
+	toponetfromtable13.testcase \
+	toponetfromtable14.testcase \
+	toponetfromtable15.testcase \
+	toponetfromtable16.testcase \
+	toponetfromtable17.testcase \
+	toponettotable1.testcase \
+	toponettotable2.testcase \
+	toponettotable3.testcase \
+	toponettotable4.testcase \
+	toponettotable5.testcase \
+	toponettotable6.testcase \
+	toponettotable7.testcase \
+	toponettotable8.testcase \
+	toponettotable9.testcase \
+	toponettotable10.testcase \
+	toponettotable11.testcase \
+	toponettotable12.testcase \
+	toponettotable13.testcase \
+	toponettotable14.testcase \
+	toponettotable15.testcase \
+	toponettotable16.testcase \
+	toponettotable17.testcase \
+	toponettotable18.testcase \
+	toponettotable19.testcase \
+	toponettotable20.testcase \
+	toponettotable21.testcase \
+	toponettotable22.testcase \
+	toponettotable23.testcase \
+	toponettotable24.testcase \
+	toponettotable25.testcase \
+	toponettotable26.testcase \
+	toponettotablegen1.testcase \
+	toponettotablegen2.testcase \
+	toponettotablegen3.testcase \
+	toponettotablegen4.testcase \
+	toponettotablegen5.testcase \
+	toponettotablegen6.testcase \
+	toponettotablegen7.testcase \
+	toponettotablegen8.testcase \
+	toponettotablegen9.testcase \
+	toponettotablegen10.testcase \
+	toponettotablegen11.testcase \
+	toponettotablegen12.testcase \
+	toponettotablegen13.testcase \
+	toponettotablegen14.testcase \
+	toponettotablegen15.testcase \
+	toponettotablegen16.testcase \
+	toponettotablegen17.testcase \
+	toponettotablegen18.testcase \
+	toponettotablegen19.testcase \
+	toponettotablegen20.testcase \
+	toponettotablegen21.testcase \
+	toponettotablegen22.testcase \
+	toponettotablegen23.testcase \
+	toponettotablegen24.testcase \
+	toponettotablegen25.testcase \
+	toponettotablegen26.testcase \
+	toponettotablegen27.testcase \
+	toponettotablegen28.testcase \
+	toponettotablegen29.testcase \
+	toponettotablegen30.testcase \
+	toponettotablegen31.testcase \
+	validatetopogeo1.testcase \
+	validatetopogeo2.testcase \
+	validatetopogeo3.testcase \
+	validatetopogeo4.testcase \
+	validatetopogeo5.testcase \
+	validlogicalnet1.testcase \
+	validlogicalnet2.testcase \
+	validlogicalnet3.testcase \
+	validlogicalnet4.testcase \
+	validlogicalnet5.testcase \
+	validspatialnet1.testcase \
+	validspatialnet2.testcase \
+	validspatialnet3.testcase \
+	validspatialnet4.testcase \
+	validspatialnet5.testcase
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/sql_stmt_lwgeom_22_tests/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign test/sql_stmt_lwgeom_22_tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface1.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface1.testcase
new file mode 100644
index 0000000..06136f5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface1.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - NULL Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface10.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface10.testcase
new file mode 100644
index 0000000..92dd107
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface10.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - NULL Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface11.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface11.testcase
new file mode 100644
index 0000000..05591cb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface11.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Double Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface12.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface12.testcase
new file mode 100644
index 0000000..ac329d3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface12.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Text Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface13.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface13.testcase
new file mode 100644
index 0000000..118c315
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface13.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - BLOB Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface14.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface14.testcase
new file mode 100644
index 0000000..b06c95e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface14.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Int Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface15.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface15.testcase
new file mode 100644
index 0000000..9fc3c6d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface15.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Double Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, 1.3);
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface16.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface16.testcase
new file mode 100644
index 0000000..3abb727
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface16.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface17.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface17.testcase
new file mode 100644
index 0000000..525c62a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface17.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface18.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface18.testcase
new file mode 100644
index 0000000..2ec150e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface18.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Point Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface19.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface19.testcase
new file mode 100644
index 0000000..4639cee
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface19.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface2.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface2.testcase
new file mode 100644
index 0000000..642af10
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface2.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Int Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface20.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface20.testcase
new file mode 100644
index 0000000..e748670
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface20.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - MultiLinestring Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface3.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface3.testcase
new file mode 100644
index 0000000..2b8bf2b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface3.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Double Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface4.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface4.testcase
new file mode 100644
index 0000000..dd97a00
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface4.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface5.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface5.testcase
new file mode 100644
index 0000000..d755050
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface5.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Text Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface6.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface6.testcase
new file mode 100644
index 0000000..9033151
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface6.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - NULL Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface7.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface7.testcase
new file mode 100644
index 0000000..1c3e429
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface7.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Double Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface8.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface8.testcase
new file mode 100644
index 0000000..168d726
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface8.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - Text Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgemodface9.testcase b/test/sql_stmt_lwgeom_22_tests/addedgemodface9.testcase
new file mode 100644
index 0000000..3904c4d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgemodface9.testcase
@@ -0,0 +1,7 @@
+AddEdgeModFace - BLOB Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeModFace('topology', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeModFace('topology', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces1.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces1.testcase
new file mode 100644
index 0000000..fafd3dd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces1.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - NULL Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces10.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces10.testcase
new file mode 100644
index 0000000..544bcc2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces10.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - NULL Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces11.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces11.testcase
new file mode 100644
index 0000000..e2da37b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces11.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Double Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces12.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces12.testcase
new file mode 100644
index 0000000..c0f80d1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces12.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Text Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces13.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces13.testcase
new file mode 100644
index 0000000..326db12
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces13.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - BLOB Node To
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces14.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces14.testcase
new file mode 100644
index 0000000..99cc3aa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces14.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Int Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces15.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces15.testcase
new file mode 100644
index 0000000..ff6f467
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces15.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Double Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, 1.3);
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces16.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces16.testcase
new file mode 100644
index 0000000..8d433f4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces16.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces17.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces17.testcase
new file mode 100644
index 0000000..2d858d4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces17.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces18.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces18.testcase
new file mode 100644
index 0000000..e2b1a1e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces18.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Point Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces19.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces19.testcase
new file mode 100644
index 0000000..309a4de
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces19.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces2.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces2.testcase
new file mode 100644
index 0000000..1ab590a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces2.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Int Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces20.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces20.testcase
new file mode 100644
index 0000000..5e28039
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces20.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - MultiLinestring Geometry
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces3.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces3.testcase
new file mode 100644
index 0000000..46dfb3d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces3.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Double Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces4.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces4.testcase
new file mode 100644
index 0000000..476feb4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces4.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces5.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces5.testcase
new file mode 100644
index 0000000..30f455a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces5.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Text Topology
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces6.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces6.testcase
new file mode 100644
index 0000000..2a0a18b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces6.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - NULL Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces7.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces7.testcase
new file mode 100644
index 0000000..983d13a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces7.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Double Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces8.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces8.testcase
new file mode 100644
index 0000000..a006a32
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces8.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - Text Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addedgenewfaces9.testcase b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces9.testcase
new file mode 100644
index 0000000..b7452a2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addedgenewfaces9.testcase
@@ -0,0 +1,7 @@
+AddEdgeNewFaces - BLOB Node From
+:memory: #use in-memory database
+SELECT ST_AddEdgeNewFaces('topology', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddEdgeNewFaces('topology', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge1.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge1.testcase
new file mode 100644
index 0000000..383f200
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge1.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - NULL Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge10.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge10.testcase
new file mode 100644
index 0000000..80a3249
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge10.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - NULL Node To
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge11.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge11.testcase
new file mode 100644
index 0000000..0b1bebd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge11.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Double Node To
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge12.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge12.testcase
new file mode 100644
index 0000000..2d80fe5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge12.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Text Node To
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge13.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge13.testcase
new file mode 100644
index 0000000..c5fc479
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge13.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - BLOB Node To
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge14.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge14.testcase
new file mode 100644
index 0000000..24665a6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge14.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Int Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge15.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge15.testcase
new file mode 100644
index 0000000..092df75
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge15.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Double Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, 1.3);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge16.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge16.testcase
new file mode 100644
index 0000000..4b18f7a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge16.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge17.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge17.testcase
new file mode 100644
index 0000000..ce31a49
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge17.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge18.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge18.testcase
new file mode 100644
index 0000000..aff61f7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge18.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Point Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge19.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge19.testcase
new file mode 100644
index 0000000..3b34c77
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge19.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge2.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge2.testcase
new file mode 100644
index 0000000..4228ca1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge2.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Int Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge20.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge20.testcase
new file mode 100644
index 0000000..cd09fc3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge20.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - MultiLinestring Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge3.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge3.testcase
new file mode 100644
index 0000000..264236c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge3.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Double Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge4.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge4.testcase
new file mode 100644
index 0000000..3dbc86c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge4.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge5.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge5.testcase
new file mode 100644
index 0000000..c5b42bc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge5.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Text Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge6.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge6.testcase
new file mode 100644
index 0000000..6f612e0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge6.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - NULL Node From
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge7.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge7.testcase
new file mode 100644
index 0000000..00744c9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge7.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Double Node From
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge8.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge8.testcase
new file mode 100644
index 0000000..5a91da8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge8.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - Text Node From
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisoedge9.testcase b/test/sql_stmt_lwgeom_22_tests/addisoedge9.testcase
new file mode 100644
index 0000000..b1fab8f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisoedge9.testcase
@@ -0,0 +1,7 @@
+AddIsoEdge - BLOB Node From
+:memory: #use in-memory database
+SELECT ST_AddIsoEdge('topology', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoEdge('topology', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonetnode1.testcase b/test/sql_stmt_lwgeom_22_tests/addisonetnode1.testcase
new file mode 100644
index 0000000..38cba50
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonetnode1.testcase
@@ -0,0 +1,7 @@
+AddIsoNetNode - NULL Network
+:memory: #use in-memory database
+SELECT ST_AddIsoNetNode(NULL, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNetNode(NULL, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonetnode2.testcase b/test/sql_stmt_lwgeom_22_tests/addisonetnode2.testcase
new file mode 100644
index 0000000..98e446a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonetnode2.testcase
@@ -0,0 +1,7 @@
+AddIsoNetNode - Int Network
+:memory: #use in-memory database
+SELECT ST_AddIsoNetNode(1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNetNode(1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonetnode3.testcase b/test/sql_stmt_lwgeom_22_tests/addisonetnode3.testcase
new file mode 100644
index 0000000..ca1bee5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonetnode3.testcase
@@ -0,0 +1,7 @@
+AddIsoNetNode - Double Network
+:memory: #use in-memory database
+SELECT ST_AddIsoNetNode(1.5, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNetNode(1.5, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonetnode4.testcase b/test/sql_stmt_lwgeom_22_tests/addisonetnode4.testcase
new file mode 100644
index 0000000..acaa22f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonetnode4.testcase
@@ -0,0 +1,7 @@
+AddIsoNetNode - BLOB Network
+:memory: #use in-memory database
+SELECT ST_AddIsoNetNode(zeroblob(9), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNetNode(zeroblob(9), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonetnode5.testcase b/test/sql_stmt_lwgeom_22_tests/addisonetnode5.testcase
new file mode 100644
index 0000000..d75d0b6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonetnode5.testcase
@@ -0,0 +1,7 @@
+AddIsoNetNode - NULL Point
+:memory: #use in-memory database
+SELECT ST_AddIsoNetNode('roads', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNetNode('roads', NULL)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode1.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode1.testcase
new file mode 100644
index 0000000..51c0ca6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode1.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - NULL Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoNode(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode10.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode10.testcase
new file mode 100644
index 0000000..932a689
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode10.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Double Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, 1.1);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode11.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode11.testcase
new file mode 100644
index 0000000..f7e8537
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode11.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode12.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode12.testcase
new file mode 100644
index 0000000..0d00a71
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode12.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Text Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', 'face', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', 'face', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode13.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode13.testcase
new file mode 100644
index 0000000..2a24fa3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode13.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', 'face', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', 'face', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode14.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode14.testcase
new file mode 100644
index 0000000..800c855
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode14.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Linestring Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode15.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode15.testcase
new file mode 100644
index 0000000..533b229
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode15.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode16.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode16.testcase
new file mode 100644
index 0000000..3225af1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode16.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode17.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode17.testcase
new file mode 100644
index 0000000..7e88102
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode17.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - NULL Face
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', NULL, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', NULL, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode2.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode2.testcase
new file mode 100644
index 0000000..9b0f802
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode2.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Int Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoNode(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode3.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode3.testcase
new file mode 100644
index 0000000..ed02d46
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode3.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Double Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoNode(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode4.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode4.testcase
new file mode 100644
index 0000000..4f87681
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode4.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Blob Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoNode(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode5.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode5.testcase
new file mode 100644
index 0000000..ea99873
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode5.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Text Topology
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode6.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode6.testcase
new file mode 100644
index 0000000..a3cb94d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode6.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Double Face
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode7.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode7.testcase
new file mode 100644
index 0000000..329037d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode7.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - BLOB Face
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode8.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode8.testcase
new file mode 100644
index 0000000..96046f6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode8.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Text Face
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', 'face', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', 'face', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addisonode9.testcase b/test/sql_stmt_lwgeom_22_tests/addisonode9.testcase
new file mode 100644
index 0000000..d686d3a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addisonode9.testcase
@@ -0,0 +1,7 @@
+AddIsoNode - Int Geometry
+:memory: #use in-memory database
+SELECT ST_AddIsoNode('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_AddIsoNode('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink1.testcase b/test/sql_stmt_lwgeom_22_tests/addlink1.testcase
new file mode 100644
index 0000000..facb486
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink1.testcase
@@ -0,0 +1,7 @@
+AddLink - NULL Network
+:memory: #use in-memory database
+SELECT ST_AddLink(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink(NULL, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink10.testcase b/test/sql_stmt_lwgeom_22_tests/addlink10.testcase
new file mode 100644
index 0000000..7287543
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink10.testcase
@@ -0,0 +1,7 @@
+AddLink - NULL Node To
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 1, NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink11.testcase b/test/sql_stmt_lwgeom_22_tests/addlink11.testcase
new file mode 100644
index 0000000..9b4e49f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink11.testcase
@@ -0,0 +1,7 @@
+AddLink - Double Node To
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 1, 2.4, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink12.testcase b/test/sql_stmt_lwgeom_22_tests/addlink12.testcase
new file mode 100644
index 0000000..296ac50
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink12.testcase
@@ -0,0 +1,7 @@
+AddLink - Text Node To
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 1, 'to', GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink13.testcase b/test/sql_stmt_lwgeom_22_tests/addlink13.testcase
new file mode 100644
index 0000000..4597bb2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink13.testcase
@@ -0,0 +1,7 @@
+AddLink - BLOB Node To
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 1, zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink2.testcase b/test/sql_stmt_lwgeom_22_tests/addlink2.testcase
new file mode 100644
index 0000000..b57f378
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink2.testcase
@@ -0,0 +1,7 @@
+AddLink - Int Network
+:memory: #use in-memory database
+SELECT ST_AddLink(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink(1, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink3.testcase b/test/sql_stmt_lwgeom_22_tests/addlink3.testcase
new file mode 100644
index 0000000..9ee2c4c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink3.testcase
@@ -0,0 +1,7 @@
+AddLink - Double Network
+:memory: #use in-memory database
+SELECT ST_AddLink(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink(1.2, 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink4.testcase b/test/sql_stmt_lwgeom_22_tests/addlink4.testcase
new file mode 100644
index 0000000..cf9003c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink4.testcase
@@ -0,0 +1,7 @@
+AddLink - BLOB Network
+:memory: #use in-memory database
+SELECT ST_AddLink(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink(zeroblob(4), 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink5.testcase b/test/sql_stmt_lwgeom_22_tests/addlink5.testcase
new file mode 100644
index 0000000..80f21b7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink5.testcase
@@ -0,0 +1,7 @@
+AddLink - Text Network
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 1, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink6.testcase b/test/sql_stmt_lwgeom_22_tests/addlink6.testcase
new file mode 100644
index 0000000..5c28f49
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink6.testcase
@@ -0,0 +1,7 @@
+AddLink - NULL Node From
+:memory: #use in-memory database
+SELECT ST_AddLink('net', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', NULL, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink7.testcase b/test/sql_stmt_lwgeom_22_tests/addlink7.testcase
new file mode 100644
index 0000000..936a5ad
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink7.testcase
@@ -0,0 +1,7 @@
+AddLink - Double Node From
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 1.3, 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink8.testcase b/test/sql_stmt_lwgeom_22_tests/addlink8.testcase
new file mode 100644
index 0000000..a7eed8d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink8.testcase
@@ -0,0 +1,7 @@
+AddLink - Text Node From
+:memory: #use in-memory database
+SELECT ST_AddLink('net', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', 'from', 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/addlink9.testcase b/test/sql_stmt_lwgeom_22_tests/addlink9.testcase
new file mode 100644
index 0000000..5065cb4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/addlink9.testcase
@@ -0,0 +1,7 @@
+AddLink - BLOB Node From
+:memory: #use in-memory database
+SELECT ST_AddLink('net', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_AddLink('net', zeroblob(4), 2, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom1.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom1.testcase
new file mode 100644
index 0000000..9a6f9dc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom1.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - NULL Topology
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom(NULL, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom(NULL, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom10.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom10.testcase
new file mode 100644
index 0000000..c892586
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom10.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Double Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, 1.1);
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom11.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom11.testcase
new file mode 100644
index 0000000..f11f581
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom11.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom12.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom12.testcase
new file mode 100644
index 0000000..008e8ae
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom12.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Text Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', 'edge', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', 'edge', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom13.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom13.testcase
new file mode 100644
index 0000000..ab9b9b1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom13.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', 'edge', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', 'edge', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom14.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom14.testcase
new file mode 100644
index 0000000..ccd4617
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom14.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Point Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom15.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom15.testcase
new file mode 100644
index 0000000..10bd960
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom15.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom16.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom16.testcase
new file mode 100644
index 0000000..b677cb9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom16.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - MultiLinestring Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, GeomFromText('MULTILINESTRING((0 0, 1 1), (4 4, 5 5))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom17.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom17.testcase
new file mode 100644
index 0000000..61d97cd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom17.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - NULL Edge
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom2.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom2.testcase
new file mode 100644
index 0000000..3c72c09
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom2.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Int Topology
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom(1, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom(1, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom3.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom3.testcase
new file mode 100644
index 0000000..1ee36e0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom3.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Double Topology
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom(1.5, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom(1.5, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom4.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom4.testcase
new file mode 100644
index 0000000..63b1281
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom4.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Blob Topology
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom(zeroblob(4), -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom(zeroblob(4), -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom5.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom5.testcase
new file mode 100644
index 0000000..f785044
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom5.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Text Topology
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom6.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom6.testcase
new file mode 100644
index 0000000..13fa149
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom6.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Double Edge
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', 2.0, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', 2.0, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom7.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom7.testcase
new file mode 100644
index 0000000..0e07bfc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom7.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - BLOB Edge
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom8.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom8.testcase
new file mode 100644
index 0000000..2b174d3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom8.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Text Edge
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', 'edge', GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', 'Edge', GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changeedgegeom9.testcase b/test/sql_stmt_lwgeom_22_tests/changeedgegeom9.testcase
new file mode 100644
index 0000000..bd61821
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changeedgegeom9.testcase
@@ -0,0 +1,7 @@
+ChangeEdgeGeom - Int Geometry
+:memory: #use in-memory database
+SELECT ST_ChangeEdgeGeom('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeEdgeGeom('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom1.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom1.testcase
new file mode 100644
index 0000000..0420868
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom1.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - NULL Network
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom(NULL, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom(NULL, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom2.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom2.testcase
new file mode 100644
index 0000000..baebe25
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom2.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - Int Network
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom(1, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom(1, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom3.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom3.testcase
new file mode 100644
index 0000000..b495f33
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom3.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - Double Network
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom(1.5, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom(1.5, -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom4.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom4.testcase
new file mode 100644
index 0000000..8cc5c41
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom4.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - Blob Network
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom(zeroblob(4), -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom(zeroblob(4), -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom5.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom5.testcase
new file mode 100644
index 0000000..754599c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom5.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - Text Network
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom6.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom6.testcase
new file mode 100644
index 0000000..de70006
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom6.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - Double Link
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom('topology', 2.0, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom('topology', 2.0, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom7.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom7.testcase
new file mode 100644
index 0000000..bd108f2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom7.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - BLOB Link
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom('topology', zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom('topology', zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/changelinkgeom8.testcase b/test/sql_stmt_lwgeom_22_tests/changelinkgeom8.testcase
new file mode 100644
index 0000000..f92e8b3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/changelinkgeom8.testcase
@@ -0,0 +1,7 @@
+ChangeLinkGeom - Text Link
+:memory: #use in-memory database
+SELECT ST_ChangeLinkGeom('topology', 'Link', GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ChangeLinkGeom('topology', 'Link', GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork1.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork1.testcase
new file mode 100644
index 0000000..d1d0cc9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork1.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - NULL Network
+:memory: #use in-memory database
+SELECT CreateNetwork(NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork(NULL)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork10.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork10.testcase
new file mode 100644
index 0000000..1a0c9c2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork10.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Int Spatial
+:memory: #use in-memory database
+SELECT CreateNetwork('roads2', 1);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads2', 1)
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork11.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork11.testcase
new file mode 100644
index 0000000..6c63a0e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork11.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - NULL Srid
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsB', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsB', 1, NULL);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork12.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork12.testcase
new file mode 100644
index 0000000..64292c2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork12.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Int Srid
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsC', 1, 4326);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsC', 1, 4326);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork13.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork13.testcase
new file mode 100644
index 0000000..b47780f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork13.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Double Srid
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsD', 1, 1.5);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsD', 1, 1.5);
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork14.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork14.testcase
new file mode 100644
index 0000000..7bf1f92
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork14.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Text Srid
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 1, 'alpha');
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 1, 'alpha');
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork15.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork15.testcase
new file mode 100644
index 0000000..2d8b57c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork15.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Blob Srid
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 1, zeroblob(4));
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork16.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork16.testcase
new file mode 100644
index 0000000..ddfbc4a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork16.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - NULL hasZ
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsZ', 1, 4326, NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsZ', 1, 4326, NULL);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork17.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork17.testcase
new file mode 100644
index 0000000..e81f47b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork17.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Int hasZ
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsX', 1, 4326, 1);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsX', 1, 4326, 1);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork18.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork18.testcase
new file mode 100644
index 0000000..6ced7e8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork18.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Double hasZ
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsD', 1, 4326, 1.5);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsD', 1, 4326, 1.5);
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork19.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork19.testcase
new file mode 100644
index 0000000..08c9f1b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork19.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Text hasZ
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 1, 4326, 'alpha');
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 1, 4326, 'alpha');
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork2.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork2.testcase
new file mode 100644
index 0000000..785a873
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork2.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Int Network
+:memory: #use in-memory database
+SELECT CreateNetwork(1);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork(1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork20.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork20.testcase
new file mode 100644
index 0000000..bea4295
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork20.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Blob hasZ
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 1, 4326, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 1, 4326, zeroblob(4));
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork21.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork21.testcase
new file mode 100644
index 0000000..9262d79
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork21.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - NULL allow-coincident
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsW', 1, 4326, 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsW', 1, 4326, 1, NULL);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork22.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork22.testcase
new file mode 100644
index 0000000..6db911a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork22.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Int allow-coincident
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsY', 1, 4326, 1, 1);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsY', 1, 4326, 1, 1);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork23.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork23.testcase
new file mode 100644
index 0000000..3c52dc2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork23.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Double allow-coincident
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsE', 1, 4326, 1, 1.5);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsE', 1, 4326, 1, 1.5);
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork24.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork24.testcase
new file mode 100644
index 0000000..224c5f9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork24.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Text allow-coincident
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 1, 4326, 1, 'alpha');
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 1, 4326, 1, 'alpha');
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork25.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork25.testcase
new file mode 100644
index 0000000..67ec3b1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork25.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Blob allow-coincident
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 1, 4326, 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 1, 4326, 1, zeroblob(4));
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork3.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork3.testcase
new file mode 100644
index 0000000..f414966
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork3.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Double Network
+:memory: #use in-memory database
+SELECT CreateNetwork(1.1);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork(1.1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork4.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork4.testcase
new file mode 100644
index 0000000..5c7f423
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork4.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - BLOB Network
+:memory: #use in-memory database
+SELECT CreateNetwork(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork(zeroblob(4))
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork5.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork5.testcase
new file mode 100644
index 0000000..7de4803
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork5.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Text Network
+:memory: #use in-memory database
+SELECT CreateNetwork('roads');
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads')
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork6.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork6.testcase
new file mode 100644
index 0000000..17b60d7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork6.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - NULL Spatial
+:memory: #use in-memory database
+SELECT CreateNetwork('roadsA', NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roadsA', NULL)
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork7.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork7.testcase
new file mode 100644
index 0000000..e6593f7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork7.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - BLOB Spatial
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', zeroblob(4))
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork8.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork8.testcase
new file mode 100644
index 0000000..811e2d0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork8.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - TEXT Spatial
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 'beta');
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 'beta')
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createnetwork9.testcase b/test/sql_stmt_lwgeom_22_tests/createnetwork9.testcase
new file mode 100644
index 0000000..2d35364
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createnetwork9.testcase
@@ -0,0 +1,7 @@
+CreateNetwork - Double Spatial
+:memory: #use in-memory database
+SELECT CreateNetwork('roads', 3.1);
+1 # rows (not including the header row)
+1 # columns
+CreateNetwork('roads', 3.1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo1.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo1.testcase
new file mode 100644
index 0000000..5d494ea
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo1.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - NULL Topology
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo(NULL, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo(NULL, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo10.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo10.testcase
new file mode 100644
index 0000000..41be5b8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo10.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - non existing Topology
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo('topology', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo('topology', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo2.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo2.testcase
new file mode 100644
index 0000000..a446b76
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo2.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - Int Topology
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo(1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo(1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo3.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo3.testcase
new file mode 100644
index 0000000..37a0d91
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo3.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - Double Topology
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo(1.5, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo(1.5, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo4.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo4.testcase
new file mode 100644
index 0000000..7d55abe
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo4.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo(zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo(zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo5.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo5.testcase
new file mode 100644
index 0000000..1c013c0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo5.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - NULL GeomCollection
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo6.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo6.testcase
new file mode 100644
index 0000000..7bd1c72
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo6.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - Int GeomCollection
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo('topology', 1);
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo('topology', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo7.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo7.testcase
new file mode 100644
index 0000000..9266e2e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo7.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - Double GeomCollection
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo('topology', 1.4);
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo('topology', 1.4)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo8.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo8.testcase
new file mode 100644
index 0000000..c4d7bdc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo8.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - Text GeomCollection
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo('topology', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo('topology', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopogeo9.testcase b/test/sql_stmt_lwgeom_22_tests/createtopogeo9.testcase
new file mode 100644
index 0000000..c38551a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopogeo9.testcase
@@ -0,0 +1,7 @@
+ST_CreateTopoGeo - Invalid BLOB GeomCollection
+:memory: #use in-memory database
+SELECT ST_CreateTopoGeo('topology', zeroblob(100));
+1 # rows (not including the header row)
+1 # columns
+ST_CreateTopoGeo('topology', zeroblob(100))
+SQL/MM Spatial exception - not a Geometry.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer1.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer1.testcase
new file mode 100644
index 0000000..be2127d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer(NULL, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer(NULL, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer10.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer10.testcase
new file mode 100644
index 0000000..40e965c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - NULL ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, NULL, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, NULL, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer11.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer11.testcase
new file mode 100644
index 0000000..966a218
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - INT ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 1, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 1, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer12.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer12.testcase
new file mode 100644
index 0000000..ede6cc7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Double ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 1.2, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 1.2, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer13.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer13.testcase
new file mode 100644
index 0000000..6c09289
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - BLOB ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, zeroblob(4), NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, zeroblob(4), NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer14.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer14.testcase
new file mode 100644
index 0000000..acc786a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Text Column
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'column', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'column', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer15.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer15.testcase
new file mode 100644
index 0000000..48e33fc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Int Column
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 1, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', 1, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer16.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer16.testcase
new file mode 100644
index 0000000..8fadd6f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Double Column
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 1.2, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', 1.2, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer17.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer17.testcase
new file mode 100644
index 0000000..f4c06e0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - BLOB Column
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer18.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer18.testcase
new file mode 100644
index 0000000..7f1c70c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer18.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - NULL TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer19.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer19.testcase
new file mode 100644
index 0000000..d6d6936
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer19.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Double TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer2.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer2.testcase
new file mode 100644
index 0000000..8b9515a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer(1, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer(1, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer20.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer20.testcase
new file mode 100644
index 0000000..1ecd25a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer20.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - BLOB TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer21.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer21.testcase
new file mode 100644
index 0000000..11e4064
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer21.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Text TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer22.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer22.testcase
new file mode 100644
index 0000000..3e23ac2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer22.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - BLOB is-view
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'geometry', 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer23.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer23.testcase
new file mode 100644
index 0000000..7c06bc5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer23.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - TEXT is-view
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'geometry', 'out', 'no');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out', 'no')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer24.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer24.testcase
new file mode 100644
index 0000000..a6c9417
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer24.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Double is-view
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'geometry', 'out', 1.5);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out', 1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer25.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer25.testcase
new file mode 100644
index 0000000..b3076b9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer25.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - NULL is-view
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'geometry', 'out', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer26.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer26.testcase
new file mode 100644
index 0000000..66f8bfc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer26.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Integer is-view
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', 'geometry', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', zeroblob(4), 'out', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer3.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer3.testcase
new file mode 100644
index 0000000..b8fd433
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer(1.5, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer(1.5, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer4.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer4.testcase
new file mode 100644
index 0000000..8a7d8d8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer(zeroblob(4), NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer(zeroblob(4), NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer5.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer5.testcase
new file mode 100644
index 0000000..b16a7ac
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer6.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer6.testcase
new file mode 100644
index 0000000..397ebd4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', 'a', 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', 'a', 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer7.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer7.testcase
new file mode 100644
index 0000000..fa778b3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - INT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', 1, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', 1, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer8.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer8.testcase
new file mode 100644
index 0000000..c0d5e65
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - Double prefix
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', 1.2, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', 1.2, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopolayer9.testcase b/test/sql_stmt_lwgeom_22_tests/createtopolayer9.testcase
new file mode 100644
index 0000000..84e5cf2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopolayer9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_CreateTopoLayer - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoGeo_CreateTopoLayer('topology', zeroblob(4), 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_CreateTopoLayer('topology', zeroblob(4), 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology1.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology1.testcase
new file mode 100644
index 0000000..8c9ffbd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology1.testcase
@@ -0,0 +1,7 @@
+CreateTopology - NULL Topology
+:memory: #use in-memory database
+SELECT CreateTopology(NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology(NULL)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology10.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology10.testcase
new file mode 100644
index 0000000..b49cb34
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology10.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Int Srid
+:memory: #use in-memory database
+SELECT CreateTopology('topo2', 4326);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo2', 4326)
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology11.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology11.testcase
new file mode 100644
index 0000000..bbd8e59
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology11.testcase
@@ -0,0 +1,7 @@
+CreateTopology - NULL tolerance
+:memory: #use in-memory database
+SELECT CreateTopology('topoB', 4326, NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoB', 4326, NULL);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology12.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology12.testcase
new file mode 100644
index 0000000..a18a690
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology12.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Int tolerance
+:memory: #use in-memory database
+SELECT CreateTopology('topoC', 4326, 1);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoC', 4326, 1);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology13.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology13.testcase
new file mode 100644
index 0000000..72819c9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology13.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Double tolerance
+:memory: #use in-memory database
+SELECT CreateTopology('topoD', 4326, 1.5);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoD', 4326, 1.5);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology14.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology14.testcase
new file mode 100644
index 0000000..07d78f6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology14.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Text tolerance
+:memory: #use in-memory database
+SELECT CreateTopology('topo', 4326, 'alpha');
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', 4326, 'alpha');
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology15.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology15.testcase
new file mode 100644
index 0000000..97b2430
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology15.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Blob tolerance
+:memory: #use in-memory database
+SELECT CreateTopology('topo', 4326, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', 4326, zeroblob(4));
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology16.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology16.testcase
new file mode 100644
index 0000000..941889f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology16.testcase
@@ -0,0 +1,7 @@
+CreateTopology - NULL hasZ
+:memory: #use in-memory database
+SELECT CreateTopology('topoZ', 4326, 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoZ', 4326, 1, NULL);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology17.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology17.testcase
new file mode 100644
index 0000000..e0d3002
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology17.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Int hasZ
+:memory: #use in-memory database
+SELECT CreateTopology('topoX', 4326, 1, 1);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoX', 4326, 1, 1);
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology18.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology18.testcase
new file mode 100644
index 0000000..a520799
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology18.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Double hasZ
+:memory: #use in-memory database
+SELECT CreateTopology('topoD', 4326, 1, 1.5);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoD', 4326, 1, 1.5);
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology19.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology19.testcase
new file mode 100644
index 0000000..4fc32bb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology19.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Text hasZ
+:memory: #use in-memory database
+SELECT CreateTopology('topo', 4326, 1, 'alpha');
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', 4326, 1, 'alpha');
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology2.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology2.testcase
new file mode 100644
index 0000000..f94663f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology2.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Int Topology
+:memory: #use in-memory database
+SELECT CreateTopology(1);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology(1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology20.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology20.testcase
new file mode 100644
index 0000000..cc799e0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology20.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Blob hasZ
+:memory: #use in-memory database
+SELECT CreateTopology('topo', 4326, 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', 4326, 1, zeroblob(4));
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology3.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology3.testcase
new file mode 100644
index 0000000..573737d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology3.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Double Topology
+:memory: #use in-memory database
+SELECT CreateTopology(1.1);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology(1.1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology4.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology4.testcase
new file mode 100644
index 0000000..8c26ccb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology4.testcase
@@ -0,0 +1,7 @@
+CreateTopology - BLOB Topology
+:memory: #use in-memory database
+SELECT CreateTopology(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateTopology(zeroblob(4))
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology5.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology5.testcase
new file mode 100644
index 0000000..eb29185
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology5.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Text Topology
+:memory: #use in-memory database
+SELECT CreateTopology('topo1');
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo1')
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology6.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology6.testcase
new file mode 100644
index 0000000..4414e05
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology6.testcase
@@ -0,0 +1,7 @@
+CreateTopology - NULL Srid
+:memory: #use in-memory database
+SELECT CreateTopology('topoA', NULL);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topoA', NULL)
+1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology7.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology7.testcase
new file mode 100644
index 0000000..07ea13b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology7.testcase
@@ -0,0 +1,7 @@
+CreateTopology - BLOB Srid
+:memory: #use in-memory database
+SELECT CreateTopology('topo', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', zeroblob(4))
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology8.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology8.testcase
new file mode 100644
index 0000000..f3ab7e9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology8.testcase
@@ -0,0 +1,7 @@
+CreateTopology - TEXT Srid
+:memory: #use in-memory database
+SELECT CreateTopology('topo', 'alpha');
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', 'alpha')
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/createtopology9.testcase b/test/sql_stmt_lwgeom_22_tests/createtopology9.testcase
new file mode 100644
index 0000000..b614557
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/createtopology9.testcase
@@ -0,0 +1,7 @@
+CreateTopology - Double Srid
+:memory: #use in-memory database
+SELECT CreateTopology('topo', 4326.1);
+1 # rows (not including the header row)
+1 # columns
+CreateTopology('topo', 4326.1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/dropnetwork1.testcase b/test/sql_stmt_lwgeom_22_tests/dropnetwork1.testcase
new file mode 100644
index 0000000..a7bfe72
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/dropnetwork1.testcase
@@ -0,0 +1,7 @@
+DropNetwork - NULL Network
+:memory: #use in-memory database
+SELECT DropNetwork(NULL);
+1 # rows (not including the header row)
+1 # columns
+DropNetwork(NULL)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/dropnetwork2.testcase b/test/sql_stmt_lwgeom_22_tests/dropnetwork2.testcase
new file mode 100644
index 0000000..a0e4f3e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/dropnetwork2.testcase
@@ -0,0 +1,7 @@
+DropNetwork - Int Network
+:memory: #use in-memory database
+SELECT DropNetwork(1);
+1 # rows (not including the header row)
+1 # columns
+DropNetwork(1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/dropnetwork3.testcase b/test/sql_stmt_lwgeom_22_tests/dropnetwork3.testcase
new file mode 100644
index 0000000..6434d9c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/dropnetwork3.testcase
@@ -0,0 +1,7 @@
+DropNetwork - Double Network
+:memory: #use in-memory database
+SELECT DropNetwork(1.1);
+1 # rows (not including the header row)
+1 # columns
+DropNetwork(1.1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/dropnetwork4.testcase b/test/sql_stmt_lwgeom_22_tests/dropnetwork4.testcase
new file mode 100644
index 0000000..3ea2de0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/dropnetwork4.testcase
@@ -0,0 +1,7 @@
+DropNetwork - BLOB Network
+:memory: #use in-memory database
+SELECT DropNetwork(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+DropNetwork(zeroblob(4))
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/dropnetwork5.testcase b/test/sql_stmt_lwgeom_22_tests/dropnetwork5.testcase
new file mode 100644
index 0000000..c4a12e4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/dropnetwork5.testcase
@@ -0,0 +1,7 @@
+DropNetwork - Text Network
+:memory: #use in-memory database
+SELECT DropNetwork('topoW');
+1 # rows (not including the header row)
+1 # columns
+DropNetwork('topoW')
+0
diff --git a/test/sql_stmt_lwgeom_22_tests/droptopology1.testcase b/test/sql_stmt_lwgeom_22_tests/droptopology1.testcase
new file mode 100644
index 0000000..3fe0c8b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/droptopology1.testcase
@@ -0,0 +1,7 @@
+DropTopology - NULL Topology
+:memory: #use in-memory database
+SELECT DropTopology(NULL);
+1 # rows (not including the header row)
+1 # columns
+DropTopology(NULL)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/droptopology2.testcase b/test/sql_stmt_lwgeom_22_tests/droptopology2.testcase
new file mode 100644
index 0000000..2b02c9a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/droptopology2.testcase
@@ -0,0 +1,7 @@
+DropTopology - Int Topology
+:memory: #use in-memory database
+SELECT DropTopology(1);
+1 # rows (not including the header row)
+1 # columns
+DropTopology(1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/droptopology3.testcase b/test/sql_stmt_lwgeom_22_tests/droptopology3.testcase
new file mode 100644
index 0000000..808df47
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/droptopology3.testcase
@@ -0,0 +1,7 @@
+DropTopology - Double Topology
+:memory: #use in-memory database
+SELECT DropTopology(1.1);
+1 # rows (not including the header row)
+1 # columns
+DropTopology(1.1)
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/droptopology4.testcase b/test/sql_stmt_lwgeom_22_tests/droptopology4.testcase
new file mode 100644
index 0000000..bee35df
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/droptopology4.testcase
@@ -0,0 +1,7 @@
+DropTopology - BLOB Topology
+:memory: #use in-memory database
+SELECT DropTopology(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+DropTopology(zeroblob(4))
+-1
diff --git a/test/sql_stmt_lwgeom_22_tests/droptopology5.testcase b/test/sql_stmt_lwgeom_22_tests/droptopology5.testcase
new file mode 100644
index 0000000..2270e0c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/droptopology5.testcase
@@ -0,0 +1,7 @@
+DropTopology - Text Topology
+:memory: #use in-memory database
+SELECT DropTopology('topoW');
+1 # rows (not including the header row)
+1 # columns
+DropTopology('topoW')
+0
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer1.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer1.testcase
new file mode 100644
index 0000000..74ad9a4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer(NULL, 'topolayer', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(NULL, 'topolayer', 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer10.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer10.testcase
new file mode 100644
index 0000000..c034c39
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Integer output
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer11.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer11.testcase
new file mode 100644
index 0000000..e518de0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Double output
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer12.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer12.testcase
new file mode 100644
index 0000000..c34934b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - BLOB output
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer13.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer13.testcase
new file mode 100644
index 0000000..6718d07
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Text output
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer14.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer14.testcase
new file mode 100644
index 0000000..1b3c991
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - NULL create-only
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer15.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer15.testcase
new file mode 100644
index 0000000..6884d13
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Text create-only
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1, 'no');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1, 'no')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer16.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer16.testcase
new file mode 100644
index 0000000..fb642c4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - BLOB create-only
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer17.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer17.testcase
new file mode 100644
index 0000000..c413ed3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Double create-only
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1, 1.1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer18.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer18.testcase
new file mode 100644
index 0000000..e8e66ff
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer18.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Integer create-only
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1, 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer19.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer19.testcase
new file mode 100644
index 0000000..93b2319
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer19.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - NULL with-spatial-index
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer2.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer2.testcase
new file mode 100644
index 0000000..10d3da5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Integer Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer(1, 'topolayer', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(1, 'topolayer', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer20.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer20.testcase
new file mode 100644
index 0000000..bf7d655
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer20.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - BLOB with-spatial-index
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer21.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer21.testcase
new file mode 100644
index 0000000..331db80
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer21.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Text with-spatial-index
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 'no');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 'no')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer22.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer22.testcase
new file mode 100644
index 0000000..79478eb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer22.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Double with-spatial-index
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1.5);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer23.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer23.testcase
new file mode 100644
index 0000000..ae6bf9d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer23.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Integer with-spatial-index
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer3.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer3.testcase
new file mode 100644
index 0000000..9204970
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer(1.5, 'topolayer', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(1.5, 'topolayer', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer4.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer4.testcase
new file mode 100644
index 0000000..4182aa1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer(zeroblob(5), 'topolayer', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(zeroblob(5), 'topolayer', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer5.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer5.testcase
new file mode 100644
index 0000000..0303d59
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - NULL TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, NULL, 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer6.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer6.testcase
new file mode 100644
index 0000000..c56fcf1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Integer TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 1, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 1, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer7.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer7.testcase
new file mode 100644
index 0000000..128b9f5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Double TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 1.5, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 1.5, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer8.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer8.testcase
new file mode 100644
index 0000000..7d3400b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - BLOB TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', zeroblob(4), 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, zeroblob(4), 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/exporttopolayer9.testcase b/test/sql_stmt_lwgeom_22_tests/exporttopolayer9.testcase
new file mode 100644
index 0000000..61e3dfb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/exporttopolayer9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - NULL output
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer1.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer1.testcase
new file mode 100644
index 0000000..128a042
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer(NULL, 'topolayer', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(NULL, 'topolayer', 'out', 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer10.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer10.testcase
new file mode 100644
index 0000000..fcfb12f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Integer output
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', 1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', 1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer11.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer11.testcase
new file mode 100644
index 0000000..5bb7905
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Double output
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', 1.2, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', 1.2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer12.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer12.testcase
new file mode 100644
index 0000000..1f90bda
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - BLOB output
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', zeroblob(4), 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', zeroblob(4), 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer13.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer13.testcase
new file mode 100644
index 0000000..7fbea35
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Text output
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', 'out', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer14.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer14.testcase
new file mode 100644
index 0000000..5ce72b1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Double FID
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', 'out', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', 'out', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer15.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer15.testcase
new file mode 100644
index 0000000..79441f8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ExportTopoLayer - Text FID
+:memory: #use in-memory database
+SELECT TopoGeo_ExportTopoLayer('topology', 'topolayer', 'out', 'fid');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ExportTopoLayer(topology, 'topolayer', 'out', 'fid')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer16.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer16.testcase
new file mode 100644
index 0000000..a2cef7b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - BLOB FID
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer17.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer17.testcase
new file mode 100644
index 0000000..f987653
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - NULL output
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', NULL, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', NULL, 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer2.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer2.testcase
new file mode 100644
index 0000000..35e847f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Integer Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer(1, 'topolayer', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(1, 'topolayer', 'out', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer3.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer3.testcase
new file mode 100644
index 0000000..98afe3b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer(1.5, 'topolayer', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(1.5, 'topolayer', 'out', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer4.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer4.testcase
new file mode 100644
index 0000000..7e7b1ba
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer(zeroblob(5), 'topolayer', 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(zeroblob(5), 'topolayer', 'out', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer5.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer5.testcase
new file mode 100644
index 0000000..7bfd0fb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - NULL TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', NULL, 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, NULL, 'out', 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer6.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer6.testcase
new file mode 100644
index 0000000..4bc905a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Integer TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 1, 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 1, 'out', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer7.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer7.testcase
new file mode 100644
index 0000000..aa90a8d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - Double TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 1.5, 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 1.5, 'out', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer8.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer8.testcase
new file mode 100644
index 0000000..5b1ad0d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - BLOB TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', zeroblob(4), 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, zeroblob(4), 'out', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/featuretopolayer9.testcase b/test/sql_stmt_lwgeom_22_tests/featuretopolayer9.testcase
new file mode 100644
index 0000000..f987653
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/featuretopolayer9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InsertFeatureFromTopoLayer - NULL output
+:memory: #use in-memory database
+SELECT TopoGeo_InsertFeatureFromTopoLayer('topology', 'topolayer', NULL, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InsertFeatureFromTopoLayer(topology, 'topolayer', NULL, 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint1.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint1.testcase
new file mode 100644
index 0000000..793fd71
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint1.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - NULL Topology
+:memory: #use in-memory database
+SELECT GetEdgeByPoint(NULL, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint(NULL, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint10.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint10.testcase
new file mode 100644
index 0000000..971f661
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint10.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Double Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint11.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint11.testcase
new file mode 100644
index 0000000..4dc5a45
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint11.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - NULL Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint12.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint12.testcase
new file mode 100644
index 0000000..2691961
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint12.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Text Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint13.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint13.testcase
new file mode 100644
index 0000000..238b7b7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint13.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint14.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint14.testcase
new file mode 100644
index 0000000..7203aad
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint14.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Linestring Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint15.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint15.testcase
new file mode 100644
index 0000000..ce4a659
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint15.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Polygon Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint16.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint16.testcase
new file mode 100644
index 0000000..15436ea
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint16.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint17.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint17.testcase
new file mode 100644
index 0000000..3150d2d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint17.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - NULL Tolerance
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint2.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint2.testcase
new file mode 100644
index 0000000..8e2205f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint2.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Int Topology
+:memory: #use in-memory database
+SELECT GetEdgeByPoint(1, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint(1, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint3.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint3.testcase
new file mode 100644
index 0000000..29e8e09
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint3.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Double Topology
+:memory: #use in-memory database
+SELECT GetEdgeByPoint(1.5, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint(1.5, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint4.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint4.testcase
new file mode 100644
index 0000000..1e1e788
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint4.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Blob Topology
+:memory: #use in-memory database
+SELECT GetEdgeByPoint(zeroblob(4), MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint(zeroblob(4),MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint5.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint5.testcase
new file mode 100644
index 0000000..c0177f4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint5.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Text Topology
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint6.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint6.testcase
new file mode 100644
index 0000000..d5c266a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint6.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Double Tolerance
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', MakePoint(1, 2, 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', MakePoint(1, 2, 4326), 0.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint7.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint7.testcase
new file mode 100644
index 0000000..9873e20
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint7.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - BLOB Tolerance
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', MakePoint(1, 2, 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', MakePoint(1, 2, 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint8.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint8.testcase
new file mode 100644
index 0000000..5fa0cd9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint8.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Text Tolerance
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', MakePoint(1, 2, 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', MakePoint(1, 2, 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgebypoint9.testcase b/test/sql_stmt_lwgeom_22_tests/getedgebypoint9.testcase
new file mode 100644
index 0000000..a13a55d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgebypoint9.testcase
@@ -0,0 +1,7 @@
+GetEdgeByPoint - Int Geometry
+:memory: #use in-memory database
+SELECT GetEdgeByPoint('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+GetEdgeByPoint('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed1.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed1.testcase
new file mode 100644
index 0000000..f2156db
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed1.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed(NULL, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed(NULL, 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed2.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed2.testcase
new file mode 100644
index 0000000..2877bd4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed2.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed(1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed(1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed3.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed3.testcase
new file mode 100644
index 0000000..10bc2fa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed3.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed(1.2, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed(1.2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed4.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed4.testcase
new file mode 100644
index 0000000..7e09be7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed4.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - BLOB Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed(zeroblob(4), 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed(zeroblob(4), 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed5.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed5.testcase
new file mode 100644
index 0000000..1d40827
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed5.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed('topology', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed('topology', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_geos_tests/createtopo11.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed6.testcase
similarity index 52%
rename from test/sql_stmt_geos_tests/createtopo11.testcase
rename to test/sql_stmt_lwgeom_22_tests/getedgeseed6.testcase
index fffd330..0a114d6 100644
--- a/test/sql_stmt_geos_tests/createtopo11.testcase
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed6.testcase
@@ -1,7 +1,7 @@
-CreateTopology - 3 arguments, float dim (error)
+GetEdgeSeed - NULL Face
 :memory: #use in-memory database
-SELECT CreateTopologyTables("hello_world", 4326, 3.3);
+SELECT TopoGeo_GetEdgeSeed('topology', NULL);
 1 # rows (not including the header row)
 1 # columns
-CreateTopologyTables("hello_world", 4326, 3.3)
-0
\ No newline at end of file
+TopoGeo_GetEdgeSeed('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed7.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed7.testcase
new file mode 100644
index 0000000..befa7bc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed7.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - Double Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed('topology', 1.3);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed('topology', 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed8.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed8.testcase
new file mode 100644
index 0000000..dc0e923
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed8.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - Text Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed('topology', 'face');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed('topology', 'face')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getedgeseed9.testcase b/test/sql_stmt_lwgeom_22_tests/getedgeseed9.testcase
new file mode 100644
index 0000000..61beabf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getedgeseed9.testcase
@@ -0,0 +1,7 @@
+GetEdgeSeed - BLOB Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetEdgeSeed('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetEdgeSeed('topology', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint1.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint1.testcase
new file mode 100644
index 0000000..d18f4f2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint1.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - NULL Topology
+:memory: #use in-memory database
+SELECT GetFaceByPoint(NULL, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint(NULL, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint10.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint10.testcase
new file mode 100644
index 0000000..7dd7424
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint10.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Double Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint11.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint11.testcase
new file mode 100644
index 0000000..04e7ce8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint11.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - NULL Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint12.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint12.testcase
new file mode 100644
index 0000000..0364e22
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint12.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Text Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint13.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint13.testcase
new file mode 100644
index 0000000..6ffa3bc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint13.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint14.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint14.testcase
new file mode 100644
index 0000000..9238daf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint14.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Linestring Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint15.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint15.testcase
new file mode 100644
index 0000000..6fe9b87
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint15.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Polygon Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint16.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint16.testcase
new file mode 100644
index 0000000..643e913
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint16.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint17.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint17.testcase
new file mode 100644
index 0000000..9caacc6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint17.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - NULL Tolerance
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint2.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint2.testcase
new file mode 100644
index 0000000..f71797b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint2.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Int Topology
+:memory: #use in-memory database
+SELECT GetFaceByPoint(1, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint(1, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint3.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint3.testcase
new file mode 100644
index 0000000..c8393dd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint3.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Double Topology
+:memory: #use in-memory database
+SELECT GetFaceByPoint(1.5, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint(1.5, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint4.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint4.testcase
new file mode 100644
index 0000000..860e0d9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint4.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Blob Topology
+:memory: #use in-memory database
+SELECT GetFaceByPoint(zeroblob(4), MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint(zeroblob(4),MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint5.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint5.testcase
new file mode 100644
index 0000000..7dae2d9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint5.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Text Topology
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint6.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint6.testcase
new file mode 100644
index 0000000..cb67632
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint6.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Double Tolerance
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', MakePoint(1, 2, 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', MakePoint(1, 2, 4326), 0.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint7.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint7.testcase
new file mode 100644
index 0000000..cf1c691
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint7.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - BLOB Tolerance
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', MakePoint(1, 2, 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', MakePoint(1, 2, 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint8.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint8.testcase
new file mode 100644
index 0000000..39f9cc8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint8.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Text Tolerance
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', MakePoint(1, 2, 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', MakePoint(1, 2, 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacebypoint9.testcase b/test/sql_stmt_lwgeom_22_tests/getfacebypoint9.testcase
new file mode 100644
index 0000000..ecb695e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacebypoint9.testcase
@@ -0,0 +1,7 @@
+GetFaceByPoint - Int Geometry
+:memory: #use in-memory database
+SELECT GetFaceByPoint('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+GetFaceByPoint('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges1.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges1.testcase
new file mode 100644
index 0000000..1a89ad1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges1.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - NULL Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges2.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges2.testcase
new file mode 100644
index 0000000..fffaad7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges2.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - Int Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges3.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges3.testcase
new file mode 100644
index 0000000..779dc1f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges3.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - Double Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges4.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges4.testcase
new file mode 100644
index 0000000..2835a5b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges4.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - Blob Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges5.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges5.testcase
new file mode 100644
index 0000000..e719de5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges5.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - Text Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges('topology', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges('topology', -1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges6.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges6.testcase
new file mode 100644
index 0000000..0927c11
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges6.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - Double Face
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges('topology', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges('topology', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges7.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges7.testcase
new file mode 100644
index 0000000..02cb214
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges7.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - BLOB Face
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges8.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges8.testcase
new file mode 100644
index 0000000..56f8127
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges8.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - Text Face
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges('topology', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges('topology', 'node')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceedges9.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceedges9.testcase
new file mode 100644
index 0000000..06571fb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceedges9.testcase
@@ -0,0 +1,7 @@
+GetFaceEdges - NULL Face
+:memory: #use in-memory database
+SELECT ST_GetFaceEdges('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceEdges('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry1.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry1.testcase
new file mode 100644
index 0000000..2cca200
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry1.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - NULL Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry(NULL, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry(NULL, 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry2.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry2.testcase
new file mode 100644
index 0000000..b987572
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry2.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - Int Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry(1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry(1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry3.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry3.testcase
new file mode 100644
index 0000000..fd3e155
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry3.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - Double Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry(1.2, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry(1.2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry4.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry4.testcase
new file mode 100644
index 0000000..ee7251a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry4.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry(zeroblob(4), 1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry(zeroblob(4), 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry5.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry5.testcase
new file mode 100644
index 0000000..075190e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry5.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - Text Topology
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry('topology', 1);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry('topology', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry6.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry6.testcase
new file mode 100644
index 0000000..3885216
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry6.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - NULL Face
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry7.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry7.testcase
new file mode 100644
index 0000000..4cf161c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry7.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - Double Face
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry('topology', 1.3);
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry('topology', 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry8.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry8.testcase
new file mode 100644
index 0000000..4894004
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry8.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - Text Face
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry('topology', 'face');
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry('topology', 'face')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfacegeometry9.testcase b/test/sql_stmt_lwgeom_22_tests/getfacegeometry9.testcase
new file mode 100644
index 0000000..6d0a868
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfacegeometry9.testcase
@@ -0,0 +1,7 @@
+GetFaceGeometry - BLOB Face
+:memory: #use in-memory database
+SELECT ST_GetFaceGeometry('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_GetFaceGeometry('topology', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed1.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed1.testcase
new file mode 100644
index 0000000..bfd1ccf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed1.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed(NULL, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed(NULL, 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed2.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed2.testcase
new file mode 100644
index 0000000..04be969
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed2.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed(1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed(1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed3.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed3.testcase
new file mode 100644
index 0000000..fa51133
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed3.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed(1.2, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed(1.2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed4.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed4.testcase
new file mode 100644
index 0000000..5ca52b4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed4.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - BLOB Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed(zeroblob(4), 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed(zeroblob(4), 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed5.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed5.testcase
new file mode 100644
index 0000000..6f5b2d5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed5.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed('topology', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed('topology', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed6.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed6.testcase
new file mode 100644
index 0000000..bb7c3a0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed6.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - NULL Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed7.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed7.testcase
new file mode 100644
index 0000000..80989d5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed7.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - Double Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed('topology', 1.3);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed('topology', 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed8.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed8.testcase
new file mode 100644
index 0000000..cdd2ae9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_GetFaceSeed - Text Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed('topology', 'face');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed('topology', 'face')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getfaceseed9.testcase b/test/sql_stmt_lwgeom_22_tests/getfaceseed9.testcase
new file mode 100644
index 0000000..d7817d8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getfaceseed9.testcase
@@ -0,0 +1,7 @@
+GetFaceSeed - BLOB Face
+:memory: #use in-memory database
+SELECT TopoGeo_GetFaceSeed('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_GetFaceSeed('topology', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint1.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint1.testcase
new file mode 100644
index 0000000..5fbab44
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint1.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - NULL Network
+:memory: #use in-memory database
+SELECT GetLinkByPoint(NULL, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint(NULL, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint10.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint10.testcase
new file mode 100644
index 0000000..3918993
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint10.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Double Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint11.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint11.testcase
new file mode 100644
index 0000000..4bfd475
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint11.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - NULL Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint12.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint12.testcase
new file mode 100644
index 0000000..78c6713
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint12.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Text Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint13.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint13.testcase
new file mode 100644
index 0000000..b0f2c93
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint13.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint14.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint14.testcase
new file mode 100644
index 0000000..756e6b5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint14.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Linestring Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint15.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint15.testcase
new file mode 100644
index 0000000..1f985f5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint15.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Polygon Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint16.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint16.testcase
new file mode 100644
index 0000000..90b49ab
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint16.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint17.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint17.testcase
new file mode 100644
index 0000000..78b9346
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint17.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - NULL Tolerance
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint2.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint2.testcase
new file mode 100644
index 0000000..995c3d4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint2.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Int Network
+:memory: #use in-memory database
+SELECT GetLinkByPoint(1, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint(1, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint3.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint3.testcase
new file mode 100644
index 0000000..2696613
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint3.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Double Network
+:memory: #use in-memory database
+SELECT GetLinkByPoint(1.5, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint(1.5, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint4.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint4.testcase
new file mode 100644
index 0000000..d25ad90
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint4.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Blob Network
+:memory: #use in-memory database
+SELECT GetLinkByPoint(zeroblob(4), MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint(zeroblob(4),MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint5.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint5.testcase
new file mode 100644
index 0000000..c0388c7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint5.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Text Network
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint6.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint6.testcase
new file mode 100644
index 0000000..a7a0c4e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint6.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Double Tolerance
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', MakePoint(1, 2, 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', MakePoint(1, 2, 4326), 0.0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint7.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint7.testcase
new file mode 100644
index 0000000..0b6b5ef
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint7.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - BLOB Tolerance
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', MakePoint(1, 2, 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', MakePoint(1, 2, 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint8.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint8.testcase
new file mode 100644
index 0000000..b5a4958
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint8.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Text Tolerance
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', MakePoint(1, 2, 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', MakePoint(1, 2, 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkbypoint9.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint9.testcase
new file mode 100644
index 0000000..feb3276
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkbypoint9.testcase
@@ -0,0 +1,7 @@
+GetLinkByPoint - Int Geometry
+:memory: #use in-memory database
+SELECT GetLinkByPoint('network', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+GetLinkByPoint('network', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed1.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed1.testcase
new file mode 100644
index 0000000..4deb2bd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed1.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - NULL Topology
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed(NULL, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed(NULL, 1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed2.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed2.testcase
new file mode 100644
index 0000000..65fb4c2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed2.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - Int Topology
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed(1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed(1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed3.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed3.testcase
new file mode 100644
index 0000000..4f31243
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed3.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - Double Topology
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed(1.2, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed(1.2, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed4.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed4.testcase
new file mode 100644
index 0000000..8616520
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed4.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - BLOB Topology
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed(zeroblob(4), 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed(zeroblob(4), 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed5.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed5.testcase
new file mode 100644
index 0000000..0b7e222
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed5.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - Text Topology
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed('network', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed('network', 1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed6.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed6.testcase
new file mode 100644
index 0000000..363e03e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed6.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - NULL Face
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed('network', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed('network', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed7.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed7.testcase
new file mode 100644
index 0000000..9ce573b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed7.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - Double Face
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed('network', 1.3);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed('network', 1.3)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed8.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed8.testcase
new file mode 100644
index 0000000..3988766
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed8.testcase
@@ -0,0 +1,7 @@
+TopoNet_GetLinkSeed - Text Face
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed('network', 'face');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed('network', 'face')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getlinkseed9.testcase b/test/sql_stmt_lwgeom_22_tests/getlinkseed9.testcase
new file mode 100644
index 0000000..2ff90d8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getlinkseed9.testcase
@@ -0,0 +1,7 @@
+GetLinkSeed - BLOB Face
+:memory: #use in-memory database
+SELECT TopoNet_GetLinkSeed('network', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_GetLinkSeed('network', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint1.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint1.testcase
new file mode 100644
index 0000000..070fa68
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint1.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - NULL Network
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint(NULL, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint(NULL, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint10.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint10.testcase
new file mode 100644
index 0000000..9513327
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint10.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Double Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint11.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint11.testcase
new file mode 100644
index 0000000..924b3f9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint11.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - NULL Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint12.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint12.testcase
new file mode 100644
index 0000000..fb28715
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint12.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Text Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint13.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint13.testcase
new file mode 100644
index 0000000..ac76331
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint13.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint14.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint14.testcase
new file mode 100644
index 0000000..11f5104
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint14.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Linestring Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint15.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint15.testcase
new file mode 100644
index 0000000..485c5ae
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint15.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Polygon Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint16.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint16.testcase
new file mode 100644
index 0000000..0532618
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint16.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint17.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint17.testcase
new file mode 100644
index 0000000..b650cfb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint17.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - NULL Tolerance
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint2.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint2.testcase
new file mode 100644
index 0000000..d9f3757
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint2.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Int Network
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint(1, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint(1, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint3.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint3.testcase
new file mode 100644
index 0000000..8378281
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint3.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Double Network
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint(1.5, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint(1.5, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint4.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint4.testcase
new file mode 100644
index 0000000..6839add
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint4.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Blob Network
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint(zeroblob(4), MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint(zeroblob(4),MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint5.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint5.testcase
new file mode 100644
index 0000000..76ff112
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint5.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Text Network
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint6.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint6.testcase
new file mode 100644
index 0000000..748a5d0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint6.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Double Tolerance
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', MakePoint(1, 2, 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', MakePoint(1, 2, 4326), 0.0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint7.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint7.testcase
new file mode 100644
index 0000000..bb7f01f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint7.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - BLOB Tolerance
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', MakePoint(1, 2, 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', MakePoint(1, 2, 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint8.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint8.testcase
new file mode 100644
index 0000000..d78e20b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint8.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Text Tolerance
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', MakePoint(1, 2, 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', MakePoint(1, 2, 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint9.testcase b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint9.testcase
new file mode 100644
index 0000000..4f833aa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnetnodebypoint9.testcase
@@ -0,0 +1,7 @@
+GetNetNodeByPoint - Int Geometry
+:memory: #use in-memory database
+SELECT GetNetNodeByPoint('network', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+GetNetNodeByPoint('network', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint1.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint1.testcase
new file mode 100644
index 0000000..4950207
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint1.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - NULL Topology
+:memory: #use in-memory database
+SELECT GetNodeByPoint(NULL, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint(NULL, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint10.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint10.testcase
new file mode 100644
index 0000000..7662fce
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint10.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Double Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint11.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint11.testcase
new file mode 100644
index 0000000..ee6eae1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint11.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - NULL Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint12.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint12.testcase
new file mode 100644
index 0000000..dcaa861
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint12.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Text Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint13.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint13.testcase
new file mode 100644
index 0000000..ae93c82
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint13.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint14.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint14.testcase
new file mode 100644
index 0000000..44fdb55
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint14.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Linestring Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint15.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint15.testcase
new file mode 100644
index 0000000..97e35f3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint15.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Polygon Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint16.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint16.testcase
new file mode 100644
index 0000000..c7cd209
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint16.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint17.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint17.testcase
new file mode 100644
index 0000000..7446066
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint17.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - NULL Tolerance
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint2.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint2.testcase
new file mode 100644
index 0000000..6e4445f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint2.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Int Topology
+:memory: #use in-memory database
+SELECT GetNodeByPoint(1, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint(1, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint3.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint3.testcase
new file mode 100644
index 0000000..0c5e72f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint3.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Double Topology
+:memory: #use in-memory database
+SELECT GetNodeByPoint(1.5, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint(1.5, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint4.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint4.testcase
new file mode 100644
index 0000000..90623bd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint4.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Blob Topology
+:memory: #use in-memory database
+SELECT GetNodeByPoint(zeroblob(4), MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint(zeroblob(4),MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint5.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint5.testcase
new file mode 100644
index 0000000..d178ea6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint5.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Text Topology
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint6.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint6.testcase
new file mode 100644
index 0000000..04ab5f6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint6.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Double Tolerance
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', MakePoint(1, 2, 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', MakePoint(1, 2, 4326), 0.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint7.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint7.testcase
new file mode 100644
index 0000000..86bf2ec
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint7.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - BLOB Tolerance
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', MakePoint(1, 2, 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', MakePoint(1, 2, 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint8.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint8.testcase
new file mode 100644
index 0000000..7399c4d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint8.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Text Tolerance
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', MakePoint(1, 2, 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', MakePoint(1, 2, 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/getnodebypoint9.testcase b/test/sql_stmt_lwgeom_22_tests/getnodebypoint9.testcase
new file mode 100644
index 0000000..ceae0c3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/getnodebypoint9.testcase
@@ -0,0 +1,7 @@
+GetNodeByPoint - Int Geometry
+:memory: #use in-memory database
+SELECT GetNodeByPoint('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+GetNodeByPoint('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer1.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer1.testcase
new file mode 100644
index 0000000..8135c59
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer(NULL, NULL, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer(NULL, NULL, 'table', 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer10.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer10.testcase
new file mode 100644
index 0000000..7a1790f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - NULL ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer11.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer11.testcase
new file mode 100644
index 0000000..8fb55aa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - INT ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 1, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 1, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer12.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer12.testcase
new file mode 100644
index 0000000..f64d3b4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Double ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 1.2, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 1.2, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer13.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer13.testcase
new file mode 100644
index 0000000..1eccbfa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - BLOB ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, zeroblob(4), 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, zeroblob(4), 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer14.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer14.testcase
new file mode 100644
index 0000000..aaadc7e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - NULL TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 'table', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer15.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer15.testcase
new file mode 100644
index 0000000..3cb580b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Double TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 'table', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 'table', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer16.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer16.testcase
new file mode 100644
index 0000000..d3b0631
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - BLOB TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 'table', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 'table', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer17.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer17.testcase
new file mode 100644
index 0000000..c84f10d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Text TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 'table', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer2.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer2.testcase
new file mode 100644
index 0000000..e88bb6c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer(1, NULL, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer(1, NULL, 'table', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer3.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer3.testcase
new file mode 100644
index 0000000..7a01852
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer(1.5, NULL, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer(1.5, NULL, 'table', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer4.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer4.testcase
new file mode 100644
index 0000000..feed6d5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer(zeroblob(4), NULL, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer(zeroblob(4), NULL, 'table', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer5.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer5.testcase
new file mode 100644
index 0000000..2cd9e5d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', NULL, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', NULL, 'table', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer6.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer6.testcase
new file mode 100644
index 0000000..ea181cc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', 'a', 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', 'a', 'table', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer7.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer7.testcase
new file mode 100644
index 0000000..7ca3f00
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - INT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', 1, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', 1, 'table', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer8.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer8.testcase
new file mode 100644
index 0000000..6fe7872
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - Double prefix
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', 1.2, 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', 1.2, 'table', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/inittopolayer9.testcase b/test/sql_stmt_lwgeom_22_tests/inittopolayer9.testcase
new file mode 100644
index 0000000..7618cd0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/inittopolayer9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_InitTopoLayer - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoGeo_InitTopoLayer('topology', zeroblob(4), 'table', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_InitTopoLayer('topology', zeroblob(4), 'table', 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo1.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo1.testcase
new file mode 100644
index 0000000..c95a27b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo1.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - NULL Network
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo(NULL, 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo(NULL, 'topology')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo2.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo2.testcase
new file mode 100644
index 0000000..e20461b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo2.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - Int Network
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo(1, 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo(1, 'topology')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo3.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo3.testcase
new file mode 100644
index 0000000..bb6bd55
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo3.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - Double Network
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo(1.5, 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo(1.5, 'topology')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo4.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo4.testcase
new file mode 100644
index 0000000..311fd93
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo4.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - Blob Network
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo(zeroblob(4), 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo(zeroblob(4), 'topology')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo5.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo5.testcase
new file mode 100644
index 0000000..77ea01c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo5.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - Text Network
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo('network', 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo('network', 'topology')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo6.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo6.testcase
new file mode 100644
index 0000000..be84039
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo6.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - NULL Topology
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo('network', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo('network', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo7.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo7.testcase
new file mode 100644
index 0000000..077e891
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo7.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - INT Topology
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo('network', 1);
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo('network', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo8.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo8.testcase
new file mode 100644
index 0000000..3b664c6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo8.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - Double Topology
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo('network', 1.2);
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo('network', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo9.testcase b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo9.testcase
new file mode 100644
index 0000000..3e201ce
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/loginetfromtgeo9.testcase
@@ -0,0 +1,7 @@
+ST_LogiNetFromTGeo - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_LogiNetFromTGeo('network', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_LogiNetFromTGeo('network', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal1.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal1.testcase
new file mode 100644
index 0000000..eb891ad
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal1.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - NULL Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal(NULL, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal(NULL, 1, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal10.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal10.testcase
new file mode 100644
index 0000000..1ed6227
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal10.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - NULL Edge #2
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal11.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal11.testcase
new file mode 100644
index 0000000..5edb338
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal11.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Double Edge #2
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 1, 2.4);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 1, 2.4)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal12.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal12.testcase
new file mode 100644
index 0000000..0fffaaa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal12.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Text Edge #2
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 1, 'to');
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 1, 'to')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal13.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal13.testcase
new file mode 100644
index 0000000..3a1227f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal13.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - BLOB Edge #2
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 1, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal2.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal2.testcase
new file mode 100644
index 0000000..8aae8cc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal2.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Int Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal(1, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal(1, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal3.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal3.testcase
new file mode 100644
index 0000000..e077bc8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal3.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Double Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal(1.2, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal(1.2, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal4.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal4.testcase
new file mode 100644
index 0000000..f35a324
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal4.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal(zeroblob(4), 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal(zeroblob(4), 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal5.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal5.testcase
new file mode 100644
index 0000000..35803cb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal5.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Text Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 1, 2)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal6.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal6.testcase
new file mode 100644
index 0000000..26671ba
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal6.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - NULL Edge #1
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', NULL, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', NULL, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal7.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal7.testcase
new file mode 100644
index 0000000..a283ff1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal7.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Double Edge #1
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 1.3, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 1.3, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal8.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal8.testcase
new file mode 100644
index 0000000..59873b0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal8.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - Text Edge #1
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', 'from', 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', 'from', 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgeheal9.testcase b/test/sql_stmt_lwgeom_22_tests/modedgeheal9.testcase
new file mode 100644
index 0000000..2361b34
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgeheal9.testcase
@@ -0,0 +1,7 @@
+ModEdgeHeal - BLOB Edge #1
+:memory: #use in-memory database
+SELECT ST_ModEdgeHeal('topology', zeroblob(4), 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeHeal('topology', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit1.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit1.testcase
new file mode 100644
index 0000000..aaa1635
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit1.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - NULL Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit10.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit10.testcase
new file mode 100644
index 0000000..fd54863
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit10.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Double Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, 1.1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit11.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit11.testcase
new file mode 100644
index 0000000..64e8fcc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit11.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit12.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit12.testcase
new file mode 100644
index 0000000..9031702
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit12.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Text Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', 'face', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', 'face', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit13.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit13.testcase
new file mode 100644
index 0000000..e57d1b4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit13.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', 'face', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', 'face', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit14.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit14.testcase
new file mode 100644
index 0000000..7e2f92a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit14.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Linestring Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit15.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit15.testcase
new file mode 100644
index 0000000..3e6d98a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit15.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit16.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit16.testcase
new file mode 100644
index 0000000..49ac09f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit16.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit2.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit2.testcase
new file mode 100644
index 0000000..61dc9ff
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit2.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Int Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit3.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit3.testcase
new file mode 100644
index 0000000..102facf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit3.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Double Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit4.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit4.testcase
new file mode 100644
index 0000000..ee952c5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit4.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Blob Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit5.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit5.testcase
new file mode 100644
index 0000000..6e7aa58
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit5.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Text Topology
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit6.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit6.testcase
new file mode 100644
index 0000000..c872950
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit6.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Double Face
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit7.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit7.testcase
new file mode 100644
index 0000000..319313c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit7.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - BLOB Face
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit8.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit8.testcase
new file mode 100644
index 0000000..a2760c4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit8.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Text Face
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', 'face', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', 'face', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modedgesplit9.testcase b/test/sql_stmt_lwgeom_22_tests/modedgesplit9.testcase
new file mode 100644
index 0000000..a64fab2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modedgesplit9.testcase
@@ -0,0 +1,7 @@
+ModEdgeSplit - Int Geometry
+:memory: #use in-memory database
+SELECT ST_ModEdgeSplit('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModEdgeSplit('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit1.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit1.testcase
new file mode 100644
index 0000000..dcbf2c4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit1.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - NULL Network
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit2.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit2.testcase
new file mode 100644
index 0000000..91f8d00
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit2.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Int Network
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit3.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit3.testcase
new file mode 100644
index 0000000..3cb14f6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit3.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Double Network
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit4.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit4.testcase
new file mode 100644
index 0000000..1df3abd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit4.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Blob Network
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit5.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit5.testcase
new file mode 100644
index 0000000..3e8f46b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit5.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Text Network
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit('net', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit('net', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit6.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit6.testcase
new file mode 100644
index 0000000..b304424
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit6.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Double Link
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit('net', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit('net', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit7.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit7.testcase
new file mode 100644
index 0000000..e92ebee
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit7.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - BLOB Link
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit('net', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit('net', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit8.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit8.testcase
new file mode 100644
index 0000000..8c50735
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit8.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Text Link
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit('net', 'link', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit('net', 'link', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modgeolinksplit9.testcase b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit9.testcase
new file mode 100644
index 0000000..726196e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modgeolinksplit9.testcase
@@ -0,0 +1,7 @@
+ModGeoLinkSplit - Int Geometry
+:memory: #use in-memory database
+SELECT ST_ModGeoLinkSplit('net', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModGeoLinkSplit('net', -1, 1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal1.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal1.testcase
new file mode 100644
index 0000000..2d7f465
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal1.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - NULL Network
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal(NULL, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal(NULL, 1, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal10.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal10.testcase
new file mode 100644
index 0000000..b6ee63b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal10.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - NULL Link #2
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', 1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal11.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal11.testcase
new file mode 100644
index 0000000..cbcc4d7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal11.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Double Link #2
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', 1, 2.4);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', 1, 2.4)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal12.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal12.testcase
new file mode 100644
index 0000000..82c0ebd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal12.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Text Link #2
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', 1, 'to');
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', 1, 'to')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal13.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal13.testcase
new file mode 100644
index 0000000..d9ca1bb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal13.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - BLOB Link #2
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', 1, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal2.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal2.testcase
new file mode 100644
index 0000000..dec1347
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal2.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Int Network
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal(1, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal(1, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal3.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal3.testcase
new file mode 100644
index 0000000..8bccbae
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal3.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Double Network
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal(1.2, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal(1.2, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal4.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal4.testcase
new file mode 100644
index 0000000..3957a1c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal4.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - BLOB Network
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal(zeroblob(4), 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal(zeroblob(4), 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal5.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal5.testcase
new file mode 100644
index 0000000..7388e41
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal5.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Text Network
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('topology', 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('topology', 1, 2)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal6.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal6.testcase
new file mode 100644
index 0000000..36b10ac
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal6.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - NULL Link #1
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', NULL, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', NULL, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal7.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal7.testcase
new file mode 100644
index 0000000..3b3e712
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal7.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Double Link #1
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', 1.3, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', 1.3, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal8.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal8.testcase
new file mode 100644
index 0000000..b41c5fb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal8.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - Text Link #1
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', 'from', 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', 'from', 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modlinkheal9.testcase b/test/sql_stmt_lwgeom_22_tests/modlinkheal9.testcase
new file mode 100644
index 0000000..a5fa15e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modlinkheal9.testcase
@@ -0,0 +1,7 @@
+ModLinkHeal - BLOB Link #1
+:memory: #use in-memory database
+SELECT ST_ModLinkHeal('net', zeroblob(4), 2);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLinkHeal('net', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit1.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit1.testcase
new file mode 100644
index 0000000..1b94a61
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit1.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - NULL Network
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit2.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit2.testcase
new file mode 100644
index 0000000..7dbe0b9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit2.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - Int Network
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit3.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit3.testcase
new file mode 100644
index 0000000..b486d16
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit3.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - Double Network
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit4.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit4.testcase
new file mode 100644
index 0000000..6bf1b03
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit4.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - Blob Network
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit5.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit5.testcase
new file mode 100644
index 0000000..7245920
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit5.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - Text Network
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit('net', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit('net', -1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit6.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit6.testcase
new file mode 100644
index 0000000..1ffc813
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit6.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - Double Link
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit('net', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit('net', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit7.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit7.testcase
new file mode 100644
index 0000000..414cdb7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit7.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - BLOB Link
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit('net', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit('net', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit8.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit8.testcase
new file mode 100644
index 0000000..c45c900
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit8.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - Text Link
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit('net', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit('net', 'node')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/modloglinksplit9.testcase b/test/sql_stmt_lwgeom_22_tests/modloglinksplit9.testcase
new file mode 100644
index 0000000..0c7e453
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/modloglinksplit9.testcase
@@ -0,0 +1,7 @@
+ModLogLinkSplit - NULL Link
+:memory: #use in-memory database
+SELECT ST_ModLogLinkSplit('net', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ModLogLinkSplit('net', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode1.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode1.testcase
new file mode 100644
index 0000000..f7c1b0e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode1.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - NULL Network
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode2.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode2.testcase
new file mode 100644
index 0000000..1042f8b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode2.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - Int Network
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode3.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode3.testcase
new file mode 100644
index 0000000..fbf03db
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode3.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - Double Network
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode4.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode4.testcase
new file mode 100644
index 0000000..30808e6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode4.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - Blob Network
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode5.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode5.testcase
new file mode 100644
index 0000000..cb2f1a7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode5.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - Double Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode('net', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode('net', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode6.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode6.testcase
new file mode 100644
index 0000000..c835c93
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode6.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - BLOB Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode('net', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode('net', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode7.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode7.testcase
new file mode 100644
index 0000000..be88dc1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode7.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - Text Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode('net', 'node', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode('net', 'node', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode8.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode8.testcase
new file mode 100644
index 0000000..585a484
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode8.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - NULL Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode('net', NULL, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNode('net', NULL, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonetnode9.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonetnode9.testcase
new file mode 100644
index 0000000..865eea0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonetnode9.testcase
@@ -0,0 +1,7 @@
+MoveIsoNetNode - invalid network
+:memory: #use in-memory database
+SELECT ST_MoveIsoNetNode('net', 1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNetNetNode('net', 1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode1.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode1.testcase
new file mode 100644
index 0000000..0842635
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode1.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - NULL Topology
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode10.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode10.testcase
new file mode 100644
index 0000000..a1b38da
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode10.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Double Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, 1.1);
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode11.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode11.testcase
new file mode 100644
index 0000000..46908c4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode11.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode12.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode12.testcase
new file mode 100644
index 0000000..1f22339
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode12.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Text Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', 'face', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', 'face', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode13.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode13.testcase
new file mode 100644
index 0000000..8ed06c0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode13.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', 'face', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', 'face', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode14.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode14.testcase
new file mode 100644
index 0000000..44f29c9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode14.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Linestring Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode15.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode15.testcase
new file mode 100644
index 0000000..031a66b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode15.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode16.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode16.testcase
new file mode 100644
index 0000000..e3a061b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode16.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode17.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode17.testcase
new file mode 100644
index 0000000..10b3b5f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode17.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - NULL Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', NULL, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', NULL, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode2.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode2.testcase
new file mode 100644
index 0000000..50ad7cc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode2.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Int Topology
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode3.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode3.testcase
new file mode 100644
index 0000000..f7c1a38
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode3.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Double Topology
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode4.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode4.testcase
new file mode 100644
index 0000000..50e816e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode4.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Blob Topology
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode5.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode5.testcase
new file mode 100644
index 0000000..00b59c4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode5.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Text Topology
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode6.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode6.testcase
new file mode 100644
index 0000000..4fbac34
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode6.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Double Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode7.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode7.testcase
new file mode 100644
index 0000000..25b761b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode7.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - BLOB Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode8.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode8.testcase
new file mode 100644
index 0000000..e90ac08
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode8.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Text Node
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', 'node', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', 'node', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/moveisonode9.testcase b/test/sql_stmt_lwgeom_22_tests/moveisonode9.testcase
new file mode 100644
index 0000000..02e4276
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/moveisonode9.testcase
@@ -0,0 +1,7 @@
+MoveIsoNode - Int Geometry
+:memory: #use in-memory database
+SELECT ST_MoveIsoNode('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_MoveIsoNode('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/netexception1.testcase b/test/sql_stmt_lwgeom_22_tests/netexception1.testcase
new file mode 100644
index 0000000..03e0e1b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/netexception1.testcase
@@ -0,0 +1,7 @@
+GetLastNetworkException - NULL Network
+:memory: #use in-memory database
+SELECT GetLastNetworkException(NULL);
+1 # rows (not including the header row)
+1 # columns
+GetLastNetworkException(NULL)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/netexception2.testcase b/test/sql_stmt_lwgeom_22_tests/netexception2.testcase
new file mode 100644
index 0000000..3040e15
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/netexception2.testcase
@@ -0,0 +1,7 @@
+GetLastNetworkException - Undefined Network
+:memory: #use in-memory database
+SELECT GetLastNetworkException('net');
+1 # rows (not including the header row)
+1 # columns
+GetLastNetworkException('net')
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal1.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal1.testcase
new file mode 100644
index 0000000..41f166b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal1.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - NULL Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal(NULL, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal(NULL, 1, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal10.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal10.testcase
new file mode 100644
index 0000000..bf4e84a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal10.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - NULL Edge #2
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal11.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal11.testcase
new file mode 100644
index 0000000..767f0a2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal11.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Double Edge #2
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 1, 2.4);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 1, 2.4)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal12.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal12.testcase
new file mode 100644
index 0000000..aee15fc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal12.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Text Edge #2
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 1, 'to');
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 1, 'to')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal13.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal13.testcase
new file mode 100644
index 0000000..4724897
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal13.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - BLOB Edge #2
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 1, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal2.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal2.testcase
new file mode 100644
index 0000000..fdc57b5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal2.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Int Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal(1, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal(1, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal3.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal3.testcase
new file mode 100644
index 0000000..56a64b2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal3.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Double Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal(1.2, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal(1.2, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal4.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal4.testcase
new file mode 100644
index 0000000..a3fcffe
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal4.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal(zeroblob(4), 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal(zeroblob(4), 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal5.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal5.testcase
new file mode 100644
index 0000000..7556a03
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal5.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Text Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 1, 2)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal6.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal6.testcase
new file mode 100644
index 0000000..bb6ea7d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal6.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - NULL Edge #1
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', NULL, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', NULL, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal7.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal7.testcase
new file mode 100644
index 0000000..31d4f9d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal7.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Double Edge #1
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 1.3, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 1.3, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal8.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal8.testcase
new file mode 100644
index 0000000..f26aa50
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal8.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - Text Edge #1
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', 'from', 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', 'from', 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgeheal9.testcase b/test/sql_stmt_lwgeom_22_tests/newedgeheal9.testcase
new file mode 100644
index 0000000..77b6146
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgeheal9.testcase
@@ -0,0 +1,7 @@
+NewEdgeHeal - BLOB Edge #1
+:memory: #use in-memory database
+SELECT ST_NewEdgeHeal('topology', zeroblob(4), 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgeHeal('topology', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit1.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit1.testcase
new file mode 100644
index 0000000..124f61e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit1.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - NULL Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit10.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit10.testcase
new file mode 100644
index 0000000..fb7ba59
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit10.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Double Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, 1.1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit11.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit11.testcase
new file mode 100644
index 0000000..8eda94e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit11.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - NULL Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit12.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit12.testcase
new file mode 100644
index 0000000..e3ba519
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit12.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Text Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', 'face', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', 'face', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit13.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit13.testcase
new file mode 100644
index 0000000..4ecb492
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit13.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', 'face', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', 'face', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit14.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit14.testcase
new file mode 100644
index 0000000..2b84bcb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit14.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Linestring Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, GeomFromText('LINESTRING(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit15.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit15.testcase
new file mode 100644
index 0000000..48ae346
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit15.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Polygon Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit16.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit16.testcase
new file mode 100644
index 0000000..a3590d9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit16.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, GeomFromText('MULTIPOINT(0 0, 1 1)', 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit2.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit2.testcase
new file mode 100644
index 0000000..f711312
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit2.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Int Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit3.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit3.testcase
new file mode 100644
index 0000000..5ed4e63
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit3.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Double Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit4.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit4.testcase
new file mode 100644
index 0000000..6244de5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit4.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Blob Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit5.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit5.testcase
new file mode 100644
index 0000000..5d247df
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit5.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Text Topology
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit6.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit6.testcase
new file mode 100644
index 0000000..a6517ab
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit6.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Double Face
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit7.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit7.testcase
new file mode 100644
index 0000000..7e0d355
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit7.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - BLOB Face
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit8.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit8.testcase
new file mode 100644
index 0000000..122f2f5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit8.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Text Face
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', 'face', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', 'face', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newedgessplit9.testcase b/test/sql_stmt_lwgeom_22_tests/newedgessplit9.testcase
new file mode 100644
index 0000000..b74e3d3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newedgessplit9.testcase
@@ -0,0 +1,7 @@
+NewEdgesSplit - Int Geometry
+:memory: #use in-memory database
+SELECT ST_NewEdgesSplit('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewEdgesSplit('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit1.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit1.testcase
new file mode 100644
index 0000000..a391f88
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit1.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - NULL Network
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit(NULL, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit(NULL, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit2.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit2.testcase
new file mode 100644
index 0000000..230bb22
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit2.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Int Network
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit(1, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit(1, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit3.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit3.testcase
new file mode 100644
index 0000000..1c0493e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit3.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Double Network
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit(1.5, -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit(1.5, -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit4.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit4.testcase
new file mode 100644
index 0000000..14d0527
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit4.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Blob Network
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit(zeroblob(4), -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit(zeroblob(4), -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit5.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit5.testcase
new file mode 100644
index 0000000..705f797
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit5.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Text Network
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit('net', -1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit('net', -1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit6.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit6.testcase
new file mode 100644
index 0000000..2c07e09
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit6.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Double Link
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit('net', 2.0, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit('net', 2.0, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit7.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit7.testcase
new file mode 100644
index 0000000..433fb36
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit7.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - BLOB Link
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit('net', zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit('net', zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit8.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit8.testcase
new file mode 100644
index 0000000..4370bd7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit8.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Text Link
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit('net', 'link', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit('net', 'link', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newgeolinksplit9.testcase b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit9.testcase
new file mode 100644
index 0000000..355e003
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newgeolinksplit9.testcase
@@ -0,0 +1,7 @@
+NewGeoLinkSplit - Int Geometry
+:memory: #use in-memory database
+SELECT ST_NewGeoLinkSplit('net', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewGeoLinkSplit('net', -1, 1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal1.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal1.testcase
new file mode 100644
index 0000000..8b2a0f1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal1.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - NULL Network
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal(NULL, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal(NULL, 1, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal10.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal10.testcase
new file mode 100644
index 0000000..0c144ae
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal10.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - NULL Link #2
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', 1, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal11.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal11.testcase
new file mode 100644
index 0000000..550a0e8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal11.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Double Link #2
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', 1, 2.4);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', 1, 2.4)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal12.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal12.testcase
new file mode 100644
index 0000000..03660a7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal12.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Text Link #2
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', 1, 'to');
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', 1, 'to')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal13.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal13.testcase
new file mode 100644
index 0000000..a666582
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal13.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - BLOB Link #2
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', 1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', 1, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal2.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal2.testcase
new file mode 100644
index 0000000..480baa9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal2.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Int Network
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal(1, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal(1, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal3.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal3.testcase
new file mode 100644
index 0000000..aba6ff0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal3.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Double Network
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal(1.2, 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal(1.2, 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal4.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal4.testcase
new file mode 100644
index 0000000..aaf77d3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal4.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - BLOB Network
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal(zeroblob(4), 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal(zeroblob(4), 1, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal5.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal5.testcase
new file mode 100644
index 0000000..603fffb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal5.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Text Network
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('topology', 1, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('topology', 1, 2)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal6.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal6.testcase
new file mode 100644
index 0000000..01d0f59
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal6.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - NULL Link #1
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', NULL, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', NULL, 2)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal7.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal7.testcase
new file mode 100644
index 0000000..5cd9836
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal7.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Double Link #1
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', 1.3, 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', 1.3, 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal8.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal8.testcase
new file mode 100644
index 0000000..4ecdadc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal8.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - Text Link #1
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', 'from', 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', 'from', 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newlinkheal9.testcase b/test/sql_stmt_lwgeom_22_tests/newlinkheal9.testcase
new file mode 100644
index 0000000..1db15ab
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newlinkheal9.testcase
@@ -0,0 +1,7 @@
+NewLinkHeal - BLOB Link #1
+:memory: #use in-memory database
+SELECT ST_NewLinkHeal('net', zeroblob(4), 2);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLinkHeal('net', zeroblob(4), 2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit1.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit1.testcase
new file mode 100644
index 0000000..8989063
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit1.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - NULL Network
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit2.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit2.testcase
new file mode 100644
index 0000000..e37e27a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit2.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - Int Network
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit3.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit3.testcase
new file mode 100644
index 0000000..4c71376
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit3.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - Double Network
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit4.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit4.testcase
new file mode 100644
index 0000000..cc81428
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit4.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - Blob Network
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit5.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit5.testcase
new file mode 100644
index 0000000..eee079c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit5.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - Text Network
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit('net', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit('net', -1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit6.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit6.testcase
new file mode 100644
index 0000000..6f31832
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit6.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - Double Link
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit('net', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit('net', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit7.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit7.testcase
new file mode 100644
index 0000000..df05330
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit7.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - BLOB Link
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit('net', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit('net', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit8.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit8.testcase
new file mode 100644
index 0000000..1bf00b0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit8.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - Text Link
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit('net', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit('net', 'node')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/newloglinksplit9.testcase b/test/sql_stmt_lwgeom_22_tests/newloglinksplit9.testcase
new file mode 100644
index 0000000..7beedcc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/newloglinksplit9.testcase
@@ -0,0 +1,7 @@
+NewLogLinkSplit - NULL Link
+:memory: #use in-memory database
+SELECT ST_NewLogLinkSplit('net', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_NewLogLinkSplit('net', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface1.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface1.testcase
new file mode 100644
index 0000000..b3eeac2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface1.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - NULL Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface2.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface2.testcase
new file mode 100644
index 0000000..dccb6a3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface2.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - Int Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface3.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface3.testcase
new file mode 100644
index 0000000..a5858c1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface3.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - Double Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface4.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface4.testcase
new file mode 100644
index 0000000..9cbf9e3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface4.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - Blob Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface5.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface5.testcase
new file mode 100644
index 0000000..2556f97
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface5.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - Text Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace('topology', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace('topology', -1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface6.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface6.testcase
new file mode 100644
index 0000000..8ab6394
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface6.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - Double Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace('topology', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace('topology', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface7.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface7.testcase
new file mode 100644
index 0000000..71d0500
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface7.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - BLOB Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface8.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface8.testcase
new file mode 100644
index 0000000..04328ce
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface8.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - Text Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace('topology', 'edge');
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace('topology', 'edge')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgemodface9.testcase b/test/sql_stmt_lwgeom_22_tests/remedgemodface9.testcase
new file mode 100644
index 0000000..6390b52
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgemodface9.testcase
@@ -0,0 +1,7 @@
+RemEdgeModFace - NULL Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeModFace('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeModFace('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface1.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface1.testcase
new file mode 100644
index 0000000..17b1300
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface1.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - NULL Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface2.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface2.testcase
new file mode 100644
index 0000000..a065541
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface2.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - Int Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface3.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface3.testcase
new file mode 100644
index 0000000..767e48a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface3.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - Double Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface4.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface4.testcase
new file mode 100644
index 0000000..492e936
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface4.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - Blob Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface5.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface5.testcase
new file mode 100644
index 0000000..b268527
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface5.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - Text Topology
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace('topology', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace('topology', -1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface6.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface6.testcase
new file mode 100644
index 0000000..d596e79
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface6.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - Double Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace('topology', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace('topology', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface7.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface7.testcase
new file mode 100644
index 0000000..913a44e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface7.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - BLOB Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface8.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface8.testcase
new file mode 100644
index 0000000..b80b42d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface8.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - Text Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace('topology', 'edge');
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace('topology', 'edge')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remedgenewface9.testcase b/test/sql_stmt_lwgeom_22_tests/remedgenewface9.testcase
new file mode 100644
index 0000000..a964533
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remedgenewface9.testcase
@@ -0,0 +1,7 @@
+RemEdgeNewFace - NULL Edge
+:memory: #use in-memory database
+SELECT ST_RemEdgeNewFace('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_RemEdgeNewFace('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge1.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge1.testcase
new file mode 100644
index 0000000..ad8da8f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge1.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - NULL Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge2.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge2.testcase
new file mode 100644
index 0000000..82aa5ef
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge2.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - Int Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge3.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge3.testcase
new file mode 100644
index 0000000..c0b1ccf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge3.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - Double Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge4.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge4.testcase
new file mode 100644
index 0000000..ddfd736
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge4.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - Blob Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge5.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge5.testcase
new file mode 100644
index 0000000..b8ff5b2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge5.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - Text Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge('topology', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge('topology', -1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge6.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge6.testcase
new file mode 100644
index 0000000..5b658ab
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge6.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - Double Edge
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge('topology', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge('topology', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge7.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge7.testcase
new file mode 100644
index 0000000..9820468
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge7.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - BLOB RemIsoEdge
+:memory: #use in-memory database
+SELECT ST_RemIsoNode('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge8.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge8.testcase
new file mode 100644
index 0000000..682345a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge8.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - Text Edge
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge('topology', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge('topology', 'node')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisoedge9.testcase b/test/sql_stmt_lwgeom_22_tests/remisoedge9.testcase
new file mode 100644
index 0000000..02b650a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisoedge9.testcase
@@ -0,0 +1,7 @@
+RemIsoEdge - NULL Edge
+:memory: #use in-memory database
+SELECT ST_RemIsoEdge('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoEdge('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode1.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode1.testcase
new file mode 100644
index 0000000..85372d5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode1.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - NULL Network
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode2.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode2.testcase
new file mode 100644
index 0000000..6ede979
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode2.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - Int Network
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode3.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode3.testcase
new file mode 100644
index 0000000..5e97f6e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode3.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - Double Network
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode4.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode4.testcase
new file mode 100644
index 0000000..6eeeb9e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode4.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - Blob Network
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode5.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode5.testcase
new file mode 100644
index 0000000..770504c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode5.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - Text Network
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode('net', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode('net', -1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode6.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode6.testcase
new file mode 100644
index 0000000..f4fed59
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode6.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - Double Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode('net', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode('net', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode7.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode7.testcase
new file mode 100644
index 0000000..af024b5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode7.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - BLOB Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode('net', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode('net', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode8.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode8.testcase
new file mode 100644
index 0000000..a50ce79
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode8.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - Text Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode('net', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode('net', 'node')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonetnode9.testcase b/test/sql_stmt_lwgeom_22_tests/remisonetnode9.testcase
new file mode 100644
index 0000000..cd06989
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonetnode9.testcase
@@ -0,0 +1,7 @@
+RemIsoNetNode - NULL Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNetNode('net', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNetNode('net', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode1.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode1.testcase
new file mode 100644
index 0000000..d20b34d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode1.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - NULL Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoNode(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode2.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode2.testcase
new file mode 100644
index 0000000..6a4fe5e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode2.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - Int Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoNode(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode3.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode3.testcase
new file mode 100644
index 0000000..b8ff5c8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode3.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - Double Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoNode(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode4.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode4.testcase
new file mode 100644
index 0000000..76a69f1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode4.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - Blob Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoNode(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode5.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode5.testcase
new file mode 100644
index 0000000..80bc722
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode5.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - Text Topology
+:memory: #use in-memory database
+SELECT ST_RemIsoNode('topology', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode('topology', -1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode6.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode6.testcase
new file mode 100644
index 0000000..1c09b86
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode6.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - Double Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNode('topology', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode('topology', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode7.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode7.testcase
new file mode 100644
index 0000000..990d91a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode7.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - BLOB Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNode('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode8.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode8.testcase
new file mode 100644
index 0000000..baac281
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode8.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - Text Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNode('topology', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode('topology', 'node')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remisonode9.testcase b/test/sql_stmt_lwgeom_22_tests/remisonode9.testcase
new file mode 100644
index 0000000..3d2debb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remisonode9.testcase
@@ -0,0 +1,7 @@
+RemIsoNode - NULL Node
+:memory: #use in-memory database
+SELECT ST_RemIsoNode('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_RemIsoNode('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink1.testcase b/test/sql_stmt_lwgeom_22_tests/remlink1.testcase
new file mode 100644
index 0000000..41c9c53
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink1.testcase
@@ -0,0 +1,7 @@
+RemoveLink - NULL Network
+:memory: #use in-memory database
+SELECT ST_RemoveLink(NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink(NULL, -1)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink2.testcase b/test/sql_stmt_lwgeom_22_tests/remlink2.testcase
new file mode 100644
index 0000000..459897d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink2.testcase
@@ -0,0 +1,7 @@
+RemoveLink - Int Network
+:memory: #use in-memory database
+SELECT ST_RemoveLink(1, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink(1, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink3.testcase b/test/sql_stmt_lwgeom_22_tests/remlink3.testcase
new file mode 100644
index 0000000..363e373
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink3.testcase
@@ -0,0 +1,7 @@
+RemoveLink - Double Network
+:memory: #use in-memory database
+SELECT ST_RemoveLink(1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink(1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink4.testcase b/test/sql_stmt_lwgeom_22_tests/remlink4.testcase
new file mode 100644
index 0000000..a741deb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink4.testcase
@@ -0,0 +1,7 @@
+RemoveLink - Blob Network
+:memory: #use in-memory database
+SELECT ST_RemoveLink(zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink(zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink5.testcase b/test/sql_stmt_lwgeom_22_tests/remlink5.testcase
new file mode 100644
index 0000000..dcbb9f9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink5.testcase
@@ -0,0 +1,7 @@
+RemoveLink - Text Network
+:memory: #use in-memory database
+SELECT ST_RemoveLink('net', -1);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink('net', -1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink6.testcase b/test/sql_stmt_lwgeom_22_tests/remlink6.testcase
new file mode 100644
index 0000000..5dde887
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink6.testcase
@@ -0,0 +1,7 @@
+RemoveLink - Double Link
+:memory: #use in-memory database
+SELECT ST_RemoveLink('net', 2.0);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink('net', 2.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink7.testcase b/test/sql_stmt_lwgeom_22_tests/remlink7.testcase
new file mode 100644
index 0000000..e4bc021
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink7.testcase
@@ -0,0 +1,7 @@
+RemoveLink - BLOB Link
+:memory: #use in-memory database
+SELECT ST_RemoveLink('net', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink('net', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink8.testcase b/test/sql_stmt_lwgeom_22_tests/remlink8.testcase
new file mode 100644
index 0000000..fc515be
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink8.testcase
@@ -0,0 +1,7 @@
+RemoveLink - Text Link
+:memory: #use in-memory database
+SELECT ST_RemoveLink('net', 'node');
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink('net', 'link')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/remlink9.testcase b/test/sql_stmt_lwgeom_22_tests/remlink9.testcase
new file mode 100644
index 0000000..e3acb93
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/remlink9.testcase
@@ -0,0 +1,7 @@
+RemoveLink - NULL Link
+:memory: #use in-memory database
+SELECT ST_RemoveLink('net', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_RemoveLink('net', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer1.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer1.testcase
new file mode 100644
index 0000000..7b9ffc0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer(NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer(NULL, 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer2.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer2.testcase
new file mode 100644
index 0000000..a2e83c7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer(1, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer(1, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer3.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer3.testcase
new file mode 100644
index 0000000..708234f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer(1.5, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer(1.5, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer4.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer4.testcase
new file mode 100644
index 0000000..1cad3b3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer(zeroblob(4), 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer(zeroblob(4), 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer5.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer5.testcase
new file mode 100644
index 0000000..4aa0521
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer6.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer6.testcase
new file mode 100644
index 0000000..5b2fd17
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - TEXT TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer('topology', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer('topology', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer7.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer7.testcase
new file mode 100644
index 0000000..b8d42a5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - INT TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer('topology', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer('topology', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer8.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer8.testcase
new file mode 100644
index 0000000..cd7ac72
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - Double TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer('topology', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer('topology', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/removetopolayer9.testcase b/test/sql_stmt_lwgeom_22_tests/removetopolayer9.testcase
new file mode 100644
index 0000000..6ba9aa3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/removetopolayer9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_RemoveTopoLayer - BLOB TopoLayer
+:memory: #use in-memory database
+SELECT TopoGeo_RemoveTopoLayer('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_RemoveTopoLayer('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom1.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom1.testcase
new file mode 100644
index 0000000..7ed93db
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom1.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - NULL Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom(NULL, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom(NULL, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom10.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom10.testcase
new file mode 100644
index 0000000..de21dcf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom10.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - non existing Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom('network', MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom('network', MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom2.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom2.testcase
new file mode 100644
index 0000000..5aa2b53
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom2.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - Int Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom(1, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom(1, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom3.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom3.testcase
new file mode 100644
index 0000000..c0cf1f7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom3.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - Double Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom(1.5, MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom(1.5, MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom4.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom4.testcase
new file mode 100644
index 0000000..26be2d3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom4.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - BLOB Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom(zeroblob(4), MakePoint(1, 2, 4326));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom(zeroblob(4), MakePoint(1, 2, 4326))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom5.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom5.testcase
new file mode 100644
index 0000000..3479c68
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom5.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - NULL GeomCollection
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom('network', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom('network', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom6.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom6.testcase
new file mode 100644
index 0000000..fdbba22
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom6.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - Int GeomCollection
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom('network', 1);
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom('network', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom7.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom7.testcase
new file mode 100644
index 0000000..8c07947
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom7.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - Double GeomCollection
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom('network', 1.4);
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom('network', 1.4)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom8.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom8.testcase
new file mode 100644
index 0000000..b6071eb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom8.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - Text GeomCollection
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom('network', 'geom');
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom('network', 'geom')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom9.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom9.testcase
new file mode 100644
index 0000000..5c3aa37
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromgeom9.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromGeom - Invalid BLOB GeomCollection
+:memory: #use in-memory database
+SELECT ST_SpatNetFromGeom('network', zeroblob(100));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromGeom('network', zeroblob(100))
+SQL/MM Spatial exception - not a Geometry.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo1.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo1.testcase
new file mode 100644
index 0000000..82b07f7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo1.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - NULL Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo(NULL, 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo(NULL, 'topology')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo2.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo2.testcase
new file mode 100644
index 0000000..722d125
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo2.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - Int Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo(1, 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo(1, 'topology')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo3.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo3.testcase
new file mode 100644
index 0000000..65494d0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo3.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - Double Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo(1.5, 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo(1.5, 'topology')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo4.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo4.testcase
new file mode 100644
index 0000000..00d4f65
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo4.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - Blob Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo(zeroblob(4), 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo(zeroblob(4), 'topology')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo5.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo5.testcase
new file mode 100644
index 0000000..f14f158
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo5.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - Text Network
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo('network', 'topology');
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo('network', 'topology')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo6.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo6.testcase
new file mode 100644
index 0000000..739504f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo6.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - NULL Topology
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo('network', NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo('network', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo7.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo7.testcase
new file mode 100644
index 0000000..100f6df
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo7.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - INT Topology
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo('network', 1);
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo('network', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo8.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo8.testcase
new file mode 100644
index 0000000..1fec323
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo8.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - Double Topology
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo('network', 1.2);
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo('network', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo9.testcase b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo9.testcase
new file mode 100644
index 0000000..44aaaa3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/spatnetfromtgeo9.testcase
@@ -0,0 +1,7 @@
+ST_SpatNetFromTGeo - BLOB Topology
+:memory: #use in-memory database
+SELECT ST_SpatNetFromTGeo('network', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_SpatNetFromTGeo('network', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_tests/st_asx3d25.testcase b/test/sql_stmt_lwgeom_22_tests/st_asx3d25.testcase
similarity index 65%
rename from test/sql_stmt_lwgeom_tests/st_asx3d25.testcase
rename to test/sql_stmt_lwgeom_22_tests/st_asx3d25.testcase
index e449650..f060233 100644
--- a/test/sql_stmt_lwgeom_tests/st_asx3d25.testcase
+++ b/test/sql_stmt_lwgeom_22_tests/st_asx3d25.testcase
@@ -4,4 +4,4 @@ SELECT ST_AsX3D(GeomFromText('GEOMETRYCOLLECTIONZ(LINESTRINGZ(10.12345678 10.987
 1 # rows (not including the header row)
 1 # columns
 ST_AsX3D(GeomFromText('GEOMETRYCOLLECTIONZ(LINESTRINGZ(10.12345678 10.98765432 101.123, 11 10 102, 11.321 11.12 103.6453128), POINTZ(15.1234567 14.7654321 7.654321))', 4326), 6, 0)
-<MultiGeometry srsName="epsg:4326"><geometryMember>15.123457 14.765432 7.654321</geometryMember><geometryMember><LineSet  vertexCount='3'><Coordinate point='10.123457 10.987654 101.123 11 10 102 11.321 11.12 103.645313' /></LineSet></geometryMember></MultiGeometry>:0
+<Shape>15.123457 14.765432 7.654321<Shape><LineSet  vertexCount='3'><Coordinate point='10.123457 10.987654 101.123 11 10 102 11.321 11.12 103.645313' /></LineSet>
diff --git a/test/sql_stmt_lwgeom_tests/st_asx3d26.testcase b/test/sql_stmt_lwgeom_22_tests/st_asx3d26.testcase
similarity index 64%
rename from test/sql_stmt_lwgeom_tests/st_asx3d26.testcase
rename to test/sql_stmt_lwgeom_22_tests/st_asx3d26.testcase
index 9195e9e..2053385 100644
--- a/test/sql_stmt_lwgeom_tests/st_asx3d26.testcase
+++ b/test/sql_stmt_lwgeom_22_tests/st_asx3d26.testcase
@@ -4,4 +4,4 @@ SELECT ST_AsX3D(GeomFromText('GEOMETRYCOLLECTIONZ(LINESTRINGZ(10.12345678 10.987
 1 # rows (not including the header row)
 1 # columns
 ST_AsX3D(GeomFromText('GEOMETRYCOLLECTIONZ(LINESTRINGZ(10.12345678 10.98765432 101.123, 11 10 102, 11.321 11.12 103.6453128), POINTZ(15.1234567 14.7654321 7.654321))', 4326), 6, 1)
-<MultiGeometry srsName="urn:ogc:def:crs:epsg::4326"><geometryMember>15.123457 14.765432 7.654321</geometryMember><geometryMember><LineSet  vertexCount='3'><Coordinate point='10.123457 10.987654 101.123 11 10 102 11.321 11.12 103.645313' /></LineSet></geometryMember></MultiGeometry>:0
+<Shape>14.765432 15.123457 7.654321<Shape><LineSet  vertexCount='3'><Coordinate point='10.987654 10.123457 101.123 10 11 102 11.12 11.321 103.645313' /></LineSet>
diff --git a/test/sql_stmt_lwgeom_tests/st_asx3d30.testcase b/test/sql_stmt_lwgeom_22_tests/st_asx3d30.testcase
similarity index 62%
rename from test/sql_stmt_lwgeom_tests/st_asx3d30.testcase
rename to test/sql_stmt_lwgeom_22_tests/st_asx3d30.testcase
index 5635b22..8404e6c 100644
--- a/test/sql_stmt_lwgeom_tests/st_asx3d30.testcase
+++ b/test/sql_stmt_lwgeom_22_tests/st_asx3d30.testcase
@@ -4,4 +4,5 @@ SELECT ST_AsX3D(GeomFromText('GEOMETRYCOLLECTIONZ(LINESTRINGZ(10.12345678 10.987
 1 # rows (not including the header row)
 1 # columns
 ST_AsX3D(GeomFromText('GEOMETRYCOLLECTIONZ(LINESTRINGZ(10.12345678 10.98765432 101.123, 11 10 102, 11.321 11.12 103.6453128), POINTZ(15.1234567 14.7654321 7.654321))', 4326), 6, 1, 'test_')
-<test_MultiGeometry srsName="urn:ogc:def:crs:epsg::4326"><test_geometryMember>15.123457 14.765432 7.654321</test_geometryMember><test_geometryMember><LineSet test_ vertexCount='3'><Coordinate point='10.123457 10.987654 101.123 11 10 102 11.321 11.12 103.645313' /></LineSet></test_geometryMember></test_MultiGeometry>:0
+<Shapetest_>14.765432 15.123457 7.654321<Shapetest_><LineSet test_ vertexCount='3'><Coordinate point='10.987654 10.123457 101.123 10 11 102 11.12 11.321 103.645313' /></LineSet>
+ 
diff --git a/test/sql_stmt_lwgeom_22_tests/st_split8.testcase b/test/sql_stmt_lwgeom_22_tests/st_split8.testcase
new file mode 100644
index 0000000..96185d6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/st_split8.testcase
@@ -0,0 +1,7 @@
+ST_Split - Line-Multiline (error)
+:memory: #use in-memory database
+SELECT AsText(ST_Split(GeomFromText('LINESTRING(0 1, 10 1)'), GeomFromText('MULTILINESTRING((3 0, 3 3), (5 0, 5 3))')));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_Split(GeomFromText('LINESTRING(0 1, 10 1)'), GeomFromText('MULTILINESTRING((3 0, 3 3), (5 0, 5 3))')))
+MULTILINESTRING((0 1, 3 1), (3 1, 5 1), (5 1, 10 1))
diff --git a/test/sql_stmt_lwgeom_22_tests/topoexception1.testcase b/test/sql_stmt_lwgeom_22_tests/topoexception1.testcase
new file mode 100644
index 0000000..a2976e5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topoexception1.testcase
@@ -0,0 +1,7 @@
+GetLastTopologyException - NULL Topology
+:memory: #use in-memory database
+SELECT GetLastTopologyException(NULL);
+1 # rows (not including the header row)
+1 # columns
+GetLastTopologyException(NULL)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topoexception2.testcase b/test/sql_stmt_lwgeom_22_tests/topoexception2.testcase
new file mode 100644
index 0000000..e69c4df
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topoexception2.testcase
@@ -0,0 +1,7 @@
+GetLastTopologyException - Undefined Topology
+:memory: #use in-memory database
+SELECT GetLastTopologyException('topo');
+1 # rows (not including the header row)
+1 # columns
+GetLastTopologyException('topo')
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline1.testcase
new file mode 100644
index 0000000..b6da0cf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString(NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString(NULL, GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline10.testcase
new file mode 100644
index 0000000..b9e1915
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Double Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline11.testcase
new file mode 100644
index 0000000..67eb924
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - NULL Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline12.testcase
new file mode 100644
index 0000000..934408c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Text Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline13.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline13.testcase
new file mode 100644
index 0000000..e83dd61
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline14.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline14.testcase
new file mode 100644
index 0000000..bc81b54
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Point Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', MakePoint(0, 1, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', MakePoint(0, 1, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline15.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline15.testcase
new file mode 100644
index 0000000..ea910a1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Polygon Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline16.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline16.testcase
new file mode 100644
index 0000000..ca97b7e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - MULTILINESTRING Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', GeomFromText('MULTILINESTRING((0 0, 1 1), (2 2, 3 3))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', GeomFromText('MULTILINESTRING((0 0, 1 1), (2 2, 3 3))', 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline17.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline17.testcase
new file mode 100644
index 0000000..bb4b904
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - NULL Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline2.testcase
new file mode 100644
index 0000000..4526320
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString(1, GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString(1, GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline3.testcase
new file mode 100644
index 0000000..b4ebf7b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString(1.5, GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString(1.5, GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline4.testcase
new file mode 100644
index 0000000..a86106a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString(zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString(zeroblob(4), GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline5.testcase
new file mode 100644
index 0000000..4cd0506
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline6.testcase
new file mode 100644
index 0000000..7cf1dc9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Double Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline7.testcase
new file mode 100644
index 0000000..2a66724
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - BLOB Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline8.testcase
new file mode 100644
index 0000000..8fbc554
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Text Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddline9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddline9.testcase
new file mode 100644
index 0000000..e5b4568
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddline9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddLineString - Int Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddLineString('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddLineString('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint1.testcase
new file mode 100644
index 0000000..d5bcaa3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint(NULL, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint(NULL, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint10.testcase
new file mode 100644
index 0000000..6d50a0c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Double Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', 1.1, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', 1.1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint11.testcase
new file mode 100644
index 0000000..8e016e2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - NULL Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint12.testcase
new file mode 100644
index 0000000..1d821fb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Text Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', 'geom', 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', 'geom', 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint13.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint13.testcase
new file mode 100644
index 0000000..08f2709
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint14.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint14.testcase
new file mode 100644
index 0000000..4e19c85
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Linestring Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', GeomFromText('LINESTRING(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint15.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint15.testcase
new file mode 100644
index 0000000..900cee5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Polygon Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint16.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint16.testcase
new file mode 100644
index 0000000..26c064b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - MULTIPOINT Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', GeomFromText('MULTIPOINT(0 0, 1 1)', 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint17.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint17.testcase
new file mode 100644
index 0000000..c80d7e1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - NULL Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint2.testcase
new file mode 100644
index 0000000..f79b317
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint(1, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint(1, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint3.testcase
new file mode 100644
index 0000000..758497f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint(1.5, MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint(1.5, MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint4.testcase
new file mode 100644
index 0000000..3fdfc99
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint(zeroblob(4), MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint(zeroblob(4),MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint5.testcase
new file mode 100644
index 0000000..ca42c35
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint6.testcase
new file mode 100644
index 0000000..a1a3e27
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Double Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), 0.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), 0.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint7.testcase
new file mode 100644
index 0000000..1433bd5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - BLOB Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint8.testcase
new file mode 100644
index 0000000..313e59a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Text Tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), 'tol');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', MakePoint(1, 2, 4326), 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint9.testcase
new file mode 100644
index 0000000..44c659b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoaddpoint9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_AddPoint - Int Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_AddPoint('topology', -1, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_AddPoint('topology', -1, 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone1.testcase
new file mode 100644
index 0000000..f498e9d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - NULL Topology (origin)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone('a', NULL, 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone('a', NULL, 'destination')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone10.testcase
new file mode 100644
index 0000000..8c1983f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Double db-prefix
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(1.5, 'origin', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 'origin', 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone11.testcase
new file mode 100644
index 0000000..1371a6d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - BLOB db-prefix
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(zeroblob(4), 'origin', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(zeroblob(4), 'origin', 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone12.testcase
new file mode 100644
index 0000000..d3d0060
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Integer db-prefix
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(1, 'origin', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(1, 'origin', 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone2.testcase
new file mode 100644
index 0000000..9375da1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Int Topology (origin)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone('a', 1, 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone('a', 1, 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone3.testcase
new file mode 100644
index 0000000..034ba4d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Double Topology (origin)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, 1.5, 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 1.5, 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone4.testcase
new file mode 100644
index 0000000..1aca175
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Blob Topology (origin)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, zeroblob(4), 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, zeroblob(4), 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone5.testcase
new file mode 100644
index 0000000..43f3ff2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Text Topology (origin)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, 'topology', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 'topology', 'destination')
+SQL/MM Spatial exception - invalid topology name (origin).
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone6.testcase
new file mode 100644
index 0000000..04530ad
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - NULL Topology (destination)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, 'origin', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 'origin', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone7.testcase
new file mode 100644
index 0000000..e5125d0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - INT Topology (destination)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, 'origin', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 'origin', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone8.testcase
new file mode 100644
index 0000000..309920b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - Double Topology (destination)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, 'origin', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 'origin', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoclone9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoclone9.testcase
new file mode 100644
index 0000000..b791857
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoclone9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_Clone - BLOB Topology (destination)
+:memory: #use in-memory database
+SELECT TopoGeo_Clone(NULL, 'origin', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_Clone(NULL, 'origin', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable1.testcase
new file mode 100644
index 0000000..ea4bea7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable(NULL, NULL, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable(NULL, NULL, 'table', NULL, 0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable10.testcase
new file mode 100644
index 0000000..d7fe4a8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - NULL table
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, NULL, NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, NULL, NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable11.testcase
new file mode 100644
index 0000000..a91cc93
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - INT table
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 1, NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 1, NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable12.testcase
new file mode 100644
index 0000000..a1ccbb8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double table
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 1.2, NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 1.2, NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable13.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable13.testcase
new file mode 100644
index 0000000..94118b5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - BLOB table
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, zeroblob(4), NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, zeroblob(4), NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable14.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable14.testcase
new file mode 100644
index 0000000..e7991de
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Text Column
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', 'column', 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', 'column', 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable15.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable15.testcase
new file mode 100644
index 0000000..bf0d69c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Int Column
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', 1, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', 1, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable16.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable16.testcase
new file mode 100644
index 0000000..1ea21ac
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double Column
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', 1.2, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', 1.2, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable17.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable17.testcase
new file mode 100644
index 0000000..6a60bca
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - BLOB Column
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', zeroblob(4), 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', zeroblob(4), 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable18.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable18.testcase
new file mode 100644
index 0000000..e4074c4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable18.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - NULL tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable19.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable19.testcase
new file mode 100644
index 0000000..38dc5cc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable19.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Text tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 'zero');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 'zero')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable2.testcase
new file mode 100644
index 0000000..8828f3c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable(1, NULL, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable(1, NULL, 'table', NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable20.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable20.testcase
new file mode 100644
index 0000000..3347c0b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable20.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - BLOB tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable21.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable21.testcase
new file mode 100644
index 0000000..70cb5b6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable21.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0.001);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0.001)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable22.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable22.testcase
new file mode 100644
index 0000000..59076ac
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable22.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - NULL line-max-points
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, NULL, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable23.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable23.testcase
new file mode 100644
index 0000000..d7b7e6b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable23.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double line-max-points
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, 1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, 1.5, -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable24.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable24.testcase
new file mode 100644
index 0000000..4bce35b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable24.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Text line-max-points
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, 'abc', -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, 'abc', -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable25.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable25.testcase
new file mode 100644
index 0000000..2bfb9cd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable25.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - BLOB line-max-points
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, zeroblob(4), -1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable26.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable26.testcase
new file mode 100644
index 0000000..0a441e6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable26.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Integer line-max-points / Integer max-length
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, -1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable27.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable27.testcase
new file mode 100644
index 0000000..4b247f9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable27.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - NULL max-length
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable28.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable28.testcase
new file mode 100644
index 0000000..6bdea96
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable28.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - BLOB max-length
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable29.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable29.testcase
new file mode 100644
index 0000000..58e3652
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable29.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Text max-length
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, 'abc');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, 'abc')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable3.testcase
new file mode 100644
index 0000000..dddf22f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable(1.5, NULL, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable(1.5, NULL, 'table', NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable30.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable30.testcase
new file mode 100644
index 0000000..7cfbd47
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable30.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double max-length
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, 5000.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0, -1, 5000.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable4.testcase
new file mode 100644
index 0000000..7e463bb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable(zeroblob(4), NULL, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable(zeroblob(4), NULL, 'table', NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable5.testcase
new file mode 100644
index 0000000..caca4ab
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', NULL, 'table', NULL, 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable6.testcase
new file mode 100644
index 0000000..5fdcf7c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', 'a', 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', 'a', 'table', NULL, 0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable7.testcase
new file mode 100644
index 0000000..c07275a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - INT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', 1, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', 1, 'table', NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable8.testcase
new file mode 100644
index 0000000..2ad854a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - Double prefix
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', 1.2, 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', 1.2, 'table', NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeofromtable9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeofromtable9.testcase
new file mode 100644
index 0000000..41332ce
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeofromtable9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_FromGeoTable - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoGeo_FromGeoTable('topology', zeroblob(4), 'table', NULL, 0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_FromGeoTable('topology', zeroblob(4), 'table', NULL, 0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline1.testcase
new file mode 100644
index 0000000..72731ab
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Ok #1
+:memory: #use in-memory database
+SELECT AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 1, 2 3)', 4326), 512, -1));
+1 # rows (not including the header row)
+1 # columns
+AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 1, 2 3)', 4326), 512, -1))
+MULTILINESTRING((0 1, 2 3))
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline10.testcase
new file mode 100644
index 0000000..48b1b6e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Text max points
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), 'alpha', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), 'alpha', 1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline11.testcase
new file mode 100644
index 0000000..fd0c2bf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - BLOB max points
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), zeroblob(4), -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), zeroblob(4), -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline12.testcase
new file mode 100644
index 0000000..5709b22
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - NULL max-length
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), -1, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), -1, NULL)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline13.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline13.testcase
new file mode 100644
index 0000000..13ef75d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - TEXT max-length
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), -1, 'abc');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), -1, 'abc')
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline14.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline14.testcase
new file mode 100644
index 0000000..3a62028
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - BLOB max-length
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), -1, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), -1, zeroblob(4))
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline15.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline15.testcase
new file mode 100644
index 0000000..e2c781c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Int max-length
+:memory: #use in-memory database
+SELECT AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRINGM(1 2 3, 4 5 6)', 4326), -1, 1000));
+1 # rows (not including the header row)
+1 # columns
+AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRINGM(1 2 3, 4 5 6)', 4326), -1, 1000))
+MULTILINESTRING M((1 2 3, 4 5 6))
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline16.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline16.testcase
new file mode 100644
index 0000000..072c581
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Double max-length
+:memory: #use in-memory database
+SELECT AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRINGZM(1 2 3 4, 5 6 7 8)', 4326), -1, 1000.0));
+1 # rows (not including the header row)
+1 # columns
+AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRINGZM(1 2 3 4, 5 6 7 8)', 4326), -1, 1000.0))
+MULTILINESTRING ZM((1 2 3 4, 5 6 7 8))
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline2.testcase
new file mode 100644
index 0000000..aed6875
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Ok #2
+:memory: #use in-memory database
+SELECT AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRINGZ(1 2 3, 4 5 6)', 4326), -1, -1));
+1 # rows (not including the header row)
+1 # columns
+AsText(TopoGeo_SubdivideLines(GeomFromText('LINESTRINGZ(1 2 3, 4 5 6)', 4326), -1, -1))
+MULTILINESTRING Z((1 2 3, 4 5 6))
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline3.testcase
new file mode 100644
index 0000000..1661aa3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - NULL Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(NULL, -1, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(NULL, -1, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline4.testcase
new file mode 100644
index 0000000..a52a879
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Integer Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(1, -1, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(1, -1, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline5.testcase
new file mode 100644
index 0000000..b49eb92
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Double Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(1.2, -1, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(1.2, -1, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline6.testcase
new file mode 100644
index 0000000..82678d5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Text Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines('alpha', -1, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines('alpha', -1, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline7.testcase
new file mode 100644
index 0000000..af3730b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - invalid BLOB Geometry
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(zeroblob(100), -1, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(zeroblob(100), -1, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline8.testcase
new file mode 100644
index 0000000..33b93ef
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - NULL max points
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), NULL, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), NULL, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeosplitline9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeosplitline9.testcase
new file mode 100644
index 0000000..a97d19d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeosplitline9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_SubdivideLines - Double max points
+:memory: #use in-memory database
+SELECT TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), 1.5, -1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_SubdivideLines(GeomFromText('LINESTRING(0 0, 1 1)', 4326), 1.5, -1)
+(NULL)
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable1.testcase
new file mode 100644
index 0000000..60b4495
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable(NULL, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable(NULL, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable10.testcase
new file mode 100644
index 0000000..d8b6229
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - NULL ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, NULL, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, NULL, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable11.testcase
new file mode 100644
index 0000000..1245ca7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - INT ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 1, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 1, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable12.testcase
new file mode 100644
index 0000000..5361297
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Double ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 1.2, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 1.2, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable13.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable13.testcase
new file mode 100644
index 0000000..1a16772
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - BLOB ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, zeroblob(4), NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, zeroblob(4), NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable14.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable14.testcase
new file mode 100644
index 0000000..132507c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Text Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', 'column', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', 'column', 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable15.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable15.testcase
new file mode 100644
index 0000000..981413a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Int Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', 1, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', 1, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable16.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable16.testcase
new file mode 100644
index 0000000..31aeadf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Double Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', 1.2, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', 1.2, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable17.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable17.testcase
new file mode 100644
index 0000000..f9322e0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - BLOB Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', zeroblob(4), 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', zeroblob(4), 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable18.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable18.testcase
new file mode 100644
index 0000000..8c834e6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable18.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - NULL out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable19.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable19.testcase
new file mode 100644
index 0000000..54d9890
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable19.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Double out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable2.testcase
new file mode 100644
index 0000000..09af1db
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable(1, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable(1, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable20.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable20.testcase
new file mode 100644
index 0000000..3982876
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable20.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - BLOB out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable21.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable21.testcase
new file mode 100644
index 0000000..5e5a17d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable21.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Text out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable22.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable22.testcase
new file mode 100644
index 0000000..1d3cc5a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable22.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Text with-spatial-index
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', 'tol');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable23.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable23.testcase
new file mode 100644
index 0000000..a4ce09f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable23.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - BLOB with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable24.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable24.testcase
new file mode 100644
index 0000000..0b86fc5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable24.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Double with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', 1.1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable25.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable25.testcase
new file mode 100644
index 0000000..a20cb4a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable25.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - NULL with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable26.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable26.testcase
new file mode 100644
index 0000000..627ffde
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable26.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Integer with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable3.testcase
new file mode 100644
index 0000000..9a9e8ba
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable(1.5, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable(1.5, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable4.testcase
new file mode 100644
index 0000000..55ff8f7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable(zeroblob(4), NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable(zeroblob(4), NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable5.testcase
new file mode 100644
index 0000000..b690195
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable6.testcase
new file mode 100644
index 0000000..e1c3d1f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', 'a', 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', 'a', 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable7.testcase
new file mode 100644
index 0000000..2b7481e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - INT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', 1, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', 1, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable8.testcase
new file mode 100644
index 0000000..3b45f2b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - Double prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', 1.2, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', 1.2, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototable9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototable9.testcase
new file mode 100644
index 0000000..cdd6ea5
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototable9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTable - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTable('topology', zeroblob(4), 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTable('topology', zeroblob(4), 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen1.testcase
new file mode 100644
index 0000000..252bc45
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - NULL Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize(NULL, NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize(NULL, NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen10.testcase
new file mode 100644
index 0000000..0cbf2ad
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - NULL ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, NULL, NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, NULL, NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen11.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen11.testcase
new file mode 100644
index 0000000..3dcb763
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen11.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - INT ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 1, NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 1, NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen12.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen12.testcase
new file mode 100644
index 0000000..a2267fd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen12.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 1.2, NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 1.2, NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen13.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen13.testcase
new file mode 100644
index 0000000..8f91e47
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen13.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - BLOB ref-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, zeroblob(4), NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, zeroblob(4), NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen14.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen14.testcase
new file mode 100644
index 0000000..8092da4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen14.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Text Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', 'column', 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', 'column', 'out', 10.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen15.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen15.testcase
new file mode 100644
index 0000000..7b2a10c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen15.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Int Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', 1, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', 1, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen16.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen16.testcase
new file mode 100644
index 0000000..fd2d4ba
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen16.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', 1.2, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', 1.2, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen17.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen17.testcase
new file mode 100644
index 0000000..1ace95c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen17.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - BLOB Column
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', zeroblob(4), 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', zeroblob(4), 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen18.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen18.testcase
new file mode 100644
index 0000000..b4c884e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen18.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - NULL out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, NULL, 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, NULL, 10.0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen19.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen19.testcase
new file mode 100644
index 0000000..fd5bd99
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen19.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 1.2, 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 1.2, 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen2.testcase
new file mode 100644
index 0000000..160a29e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Int Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize(1, NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize(1, NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen20.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen20.testcase
new file mode 100644
index 0000000..4c33efe
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen20.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - BLOB out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, zeroblob(4), 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, zeroblob(4), 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen21.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen21.testcase
new file mode 100644
index 0000000..35883b4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen21.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Text out-table
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen22.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen22.testcase
new file mode 100644
index 0000000..d96d166
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen22.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Text tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 'no', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 'no', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen23.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen23.testcase
new file mode 100644
index 0000000..1aa5729
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen23.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - BLOB toleramce
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen24.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen24.testcase
new file mode 100644
index 0000000..50fe582
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen24.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double toleramce
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen25.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen25.testcase
new file mode 100644
index 0000000..9a1a387
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen25.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - NULL toleramce
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen26.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen26.testcase
new file mode 100644
index 0000000..c11a0c7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen26.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Integer tolerance
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen27.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen27.testcase
new file mode 100644
index 0000000..1047d47
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen27.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Text with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, 'no');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, 'no')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen28.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen28.testcase
new file mode 100644
index 0000000..6fea726
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen28.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - BLOB with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen29.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen29.testcase
new file mode 100644
index 0000000..877b421
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen29.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, 1.1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen3.testcase
new file mode 100644
index 0000000..55f02a8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize(1.5, NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize(1.5, NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen30.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen30.testcase
new file mode 100644
index 0000000..339faf6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen30.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - NULL with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen31.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen31.testcase
new file mode 100644
index 0000000..6514231
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen31.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Integer with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0, 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen4.testcase
new file mode 100644
index 0000000..fe2cb70
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Blob Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize(zeroblob(4), NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize(zeroblob(4), NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen5.testcase
new file mode 100644
index 0000000..b7e9aff
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Text Topology
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen6.testcase
new file mode 100644
index 0000000..a6199ee
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', 'a', 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', 'a', 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen7.testcase
new file mode 100644
index 0000000..d49056b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - INT prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', 1, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', 1, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen8.testcase
new file mode 100644
index 0000000..851d114
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - Double prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', 1.2, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', 1.2, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeototablegen9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeototablegen9.testcase
new file mode 100644
index 0000000..df7dc73
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeototablegen9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_ToGeoTableGeneralize - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoGeo_ToGeoTableGeneralize('topology', zeroblob(4), 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_ToGeoTableGeneralize('topology', zeroblob(4), 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds1.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds1.testcase
new file mode 100644
index 0000000..203927e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds1.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - NULL Topology 
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds(NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds(NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds10.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds10.testcase
new file mode 100644
index 0000000..33719b7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds10.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Text mode
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds('topology', 'mode');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds('topology', 'mode')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds2.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds2.testcase
new file mode 100644
index 0000000..4a557ef
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds2.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Int Topology 
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds(1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds(1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds3.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds3.testcase
new file mode 100644
index 0000000..fafb139
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds3.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Double Topology 
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds(1.5);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds(1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds4.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds4.testcase
new file mode 100644
index 0000000..509d030
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds4.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Blob Topology 
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds(zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds5.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds5.testcase
new file mode 100644
index 0000000..86b59b6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds5.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Text Topology 
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds('topology');
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds('topology')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds6.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds6.testcase
new file mode 100644
index 0000000..c5e6f7e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds6.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - NULL mode
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds('topology', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds('topology', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds7.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds7.testcase
new file mode 100644
index 0000000..12af1d7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds7.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Int mode
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds('topology', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds('topology', 1)
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds8.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds8.testcase
new file mode 100644
index 0000000..65fff87
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds8.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Double mode
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds('topology', 1.5);
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds('topology', 1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds9.testcase b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds9.testcase
new file mode 100644
index 0000000..7d6035e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/topogeoupdateseeds9.testcase
@@ -0,0 +1,7 @@
+TopoGeo_UpdateSeeds - Blob mode
+:memory: #use in-memory database
+SELECT TopoGeo_UpdateSeeds('topology', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoGeo_UpdateSeeds('topology', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone1.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone1.testcase
new file mode 100644
index 0000000..f49d6b9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone1.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - NULL Network (origin)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, NULL, 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, NULL, 'destination')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone10.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone10.testcase
new file mode 100644
index 0000000..e6c730f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone10.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Double db-prefix
+:memory: #use in-memory database
+SELECT TopoNet_Clone(1.5, 'origin', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(1.5, 'origin', 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone11.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone11.testcase
new file mode 100644
index 0000000..ae7d778
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone11.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Integer db-prefix
+:memory: #use in-memory database
+SELECT TopoNet_Clone(1, 'origin', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(1, 'origin', 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone12.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone12.testcase
new file mode 100644
index 0000000..b5262fb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone12.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - BLOB db-prefix
+:memory: #use in-memory database
+SELECT TopoNet_Clone(zeroblob(4), 'origin', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(zeroblob(4), 'origin', 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone2.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone2.testcase
new file mode 100644
index 0000000..0b52f15
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone2.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Int Network (origin)
+:memory: #use in-memory database
+SELECT TopoNet_Clone("a", 1, 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone("a", 1, 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone3.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone3.testcase
new file mode 100644
index 0000000..71f38a1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone3.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Double Network (origin)
+:memory: #use in-memory database
+SELECT TopoNet_Clone("a", 1.5, 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone("a", 1.5, 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone4.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone4.testcase
new file mode 100644
index 0000000..1856c72
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone4.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Blob Network (origin)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, zeroblob(4), 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, zeroblob(4), 'destination')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone5.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone5.testcase
new file mode 100644
index 0000000..b6ba2c3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone5.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Text Network (origin)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, 'topology', 'destination');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, 'topology', 'destination')
+SQL/MM Spatial exception - invalid network name (origin).
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone6.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone6.testcase
new file mode 100644
index 0000000..451cbb9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone6.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - NULL Network (destination)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, 'origin', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, 'origin', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone7.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone7.testcase
new file mode 100644
index 0000000..38cae34
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone7.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - INT Network (destination)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, 'origin', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, 'origin', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone8.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone8.testcase
new file mode 100644
index 0000000..94cf346
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone8.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - Double Network (destination)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, 'origin', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, 'origin', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetclone9.testcase b/test/sql_stmt_lwgeom_22_tests/toponetclone9.testcase
new file mode 100644
index 0000000..b07e124
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetclone9.testcase
@@ -0,0 +1,7 @@
+TopoNet_Clone - BLOB Network (destination)
+:memory: #use in-memory database
+SELECT TopoNet_Clone(NULL, 'origin', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_Clone(NULL, 'origin', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable1.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable1.testcase
new file mode 100644
index 0000000..e0d6e1c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable1.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - NULL Network
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable(NULL, NULL, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable(NULL, NULL, 'table', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable10.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable10.testcase
new file mode 100644
index 0000000..209a13a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable10.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - NULL table
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, NULL, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, NULL, NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable11.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable11.testcase
new file mode 100644
index 0000000..6c392f4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable11.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - INT table
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 1, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 1, NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable12.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable12.testcase
new file mode 100644
index 0000000..06f1e4b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable12.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Double table
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 1.2, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 1.2, NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable13.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable13.testcase
new file mode 100644
index 0000000..e5b614e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable13.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - BLOB table
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, zeroblob(4), NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, zeroblob(4), NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable14.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable14.testcase
new file mode 100644
index 0000000..2ad8b75
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable14.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Text Column
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 'table', 'column');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 'table', 'column')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable15.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable15.testcase
new file mode 100644
index 0000000..8df3cd6
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable15.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Int Column
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 'table', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 'table', 1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable16.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable16.testcase
new file mode 100644
index 0000000..6d1b014
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable16.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Double Column
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 'table', 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 'table', 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable17.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable17.testcase
new file mode 100644
index 0000000..6c9196b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable17.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - BLOB Column
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 'table', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 'table', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable2.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable2.testcase
new file mode 100644
index 0000000..e628315
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable2.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Int Network
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable(1, NULL, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable(1, NULL, 'table', NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable3.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable3.testcase
new file mode 100644
index 0000000..8cb16cf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable3.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Double Network
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable(1.5, NULL, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable(1.5, NULL, 'table', NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable4.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable4.testcase
new file mode 100644
index 0000000..c6c4554
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable4.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Blob Network
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable(zeroblob(4), NULL, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable(zeroblob(4), NULL, 'table', NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable5.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable5.testcase
new file mode 100644
index 0000000..38b1055
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable5.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Text Network
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', NULL, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', NULL, 'table', NULL)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable6.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable6.testcase
new file mode 100644
index 0000000..d127d9a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable6.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', 'a', 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', 'a', 'table', NULL)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable7.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable7.testcase
new file mode 100644
index 0000000..950d49f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable7.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - INT prefix
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', 1, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', 1, 'table', NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable8.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable8.testcase
new file mode 100644
index 0000000..f621d03
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable8.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - Double prefix
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', 1.2, 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', 1.2, 'table', NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponetfromtable9.testcase b/test/sql_stmt_lwgeom_22_tests/toponetfromtable9.testcase
new file mode 100644
index 0000000..2c3661f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponetfromtable9.testcase
@@ -0,0 +1,7 @@
+TopoNet_FromGeoTable - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoNet_FromGeoTable('network', zeroblob(4), 'table', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_FromGeoTable('network', zeroblob(4), 'table', NULL)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable1.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable1.testcase
new file mode 100644
index 0000000..b4353dc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable1.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - NULL Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable(NULL, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable(NULL, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable10.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable10.testcase
new file mode 100644
index 0000000..5f592b8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable10.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - NULL ref-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, NULL, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, NULL, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable11.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable11.testcase
new file mode 100644
index 0000000..c7fb39e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable11.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - INT ref-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 1, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 1, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable12.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable12.testcase
new file mode 100644
index 0000000..766e211
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable12.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Double ref-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 1.2, NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 1.2, NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable13.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable13.testcase
new file mode 100644
index 0000000..b400604
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable13.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - BLOB table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, zeroblob(4), NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, zeroblob(4), NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable14.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable14.testcase
new file mode 100644
index 0000000..c98d582
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable14.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Text Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', 'column', 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', 'column', 'out')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable15.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable15.testcase
new file mode 100644
index 0000000..af3680c
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable15.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Int Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', 1, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', 1, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable16.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable16.testcase
new file mode 100644
index 0000000..4940282
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable16.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Double Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', 1.2, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', 1.2, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable17.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable17.testcase
new file mode 100644
index 0000000..f322e21
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable17.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - BLOB Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', zeroblob(4), 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', zeroblob(4), 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable18.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable18.testcase
new file mode 100644
index 0000000..289a5a4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable18.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - NULL out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('topology', NULL, 'table', NULL, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('topology', NULL, 'table', NULL, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable19.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable19.testcase
new file mode 100644
index 0000000..cf53e38
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable19.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Double out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('topology', NULL, 'table', NULL, 1.2);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('topology', NULL, 'table', NULL, 1.2)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable2.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable2.testcase
new file mode 100644
index 0000000..4ff910e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable2.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Int Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable(1, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable(1, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable20.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable20.testcase
new file mode 100644
index 0000000..f9c8376
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable20.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - BLOB out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('topology', NULL, 'table', NULL, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('topology', NULL, 'table', NULL, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable21.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable21.testcase
new file mode 100644
index 0000000..fed7ebb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable21.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Text out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable22.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable22.testcase
new file mode 100644
index 0000000..b71ab30
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable22.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Text with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', 'no');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', 'no')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable23.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable23.testcase
new file mode 100644
index 0000000..4f61322
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable23.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - BLOB with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable24.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable24.testcase
new file mode 100644
index 0000000..67bfc92
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable24.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Double with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', 1.1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable25.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable25.testcase
new file mode 100644
index 0000000..11dd2e9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable25.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - NULL with-spatial-index
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable26.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable26.testcase
new file mode 100644
index 0000000..3cd3858
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable26.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Integer with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out', 1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable3.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable3.testcase
new file mode 100644
index 0000000..54fd361
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable3.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Double Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable(1.5, NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable(1.5, NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable4.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable4.testcase
new file mode 100644
index 0000000..421f9c7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable4.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Blob Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable(zeroblob(4), NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable(zeroblob(4), NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable5.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable5.testcase
new file mode 100644
index 0000000..cd6386a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable5.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Text Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', NULL, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable6.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable6.testcase
new file mode 100644
index 0000000..79656f3
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable6.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', 'a', 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', 'a', 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable7.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable7.testcase
new file mode 100644
index 0000000..18af3a1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable7.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - INT prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', 1, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', 1, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable8.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable8.testcase
new file mode 100644
index 0000000..58b2bdf
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable8.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - Double prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', 1.2, 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', 1.2, 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotable9.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotable9.testcase
new file mode 100644
index 0000000..5a21c54
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotable9.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTable - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTable('network', zeroblob(4), 'table', NULL, 'out');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTable('network', zeroblob(4), 'table', NULL, 'out')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen1.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen1.testcase
new file mode 100644
index 0000000..f5abafb
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen1.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - NULL Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize(NULL, NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize(NULL, NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen10.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen10.testcase
new file mode 100644
index 0000000..3ff2992
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen10.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - NULL ref-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, NULL, NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, NULL, NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen11.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen11.testcase
new file mode 100644
index 0000000..6a149d1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen11.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - INT ref-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 1, NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 1, NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen12.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen12.testcase
new file mode 100644
index 0000000..fe3a22e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen12.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double ref-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 1.2, NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 1.2, NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen13.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen13.testcase
new file mode 100644
index 0000000..61545dd
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen13.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - BLOB table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, zeroblob(4), NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, zeroblob(4), NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen14.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen14.testcase
new file mode 100644
index 0000000..05f2b03
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen14.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Text Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', 'column', 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', 'column', 'out', 10.0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen15.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen15.testcase
new file mode 100644
index 0000000..c5ba512
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen15.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Int Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', 1, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', 1, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen16.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen16.testcase
new file mode 100644
index 0000000..b9dbb5b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen16.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', 1.2, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', 1.2, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen17.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen17.testcase
new file mode 100644
index 0000000..c105792
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen17.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - BLOB Column
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', zeroblob(4), 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', zeroblob(4), 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen18.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen18.testcase
new file mode 100644
index 0000000..da8cb3b
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen18.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - NULL out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('topology', NULL, 'table', NULL, NULL, 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('topology', NULL, 'table', NULL, NULL, 10.0)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen19.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen19.testcase
new file mode 100644
index 0000000..592d050
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen19.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 1.2, 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('topology', NULL, 'table', NULL, 1.2, 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen2.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen2.testcase
new file mode 100644
index 0000000..024a5c2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen2.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Int Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize(1, NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize(1, NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen20.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen20.testcase
new file mode 100644
index 0000000..a72a9c1
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen20.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - BLOB out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('topology', NULL, 'table', NULL, zeroblob(4), 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('topology', NULL, 'table', NULL, zeroblob(4), 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen21.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen21.testcase
new file mode 100644
index 0000000..8ae8e47
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen21.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Text out-table
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen22.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen22.testcase
new file mode 100644
index 0000000..6854830
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen22.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Text tolerance
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 'tol');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 'tol')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen23.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen23.testcase
new file mode 100644
index 0000000..24a5da8
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen23.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - BLOB tolerance
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen24.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen24.testcase
new file mode 100644
index 0000000..c319b08
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen24.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double tolerance
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 1.1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 1.1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen25.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen25.testcase
new file mode 100644
index 0000000..c21ef06
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen25.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - NULL tolerance
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen26.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen26.testcase
new file mode 100644
index 0000000..85c576a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen26.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Integer tolerance
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen27.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen27.testcase
new file mode 100644
index 0000000..67d3610
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen27.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Text with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, 'no');
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, 'no')
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen28.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen28.testcase
new file mode 100644
index 0000000..01da82f
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen28.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - BLOB with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen29.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen29.testcase
new file mode 100644
index 0000000..000e4d9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen29.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, 1.1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, 1.1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen3.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen3.testcase
new file mode 100644
index 0000000..977bd56
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen3.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize(1.5, NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize(1.5, NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen30.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen30.testcase
new file mode 100644
index 0000000..b972b01
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen30.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Integer with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, 1);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, 1)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen31.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen31.testcase
new file mode 100644
index 0000000..e19ce4d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen31.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - NULL with-spatial-inxed
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, NULL);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0, NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen4.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen4.testcase
new file mode 100644
index 0000000..a05733a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen4.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Blob Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize(zeroblob(4), NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize(zeroblob(4), NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen5.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen5.testcase
new file mode 100644
index 0000000..58cfe5e
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen5.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Text Network
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', NULL, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen6.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen6.testcase
new file mode 100644
index 0000000..857af60
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen6.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - TEXT prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', 'a', 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', 'a', 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen7.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen7.testcase
new file mode 100644
index 0000000..a528d56
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen7.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - INT prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', 1, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', 1, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen8.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen8.testcase
new file mode 100644
index 0000000..510e1e4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen8.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - Double prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', 1.2, 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', 1.2, 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/toponettotablegen9.testcase b/test/sql_stmt_lwgeom_22_tests/toponettotablegen9.testcase
new file mode 100644
index 0000000..e0cc314
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/toponettotablegen9.testcase
@@ -0,0 +1,7 @@
+TopoNet_ToGeoTableGeneralize - BLOB prefix
+:memory: #use in-memory database
+SELECT TopoNet_ToGeoTableGeneralize('network', zeroblob(4), 'table', NULL, 'out', 10.0);
+1 # rows (not including the header row)
+1 # columns
+TopoNet_ToGeoTableGeneralize('network', zeroblob(4), 'table', NULL, 'out', 10.0)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validatetopogeo1.testcase b/test/sql_stmt_lwgeom_22_tests/validatetopogeo1.testcase
new file mode 100644
index 0000000..633bef2
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validatetopogeo1.testcase
@@ -0,0 +1,7 @@
+ST_ValidateTopoGeo - NULL Topology
+:memory: #use in-memory database
+SELECT ST_ValidateTopoGeo(NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidateTopoGeo(NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validatetopogeo2.testcase b/test/sql_stmt_lwgeom_22_tests/validatetopogeo2.testcase
new file mode 100644
index 0000000..8c426fc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validatetopogeo2.testcase
@@ -0,0 +1,7 @@
+ST_ValidateTopoGeo - Int Topology
+:memory: #use in-memory database
+SELECT ST_ValidateTopoGeo(1);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidateTopoGeo(1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validatetopogeo3.testcase b/test/sql_stmt_lwgeom_22_tests/validatetopogeo3.testcase
new file mode 100644
index 0000000..fb9a6c9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validatetopogeo3.testcase
@@ -0,0 +1,7 @@
+ST_ValidateTopoGeo - Double Topology
+:memory: #use in-memory database
+SELECT ST_ValidateTopoGeo(1.5);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidateTopoGeo(1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validatetopogeo4.testcase b/test/sql_stmt_lwgeom_22_tests/validatetopogeo4.testcase
new file mode 100644
index 0000000..32aa6dc
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validatetopogeo4.testcase
@@ -0,0 +1,7 @@
+ST_ValidateTopoGeo - Blob Topology
+:memory: #use in-memory database
+SELECT ST_ValidateTopoGeo(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ValidateTopoGeo(zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validatetopogeo5.testcase b/test/sql_stmt_lwgeom_22_tests/validatetopogeo5.testcase
new file mode 100644
index 0000000..03dc517
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validatetopogeo5.testcase
@@ -0,0 +1,7 @@
+ST_ValidateTopoGeo - Text Topology
+:memory: #use in-memory database
+SELECT ST_ValidateTopoGeo('topology');
+1 # rows (not including the header row)
+1 # columns
+ST_ValidateTopoGeo('topology')
+SQL/MM Spatial exception - invalid topology name.
diff --git a/test/sql_stmt_lwgeom_22_tests/validlogicalnet1.testcase b/test/sql_stmt_lwgeom_22_tests/validlogicalnet1.testcase
new file mode 100644
index 0000000..3c84be4
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validlogicalnet1.testcase
@@ -0,0 +1,7 @@
+ST_ValidLogicalNet - NULL Network
+:memory: #use in-memory database
+SELECT ST_ValidLogicalNet(NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidLogicalNet(NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validlogicalnet2.testcase b/test/sql_stmt_lwgeom_22_tests/validlogicalnet2.testcase
new file mode 100644
index 0000000..3f0647d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validlogicalnet2.testcase
@@ -0,0 +1,7 @@
+ST_ValidLogicalNet - Int Network
+:memory: #use in-memory database
+SELECT ST_ValidLogicalNet(1);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidLogicalNet(1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validlogicalnet3.testcase b/test/sql_stmt_lwgeom_22_tests/validlogicalnet3.testcase
new file mode 100644
index 0000000..f0a0183
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validlogicalnet3.testcase
@@ -0,0 +1,7 @@
+ST_ValidLogicalNet - Double Network
+:memory: #use in-memory database
+SELECT ST_ValidLogicalNet(1.5);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidLogicalNet(1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validlogicalnet4.testcase b/test/sql_stmt_lwgeom_22_tests/validlogicalnet4.testcase
new file mode 100644
index 0000000..67afea7
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validlogicalnet4.testcase
@@ -0,0 +1,7 @@
+ST_ValidLogicalNet - Blob Network
+:memory: #use in-memory database
+SELECT ST_ValidLogicalNet(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ValidLogicalNet(zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validlogicalnet5.testcase b/test/sql_stmt_lwgeom_22_tests/validlogicalnet5.testcase
new file mode 100644
index 0000000..cbdf692
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validlogicalnet5.testcase
@@ -0,0 +1,7 @@
+ST_ValidLogicalNet - Text Network
+:memory: #use in-memory database
+SELECT ST_ValidLogicalNet('network');
+1 # rows (not including the header row)
+1 # columns
+ST_ValidLogicalNet('network')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_lwgeom_22_tests/validspatialnet1.testcase b/test/sql_stmt_lwgeom_22_tests/validspatialnet1.testcase
new file mode 100644
index 0000000..f9b23e0
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validspatialnet1.testcase
@@ -0,0 +1,7 @@
+ST_ValidSpatialNet - NULL Network
+:memory: #use in-memory database
+SELECT ST_ValidSpatialNet(NULL);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidSpatialNet(NULL)
+SQL/MM Spatial exception - null argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validspatialnet2.testcase b/test/sql_stmt_lwgeom_22_tests/validspatialnet2.testcase
new file mode 100644
index 0000000..e2dd299
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validspatialnet2.testcase
@@ -0,0 +1,7 @@
+ST_ValidSpatialNet - Int Network
+:memory: #use in-memory database
+SELECT ST_ValidSpatialNet(1);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidSpatialNet(1)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validspatialnet3.testcase b/test/sql_stmt_lwgeom_22_tests/validspatialnet3.testcase
new file mode 100644
index 0000000..981eb2d
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validspatialnet3.testcase
@@ -0,0 +1,7 @@
+ST_ValidSpatialNet - Double Network
+:memory: #use in-memory database
+SELECT ST_ValidSpatialNet(1.5);
+1 # rows (not including the header row)
+1 # columns
+ST_ValidSpatialNet(1.5)
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validspatialnet4.testcase b/test/sql_stmt_lwgeom_22_tests/validspatialnet4.testcase
new file mode 100644
index 0000000..9c1bb57
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validspatialnet4.testcase
@@ -0,0 +1,7 @@
+ST_ValidSpatialNet - Blob Network
+:memory: #use in-memory database
+SELECT ST_ValidSpatialNet(zeroblob(4));
+1 # rows (not including the header row)
+1 # columns
+ST_ValidSpatialNet(zeroblob(4))
+SQL/MM Spatial exception - invalid argument.
diff --git a/test/sql_stmt_lwgeom_22_tests/validspatialnet5.testcase b/test/sql_stmt_lwgeom_22_tests/validspatialnet5.testcase
new file mode 100644
index 0000000..f83be65
--- /dev/null
+++ b/test/sql_stmt_lwgeom_22_tests/validspatialnet5.testcase
@@ -0,0 +1,7 @@
+ST_ValidSpatialNet - Text Network
+:memory: #use in-memory database
+SELECT ST_ValidSpatialNet('network');
+1 # rows (not including the header row)
+1 # columns
+ST_ValidSpatialNet('network')
+SQL/MM Spatial exception - invalid network name.
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_lwgeom_tests/3dlength1.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_lwgeom_tests/3dlength1.testcase
index 29eb76c..769cad7 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_lwgeom_tests/3dlength1.testcase
@@ -1,7 +1,7 @@
-ST_VoronojDiagram - integer input (error)
+3dLength - NULL geometry
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT ST_3dLength(NULL)
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+ST_3dLength(NULL)
 (NULL)
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_lwgeom_tests/3dlength2.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_lwgeom_tests/3dlength2.testcase
index 29eb76c..7b19532 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_lwgeom_tests/3dlength2.testcase
@@ -1,7 +1,7 @@
-ST_VoronojDiagram - integer input (error)
+3dLength - INT geometry
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT ST_3dLength(1)
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+ST_3dLength(1)
 (NULL)
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_lwgeom_tests/3dlength3.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_lwgeom_tests/3dlength3.testcase
index 29eb76c..08bcbf8 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_lwgeom_tests/3dlength3.testcase
@@ -1,7 +1,7 @@
-ST_VoronojDiagram - integer input (error)
+3dLength - DOUBLE geometry
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT ST_3dLength(1.5)
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+ST_3dLength(1.5)
 (NULL)
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_lwgeom_tests/3dlength4.testcase
similarity index 50%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_lwgeom_tests/3dlength4.testcase
index 29eb76c..07907d5 100644
--- a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase
+++ b/test/sql_stmt_lwgeom_tests/3dlength4.testcase
@@ -1,7 +1,7 @@
-ST_VoronojDiagram - integer input (error)
+3dLength - TEXT geometry
 :memory: #use in-memory database
-SELECT ST_VoronojDiagram(1);
+SELECT ST_3dLength('alpha')
 1 # rows (not including the header row)
 1 # columns
-ST_VoronojDiagram(1)
+ST_3dLength('alpha')
 (NULL)
diff --git a/test/sql_stmt_lwgeom_tests/3dlength5.testcase b/test/sql_stmt_lwgeom_tests/3dlength5.testcase
new file mode 100644
index 0000000..1fda4a9
--- /dev/null
+++ b/test/sql_stmt_lwgeom_tests/3dlength5.testcase
@@ -0,0 +1,7 @@
+3dLength - invalid BLOB geometry
+:memory: #use in-memory database
+SELECT ST_3dLength(zeroblob(100))
+1 # rows (not including the header row)
+1 # columns
+ST_3dLength(zeroblob(100))
+(NULL)
diff --git a/test/sql_stmt_lwgeom_tests/3dlength6.testcase b/test/sql_stmt_lwgeom_tests/3dlength6.testcase
new file mode 100644
index 0000000..a8e88aa
--- /dev/null
+++ b/test/sql_stmt_lwgeom_tests/3dlength6.testcase
@@ -0,0 +1,7 @@
+3dLength - Point geometry
+:memory: #use in-memory database
+SELECT ST_3dLength(ST_GeomFromText('POINT(1 2)'))
+1 # rows (not including the header row)
+1 # columns
+ST_3dLength(ST_GeomFromText('POINT(1 2)'))
+(NULL)
diff --git a/test/sql_stmt_lwgeom_tests/3dlength7.testcase b/test/sql_stmt_lwgeom_tests/3dlength7.testcase
new file mode 100644
index 0000000..7aa4d14
--- /dev/null
+++ b/test/sql_stmt_lwgeom_tests/3dlength7.testcase
@@ -0,0 +1,7 @@
+3dLength - 2D linestring
+:memory: #use in-memory database
+SELECT ST_3dLength(ST_GeomFromText('LINESTRING(0 0, 1 0, 1 1, 2 1, 2 2, 3 2, 3 3)'))
+1 # rows (not including the header row)
+1 # columns
+ST_3dLength(ST_GeomFromText('LINESTRING(0 0, 1 0, 1 1, 2 1, 2 2, 3 2, 3 3)'))
+6.0
diff --git a/test/sql_stmt_lwgeom_tests/3dlength8.testcase b/test/sql_stmt_lwgeom_tests/3dlength8.testcase
new file mode 100644
index 0000000..0afd28a
--- /dev/null
+++ b/test/sql_stmt_lwgeom_tests/3dlength8.testcase
@@ -0,0 +1,7 @@
+3dLength - 3D linestring
+:memory: #use in-memory database
+SELECT ST_3dLength(ST_GeomFromText('LINESTRING Z(0 0 0, 1 0 0, 1 0 1, 2 0 1, 2 0 2, 3 0 2, 3 0 3)'))
+1 # rows (not including the header row)
+1 # columns
+ST_3dLength(ST_GeomFromText('LINESTRING Z(0 0 0, 1 0 0, 1 0 1, 2 0 1, 2 0 2, 3 0 2, 3 0 3)'))
+6.0
diff --git a/test/sql_stmt_lwgeom_tests/Makefile.am b/test/sql_stmt_lwgeom_tests/Makefile.am
index 47d7a0c..2f63e2f 100644
--- a/test/sql_stmt_lwgeom_tests/Makefile.am
+++ b/test/sql_stmt_lwgeom_tests/Makefile.am
@@ -9,6 +9,14 @@ EXTRA_DIST = 3ddistance10.testcase \
 	3ddistance7.testcase \
 	3ddistance8.testcase \
 	3ddistance9.testcase \
+	3dlength1.testcase \
+	3dlength2.testcase \
+	3dlength3.testcase \
+	3dlength4.testcase \
+	3dlength5.testcase \
+	3dlength6.testcase \
+	3dlength7.testcase \
+	3dlength8.testcase \
 	3dmaxdistance10.testcase \
 	3dmaxdistance1.testcase \
 	3dmaxdistance2.testcase \
@@ -45,13 +53,10 @@ EXTRA_DIST = 3ddistance10.testcase \
 	st_asx3d22.testcase \
 	st_asx3d23.testcase \
 	st_asx3d24.testcase \
-	st_asx3d25.testcase \
-	st_asx3d26.testcase \
 	st_asx3d27.testcase \
 	st_asx3d28.testcase \
 	st_asx3d29.testcase \
 	st_asx3d2.testcase \
-	st_asx3d30.testcase \
 	st_asx3d3.testcase \
 	st_asx3d4.testcase \
 	st_asx3d5.testcase \
@@ -267,7 +272,6 @@ EXTRA_DIST = 3ddistance10.testcase \
 	st_split5.testcase \
 	st_split6.testcase \
 	st_split7.testcase \
-	st_split8.testcase \
 	st_split9.testcase \
 	st_node1.testcase \
 	st_node2.testcase \
diff --git a/test/sql_stmt_lwgeom_tests/Makefile.in b/test/sql_stmt_lwgeom_tests/Makefile.in
index 9d161ac..34eeb7b 100644
--- a/test/sql_stmt_lwgeom_tests/Makefile.in
+++ b/test/sql_stmt_lwgeom_tests/Makefile.in
@@ -261,6 +261,14 @@ EXTRA_DIST = 3ddistance10.testcase \
 	3ddistance7.testcase \
 	3ddistance8.testcase \
 	3ddistance9.testcase \
+	3dlength1.testcase \
+	3dlength2.testcase \
+	3dlength3.testcase \
+	3dlength4.testcase \
+	3dlength5.testcase \
+	3dlength6.testcase \
+	3dlength7.testcase \
+	3dlength8.testcase \
 	3dmaxdistance10.testcase \
 	3dmaxdistance1.testcase \
 	3dmaxdistance2.testcase \
@@ -297,13 +305,10 @@ EXTRA_DIST = 3ddistance10.testcase \
 	st_asx3d22.testcase \
 	st_asx3d23.testcase \
 	st_asx3d24.testcase \
-	st_asx3d25.testcase \
-	st_asx3d26.testcase \
 	st_asx3d27.testcase \
 	st_asx3d28.testcase \
 	st_asx3d29.testcase \
 	st_asx3d2.testcase \
-	st_asx3d30.testcase \
 	st_asx3d3.testcase \
 	st_asx3d4.testcase \
 	st_asx3d5.testcase \
@@ -519,7 +524,6 @@ EXTRA_DIST = 3ddistance10.testcase \
 	st_split5.testcase \
 	st_split6.testcase \
 	st_split7.testcase \
-	st_split8.testcase \
 	st_split9.testcase \
 	st_node1.testcase \
 	st_node2.testcase \
diff --git a/test/sql_stmt_lwgeom_tests/st_split9.testcase b/test/sql_stmt_lwgeom_tests/st_split9.testcase
index feeefee..05a54e8 100644
--- a/test/sql_stmt_lwgeom_tests/st_split9.testcase
+++ b/test/sql_stmt_lwgeom_tests/st_split9.testcase
@@ -1,7 +1,7 @@
 ST_Split - Polygon-Multiline (error)
 :memory: #use in-memory database
-SELECT ST_Split(GeomFromText('POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))'), GeomFromText('MULTILINESTRING((3 0, 3 3), (5 0, 5 3))'));
+SELECT ST_Split(GeomFromText('POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))'), GeomFromText('MULTILINESTRING((3 -1, 3 11), (5 -1, 5 11))'));
 1 # rows (not including the header row)
 1 # columns
-ST_Split(GeomFromText('POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))'), GeomFromText('MULTILINESTRING((3 0, 3 3), (5 0, 5 3))'))
+ST_Split(GeomFromText('POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))'), GeomFromText('MULTILINESTRING((3 -1, 3 11), (5 -1, 5 11))'))
 (NULL)
diff --git a/test/sql_stmt_tests/Makefile.am b/test/sql_stmt_tests/Makefile.am
index 7967869..a7b8a3e 100644
--- a/test/sql_stmt_tests/Makefile.am
+++ b/test/sql_stmt_tests/Makefile.am
@@ -457,6 +457,21 @@ EXTRA_DIST = addpoint10.testcase \
 	clonetable13.testcase \
 	clonetable14.testcase \
 	clonetable15.testcase \
+	createclonetable1.testcase \
+	createclonetable2.testcase \
+	createclonetable3.testcase \
+	createclonetable4.testcase \
+	createclonetable5.testcase \
+	createclonetable6.testcase \
+	createclonetable7.testcase \
+	createclonetable8.testcase \
+	createclonetable9.testcase \
+	createclonetable10.testcase \
+	createclonetable11.testcase \
+	createclonetable12.testcase \
+	createclonetable13.testcase \
+	createclonetable14.testcase \
+	createclonetable15.testcase \
 	ch_m.testcase \
 	cm_m.testcase \
 	collect10.testcase \
diff --git a/test/sql_stmt_tests/Makefile.in b/test/sql_stmt_tests/Makefile.in
index 07d206f..b47092a 100644
--- a/test/sql_stmt_tests/Makefile.in
+++ b/test/sql_stmt_tests/Makefile.in
@@ -709,6 +709,21 @@ EXTRA_DIST = addpoint10.testcase \
 	clonetable13.testcase \
 	clonetable14.testcase \
 	clonetable15.testcase \
+	createclonetable1.testcase \
+	createclonetable2.testcase \
+	createclonetable3.testcase \
+	createclonetable4.testcase \
+	createclonetable5.testcase \
+	createclonetable6.testcase \
+	createclonetable7.testcase \
+	createclonetable8.testcase \
+	createclonetable9.testcase \
+	createclonetable10.testcase \
+	createclonetable11.testcase \
+	createclonetable12.testcase \
+	createclonetable13.testcase \
+	createclonetable14.testcase \
+	createclonetable15.testcase \
 	ch_m.testcase \
 	cm_m.testcase \
 	collect10.testcase \
diff --git a/test/sql_stmt_tests/collect10.testcase b/test/sql_stmt_tests/collect10.testcase
index 0589aa9..0ba1bcd 100644
--- a/test/sql_stmt_tests/collect10.testcase
+++ b/test/sql_stmt_tests/collect10.testcase
@@ -4,5 +4,5 @@ SELECT AsText(COLLECT(GeomFromText("POINT(1 2)"), GeomFromText("POINTM(4 5 3.2)"
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINT(1 2)"), GeomFromText("POINTM(4 5 3.2)")))
-MULTIPOINT M(1 2 0, 4 5 3.2)
+MULTIPOINT(1 2, 4 5)
 
diff --git a/test/sql_stmt_tests/collect11.testcase b/test/sql_stmt_tests/collect11.testcase
index a58a55e..3fa0207 100644
--- a/test/sql_stmt_tests/collect11.testcase
+++ b/test/sql_stmt_tests/collect11.testcase
@@ -4,5 +4,5 @@ SELECT AsText(COLLECT(GeomFromText("POINT(1 2)"), GeomFromText("POINTZM(4 5 3.2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINT(1 2)"), GeomFromText("POINTZM(4 5 3.2 6)")))
-MULTIPOINT ZM(1 2 0 0, 4 5 3.2 6)
+MULTIPOINT(1 2, 4 5)
 
diff --git a/test/sql_stmt_tests/collect13.testcase b/test/sql_stmt_tests/collect13.testcase
index afc453e..3a80c95 100644
--- a/test/sql_stmt_tests/collect13.testcase
+++ b/test/sql_stmt_tests/collect13.testcase
@@ -4,5 +4,5 @@ SELECT AsText(COLLECT(GeomFromText("POINTZ(4 5 3.2)"), GeomFromText("POINTM(1 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINTZ(4 5 3.2)"), GeomFromText("POINTM(1 2 6)")))
-MULTIPOINT ZM(4 5 3.2 0, 1 2 0 6)
+MULTIPOINT Z(4 5 3.2, 1 2 0)
 
diff --git a/test/sql_stmt_tests/collect14.testcase b/test/sql_stmt_tests/collect14.testcase
index e0ea98e..03aa3ed 100644
--- a/test/sql_stmt_tests/collect14.testcase
+++ b/test/sql_stmt_tests/collect14.testcase
@@ -4,5 +4,5 @@ SELECT AsText(COLLECT(GeomFromText("POINTZ(4 5 3.2)"), GeomFromText("POINTZM(1 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINTZ(4 5 3.2)"), GeomFromText("POINTZM(1 2 6 4)")))
-MULTIPOINT ZM(4 5 3.2 0, 1 2 6 4)
+MULTIPOINT Z(4 5 3.2, 1 2 6)
 
diff --git a/test/sql_stmt_tests/collect15.testcase b/test/sql_stmt_tests/collect15.testcase
index 18791ec..8bd4693 100644
--- a/test/sql_stmt_tests/collect15.testcase
+++ b/test/sql_stmt_tests/collect15.testcase
@@ -4,5 +4,5 @@ SELECT AsText(COLLECT(GeomFromText("POINTM(4 5 3.2)"), GeomFromText("POINTZM(1 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINTM(4 5 3.2)"), GeomFromText("POINTZM(1 2 6 4)")))
-MULTIPOINT ZM(4 5 0 3.2, 1 2 6 4)
+MULTIPOINT M(4 5 3.2, 1 2 4)
 
diff --git a/test/sql_stmt_tests/collect17.testcase b/test/sql_stmt_tests/collect17.testcase
index 3afe019..48d11b6 100644
--- a/test/sql_stmt_tests/collect17.testcase
+++ b/test/sql_stmt_tests/collect17.testcase
@@ -4,5 +4,5 @@ SELECT AsText(COLLECT(GeomFromText("POINTM(4 5 3.2)"), GeomFromText("POINTZ(1 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINTM(4 5 3.2)"), GeomFromText("POINTZ(1 2 6)")))
-MULTIPOINT ZM(4 5 0 3.2, 1 2 6 0)
+MULTIPOINT M(4 5 3.2, 1 2 0)
 
diff --git a/test/sql_stmt_tests/collect24.testcase b/test/sql_stmt_tests/collect24.testcase
index 9a6d94a..775f2af 100644
--- a/test/sql_stmt_tests/collect24.testcase
+++ b/test/sql_stmt_tests/collect24.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("Linestring(1 2, 3 4)"), GeomFromText("LINEST
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("Linestring(1 2, 3 4)"), GeomFromText("LINESTRINGZM(4 5 3.2 6, 1 2 4.6 8, 4 2 3.1 9)")))
-MULTILINESTRING ZM((1 2 0 0, 3 4 0 0), (4 5 3.2 6, 1 2 4.6 8, 4 2 3.1 9))
-
+MULTILINESTRING((1 2, 3 4), (4 5, 1 2, 4 2))
diff --git a/test/sql_stmt_tests/collect25.testcase b/test/sql_stmt_tests/collect25.testcase
index b0684d5..467afed 100644
--- a/test/sql_stmt_tests/collect25.testcase
+++ b/test/sql_stmt_tests/collect25.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("Linestring(1 2, 3 4)"), GeomFromText("LINEST
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("Linestring(1 2, 3 4)"), GeomFromText("LINESTRINGZ(4 5 3.2, 1 2 4.6, 4 2 3.1)")))
-MULTILINESTRING Z((1 2 0, 3 4 0), (4 5 3.2, 1 2 4.6, 4 2 3.1))
-
+MULTILINESTRING((1 2, 3 4), (4 5, 1 2, 4 2))
diff --git a/test/sql_stmt_tests/collect26.testcase b/test/sql_stmt_tests/collect26.testcase
index 075d463..9ffca74 100644
--- a/test/sql_stmt_tests/collect26.testcase
+++ b/test/sql_stmt_tests/collect26.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("Linestring(1 2, 3 4)"), GeomFromText("LINEST
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("Linestring(1 2, 3 4)"), GeomFromText("LINESTRINGM(4 5 3.2, 1 2 4.6, 4 2 3.1)")))
-MULTILINESTRING M((1 2 0, 3 4 0), (4 5 3.2, 1 2 4.6, 4 2 3.1))
-
+MULTILINESTRING((1 2, 3 4), (4 5, 1 2, 4 2))
diff --git a/test/sql_stmt_tests/collect28.testcase b/test/sql_stmt_tests/collect28.testcase
index 21002f7..fcc36ac 100644
--- a/test/sql_stmt_tests/collect28.testcase
+++ b/test/sql_stmt_tests/collect28.testcase
@@ -5,4 +5,3 @@ SELECT AsText(COLLECT(GeomFromText("LINESTRINGZ(1 2 4, 3 4 2)"), GeomFromText("L
 1 # columns
 AsText(COLLECT(GeomFromText("LINESTRINGZ(1 2 4, 3 4 2)"), GeomFromText("LINESTRINGZ(4 5 3.2, 1 2 4.6, 4 2 3.1)")))
 MULTILINESTRING Z((1 2 4, 3 4 2), (4 5 3.2, 1 2 4.6, 4 2 3.1))
-
diff --git a/test/sql_stmt_tests/collect29.testcase b/test/sql_stmt_tests/collect29.testcase
index 85c6ebd..31cd95f 100644
--- a/test/sql_stmt_tests/collect29.testcase
+++ b/test/sql_stmt_tests/collect29.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("LINESTRINGZ(1 2 4, 3 4 2)"), GeomFromText("L
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("LINESTRINGZ(1 2 4, 3 4 2)"), GeomFromText("LINESTRINGZM(4 5 3.2 1, 1 2 4.6 2, 4 2 3.1 3)")))
-MULTILINESTRING ZM((1 2 4 0, 3 4 2 0), (4 5 3.2 1, 1 2 4.6 2, 4 2 3.1 3))
-
+MULTILINESTRING Z((1 2 4, 3 4 2), (4 5 3.2, 1 2 4.6, 4 2 3.1))
diff --git a/test/sql_stmt_tests/collect30.testcase b/test/sql_stmt_tests/collect30.testcase
index 9029b57..7fc4f50 100644
--- a/test/sql_stmt_tests/collect30.testcase
+++ b/test/sql_stmt_tests/collect30.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("LINESTRINGZ(1 2 4, 3 4 2)"), GeomFromText("L
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("LINESTRINGZ(1 2 4, 3 4 2)"), GeomFromText("LINESTRINGM(4 5 1, 1 2 2, 4 2 3)")))
-MULTILINESTRING ZM((1 2 4 0, 3 4 2 0), (4 5 0 1, 1 2 0 2, 4 2 0 3))
-
+MULTILINESTRING Z((1 2 4, 3 4 2), (4 5 0, 1 2 0, 4 2 0))
diff --git a/test/sql_stmt_tests/collect34.testcase b/test/sql_stmt_tests/collect34.testcase
index dd05bb4..2ad0f64 100644
--- a/test/sql_stmt_tests/collect34.testcase
+++ b/test/sql_stmt_tests/collect34.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("LINESTRINGM(1 2 4, 3 4 2)"), GeomFromText("L
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("LINESTRINGM(1 2 4, 3 4 2)"), GeomFromText("LINESTRINGZM(4 5 3.2 1, 1 2 4.6 2, 4 2 3.1 3)")))
-MULTILINESTRING ZM((1 2 0 4, 3 4 0 2), (4 5 3.2 1, 1 2 4.6 2, 4 2 3.1 3))
-
+MULTILINESTRING M((1 2 4, 3 4 2), (4 5 1, 1 2 2, 4 2 3))
diff --git a/test/sql_stmt_tests/collect35.testcase b/test/sql_stmt_tests/collect35.testcase
index e57c8c6..3391595 100644
--- a/test/sql_stmt_tests/collect35.testcase
+++ b/test/sql_stmt_tests/collect35.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("LINESTRINGM(1 2 4, 3 4 2)"), GeomFromText("L
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("LINESTRINGM(1 2 4, 3 4 2)"), GeomFromText("LINESTRINGZ(4 5 3.2, 1 2 4.6, 4 2 3.1)")))
-MULTILINESTRING ZM((1 2 0 4, 3 4 0 2), (4 5 3.2 0, 1 2 4.6 0, 4 2 3.1 0))
-
+MULTILINESTRING M((1 2 4, 3 4 2), (4 5 0, 1 2 0, 4 2 0))
diff --git a/test/sql_stmt_tests/collect41.testcase b/test/sql_stmt_tests/collect41.testcase
index fd979df..2971f8d 100644
--- a/test/sql_stmt_tests/collect41.testcase
+++ b/test/sql_stmt_tests/collect41.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGONZ((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGONZ((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4))"), GeomFromText("POLYGONZM((4 5 3.2 4, 1 2 4.6 5, 4 2 3.1 3, 4 5 3.2 4),(2 3 4 1, 3 4 1 2, 3 3 1 3, 2 3 4 1))")));
-MULTIPOLYGON ZM(((1 2 4 0, 3 4 2 0, 3 2 3 0, 1 2 4 0), (1.5 2.5 4 0, 2.5 3.5 3 0, 2.5 2.3 3 0, 1.5 2.5 4 0)), ((4 5 3.2 4, 1 2 4.6 5, 4 2 3.1 3, 4 5 3.2 4), (2 3 4 1, 3 4 1 2, 3 3 1 3, 2 3 4 1)))
-
+MULTIPOLYGON Z(((1 2 4, 3 4 2, 3 2 3, 1 2 4), (1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4)), ((4 5 3.2, 1 2 4.6, 4 2 3.1, 4 5 3.2), (2 3 4, 3 4 1, 3 3 1, 2 3 4)))
diff --git a/test/sql_stmt_tests/collect42.testcase b/test/sql_stmt_tests/collect42.testcase
index 43cd402..6f7aae2 100644
--- a/test/sql_stmt_tests/collect42.testcase
+++ b/test/sql_stmt_tests/collect42.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGONZ((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGONZ((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4))"), GeomFromText("POLYGONM((4 5 4, 1 2 5, 4 2 3, 4 5 4),(2 3 1, 3 4 2, 3 3 3, 2 3 1))")))
-MULTIPOLYGON ZM(((1 2 4 0, 3 4 2 0, 3 2 3 0, 1 2 4 0), (1.5 2.5 4 0, 2.5 3.5 3 0, 2.5 2.3 3 0, 1.5 2.5 4 0)), ((4 5 0 4, 1 2 0 5, 4 2 0 3, 4 5 0 4), (2 3 0 1, 3 4 0 2, 3 3 0 3, 2 3 0 1)))
-
+MULTIPOLYGON Z(((1 2 4, 3 4 2, 3 2 3, 1 2 4), (1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4)), ((4 5 0, 1 2 0, 4 2 0, 4 5 0), (2 3 0, 3 4 0, 3 3 0, 2 3 0)))
diff --git a/test/sql_stmt_tests/collect44.testcase b/test/sql_stmt_tests/collect44.testcase
index 773c912..d170332 100644
--- a/test/sql_stmt_tests/collect44.testcase
+++ b/test/sql_stmt_tests/collect44.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGON((1 2, 3 4, 3 2, 1 2),(1.5 2.5, 2.5 3
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGON((1 2, 3 4, 3 2, 1 2),(1.5 2.5, 2.5 3.5, 2.5 2.3, 1.5 2.5))"), GeomFromText("POLYGONZM((4 5 3.2 4, 1 2 4.6 5, 4 2 3.1 3, 4 5 3.2 4),(2 3 4 1, 3 4 1 2, 3 3 1 3, 2 3 4 1))")))
-MULTIPOLYGON ZM(((1 2 0 0, 3 4 0 0, 3 2 0 0, 1 2 0 0), (1.5 2.5 0 0, 2.5 3.5 0 0, 2.5 2.3 0 0, 1.5 2.5 0 0)), ((4 5 3.2 4, 1 2 4.6 5, 4 2 3.1 3, 4 5 3.2 4), (2 3 4 1, 3 4 1 2, 3 3 1 3, 2 3 4 1)))
-
+MULTIPOLYGON(((1 2, 3 4, 3 2, 1 2), (1.5 2.5, 2.5 3.5, 2.5 2.3, 1.5 2.5)), ((4 5, 1 2, 4 2, 4 5), (2 3, 3 4, 3 3, 2 3)))
diff --git a/test/sql_stmt_tests/collect45.testcase b/test/sql_stmt_tests/collect45.testcase
index d2af3f6..c3b3f87 100644
--- a/test/sql_stmt_tests/collect45.testcase
+++ b/test/sql_stmt_tests/collect45.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGON((1 2, 3 4, 3 2, 1 2),(1.5 2.5, 2.5 3
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGON((1 2, 3 4, 3 2, 1 2),(1.5 2.5, 2.5 3.5, 2.5 2.3, 1.5 2.5))"), GeomFromText("POLYGONZ((4 5 3.2, 1 2 4.6, 4 2 3.1, 4 5 3.2),(2 3 4, 3 4 1, 3 3 1, 2 3 4))")))
-MULTIPOLYGON Z(((1 2 0, 3 4 0, 3 2 0, 1 2 0), (1.5 2.5 0, 2.5 3.5 0, 2.5 2.3 0, 1.5 2.5 0)), ((4 5 3.2, 1 2 4.6, 4 2 3.1, 4 5 3.2), (2 3 4, 3 4 1, 3 3 1, 2 3 4)))
-
+MULTIPOLYGON(((1 2, 3 4, 3 2, 1 2), (1.5 2.5, 2.5 3.5, 2.5 2.3, 1.5 2.5)), ((4 5, 1 2, 4 2, 4 5), (2 3, 3 4, 3 3, 2 3)))
diff --git a/test/sql_stmt_tests/collect46.testcase b/test/sql_stmt_tests/collect46.testcase
index 8c04d88..7581884 100644
--- a/test/sql_stmt_tests/collect46.testcase
+++ b/test/sql_stmt_tests/collect46.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGON((1 2, 3 4, 3 2, 1 2),(1.5 2.5, 2.5 3
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGON((1 2, 3 4, 3 2, 1 2),(1.5 2.5, 2.5 3.5, 2.5 2.3, 1.5 2.5))"), GeomFromText("POLYGONM((4 5 3.2, 1 2 4.6, 4 2 3.1, 4 5 3.2),(2 3 4, 3 4 1, 3 3 1, 2 3 4))")))
-MULTIPOLYGON M(((1 2 0, 3 4 0, 3 2 0, 1 2 0), (1.5 2.5 0, 2.5 3.5 0, 2.5 2.3 0, 1.5 2.5 0)), ((4 5 3.2, 1 2 4.6, 4 2 3.1, 4 5 3.2), (2 3 4, 3 4 1, 3 3 1, 2 3 4)))
-
+MULTIPOLYGON(((1 2, 3 4, 3 2, 1 2), (1.5 2.5, 2.5 3.5, 2.5 2.3, 1.5 2.5)), ((4 5, 1 2, 4 2, 4 5), (2 3, 3 4, 3 3, 2 3)))
diff --git a/test/sql_stmt_tests/collect48.testcase b/test/sql_stmt_tests/collect48.testcase
index 0a8ce37..1e9c45c 100644
--- a/test/sql_stmt_tests/collect48.testcase
+++ b/test/sql_stmt_tests/collect48.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGONM((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGONM((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4))"), GeomFromText("POLYGONZM((4 5 3.2 4, 1 2 4.6 5, 4 2 3.1 3, 4 5 3.2 4),(2 3 4 1, 3 4 1 2, 3 3 1 3, 2 3 4 1))")));
-MULTIPOLYGON ZM(((1 2 0 4, 3 4 0 2, 3 2 0 3, 1 2 0 4), (1.5 2.5 0 4, 2.5 3.5 0 3, 2.5 2.3 0 3, 1.5 2.5 0 4)), ((4 5 3.2 4, 1 2 4.6 5, 4 2 3.1 3, 4 5 3.2 4), (2 3 4 1, 3 4 1 2, 3 3 1 3, 2 3 4 1)))
-
+MULTIPOLYGON M(((1 2 4, 3 4 2, 3 2 3, 1 2 4), (1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4)), ((4 5 4, 1 2 5, 4 2 3, 4 5 4), (2 3 1, 3 4 2, 3 3 3, 2 3 1)))
diff --git a/test/sql_stmt_tests/collect49.testcase b/test/sql_stmt_tests/collect49.testcase
index 891ddce..3058e48 100644
--- a/test/sql_stmt_tests/collect49.testcase
+++ b/test/sql_stmt_tests/collect49.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POLYGONM((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POLYGONM((1 2 4, 3 4 2, 3 2 3, 1 2 4),(1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4))"), GeomFromText("POLYGONZ((4 5 3.2, 1 2 4.6, 4 2 3.1, 4 5 3.2),(2 3 4, 3 4 1, 3 3 1, 2 3 4))")))
-MULTIPOLYGON ZM(((1 2 0 4, 3 4 0 2, 3 2 0 3, 1 2 0 4), (1.5 2.5 0 4, 2.5 3.5 0 3, 2.5 2.3 0 3, 1.5 2.5 0 4)), ((4 5 3.2 0, 1 2 4.6 0, 4 2 3.1 0, 4 5 3.2 0), (2 3 4 0, 3 4 1 0, 3 3 1 0, 2 3 4 0)))
-
+MULTIPOLYGON M(((1 2 4, 3 4 2, 3 2 3, 1 2 4), (1.5 2.5 4, 2.5 3.5 3, 2.5 2.3 3, 1.5 2.5 4)), ((4 5 0, 1 2 0, 4 2 0, 4 5 0), (2 3 0, 3 4 0, 3 3 0, 2 3 0)))
diff --git a/test/sql_stmt_tests/collect9.testcase b/test/sql_stmt_tests/collect9.testcase
index 047a955..3c735a5 100644
--- a/test/sql_stmt_tests/collect9.testcase
+++ b/test/sql_stmt_tests/collect9.testcase
@@ -4,5 +4,4 @@ SELECT AsText(COLLECT(GeomFromText("POINT(1 2)"), GeomFromText("POINTZ(4 5 3.2)"
 1 # rows (not including the header row)
 1 # columns
 AsText(COLLECT(GeomFromText("POINT(1 2)"), GeomFromText("POINTZ(4 5 3.2)")))
-MULTIPOINT Z(1 2 0, 4 5 3.2)
-
+MULTIPOINT(1 2, 4 5)
diff --git a/test/sql_stmt_tests/createclonetable1.testcase b/test/sql_stmt_tests/createclonetable1.testcase
new file mode 100644
index 0000000..ec32a99
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable1.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL db-prefix
+:memory: #use in-memory database
+SELECT CreateClonedTable(NULL, 'in_table', 'out_table', 1)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable(NULL, 'in_table', 'out_table', 1)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable10.testcase b/test/sql_stmt_tests/createclonetable10.testcase
new file mode 100644
index 0000000..65595cd
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable10.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #6
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable11.testcase b/test/sql_stmt_tests/createclonetable11.testcase
new file mode 100644
index 0000000..6355768
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable11.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #7
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable12.testcase b/test/sql_stmt_tests/createclonetable12.testcase
new file mode 100644
index 0000000..fd157ee
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable12.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #8
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable13.testcase b/test/sql_stmt_tests/createclonetable13.testcase
new file mode 100644
index 0000000..58c8dbd
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable13.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #9
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', 'opt8', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', 'opt8', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable14.testcase b/test/sql_stmt_tests/createclonetable14.testcase
new file mode 100644
index 0000000..5c6639e
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable14.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #10
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', 'opt8', 'opt9', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', 'opt8', 'opt9', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable15.testcase b/test/sql_stmt_tests/createclonetable15.testcase
new file mode 100644
index 0000000..0cdc0ee
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable15.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - not existing input
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', 'opt8', 'opt9', 'opt10')
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'opt1', 'opt2', 'opt3', 'opt4', 'opt5', 'opt6', 'opt7', 'opt8', 'opt9', 'opt10')
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable2.testcase b/test/sql_stmt_tests/createclonetable2.testcase
new file mode 100644
index 0000000..79ccbf2
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable2.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL input-table
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', NULL, 'out_table', 1)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', NULL, 'out_table', 1)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable3.testcase b/test/sql_stmt_tests/createclonetable3.testcase
new file mode 100644
index 0000000..6473398
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable3.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL output-table
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', NULL, 1)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', NULL, 1)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable4.testcase b/test/sql_stmt_tests/createclonetable4.testcase
new file mode 100644
index 0000000..348eefb
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable4.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL transaction
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable5.testcase b/test/sql_stmt_tests/createclonetable5.testcase
new file mode 100644
index 0000000..913235d
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable5.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #1
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable6.testcase b/test/sql_stmt_tests/createclonetable6.testcase
new file mode 100644
index 0000000..18e04e3
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable6.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #2
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable7.testcase b/test/sql_stmt_tests/createclonetable7.testcase
new file mode 100644
index 0000000..640d50e
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable7.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #3
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', 'option-2', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', 'option-2', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable8.testcase b/test/sql_stmt_tests/createclonetable8.testcase
new file mode 100644
index 0000000..212d42e
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable8.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #4
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', 'option-2', 'opt3', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', 'option-2', 'opt3', NULL)
+(NULL)
diff --git a/test/sql_stmt_tests/createclonetable9.testcase b/test/sql_stmt_tests/createclonetable9.testcase
new file mode 100644
index 0000000..0d3246f
--- /dev/null
+++ b/test/sql_stmt_tests/createclonetable9.testcase
@@ -0,0 +1,7 @@
+CreateClonedTable() - NULL option #5
+:memory: #use in-memory database
+SELECT CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', 'option-2', 'opt3', 'opt4', NULL)
+1 # rows (not including the header row)
+1 # columns
+CreateClonedTable('prefix', 'in_table', 'out_table', 1, 'option-1', 'option-2', 'opt3', 'opt4', NULL)
+(NULL)
diff --git a/test/sql_stmt_voronoj1_tests/Makefile.am b/test/sql_stmt_voronoj1_tests/Makefile.am
new file mode 100644
index 0000000..c7d2c26
--- /dev/null
+++ b/test/sql_stmt_voronoj1_tests/Makefile.am
@@ -0,0 +1,20 @@
+
+EXTRA_DIST =  voronoj10.testcase \
+	voronoj11.testcase \
+	voronoj12.testcase \
+	voronoj13.testcase \
+	voronoj14.testcase \
+	voronoj15.testcase \
+	voronoj16.testcase \
+	voronoj17.testcase \
+	voronoj18.testcase \
+	voronoj19.testcase \
+	voronoj1.testcase \
+	voronoj20.testcase \
+	voronoj2.testcase \
+	voronoj3.testcase \
+	voronoj4.testcase \
+	voronoj5.testcase \
+	voronoj6.testcase \
+	voronoj8.testcase \
+	voronoj9.testcase 
diff --git a/src/srsinit/epsg_update/Makefile.in b/test/sql_stmt_voronoj1_tests/Makefile.in
similarity index 95%
copy from src/srsinit/epsg_update/Makefile.in
copy to test/sql_stmt_voronoj1_tests/Makefile.in
index e0a1169..f743b8b 100644
--- a/src/srsinit/epsg_update/Makefile.in
+++ b/test/sql_stmt_voronoj1_tests/Makefile.in
@@ -87,7 +87,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/srsinit/epsg_update
+subdir = test/sql_stmt_voronoj1_tests
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -251,8 +251,25 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = README.txt README-obsolete.txt auto_epsg.c \
-	epsg_from_gdal.c auto_epsg_ext.c
+EXTRA_DIST = voronoj10.testcase \
+	voronoj11.testcase \
+	voronoj12.testcase \
+	voronoj13.testcase \
+	voronoj14.testcase \
+	voronoj15.testcase \
+	voronoj16.testcase \
+	voronoj17.testcase \
+	voronoj18.testcase \
+	voronoj19.testcase \
+	voronoj1.testcase \
+	voronoj20.testcase \
+	voronoj2.testcase \
+	voronoj3.testcase \
+	voronoj4.testcase \
+	voronoj5.testcase \
+	voronoj6.testcase \
+	voronoj8.testcase \
+	voronoj9.testcase 
 
 all: all-am
 
@@ -266,9 +283,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/srsinit/epsg_update/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/sql_stmt_voronoj1_tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign src/srsinit/epsg_update/Makefile
+	  $(AUTOMAKE) --foreign test/sql_stmt_voronoj1_tests/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj1.testcase b/test/sql_stmt_voronoj1_tests/voronoj1.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj1.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj1.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj10.testcase b/test/sql_stmt_voronoj1_tests/voronoj10.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj10.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj10.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj11.testcase b/test/sql_stmt_voronoj1_tests/voronoj11.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj11.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj11.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj12.testcase b/test/sql_stmt_voronoj1_tests/voronoj12.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj12.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj12.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj13.testcase b/test/sql_stmt_voronoj1_tests/voronoj13.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj13.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj13.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj14.testcase b/test/sql_stmt_voronoj1_tests/voronoj14.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj14.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj14.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj15.testcase b/test/sql_stmt_voronoj1_tests/voronoj15.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj15.testcase
rename to test/sql_stmt_voronoj1_tests/voronoj15.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj16.testcase b/test/sql_stmt_voronoj1_tests/voronoj16.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj16.testcase
rename to test/sql_stmt_voronoj1_tests/voronoj16.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj17.testcase b/test/sql_stmt_voronoj1_tests/voronoj17.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj17.testcase
rename to test/sql_stmt_voronoj1_tests/voronoj17.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj18.testcase b/test/sql_stmt_voronoj1_tests/voronoj18.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj18.testcase
rename to test/sql_stmt_voronoj1_tests/voronoj18.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj19.testcase b/test/sql_stmt_voronoj1_tests/voronoj19.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj19.testcase
rename to test/sql_stmt_voronoj1_tests/voronoj19.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj2.testcase b/test/sql_stmt_voronoj1_tests/voronoj2.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj2.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj2.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj20.testcase b/test/sql_stmt_voronoj1_tests/voronoj20.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj20.testcase
rename to test/sql_stmt_voronoj1_tests/voronoj20.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_voronoj1_tests/voronoj3.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj3.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj4.testcase b/test/sql_stmt_voronoj1_tests/voronoj4.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj4.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj4.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj5.testcase b/test/sql_stmt_voronoj1_tests/voronoj5.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj5.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj5.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj6.testcase b/test/sql_stmt_voronoj1_tests/voronoj6.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj6.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj6.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj8.testcase b/test/sql_stmt_voronoj1_tests/voronoj8.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj8.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj8.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj9.testcase b/test/sql_stmt_voronoj1_tests/voronoj9.testcase
similarity index 100%
copy from test/sql_stmt_geosadvanced_tests/voronoj9.testcase
copy to test/sql_stmt_voronoj1_tests/voronoj9.testcase
diff --git a/test/sql_stmt_voronoj2_tests/Makefile.am b/test/sql_stmt_voronoj2_tests/Makefile.am
new file mode 100644
index 0000000..c7d2c26
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/Makefile.am
@@ -0,0 +1,20 @@
+
+EXTRA_DIST =  voronoj10.testcase \
+	voronoj11.testcase \
+	voronoj12.testcase \
+	voronoj13.testcase \
+	voronoj14.testcase \
+	voronoj15.testcase \
+	voronoj16.testcase \
+	voronoj17.testcase \
+	voronoj18.testcase \
+	voronoj19.testcase \
+	voronoj1.testcase \
+	voronoj20.testcase \
+	voronoj2.testcase \
+	voronoj3.testcase \
+	voronoj4.testcase \
+	voronoj5.testcase \
+	voronoj6.testcase \
+	voronoj8.testcase \
+	voronoj9.testcase 
diff --git a/src/srsinit/epsg_update/Makefile.in b/test/sql_stmt_voronoj2_tests/Makefile.in
similarity index 95%
copy from src/srsinit/epsg_update/Makefile.in
copy to test/sql_stmt_voronoj2_tests/Makefile.in
index e0a1169..ca7261f 100644
--- a/src/srsinit/epsg_update/Makefile.in
+++ b/test/sql_stmt_voronoj2_tests/Makefile.in
@@ -87,7 +87,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/srsinit/epsg_update
+subdir = test/sql_stmt_voronoj2_tests
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -251,8 +251,25 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = README.txt README-obsolete.txt auto_epsg.c \
-	epsg_from_gdal.c auto_epsg_ext.c
+EXTRA_DIST = voronoj10.testcase \
+	voronoj11.testcase \
+	voronoj12.testcase \
+	voronoj13.testcase \
+	voronoj14.testcase \
+	voronoj15.testcase \
+	voronoj16.testcase \
+	voronoj17.testcase \
+	voronoj18.testcase \
+	voronoj19.testcase \
+	voronoj1.testcase \
+	voronoj20.testcase \
+	voronoj2.testcase \
+	voronoj3.testcase \
+	voronoj4.testcase \
+	voronoj5.testcase \
+	voronoj6.testcase \
+	voronoj8.testcase \
+	voronoj9.testcase 
 
 all: all-am
 
@@ -266,9 +283,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/srsinit/epsg_update/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/sql_stmt_voronoj2_tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign src/srsinit/epsg_update/Makefile
+	  $(AUTOMAKE) --foreign test/sql_stmt_voronoj2_tests/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj1.testcase b/test/sql_stmt_voronoj2_tests/voronoj1.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj1.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj1.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj10.testcase b/test/sql_stmt_voronoj2_tests/voronoj10.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj10.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj10.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj11.testcase b/test/sql_stmt_voronoj2_tests/voronoj11.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj11.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj11.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj12.testcase b/test/sql_stmt_voronoj2_tests/voronoj12.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj12.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj12.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj13.testcase b/test/sql_stmt_voronoj2_tests/voronoj13.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj13.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj13.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj14.testcase b/test/sql_stmt_voronoj2_tests/voronoj14.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj14.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj14.testcase
diff --git a/test/sql_stmt_voronoj2_tests/voronoj15.testcase b/test/sql_stmt_voronoj2_tests/voronoj15.testcase
new file mode 100644
index 0000000..8f36b7d
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/voronoj15.testcase
@@ -0,0 +1,7 @@
+ST_VoronojDiagram - (only_edges=no)
+:memory: #use in-memory database
+SELECT AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINT(10 5, 15 5, 20 4, 12 3, 17 2, 16 6)'), 0)));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINT(10 5, 15 5, 20 4, 12 3, 17 2, 16 6)'), 0)))
+MULTIPOLYGON(((9.5 2.5, 9.5 6.5, 12.5 6.5, 12.5 5.5, 9.5 2.5)), ((12.5 6.5, 14.5 6.5, 16.9 4.1, 14.5 2.5, 12.5 5.5, 12.5 6.5)), ((19.5 1.5, 14.3 1.5, 14.5 2.5, 16.9 4.1, 17.642857 4.285714, 19.5 1.5)), ((14.3 1.5, 9.5 1.5, 9.5 2.5, 12.5 5.5, 14.5 2.5, 14.3 1.5)), ((14.5 6.5, 18.75 6.5, 17.642857 4.285714, 16.9 4.1, 14.5 6.5)), ((18.75 6.5, 20.5 6.5, 20.5 1.5, 19.5 1.5, 17.642857 4.285714, 18.75 6.5)))
diff --git a/test/sql_stmt_voronoj2_tests/voronoj16.testcase b/test/sql_stmt_voronoj2_tests/voronoj16.testcase
new file mode 100644
index 0000000..b322d78
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/voronoj16.testcase
@@ -0,0 +1,7 @@
+ST_VoronojDiagram - (only_edges=yes)
+:memory: #use in-memory database
+SELECT AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINT(10 5, 15 5, 20 4, 12 3, 17 2, 16 6)'), 1)));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINT(10 5, 15 5, 20 4, 12 3, 17 2, 16 6)'), 1)))
+MULTILINESTRING((9.5 2.5, 9.5 6.5, 12.5 6.5, 12.5 5.5, 9.5 2.5), (12.5 6.5, 14.5 6.5, 16.9 4.1, 14.5 2.5, 12.5 5.5, 12.5 6.5), (19.5 1.5, 14.3 1.5, 14.5 2.5, 16.9 4.1, 17.642857 4.285714, 19.5 1.5), (14.3 1.5, 9.5 1.5, 9.5 2.5, 12.5 5.5, 14.5 2.5, 14.3 1.5), (14.5 6.5, 18.75 6.5, 17.642857 4.285714, 16.9 4.1, 14.5 6.5), (18.75 6.5, 20.5 6.5, 20.5 1.5, 19.5 1.5, 17.642857 4.285714, 18.75 6.5))
diff --git a/test/sql_stmt_voronoj2_tests/voronoj17.testcase b/test/sql_stmt_voronoj2_tests/voronoj17.testcase
new file mode 100644
index 0000000..93b8945
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/voronoj17.testcase
@@ -0,0 +1,7 @@
+ST_VoronojDiagram - (only_edges=no)
+:memory: #use in-memory database
+SELECT AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINTZ(10 5 10, 15 5 11, 20 4 12, 12 3 13, 17 2 14, 16 6 15)'), 0)));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINTZ(10 5 10, 15 5 11, 20 4 12, 12 3 13, 17 2 14, 16 6 15)'), 0)))
+MULTIPOLYGON Z(((9.5 2.5 0, 9.5 6.5 0, 12.5 6.5 0, 12.5 5.5 0, 9.5 2.5 0)), ((12.5 6.5 0, 14.5 6.5 0, 16.9 4.1 0, 14.5 2.5 0, 12.5 5.5 0, 12.5 6.5 0)), ((19.5 1.5 0, 14.3 1.5 0, 14.5 2.5 0, 16.9 4.1 0, 17.642857 4.285714 0, 19.5 1.5 0)), ((14.3 1.5 0, 9.5 1.5 0, 9.5 2.5 0, 12.5 5.5 0, 14.5 2.5 0, 14.3 1.5 0)), ((14.5 6.5 0, 18.75 6.5 0, 17.642857 4.285714 0, 16.9 4.1 0, 14.5 6.5 0)), ((18.75 6.5 0, 20.5 6.5 0, 20.5 1.5 0, 19.5 1.5 0, 17.642857 4.285714 0, 18.75 6.5 0)))
diff --git a/test/sql_stmt_voronoj2_tests/voronoj18.testcase b/test/sql_stmt_voronoj2_tests/voronoj18.testcase
new file mode 100644
index 0000000..380d558
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/voronoj18.testcase
@@ -0,0 +1,7 @@
+ST_VoronojDiagram - XYM (only_edges=no)
+:memory: #use in-memory database
+SELECT AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINTM(10 5 10, 15 5 11, 20 4 12, 12 3 13, 17 2 14, 16 6 15)'), 0)));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINTM(10 5 10, 15 5 11, 20 4 12, 12 3 13, 17 2 14, 16 6 15)'), 0)))
+MULTIPOLYGON M(((9.5 2.5 0, 9.5 6.5 0, 12.5 6.5 0, 12.5 5.5 0, 9.5 2.5 0)), ((12.5 6.5 0, 14.5 6.5 0, 16.9 4.1 0, 14.5 2.5 0, 12.5 5.5 0, 12.5 6.5 0)), ((19.5 1.5 0, 14.3 1.5 0, 14.5 2.5 0, 16.9 4.1 0, 17.642857 4.285714 0, 19.5 1.5 0)), ((14.3 1.5 0, 9.5 1.5 0, 9.5 2.5 0, 12.5 5.5 0, 14.5 2.5 0, 14.3 1.5 0)), ((14.5 6.5 0, 18.75 6.5 0, 17.642857 4.285714 0, 16.9 4.1 0, 14.5 6.5 0)), ((18.75 6.5 0, 20.5 6.5 0, 20.5 1.5 0, 19.5 1.5 0, 17.642857 4.285714 0, 18.75 6.5 0)))
diff --git a/test/sql_stmt_voronoj2_tests/voronoj19.testcase b/test/sql_stmt_voronoj2_tests/voronoj19.testcase
new file mode 100644
index 0000000..76da555
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/voronoj19.testcase
@@ -0,0 +1,7 @@
+ST_VoronojDiagram - XYZM (only_edges=no)
+:memory: #use in-memory database
+SELECT AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINTZM(10 5 10 1, 15 5 11 2, 20 4 12 3, 12 3 13 4, 17 2 14 5, 16 6 15 6)'), 0)));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINTZM(10 5 10 1, 15 5 11 2, 20 4 12 3, 12 3 13 4, 17 2 14 5, 16 6 15 6)'), 0)))
+MULTIPOLYGON ZM(((9.5 2.5 0 0, 9.5 6.5 0 0, 12.5 6.5 0 0, 12.5 5.5 0 0, 9.5 2.5 0 0)), ((12.5 6.5 0 0, 14.5 6.5 0 0, 16.9 4.1 0 0, 14.5 2.5 0 0, 12.5 5.5 0 0, 12.5 6.5 0 0)), ((19.5 1.5 0 0, 14.3 1.5 0 0, 14.5 2.5 0 0, 16.9 4.1 0 0, 17.642857 4.285714 0 0, 19.5 1.5 0 0)), ((14.3 1.5 0 0, 9.5 1.5 0 0, 9.5 2.5 0 0, 12.5 5.5 0 0, 14.5 2.5 0 0, 14.3 1.5 0 0)), ((14.5 6.5 0 0, 18.75 6.5 0 0, 17.642857 4.285714 0 0, 16.9 4.1 0 0, 14.5 6.5 0 0)), ((18.75 6.5 0 0, 20.5 6.5 0 0, 20.5 1.5 0 0, 19. [...]
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj2.testcase b/test/sql_stmt_voronoj2_tests/voronoj2.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj2.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj2.testcase
diff --git a/test/sql_stmt_voronoj2_tests/voronoj20.testcase b/test/sql_stmt_voronoj2_tests/voronoj20.testcase
new file mode 100644
index 0000000..586b916
--- /dev/null
+++ b/test/sql_stmt_voronoj2_tests/voronoj20.testcase
@@ -0,0 +1,7 @@
+ST_VoronojDiagram - (only_edges=no)
+:memory: #use in-memory database
+SELECT AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINT(5 10, 2 15, 4 20, 3 12, 2 17, 6 16)'), 0)));
+1 # rows (not including the header row)
+1 # columns
+AsText(ST_ForceLHR(ST_VoronojDiagram(GeomFromText('MULTIPOINT(5 10, 2 15, 4 20, 3 12, 2 17, 6 16)'), 0)))
+MULTIPOLYGON(((6.5 18.75, 6.5 12.833333, 5.928571 12.928571, 4.346154 14.115385, 3.875 16, 4.285714 17.642857, 6.5 18.75)), ((1.5 13.166667, 1.5 16, 3.875 16, 4.346154 14.115385, 1.5 13.166667)), ((1.5 16, 1.5 19.5, 4.285714 17.642857, 3.875 16, 1.5 16)), ((2.5 9.5, 1.5 9.5, 1.5 13.166667, 4.346154 14.115385, 5.928571 12.928571, 2.5 9.5)), ((1.5 19.5, 1.5 20.5, 6.5 20.5, 6.5 18.75, 4.285714 17.642857, 1.5 19.5)), ((6.5 12.833333, 6.5 9.5, 2.5 9.5, 5.928571 12.928571, 6.5 12.833333)))
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj3.testcase b/test/sql_stmt_voronoj2_tests/voronoj3.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj3.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj3.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj4.testcase b/test/sql_stmt_voronoj2_tests/voronoj4.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj4.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj4.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj5.testcase b/test/sql_stmt_voronoj2_tests/voronoj5.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj5.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj5.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj6.testcase b/test/sql_stmt_voronoj2_tests/voronoj6.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj6.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj6.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj8.testcase b/test/sql_stmt_voronoj2_tests/voronoj8.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj8.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj8.testcase
diff --git a/test/sql_stmt_geosadvanced_tests/voronoj9.testcase b/test/sql_stmt_voronoj2_tests/voronoj9.testcase
similarity index 100%
rename from test/sql_stmt_geosadvanced_tests/voronoj9.testcase
rename to test/sql_stmt_voronoj2_tests/voronoj9.testcase

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



More information about the Pkg-grass-devel mailing list