Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HANA database provider #893

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 3 additions & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# The main owners and contributes of this project.
* @gdey @ARolek

# Mainter of the gpkg package:
# Maintainer of the gpkg package:
/provider/gpkg @gdey
/ui @ARolek @mapl
# Maintainer of the HANA database provider:
/provider/hana @mrylov
4 changes: 4 additions & 0 deletions .github/workflows/on_pr_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ jobs:
PGSSLKEY: ""
PGSSLCERT: ""
PGSSLROOTCERT: ""

# HANA tests
RUN_HANA_TESTS: yes
HANA_CONNECTION_STRING: "hdb://TEGOLACI:iZgd6$nOdhf@917df316-4e01-4a10-be54-eac1b6ab15fb.hana.prod-us10.hanacloud.ondemand.com:443?TLSInsecureSkipVerify&TLSServerName=host&timeout=1000&max_connections=10"
gdey marked this conversation as resolved.
Show resolved Hide resolved
run: |
go test -mod vendor -covermode atomic -coverprofile=profile.cov ./...

Expand Down
12 changes: 12 additions & 0 deletions atlas/provider_hana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// +build !noHanaProvider

package atlas

// The point of this file is to load and register the HANA provider.
// the HANA provider can be excluded during the build with the `noHanaProvider` build flag
// for example from the cmd/tegola directory:
//
// go build -tags 'noHanaProvider'
import (
_ "github.com/go-spatial/tegola/provider/hana"
)
30 changes: 17 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module github.com/go-spatial/tegola

go 1.17
go 1.18

require (
cloud.google.com/go/storage v1.28.0
github.com/Azure/azure-storage-blob-go v0.0.0-20180706173141-f0a732ea9441
github.com/BurntSushi/toml v0.4.1
github.com/SAP/go-hdb v0.111.9
github.com/ajstarks/svgo v0.0.0-20170507103333-2489f1e6d405
github.com/akrylysov/algnhsa v0.12.1
github.com/aws/aws-sdk-go v1.27.0
Expand All @@ -22,7 +23,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.6
github.com/mattn/goveralls v0.0.5
github.com/pborman/uuid v1.2.0
github.com/prometheus/client_golang v1.9.0
github.com/prometheus/client_golang v1.14.0
github.com/theckman/goconstraint v1.10.1-0.20180216224824-e867bde6e4e1
go.uber.org/zap v1.21.0
gopkg.in/go-playground/colors.v1 v1.0.2-0.20150924111726-b53ecfb39623
Expand All @@ -37,7 +38,7 @@ require (
github.com/arolek/p v0.0.0-20191103215535-df3c295ed582 // indirect
github.com/aws/aws-lambda-go v1.13.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/google/go-cmp v0.5.9 // indirect
Expand All @@ -52,20 +53,23 @@ require (
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/puddle v1.2.0 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.15.0 // indirect
github.com/prometheus/procfs v0.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.26.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.39.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/spf13/pflag v1.0.1 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/exp v0.0.0-20230116083435-1de6713980de // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/oauth2 v0.3.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
golang.org/x/tools v0.2.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.102.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
357 changes: 60 additions & 297 deletions go.sum

Large diffs are not rendered by default.

132 changes: 132 additions & 0 deletions mvtprovider/hana/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# HANA MVT Provider

The HANA MVT provider manages querying for tile requests against a HANA database with [Vector Tiles support](https://help.sap.com/docs/HANA_CLOUD_DATABASE/bc9e455fe75541b8a248b4c09b086cf5/8cd683c4bb664fd8a71fc3f19ffa7e42.html) to handle the MVT encoding at the database.

The connection between tegola and HANA is configured in a `tegola.toml` file. An example minimum connection config:


```toml
[[providers]]
name = "test_hana" # provider name is referenced from map layers (required)
type = "mvt_hana" # the type of data provider must be "mvt_hana" for this data provider (required)
uri = "hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?" # HANA connection string (required)
```

### Connection Properties

- `uri` (string): [Required] HANA connection string
- `name` (string): [Required] provider name is referenced from map layers
- `type` (string): [Required] the type of data provider. must be "hana" to use this data provider
- `srid` (int): [Optional] The default SRID for the provider. Defaults to WebMercator (3857) but also supports WGS84 (4326)

#### Connection string properties

**Example**

```
# {protocol}://{user}:{password}@{host}:{port}/{database}?{options}=
hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?TLSInsecureSkipVerify&timeout=3600&max_connections=30
```

**Options**

- `timeout`: [Optional] Driver side connection timeout in seconds.
- `TLSRootCAFile` [Optional] Path,- filename to root certificate(s).
- `TLSServerName` [Optional] ServerName to verify the hostname. By setting TLSServerName=host, the provider will set TLSServerName same as 'host' value in `uri`.
- `TLSInsecureSkipVerify` [Optional] Controls whether a client verifies the server's certificate chain and host name.
- `max_connections`: [Optional] The max connections to maintain in the connection pool. Defaults to 100. 0 means no max.
- `max_connection_idle_time`: [Optional] The maximum time an idle connection is kept alive. Defaults to "30m".
- `max_connection_life_time` [Optional] The maximum time a connection lives before it is terminated and recreated. Defaults to "1h".

## Provider Layers

In addition to the connection configuration above, Provider Layers need to be configured. A Provider Layer tells tegola how to query HANA for a certain layer. When using the HANA MVT Provider the `ST_AsMVTGeom()` MUST be used. An example minimum config using the `sql` config option:

```toml
[[providers.layers]]
name = "landuse"
# MVT data provider can use both table names and SQL statements. Internally, the provider wraps an SQL query by using
# ST_AsMVT and ST_AsMVTGeom functions.
tablename = "gis.zoning_base_3857"
```

### Provider Layers Properties

- `name` (string): [Required] the name of the layer. This is used to reference this layer from map layers.
- `geometry_fieldname` (string): [Optional] the name of the filed which contains the geometry for the feature. Defaults to `geom`.
- `id_fieldname` (string): [Optional] the name of the feature id field. defaults to `gid`.
- `geometry_type` (string): [Optional] the layer geometry type. If not set, the table will be inspected at startup to try and infer the gemetry type. Valid values are: `Point`, `LineString`, `Polygon`, `MultiPoint`, `MultiLineString`, `MultiPolygon`, `GeometryCollection`.
- `srid` (int): [Optional] the SRID of the layer. Supports `3857` (WebMercator) only.
- `sql` (string): [Required] custom SQL to use use. Supports the following tokens:
- `!BBOX!` - [Required] will be replaced with the bounding box of the tile before the query is sent to the database. `!bbox!` and`!BOX!` are supported as well for compatibilitiy with queries from Mapnik and MapServer styles.
- `!X!` - [Optional] will replaced with the "X" value of the requested tile.
- `!Y!` - [Optional] will replaced with the "Y" value of the requested tile.
- `!Z!` - [Optional] will replaced with the "Z" value of the requested tile.
- `!ZOOM!` - [Optional] will be replaced with the "Z" (zoom) value of the requested tile.
- `!SCALE_DENOMINATOR!` - [Optional] scale denominator, assuming 90.7 DPI (i.e. 0.28mm pixel size)
- `!PIXEL_WIDTH!` - [Optional] the pixel width in meters, assuming 256x256 tiles
- `!PIXEL_HEIGHT!` - [Optional] the pixel height in meters, assuming 256x256 tiles
- `!ID_FIELD!` - [Optional] the id field name
- `!GEOM_FIELD!` - [Optional] the geom field name
- `!GEOM_TYPE!` - [Optional] the geom type if defined otherwise ""
- `buffer` (int): [Optional] the buffer distance by which the clipped geometry may exceed the tile's area. Defaults to 256.
- `clip_geometry` (bool): [Optional] the flag to control whether the geometry is clipped to the tile bounds or not. Defaults to `TRUE`.

## Example mvt_hana and map config

```toml
[[providers]]
name = "test_hana"
type = "mvt_hana"
uri = "hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?" # HANA connection string (required)
srid = 3857 # The only supported srid is 3857 (optional)

[[providers.layers]]
name = "landuse"
sql = "SELECT geom, gid FROM gis.landuse WHERE !BBOX!"

[[maps]]
name = "cities"
center = [-90.2,38.6,3.0] # where to center of the map (lon, lat, zoom)

[[maps.layers]]
name = "landuse"
provider_layer = "test_hana.landuse"
min_zoom = 0
max_zoom = 14
```

## Example mvt_hana and map config for SRID 4326

When using a 4326 projection with ST_AsMVT the SQL statement needs to be modified. `ST_AsMVTGeom` is expecting data in 3857 projection so the geometries and the `!BBOX!` token need to be transformed prior to `ST_AsMVTGeom` processing them. For example:

```toml
[[providers]]
name = "test_hana"
type = "mvt_hana"
uri = "hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?" # HANA connection string (required)
srid = 3857 # The only supported srid is 3857 (optional)

[[providers.layers]]
name = "landuse"
sql = "SELECT * FROM (SELECT id, name, geom.ST_Transform(3857) AS geom FROM ne_50m_rivers_lake_centerlines) AS sub WHERE !BBOX!"

[[maps]]
name = "cities"
center = [-90.2,38.6,3.0] # where to center of the map (lon, lat, zoom)

[[maps.layers]]
name = "landuse"
provider_layer = "test_hana.landuse"
min_zoom = 0
max_zoom = 14
```

## Testing

Testing is designed to work against a live SAP HANA database. To see how to set up a database check this [github actions script](https://github.com/go-spatial/tegola/blob/master/.github/worksflows/on_pr_push.yml). To run the HANA tests, the following environment variables need to be set:

```bash
$ export RUN_HANA_TESTS=yes
$ export HANA_CONNECTION_STRING="hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?TLSInsecureSkipVerify"
```
5 changes: 5 additions & 0 deletions mvtprovider/hana/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Package hana is a placeholder for the SAP HANA database.
// The hana provider is provided by the provider.Hana provider
// please consult that for information on how to use it.
// please note that the provider type will be mvt_hana
package hana
101 changes: 101 additions & 0 deletions provider/hana/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# HANA
The HANA provider manages querying for tile requests against an [SAP HANA](https://www.sap.com/products/hana.html) database. The connection between tegola and HANA is configured in a `tegola.toml` file. An example minimum connection config:


```toml
[[providers]]
name = "test_hana" # provider name is referenced from map layers (required)
type = "hana" # the type of data provider must be "hana" for this data provider (required)
uri = "hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?" # HANA connection string (required)
```

### Connection Properties

- `uri` (string): [Required] HANA connection string
- `name` (string): [Required] provider name is referenced from map layers
- `type` (string): [Required] the type of data provider. must be "hana" to use this data provider
- `srid` (int): [Optional] The default SRID for the provider. Defaults to WebMercator (3857) but also supports WGS84 (4326)

#### Connection string properties

**Example**

```
# {protocol}://{user}:{password}@{host}:{port}/{database}?{options}=
hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?TLSInsecureSkipVerify&timeout=3600&max_connections=30
```

**Options**

- `timeout`: [Optional] Driver side connection timeout in seconds.
- `TLSRootCAFile` [Optional] Path,- filename to root certificate(s).
- `TLSServerName` [Optional] ServerName to verify the hostname. By setting TLSServerName=host, the provider will set TLSServerName same as 'host' value in `uri`.
- `TLSInsecureSkipVerify` [Optional] Controls whether a client verifies the server's certificate chain and host name.
- `max_connections`: [Optional] The max connections to maintain in the connection pool. Defaults to 100. 0 means no max.
- `max_connection_idle_time`: [Optional] The maximum time an idle connection is kept alive. Defaults to "30m".
- `max_connection_life_time` [Optional] The maximum time a connection lives before it is terminated and recreated. Defaults to "1h".

## Provider Layers
In addition to the connection configuration above, Provider Layers need to be configured. A Provider Layer tells tegola how to query HANA for a certain layer. An example minimum config:

```toml
[[providers.layers]]
name = "landuse"
# this table uses "geom" for the geometry_fieldname and "gid" for the id_fieldname so they don't need to be configured
tablename = "gis.zoning_base_3857"
```

### Provider Layers Properties

- `name` (string): [Required] the name of the layer. This is used to reference this layer from map layers.
- `tablename` (string): [*Required] the name of the database table to query against. Required if `sql` is not defined.
- `geometry_fieldname` (string): [Optional] the name of the filed which contains the geometry for the feature. defaults to `geom`.
- `id_fieldname` (string): [Optional] the name of the feature id field. defaults to `gid`.
- `fields` ([]string): [Optional] a list of fields to include alongside the feature. Can be used if `sql` is not defined.
- `srid` (int): [Optional] the SRID of the layer. Supports `3857` (WebMercator) or `4326` (WGS84).
- `geometry_type` (string): [Optional] the layer geometry type. If not set, the table will be inspected at startup to try and infer the gemetry type. Valid values are: `Point`, `LineString`, `Polygon`, `MultiPoint`, `MultiLineString`, `MultiPolygon`, `GeometryCollection`.
- `sql` (string): [*Required] custom SQL to use use. Required if `tablename` is not defined. Supports the following tokens:
- `!BBOX!` - [Required] will be replaced with the bounding box of the tile before the query is sent to the database. `!bbox!` and`!BOX!` are supported as well for compatibilitiy with queries from Mapnik and MapServer styles.
- `!ZOOM!` - [Optional] will be replaced with the "Z" (zoom) value of the requested tile.
- `!X!` - [Optional] will be replaced with the "X" value of the requested tile.
- `!Y!` - [Optional] will be replaced with the "Y" value of the requested tile.
- `!Z!` - [Optional] will be replaced with the "Z" value of the requested tile.
- `!SCALE_DENOMINATOR!` - [Optional] scale denominator, assuming 90.7 DPI (i.e. 0.28mm pixel size).
- `!PIXEL_WIDTH!` - [Optional] the pixel width in meters, assuming 256x256 tiles.
- `!PIXEL_HEIGHT!` - [Optional] the pixel height in meters, assuming 256x256 tiles.
- `!ID_FIELD!` - [Optional] the id field name.
- `!GEOM_FIELD!` - [Optional] the geom field name.
- `!GEOM_TYPE!` - [Optional] the geom type field name.

`*Required`: either the `tablename` or `sql` must be defined, but not both.

**Example minimum custom SQL config**

```toml
[[providers.layers]]
name = "rivers"
# Custom sql to be used for this layer as a sub query. ST_AsBinary and !BBOX! filter are applied automatically.
sql = "(SELECT id, geom FROM gis.rivers) AS sub"
```

## Environment Variable support
Helpful debugging environment variables:

- `TEGOLA_SQL_DEBUG`: specify the type of SQL debug information to output. Supports the following values:
- `LAYER_SQL`: print layer SQL as they’re parsed from the config file.
- `EXECUTE_SQL`: print SQL that is executed for each tile request and the number of items it returns or an error.
- `LAYER_SQL:EXECUTE_SQL`: print `LAYER_SQL` and `EXECUTE_SQL`.

Example:

```
$ TEGOLA_SQL_DEBUG=LAYER_SQL tegola serve --config=/path/to/conf.toml
```

## Testing
Testing is designed to work against a live SAP HANA database. To see how to set up a database check this [github actions script](https://github.com/go-spatial/tegola/blob/master/.github/worksflows/on_pr_push.yml). To run the HANA tests, the following environment variables need to be set:

```bash
$ export RUN_HANA_TESTS=yes
$ export HANA_CONNECTION_STRING="hdb://myuser:mypassword@something.hanacloud.ondemand.com:443?TLSInsecureSkipVerify"
```
27 changes: 27 additions & 0 deletions provider/hana/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package hana

import (
"os"
"strings"
)

// debug determines weather extra debugging output is enabled.
// change debug to true to enable additional debugging output
// for this package
const debug = false

const (
EnvSQLDebugName = "TEGOLA_SQL_DEBUG"
EnvSQLDebugLayer = "LAYER_SQL"
EnvSQLDebugExecute = "EXECUTE_SQL"
)

var (
debugLayerSQL bool
debugExecuteSQL bool
)

func init() {
debugLayerSQL = strings.Contains(os.Getenv(EnvSQLDebugName), EnvSQLDebugLayer)
debugExecuteSQL = strings.Contains(os.Getenv(EnvSQLDebugName), EnvSQLDebugExecute)
}
Loading