Skip to content

Commit 1f049ce

Browse files
authored
plpgsql: use floor for conversion, add integer tests (#736)
1 parent 3e39f06 commit 1f049ce

File tree

4 files changed

+466
-34
lines changed

4 files changed

+466
-34
lines changed

plpgsql/README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@ Start a [PostgreSQL Docker](https://hub.docker.com/_/postgres) image and copy th
2020
docker run --name pgtest -e POSTGRES_PASSWORD=postgres -d -p 5433:5432 postgres
2121
```
2222

23+
1. Re-generate the encoding SQL test script using the current CSV data:
24+
25+
```shell
26+
./update_encoding_tests.sh ../test_data/encoding.csv
27+
```
28+
2329
1. Copy the Open Location Code files to the container and change the permissions to allow the `postgres` user to read them:
2430

2531
```shell
2632
docker cp pluscode_functions.sql pgtest:/pluscode_functions.sql
2733
docker cp tests_script_l.sql pgtest:/tests_script_l.sql
34+
docker cp test_encoding.sql pgtest:/tests_script_l.sql
2835
sudo docker exec pgtest chmod a+r *.sql
2936
```
3037

@@ -34,12 +41,15 @@ Start a [PostgreSQL Docker](https://hub.docker.com/_/postgres) image and copy th
3441
docker exec -u postgres pgtest psql postgres postgres -f ./pluscode_functions.sql
3542
```
3643

37-
1. Execute tests script
44+
1. Execute the test SQL scripts:
3845

3946
```shell
4047
docker exec -u postgres pgtest psql postgres postgres -f ./tests_script_l.sql
48+
docker exec -u postgres pgtest psql postgres postgres -f ./test_encoding.sql
4149
```
4250

51+
Test failures (in the encoding functions) will result in exceptions.
52+
4353
## Functions
4454

4555
### pluscode_encode()

plpgsql/pluscode_functions.sql

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@ DECLARE
119119
FINAL_LAT_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_ROWS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
120120
latVal decimal := 0;
121121
BEGIN
122-
latVal := round(latitude * FINAL_LAT_PRECISION_);
122+
latVal := floor(latitude * FINAL_LAT_PRECISION_);
123123
latVal := latVal + LATITUDE_MAX_ * FINAL_LAT_PRECISION_;
124124
IF (latVal < 0) THEN
125125
latVal := 0;
126-
ELSIF (latVal > 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_) THEN
126+
ELSIF (latVal >= 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_) THEN
127127
latVal := 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_ - 1;
128128
END IF;
129129
RETURN latVal;
@@ -155,11 +155,11 @@ DECLARE
155155
FINAL_LNG_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_COLUMNS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
156156
lngVal decimal := 0;
157157
BEGIN
158-
lngVal := round(longitude * FINAL_LNG_PRECISION_);
158+
lngVal := floor(longitude * FINAL_LNG_PRECISION_);
159159
lngVal := lngVal + LONGITUDE_MAX_ * FINAL_LNG_PRECISION_;
160-
IF (lngVal < 0) THEN
160+
IF (lngVal <= 0) THEN
161161
lngVal := lngVal % (2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) + 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_;
162-
ELSIF (lngVal > 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) THEN
162+
ELSIF (lngVal >= 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) THEN
163163
lngVal := lngVal % (2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_);
164164
END IF;
165165
RETURN lngVal;
@@ -396,6 +396,7 @@ DECLARE
396396
PADDING_CHARACTER_ text := '0';
397397
CODE_ALPHABET_ text := '23456789CFGHJMPQRVWX';
398398
ENCODING_BASE_ int := char_length(CODE_ALPHABET_);
399+
MIN_DIGIT_COUNT_ int := 2;
399400
MAX_DIGIT_COUNT_ int := 15;
400401
PAIR_CODE_LENGTH_ int := 10;
401402
GRID_CODE_LENGTH_ int := MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_;
@@ -407,6 +408,13 @@ DECLARE
407408
ndx smallint;
408409
i_ smallint;
409410
BEGIN
411+
IF ((codeLength < MIN_DIGIT_COUNT_) OR ((codeLength < PAIR_CODE_LENGTH_) AND (codeLength % 2 = 1))) THEN
412+
RAISE EXCEPTION 'Invalid Open Location Code length - %', codeLength
413+
USING HINT = 'The Open Location Code length must be 2, 4, 6, 8, 10, 11, 12, 13, 14, or 15.';
414+
END IF;
415+
416+
codeLength := LEAST(codeLength, MAX_DIGIT_COUNT_);
417+
410418
IF (codeLength > PAIR_CODE_LENGTH_) THEN
411419
i_ := 0;
412420
WHILE (i_ < (MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_)) LOOP
@@ -461,37 +469,9 @@ RETURNS text
461469
IMMUTABLE
462470
AS $BODY$
463471
DECLARE
464-
SEPARATOR_ text := '+';
465-
SEPARATOR_POSITION_ int := 8;
466-
PADDING_CHARACTER_ text := '0';
467-
CODE_ALPHABET_ text := '23456789CFGHJMPQRVWX';
468-
ENCODING_BASE_ int := char_length(CODE_ALPHABET_);
469-
LATITUDE_MAX_ int := 90;
470-
LONGITUDE_MAX_ int := 180;
471-
MIN_DIGIT_COUNT_ int := 2;
472-
MAX_DIGIT_COUNT_ int := 15;
473-
PAIR_CODE_LENGTH_ int := 10;
474-
PAIR_PRECISION_ decimal := power(ENCODING_BASE_, 3);
475-
GRID_CODE_LENGTH_ int := MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_;
476-
GRID_COLUMNS_ int := 4;
477-
GRID_ROWS_ int := 5;
478-
FINAL_LAT_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_ROWS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
479-
FINAL_LNG_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_COLUMNS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
480-
code text := '';
481472
latVal decimal := 0;
482473
lngVal decimal := 0;
483-
latDigit smallint;
484-
lngDigit smallint;
485-
ndx smallint;
486-
i_ smallint;
487474
BEGIN
488-
IF ((codeLength < MIN_DIGIT_COUNT_) OR ((codeLength < PAIR_CODE_LENGTH_) AND (codeLength % 2 = 1))) THEN
489-
RAISE EXCEPTION 'Invalid Open Location Code length - %', codeLength
490-
USING HINT = 'The Open Location Code length must be 2, 4, 6, 8, 10, 11, 12, 13, 14, or 15.';
491-
END IF;
492-
493-
codeLength := LEAST(codeLength, MAX_DIGIT_COUNT_);
494-
495475
latVal := pluscode_latitudeToInteger(latitude);
496476
lngVal := pluscode_longitudeToInteger(longitude);
497477

0 commit comments

Comments
 (0)