Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PostgreSQL 函数源

函数源是一个数据库函数,可用于查询矢量瓦片。启动时,Martin 将查找具有合适签名的函数。

如果函数返回 bytea 值,或返回包含 bytea 和 text 值的记录,则该函数可用作函数源。text 值应该是用户定义的哈希值,例如 MD5 值,最终将用作 ETag。

有效的函数还必须具有以下参数:

参数类型描述
z(或 zoom)integer瓦片缩放参数
xinteger瓦片 x 参数
yinteger瓦片 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 返回 4326 SRID 中的几何,这是示例中存储几何的 SRID。

WHERE geom && ST_Transform(ST_TileEnvelope(z, x, y), 4326)

  • && 是空间交集运算符。因此它检查几何是否与瓦片包络相交并使用空间索引。
  • ST_Transform 用于将瓦片包络从 3857 SRID 转换为 4326 SRID,因为我们示例中的 geom 在 4326 SRID 中。

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$;