PostgreSQL 函数源
函数源是一个数据库函数,可用于查询矢量瓦片。启动时,Martin 将查找具有合适签名的函数。
如果函数返回 bytea 值,或返回包含 bytea 和 text 值的记录,则该函数可用作函数源。text 值应该是用户定义的哈希值,例如 MD5 值,最终将用作 ETag。
有效的函数还必须具有以下参数:
| 参数 | 类型 | 描述 |
|---|---|---|
z(或 zoom) | integer | 瓦片缩放参数 |
x | integer | 瓦片 x 参数 |
y | integer | 瓦片 y 参数 |
query(可选,任意名称) | json | 查询字符串参数 |
带坐标投影的简单函数
例如,如果您有一个在 WGS84(4326 SRID)中具有任意几何的表 table_source。
如果我们需要表的行字段 field_color 和几何 geom 作为函数源,则可以编写为:
CREATE OR REPLACE
FUNCTION function_zxy(z integer, x integer, y integer)
RETURNS bytea AS $$
DECLARE
mvt bytea;
BEGIN
SELECT INTO mvt ST_AsMVT(tile, 'function_zxy', 4096, 'geom') FROM (
SELECT
ST_AsMVTGeom(
ST_Transform(ST_CurveToLine(geom), 3857),
ST_TileEnvelope(z, x, y),
4096, 64, true) AS geom,
field_color AS color
FROM table_source
WHERE geom && ST_Transform(ST_TileEnvelope(z, x, y), 4326)
) as tile WHERE geom IS NOT NULL;
RETURN mvt;
END
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
tip
默认情况下,ST_TileEnvelope 生成 3857 SRID,ST_AsMVTGeom 使用 3857 SRID。
因此,许多工具(例如 osm2pgsql)直接将其数据存储在 3857 SRID 中以降低处理开销。
如果您的数据在 3857 SRID 中,您可以删除两个 ST_Transform 调用。
让我们解释函数的几个方面:
ST_Transform(ST_CurveToLine(geom), 3857)
- 由于示例中的表可以包含任意几何,我们需要转换
CIRCULARSTRING几何类型。 具体来说,我们使用ST_CurveToLine将- CIRCULAR STRING 转换为常规 LINESTRING,
- CURVEPOLYGON 转换为 POLYGON 或
- MULTISURFACE 转换为 MULTIPOLYGON。
ST_Transform是必需的,因为ST_CurveToLine返回4326SRID 中的几何,这是示例中存储几何的 SRID。
WHERE geom && ST_Transform(ST_TileEnvelope(z, x, y), 4326)
&&是空间交集运算符。因此它检查几何是否与瓦片包络相交并使用空间索引。ST_Transform用于将瓦片包络从3857SRID 转换为4326SRID,因为我们示例中的geom在4326SRID 中。
note
规划模式 IMMUTABLE STRICT PARALLEL SAFE 允许 postgres 进一步自由优化我们的函数。
您的函数可能与示例属于同一类别,但要小心不要导致意外行为。
-
IMMUTABLE该函数没有副作用。表示该函数不能修改数据库,并且在给定相同的参数值时始终返回相同的结果; 也就是说,它不执行数据库查找或以其他方式使用不直接存在于其参数列表中的信息。 如果给出此选项,则具有全常量参数的函数的任何调用都可以立即替换为函数值。
-
STRICT:如果任何参数为NULL,则不会调用我们的函数。 -
PARALLEL SAFE: 我们的函数可以安全地并行调用,因为它不修改数据库,也不使用随机性或临时表。如果函数满足以下条件,则应标记为并行不安全
- 修改任何数据库状态,
- 更改事务状态(除了使用子事务进行错误恢复),
- 访问序列(例如,通过调用 currval)或
- 对设置进行持久更改。
如果函数满足以下条件,则应标记为并行受限
- 访问临时表,
- 客户端连接状态,
- 游标,
- 准备好的语句,或
- 系统无法在并行模式下同步的各种后端本地状态 (例如,setseed 只能由组长执行,因为其他进程所做的更改 不会反映在领导者中)。
一般来说,如果函数被标记为安全而实际上是受限或不安全的,或者被标记为受限而实际上是不安全的, 则在并行查询中使用时可能会抛出错误或产生错误答案。 理论上,如果标记错误,C 语言函数可能表现出完全未定义的行为,因为系统无法保护自己免受任意 C 代码的影响, 但在最可能的情况下,结果不会比任何其他函数差。 如有疑问,函数应标记为 UNSAFE,这是默认值。
带查询参数的函数
用户可以添加 query 参数以将附加参数传递给函数。
query_params 参数是瓦片请求查询参数的 JSON 表示。查询参数可以作为简单的查询值传递,例如
curl localhost:3000/function_zxy_query/0/0/0?answer=42
您还可以使用 urlencoded 参数来编码复杂值:
curl \
--data-urlencode 'arrayParam=[1, 2, 3]' \
--data-urlencode 'numberParam=42' \
--data-urlencode 'stringParam=value' \
--data-urlencode 'booleanParam=true' \
--data-urlencode 'objectParam={"answer" : 42}' \
--get localhost:3000/function_zxy_query/0/0/0
然后 query_params 将被解析为:
{
"arrayParam": [1, 2, 3],
"numberParam": 42,
"stringParam": "value",
"booleanParam": true,
"objectParam": { "answer": 42 }
}
您可以使用 json 运算符访问这些参数:
...WHERE answer = (query_params->'objectParam'->>'answer')::int;
作为示例,我们在 WGS84(4326 SRID)中的 table_source 有一个 integer 类型的列 answer。
函数 function_zxy_query 将返回一个 MVT 瓦片,其中 answer 列作为属性。
CREATE OR REPLACE
FUNCTION function_zxy_query(z integer, x integer, y integer, query_params json)
RETURNS bytea AS $$
DECLARE
mvt bytea;
BEGIN
SELECT INTO mvt ST_AsMVT(tile, 'function_zxy_query', 4096, 'geom') FROM (
SELECT
ST_AsMVTGeom(
ST_Transform(ST_CurveToLine(geom), 3857),
ST_TileEnvelope(z, x, y),
4096, 64, true) AS geom
FROM table_source
WHERE geom && ST_Transform(ST_TileEnvelope(z, x, y), 4326) AND
answer = (query_params->>'answer')::int
) as tile WHERE geom IS NOT NULL;
RETURN mvt;
END
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
修改 TileJSON
Martin 将自动为每个函数源生成基本的 TileJSON 清单。
这将包含函数的 name 和 description,以及可选的 minzoom、maxzoom 和 bounds(如果通过配置方法之一指定)。
例如,如果有一个函数 public.function_zxy_query_jsonb,默认的 TileJSON 可能如下所示:
{
"tilejson": "3.0.0",
"tiles": [
"http://localhost:3111/function_zxy_query_jsonb/{z}/{x}/{y}"
],
"name": "function_zxy_query_jsonb",
"description": "public.function_zxy_query_jsonb"
}
note
URL 将自动调整以匹配请求主机
SQL 注释中的 TileJSON
要修改自动生成的 TileJSON,您可以在函数上添加有效的 JSON 作为 SQL 注释。
Martin 将使用 JSON Merge patch 将函数注释合并到生成的 TileJSON 中。
以下示例将 attribution 和 version 字段添加到 TileJSON。
note
此示例使用 EXECUTE 确保注释是有效的 JSON
(否则 PostgreSQL 将抛出错误)。
您可以使用其他创建 SQL 注释的方法。
DO $do$ BEGIN
EXECUTE 'COMMENT ON FUNCTION my_function_name IS $tj$' || $$
{
"description": "my new description",
"attribution": "my attribution",
"vector_layers": [
{
"id": "my_layer_id",
"fields": {
"field1": "String",
"field2": "Number"
}
}
]
}
$$::json || '$tj$';
END $do$;