diff --git a/clouds/bigquery/modules/doc/quadbin/QUADBIN_DISTANCE.md b/clouds/bigquery/modules/doc/quadbin/QUADBIN_DISTANCE.md new file mode 100644 index 000000000..773732c68 --- /dev/null +++ b/clouds/bigquery/modules/doc/quadbin/QUADBIN_DISTANCE.md @@ -0,0 +1,23 @@ +## QUADBIN_DISTANCE + +```sql:signature +QUADBIN_DISTANCE(origin, destination) +``` + +**Description** + +Returns the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance) between two quadbin indexes. The origin and destination indices must have the same resolution. Otherwise `NULL` will be returned. + +* `origin`: `INT64` origin quadbin index. +* `destination`: `INT64` destination quadbin index. + +**Return type** + +`GEOGRAPHY` + +**Example** + +```sql +SELECT carto.QUADBIN_DISTANCE(5207251884775047167, 5207128739472736255); +-- 1 +``` diff --git a/clouds/bigquery/modules/sql/quadbin/QUADBIN_DISTANCE.sql b/clouds/bigquery/modules/sql/quadbin/QUADBIN_DISTANCE.sql new file mode 100644 index 000000000..7bdb8945b --- /dev/null +++ b/clouds/bigquery/modules/sql/quadbin/QUADBIN_DISTANCE.sql @@ -0,0 +1,25 @@ +---------------------------- +-- Copyright (C) 2023 CARTO +---------------------------- + +CREATE OR REPLACE FUNCTION `@@BQ_DATASET@@.QUADBIN_DISTANCE` +(origin INT64, destination INT64) +RETURNS INT64 +AS (( + IF(origin IS NULL OR destination IS NULL, + NULL, + (WITH __quadbin_coords AS ( + SELECT + `@@BQ_DATASET@@.QUADBIN_TOZXY`(origin) AS origin_coords, + `@@BQ_DATASET@@.QUADBIN_TOZXY`(destination) AS destination_coords + ) + SELECT IF(origin_coords.z != destination_coords.z, + NULL, + GREATEST( + ABS(destination_coords.x - origin_coords.x), + ABS(destination_coords.y - origin_coords.y) + ) + ) + FROM __quadbin_coords) + ) +)); diff --git a/clouds/bigquery/modules/test/h3/H3_POLYFILL_TABLE.test.js b/clouds/bigquery/modules/test/h3/H3_POLYFILL_TABLE.test.js index 9675f27f7..c27fe11ae 100644 --- a/clouds/bigquery/modules/test/h3/H3_POLYFILL_TABLE.test.js +++ b/clouds/bigquery/modules/test/h3/H3_POLYFILL_TABLE.test.js @@ -17,4 +17,4 @@ UNNEST(\`@@BQ_DATASET@@.__H3_POLYFILL_INIT\`(geom,\`@@BQ_DATASET@@.__H3_POLYFILL UNNEST(\`@@BQ_DATASET@@.H3_TOCHILDREN\`(parent,12)) AS h3) SELECT * EXCEPT (geom) FROM __cells WHERE ST_INTERSECTS(geom, \`@@BQ_DATASET@@.H3_CENTER\`(h3));`.replace(/@@BQ_DATASET@@/g, BQ_DATASET)); -}); +}); \ No newline at end of file diff --git a/clouds/bigquery/modules/test/quadbin/QUADBIN_DISTANCE.test.js b/clouds/bigquery/modules/test/quadbin/QUADBIN_DISTANCE.test.js new file mode 100644 index 000000000..47a57b191 --- /dev/null +++ b/clouds/bigquery/modules/test/quadbin/QUADBIN_DISTANCE.test.js @@ -0,0 +1,8 @@ +const { runQuery } = require('../../../common/test-utils'); + +test('QUADBIN_DISTANCE should work', async () => { + const query = 'SELECT `@@BQ_DATASET@@.QUADBIN_DISTANCE`(5207251884775047167, 5207128739472736255) AS output'; + const rows = await runQuery(query); + expect(rows.length).toEqual(1); + expect(rows[0].output).toEqual(1); +}); \ No newline at end of file diff --git a/clouds/bigquery/modules/test/quadbin/QUADBIN_POLYFILL_TABLE.test.js b/clouds/bigquery/modules/test/quadbin/QUADBIN_POLYFILL_TABLE.test.js index ff444e35f..977d996a9 100644 --- a/clouds/bigquery/modules/test/quadbin/QUADBIN_POLYFILL_TABLE.test.js +++ b/clouds/bigquery/modules/test/quadbin/QUADBIN_POLYFILL_TABLE.test.js @@ -17,4 +17,4 @@ UNNEST(\`@@BQ_DATASET@@.__QUADBIN_POLYFILL_INIT\`(geom,\`@@BQ_DATASET@@.__QUADBI UNNEST(\`@@BQ_DATASET@@.QUADBIN_TOCHILDREN\`(parent,12)) AS quadbin) SELECT * EXCEPT (geom) FROM __cells WHERE ST_INTERSECTS(geom, \`@@BQ_DATASET@@.QUADBIN_CENTER\`(quadbin));`.replace(/@@BQ_DATASET@@/g, BQ_DATASET)); -}); +}); \ No newline at end of file diff --git a/clouds/postgres/modules/doc/quadbin/QUADBIN_DISTANCE.md b/clouds/postgres/modules/doc/quadbin/QUADBIN_DISTANCE.md new file mode 100644 index 000000000..2d72a8c1d --- /dev/null +++ b/clouds/postgres/modules/doc/quadbin/QUADBIN_DISTANCE.md @@ -0,0 +1,23 @@ +## QUADBIN_DISTANCE + +```sql:signature +QUADBIN_DISTANCE(origin, destination) +``` + +**Description** + +Returns the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance) between two quadbin indexes. The origin and destination indices must have the same resolution. Otherwise `NULL` will be returned. + +* `origin`: `BIGINT` origin quadbin index. +* `destination`: `BIGINT` destination quadbin index. + +**Return type** + +`GEOGRAPHY` + +**Example** + +```sql +SELECT carto.QUADBIN_DISTANCE(5207251884775047167, 5207128739472736255); +-- 1 +``` diff --git a/clouds/postgres/modules/sql/quadbin/QUADBIN_DISTANCE.sql b/clouds/postgres/modules/sql/quadbin/QUADBIN_DISTANCE.sql new file mode 100644 index 000000000..24cb236de --- /dev/null +++ b/clouds/postgres/modules/sql/quadbin/QUADBIN_DISTANCE.sql @@ -0,0 +1,32 @@ +---------------------------- +-- Copyright (C) 2023 CARTO +---------------------------- + +CREATE OR REPLACE FUNCTION @@PG_SCHEMA@@.QUADBIN_DISTANCE +(origin BIGINT, destination BIGINT) +RETURNS BIGINT +AS +$BODY$ + SELECT + CASE WHEN origin IS NULL OR destination IS NULL THEN + NULL + ELSE + (WITH __quadbin_coords AS ( + SELECT + @@PG_SCHEMA@@.QUADBIN_TOZXY(origin) AS origin_coords, + @@PG_SCHEMA@@.QUADBIN_TOZXY(destination) AS destination_coords + ) + SELECT + CASE WHEN (origin_coords->>'z')::INT != (destination_coords->>'z')::INT THEN + NULL + ELSE + GREATEST( + ABS((destination_coords->>'x')::BIGINT - (origin_coords->>'x')::BIGINT), + ABS((destination_coords->>'y')::BIGINT - (origin_coords->>'y')::BIGINT) + ) + END + FROM __quadbin_coords + ) + END +$BODY$ +LANGUAGE sql IMMUTABLE PARALLEL SAFE; diff --git a/clouds/postgres/modules/test/quadbin/test_QUADBIN_DISTANCE.py b/clouds/postgres/modules/test/quadbin/test_QUADBIN_DISTANCE.py new file mode 100644 index 000000000..68bb559c1 --- /dev/null +++ b/clouds/postgres/modules/test/quadbin/test_QUADBIN_DISTANCE.py @@ -0,0 +1,10 @@ +from test_utils import run_query + + +def test_quadbin_resolution(): + """Computes distance between quadbins.""" + result = run_query( + 'SELECT @@PG_SCHEMA@@.QUADBIN_DISTANCE' + '(5207251884775047167, 5207128739472736255)' + ) + assert result[0][0] == 1 diff --git a/clouds/redshift/modules/doc/quadbin/QUADBIN_DISTANCE.md b/clouds/redshift/modules/doc/quadbin/QUADBIN_DISTANCE.md new file mode 100644 index 000000000..2d72a8c1d --- /dev/null +++ b/clouds/redshift/modules/doc/quadbin/QUADBIN_DISTANCE.md @@ -0,0 +1,23 @@ +## QUADBIN_DISTANCE + +```sql:signature +QUADBIN_DISTANCE(origin, destination) +``` + +**Description** + +Returns the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance) between two quadbin indexes. The origin and destination indices must have the same resolution. Otherwise `NULL` will be returned. + +* `origin`: `BIGINT` origin quadbin index. +* `destination`: `BIGINT` destination quadbin index. + +**Return type** + +`GEOGRAPHY` + +**Example** + +```sql +SELECT carto.QUADBIN_DISTANCE(5207251884775047167, 5207128739472736255); +-- 1 +``` diff --git a/clouds/redshift/modules/sql/quadbin/QUADBIN_DISTANCE.sql b/clouds/redshift/modules/sql/quadbin/QUADBIN_DISTANCE.sql new file mode 100644 index 000000000..44c3cf092 --- /dev/null +++ b/clouds/redshift/modules/sql/quadbin/QUADBIN_DISTANCE.sql @@ -0,0 +1,28 @@ +---------------------------- +-- Copyright (C) 2023 CARTO +---------------------------- + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.QUADBIN_DISTANCE +(origin BIGINT, destination BIGINT) +RETURNS BIGINT +STABLE +AS $$ + SELECT CASE WHEN $1 IS NULL OR $2 IS NULL THEN + NULL + ELSE + CASE WHEN @@RS_SCHEMA@@.QUADBIN_RESOLUTION($1) != @@RS_SCHEMA@@.QUADBIN_RESOLUTION($2) THEN + NULL + ELSE + GREATEST( + ABS( + (@@RS_SCHEMA@@.__QUADBIN_TOZXY_X($2) >> (32 - CAST(@@RS_SCHEMA@@.QUADBIN_RESOLUTION($2) AS INT))) - + (@@RS_SCHEMA@@.__QUADBIN_TOZXY_X($1) >> (32 - CAST(@@RS_SCHEMA@@.QUADBIN_RESOLUTION($1) AS INT))) + ), + ABS( + (@@RS_SCHEMA@@.__QUADBIN_TOZXY_Y($2) >> (32 - CAST(@@RS_SCHEMA@@.QUADBIN_RESOLUTION($2) AS INT))) - + (@@RS_SCHEMA@@.__QUADBIN_TOZXY_Y($1) >> (32 - CAST(@@RS_SCHEMA@@.QUADBIN_RESOLUTION($1) AS INT))) + ) + ) + END + END +$$ LANGUAGE sql; diff --git a/clouds/redshift/modules/sql/quadbin/QUADBIN_TOZXY.sql b/clouds/redshift/modules/sql/quadbin/QUADBIN_TOZXY.sql index 610162174..597086670 100644 --- a/clouds/redshift/modules/sql/quadbin/QUADBIN_TOZXY.sql +++ b/clouds/redshift/modules/sql/quadbin/QUADBIN_TOZXY.sql @@ -2,90 +2,6 @@ -- Copyright (C) 2022 CARTO ---------------------------- -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED5 -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT ($1 | ($1 >> 16)) & CAST(FROM_HEX('00000000FFFFFFFF') AS BIGINT) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED4 -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED5( - ($1 | ($1 >> 8)) & CAST(FROM_HEX('0000FFFF0000FFFF') AS BIGINT) - ) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED3 -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED4( - ($1 | ($1 >> 4)) & CAST(FROM_HEX('00FF00FF00FF00FF') AS BIGINT) - ) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED2 -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED3( - ($1 | ($1 >> 2)) & CAST(FROM_HEX('0F0F0F0F0F0F0F0F') AS BIGINT) - ) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED1 -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED2( - ($1 | ($1 >> 1)) & CAST(FROM_HEX('3333333333333333') AS BIGINT) - ) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_PREINTERLEAVED -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED1( - $1 & CAST(FROM_HEX('5555555555555555') AS BIGINT) - ) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_X -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_PREINTERLEAVED( - ($1 & CAST(FROM_HEX('00FFFFFFFFFFFFF') AS BIGINT)) << 12 - ) -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_Y -(BIGINT) --- (quadbin) -RETURNS BIGINT -STABLE -AS $$ - SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_X($1 >> 1) -$$ LANGUAGE sql; - CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.QUADBIN_TOZXY (BIGINT) -- (quadbin) diff --git a/clouds/redshift/modules/sql/quadbin/__QUADBIN_TOZXY_X.sql b/clouds/redshift/modules/sql/quadbin/__QUADBIN_TOZXY_X.sql new file mode 100644 index 000000000..fb9467ea8 --- /dev/null +++ b/clouds/redshift/modules/sql/quadbin/__QUADBIN_TOZXY_X.sql @@ -0,0 +1,78 @@ +---------------------------- +-- Copyright (C) 2022 CARTO +---------------------------- + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED5 +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT ($1 | ($1 >> 16)) & CAST(FROM_HEX('00000000FFFFFFFF') AS BIGINT) +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED4 +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED5( + ($1 | ($1 >> 8)) & CAST(FROM_HEX('0000FFFF0000FFFF') AS BIGINT) + ) +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED3 +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED4( + ($1 | ($1 >> 4)) & CAST(FROM_HEX('00FF00FF00FF00FF') AS BIGINT) + ) +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED2 +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED3( + ($1 | ($1 >> 2)) & CAST(FROM_HEX('0F0F0F0F0F0F0F0F') AS BIGINT) + ) +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED1 +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED2( + ($1 | ($1 >> 1)) & CAST(FROM_HEX('3333333333333333') AS BIGINT) + ) +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_PREINTERLEAVED +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_INTERLEAVED1( + $1 & CAST(FROM_HEX('5555555555555555') AS BIGINT) + ) +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_X +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_XY_PREINTERLEAVED( + ($1 & CAST(FROM_HEX('00FFFFFFFFFFFFF') AS BIGINT)) << 12 + ) +$$ LANGUAGE sql; diff --git a/clouds/redshift/modules/sql/quadbin/__QUADBIN_TOZXY_Y.sql b/clouds/redshift/modules/sql/quadbin/__QUADBIN_TOZXY_Y.sql new file mode 100644 index 000000000..1941fc51a --- /dev/null +++ b/clouds/redshift/modules/sql/quadbin/__QUADBIN_TOZXY_Y.sql @@ -0,0 +1,12 @@ +---------------------------- +-- Copyright (C) 2022 CARTO +---------------------------- + +CREATE OR REPLACE FUNCTION @@RS_SCHEMA@@.__QUADBIN_TOZXY_Y +(BIGINT) +-- (quadbin) +RETURNS BIGINT +STABLE +AS $$ + SELECT @@RS_SCHEMA@@.__QUADBIN_TOZXY_X($1 >> 1) +$$ LANGUAGE sql; diff --git a/clouds/redshift/modules/test/quadbin/test_QUADBIN_DISTANCE.py b/clouds/redshift/modules/test/quadbin/test_QUADBIN_DISTANCE.py new file mode 100644 index 000000000..ac06ab904 --- /dev/null +++ b/clouds/redshift/modules/test/quadbin/test_QUADBIN_DISTANCE.py @@ -0,0 +1,11 @@ +from test_utils import run_query + + +def test_quadbin_distance(): + result = run_query( + 'SELECT @@RS_SCHEMA@@.QUADBIN_DISTANCE' + '(5207251884775047167, 5207128739472736255)' + ) + + assert len(result[0]) == 1 + assert result[0][0] == 1 diff --git a/clouds/snowflake/modules/doc/quadbin/QUADBIN_DISTANCE.md b/clouds/snowflake/modules/doc/quadbin/QUADBIN_DISTANCE.md new file mode 100644 index 000000000..2d72a8c1d --- /dev/null +++ b/clouds/snowflake/modules/doc/quadbin/QUADBIN_DISTANCE.md @@ -0,0 +1,23 @@ +## QUADBIN_DISTANCE + +```sql:signature +QUADBIN_DISTANCE(origin, destination) +``` + +**Description** + +Returns the [Chebyshev distance](https://en.wikipedia.org/wiki/Chebyshev_distance) between two quadbin indexes. The origin and destination indices must have the same resolution. Otherwise `NULL` will be returned. + +* `origin`: `BIGINT` origin quadbin index. +* `destination`: `BIGINT` destination quadbin index. + +**Return type** + +`GEOGRAPHY` + +**Example** + +```sql +SELECT carto.QUADBIN_DISTANCE(5207251884775047167, 5207128739472736255); +-- 1 +``` diff --git a/clouds/snowflake/modules/sql/quadbin/QUADBIN_DISTANCE.sql b/clouds/snowflake/modules/sql/quadbin/QUADBIN_DISTANCE.sql new file mode 100644 index 000000000..a7979336b --- /dev/null +++ b/clouds/snowflake/modules/sql/quadbin/QUADBIN_DISTANCE.sql @@ -0,0 +1,33 @@ +---------------------------- +-- Copyright (C) 2023 CARTO +---------------------------- + +CREATE OR REPLACE FUNCTION @@SF_SCHEMA@@._QUADBIN_DISTANCE +(origin STRING, destination STRING) +RETURNS STRING +LANGUAGE JAVASCRIPT +IMMUTABLE +AS $$ + if (!ORIGIN || !DESTINATION) { + return null; + } + + @@SF_LIBRARY_QUADBIN@@ + + origin_coords = quadbinLib.quadbinToTile(ORIGIN); + destination_coords = quadbinLib.quadbinToTile(DESTINATION); + + if (origin_coords.z != destination_coords.z) { + return null; + } + return Math.max(Math.abs(origin_coords.x - destination_coords.x), Math.abs(origin_coords.y - destination_coords.y)); +$$; + + +CREATE OR REPLACE SECURE FUNCTION @@SF_SCHEMA@@.QUADBIN_DISTANCE +(origin BIGINT, destination BIGINT) +RETURNS BIGINT +IMMUTABLE +AS $$ + CAST(@@SF_SCHEMA@@._QUADBIN_DISTANCE(TO_VARCHAR(ORIGIN, 'xxxxxxxxxxxxxxxx'), TO_VARCHAR(DESTINATION, 'xxxxxxxxxxxxxxxx')) AS BIGINT) +$$; diff --git a/clouds/snowflake/modules/test/quadbin/QUADBIN_DISTANCE.test.js b/clouds/snowflake/modules/test/quadbin/QUADBIN_DISTANCE.test.js new file mode 100644 index 000000000..ff80129ad --- /dev/null +++ b/clouds/snowflake/modules/test/quadbin/QUADBIN_DISTANCE.test.js @@ -0,0 +1,8 @@ +const { runQuery } = require('../../../common/test-utils'); + +test('QUADBIN_DISTANCE should work', async () => { + const query = 'SELECT QUADBIN_DISTANCE(5207251884775047167, 5207128739472736255) AS OUTPUT'; + const rows = await runQuery(query); + expect(rows.length).toEqual(1); + expect(rows[0].OUTPUT).toEqual(1); +}); \ No newline at end of file