Skip to content

Commit

Permalink
Fix bounds checking of BIGINT (#148)
Browse files Browse the repository at this point in the history
This introduces a pseudo-type NUMERIC that is used internally to hold
exact values before they are cast into the used type. The previous
logic was to make all integers into BIGINT and all decimals into
DOUBLE PRECISION which caused some bounds checking to be impossible to
detect.

Fixes #116
Fixes #121
  • Loading branch information
elliotchance authored Mar 3, 2023
1 parent 28157a4 commit e423a6e
Show file tree
Hide file tree
Showing 26 changed files with 897 additions and 96 deletions.
4 changes: 2 additions & 2 deletions tests/as.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ INSERT INTO t1 (x) VALUES (0);

EXPLAIN SELECT 1 AS bob FROM t1;
-- EXPLAIN: TABLE ":memory:".PUBLIC.T1 (X INTEGER)
-- EXPLAIN: EXPR (BOB BIGINT)
-- EXPLAIN: EXPR (BOB NUMERIC)

SELECT 1 AS bob FROM t1;
-- BOB: 1

EXPLAIN SELECT 1 AS "Bob" FROM t1;
-- EXPLAIN: TABLE ":memory:".PUBLIC.T1 (X INTEGER)
-- EXPLAIN: EXPR ("Bob" BIGINT)
-- EXPLAIN: EXPR ("Bob" NUMERIC)

SELECT 1 AS "Bob" FROM t1;
-- Bob: 1
Expand Down
54 changes: 54 additions & 0 deletions tests/bigint.sql
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,57 @@ SELECT CAST(x AS BOOLEAN) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
-- error 42846: cannot coerce BIGINT to BOOLEAN

VALUES CAST(123 AS BIGINT) + 53.7;
-- COL1: 176

VALUES 53.7 + CAST(123 AS BIGINT);
-- COL1: 176

VALUES CAST(5000000000000000000 AS BIGINT) + 5000000000000000000.7;
-- error 22003: numeric value out of range

VALUES 5000000000000000000.7 + CAST(5000000000000000000 AS BIGINT);
-- error 22003: numeric value out of range

VALUES CAST(123 AS BIGINT) - 53.7;
-- COL1: 70

VALUES 53.7 - CAST(123 AS BIGINT);
-- COL1: -70

VALUES CAST(-5000000000000000000 AS BIGINT) - 5000000000000000000.7;
-- error 22003: numeric value out of range

VALUES -5000000000000000000.7 - CAST(5000000000000000000 AS BIGINT);
-- error 22003: numeric value out of range

VALUES CAST(123 AS BIGINT) * 53.7;
-- COL1: 6519

VALUES -53.7 * CAST(123 AS BIGINT);
-- COL1: -6519

VALUES CAST(-5000000000000000000 AS BIGINT) * 200000.7;
-- error 22003: numeric value out of range

VALUES -5000000000000000000.7 * CAST(5000000000000000000 AS BIGINT);
-- error 22003: numeric value out of range

VALUES CAST(123 AS BIGINT) / 53.7;
-- COL1: 2

VALUES -123.7 / CAST(53 AS BIGINT);
-- COL1: -3

VALUES CAST(-5000000000000000000 AS BIGINT) / 0.02;
-- error 22012: division by zero

VALUES -5000000000000000000.7 / CAST(3.2 AS BIGINT);
-- COL1: -1666666666666666667

VALUES CAST(-5000000000000000000 AS BIGINT) / 0;
-- error 22012: division by zero

VALUES -5000000000000000000 / CAST(0.1 AS BIGINT);
-- error 22012: division by zero
2 changes: 1 addition & 1 deletion tests/cast.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ VALUES CAST(123 AS SMALLINT);
-- COL1: 123

VALUES CAST(123 AS BOOLEAN);
-- error 42846: cannot coerce BIGINT to BOOLEAN
-- error 42846: cannot coerce NUMERIC to BOOLEAN

EXPLAIN VALUES CAST(123 AS SMALLINT);
-- EXPLAIN: VALUES (COL1 SMALLINT) = ROW(CAST(123 AS SMALLINT))
10 changes: 5 additions & 5 deletions tests/coalesce.sql
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
EXPLAIN VALUES COALESCE(1);
-- EXPLAIN: VALUES (COL1 BIGINT) = ROW(COALESCE(1))
-- EXPLAIN: VALUES (COL1 NUMERIC) = ROW(COALESCE(1))

EXPLAIN VALUES COALESCE(1, 2);
-- EXPLAIN: VALUES (COL1 BIGINT) = ROW(COALESCE(1, 2))
-- EXPLAIN: VALUES (COL1 NUMERIC) = ROW(COALESCE(1, 2))

EXPLAIN VALUES COALESCE(1, 2, 3);
-- EXPLAIN: VALUES (COL1 BIGINT) = ROW(COALESCE(1, 2, 3))
-- EXPLAIN: VALUES (COL1 NUMERIC) = ROW(COALESCE(1, 2, 3))

VALUES COALESCE(1);
-- COL1: 1
Expand All @@ -16,7 +16,7 @@ VALUES COALESCE(1, 2);
CREATE TABLE foo (f1 BIGINT);
INSERT INTO foo (f1) VALUES (NULL);
INSERT INTO foo (f1) VALUES (3);
SELECT COALESCE(f1, 2) FROM foo;
SELECT COALESCE(f1, CAST(2 AS BIGINT)) FROM foo;
SELECT COALESCE(f1) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
Expand All @@ -27,4 +27,4 @@ SELECT COALESCE(f1) FROM foo;
-- COL1: 3

VALUES COALESCE(1, 'hello');
-- error 42804: data type mismatch in argument 2 of COALESCE: expected BIGINT but got CHARACTER VARYING
-- error 42804: data type mismatch in argument 2 of COALESCE: expected NUMERIC but got CHARACTER VARYING
2 changes: 1 addition & 1 deletion tests/concatenation.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ VALUES 'foo' || 'bar';
-- COL1: foobar

VALUES 123 || 'bar';
-- error 42883: operator does not exist: BIGINT || CHARACTER VARYING
-- error 42883: operator does not exist: NUMERIC || CHARACTER VARYING
64 changes: 64 additions & 0 deletions tests/double-precision.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,67 @@ SELECT CAST(x AS DOUBLE PRECISION) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
-- COL1: 123

VALUES CAST(500000000.3 AS DOUBLE PRECISION) * 2000000000.7;
-- COL1: 1e+18

VALUES CAST(1.23 AS DOUBLE PRECISION) + 53.7;
-- COL1: 54.93

VALUES 53.7 + CAST(1.23 AS DOUBLE PRECISION);
-- COL1: 54.93

VALUES CAST(500000000 AS DOUBLE PRECISION) + 2000000000.7;
-- COL1: 2.500000e+09

VALUES 500000000.7 + CAST(2000000000 AS DOUBLE PRECISION);
-- COL1: 2.500000e+09

VALUES CAST(1.23 AS DOUBLE PRECISION) - 53.7;
-- COL1: -52.47

VALUES 53.7 - CAST(1.23 AS DOUBLE PRECISION);
-- COL1: 52.47

VALUES CAST(-2000000000.1 AS DOUBLE PRECISION) - 500000000.7;
-- COL1: -2.500000e+09

VALUES -500000000.7 - CAST(2000000000.1 AS DOUBLE PRECISION);
-- COL1: -2.500000e+09

VALUES CAST(12.3 AS DOUBLE PRECISION) * 53.7;
-- COL1: 660.51

VALUES -53.7 * CAST(12.3 AS DOUBLE PRECISION);
-- COL1: -660.51

VALUES CAST(-300000.1 AS DOUBLE PRECISION) * 200000.7;
-- COL1: -6.000023e+1

VALUES -300000.7 * CAST(200000.1 AS DOUBLE PRECISION);
-- COL1: -6.000017e+1

VALUES CAST(1.23 AS DOUBLE PRECISION) / 53.7;
-- COL1: 0.022905

VALUES -123.7 / CAST(53.1 AS DOUBLE PRECISION);
-- COL1: -2.329567

VALUES CAST(-300000000.5 AS DOUBLE PRECISION) / 0.02;
-- COL1: -1.500000e+1

VALUES -90000.7 / CAST(3.2 AS DOUBLE PRECISION);
-- COL1: -28125.21875

VALUES CAST(-30000.5 AS DOUBLE PRECISION) / 0;
-- error 22012: division by zero

VALUES -90000.5 / CAST(0.1 AS DOUBLE PRECISION);
-- COL1: -900005

CREATE TABLE foo (x DOUBLE PRECISION);
INSERT INTO foo (x) VALUES (123456789123456789123456789);
SELECT CAST(x AS BIGINT) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
-- error 22003: numeric value out of range
2 changes: 1 addition & 1 deletion tests/fold.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ VALUES LOWER('Hello');
-- COL1: hello

VALUES UPPER(123);
-- error 42883: function does not exist: UPPER(BIGINT)
-- error 42883: function does not exist: UPPER(DOUBLE PRECISION)

VALUES LOWER(TRUE);
-- error 42883: function does not exist: LOWER(BOOLEAN)
Expand Down
2 changes: 1 addition & 1 deletion tests/group-by.sql
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ SELECT min(x), max(x) FROM foo;

EXPLAIN SELECT avg(x * 2.0) FROM foo;
-- EXPLAIN: TABLE ":memory:".PUBLIC.FOO (X DOUBLE PRECISION, Y CHARACTER VARYING(32))
-- EXPLAIN: GROUP BY (AVG(":memory:".PUBLIC.FOO.X * 2) DOUBLE PRECISION)
-- EXPLAIN: GROUP BY (AVG(":memory:".PUBLIC.FOO.X * 2.0) DOUBLE PRECISION)
-- EXPLAIN: EXPR (COL1 DOUBLE PRECISION)

SELECT avg(x * 2.0) FROM foo;
Expand Down
2 changes: 1 addition & 1 deletion tests/insert.sql
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ INSERT INTO foo (x) VALUES (true);
CREATE TABLE foo (b BOOLEAN);
INSERT INTO foo (b) VALUES (123);
-- msg: CREATE TABLE 1
-- error 42846: cannot coerce BIGINT to BOOLEAN
-- error 42846: cannot coerce NUMERIC to BOOLEAN

CREATE TABLE t1 (f1 CHARACTER VARYING(10), f2 FLOAT NOT NULL);
INSERT INTO t1 (f1, f2) VALUES ('a', 1.23);
Expand Down
54 changes: 54 additions & 0 deletions tests/integer.sql
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,57 @@ SELECT CAST(x AS DOUBLE PRECISION) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
-- COL1: 123

VALUES CAST(123 AS INTEGER) + 53.7;
-- COL1: 176

VALUES 53.7 + CAST(123 AS INTEGER);
-- COL1: 176

VALUES CAST(500000000 AS INTEGER) + 2000000000.7;
-- error 22003: numeric value out of range

VALUES 500000000.7 + CAST(2000000000 AS INTEGER);
-- error 22003: numeric value out of range

VALUES CAST(123 AS INTEGER) - 53.7;
-- COL1: 69

VALUES 53.7 - CAST(123 AS INTEGER);
-- COL1: -69

VALUES CAST(-2000000000 AS INTEGER) - 500000000.7;
-- error 22003: numeric value out of range

VALUES -500000000.7 - CAST(2000000000 AS INTEGER);
-- error 22003: numeric value out of range

VALUES CAST(123 AS INTEGER) * 53.7;
-- COL1: 6605

VALUES -53.7 * CAST(123 AS INTEGER);
-- COL1: -6605

VALUES CAST(-300000 AS INTEGER) * 200000.7;
-- error 22003: numeric value out of range

VALUES -300000.7 * CAST(200000 AS INTEGER);
-- error 22003: numeric value out of range

VALUES CAST(123 AS INTEGER) / 53.7;
-- COL1: 2

VALUES -123.7 / CAST(53 AS INTEGER);
-- COL1: -2

VALUES CAST(-300000000 AS INTEGER) / 0.02;
-- error 22003: numeric value out of range

VALUES -90000.7 / CAST(3.2 AS INTEGER);
-- COL1: -30000

VALUES CAST(-30000 AS INTEGER) / 0;
-- error 22012: division by zero

VALUES -90000 / CAST(0.1 AS INTEGER);
-- error 22012: division by zero
2 changes: 1 addition & 1 deletion tests/nullif.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ VALUES NULLIF(123, 456);
-- COL1: 123

VALUES NULLIF(123, 'hello');
-- error 42804: data type mismatch in NULLIF: expected BIGINT but got CHARACTER VARYING
-- error 42804: data type mismatch in NULLIF: expected NUMERIC but got CHARACTER VARYING
64 changes: 64 additions & 0 deletions tests/real.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,67 @@ SELECT CAST(x AS DOUBLE PRECISION) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
-- COL1: 123

VALUES CAST(500000000.3 AS REAL) * 2000000000.7;
-- COL1: 1e+18

VALUES CAST(1.23 AS REAL) + 53.7;
-- COL1: 54.93

VALUES 53.7 + CAST(1.23 AS REAL);
-- COL1: 54.93

VALUES CAST(500000000 AS REAL) + 2000000000.7;
-- COL1: 2.500000e+09

VALUES 500000000.7 + CAST(2000000000 AS REAL);
-- COL1: 2.500000e+09

VALUES CAST(1.23 AS REAL) - 53.7;
-- COL1: -52.470001

VALUES 53.7 - CAST(1.23 AS REAL);
-- COL1: 52.470001

VALUES CAST(-2000000000.1 AS REAL) - 500000000.7;
-- COL1: -2.500000e+09

VALUES -500000000.7 - CAST(2000000000.1 AS REAL);
-- COL1: -2.500000e+09

VALUES CAST(12.3 AS REAL) * 53.7;
-- COL1: 660.51001

VALUES -53.7 * CAST(12.3 AS REAL);
-- COL1: -660.51001

VALUES CAST(-300000.1 AS REAL) * 200000.7;
-- COL1: -0.6000023e+11

VALUES -300000.7 * CAST(200000.1 AS REAL);
-- COL1: -0.6000017e+11

VALUES CAST(1.23 AS REAL) / 53.7;
-- COL1: 0.022905

VALUES -123.7 / CAST(53.1 AS REAL);
-- COL1: -2.329567

VALUES CAST(-300000000.5 AS REAL) / 0.02;
-- COL1: -1.500000e+1

VALUES -90000.7 / CAST(3.2 AS REAL);
-- COL1: -28125.21875

VALUES CAST(-30000.5 AS REAL) / 0;
-- error 22012: division by zero

VALUES -90000.5 / CAST(0.1 AS REAL);
-- COL1: -900005

CREATE TABLE foo (x REAL);
INSERT INTO foo (x) VALUES (123456789123456789123456789);
SELECT CAST(x AS BIGINT) FROM foo;
-- msg: CREATE TABLE 1
-- msg: INSERT 1
-- error 22003: numeric value out of range
6 changes: 3 additions & 3 deletions tests/select-where.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ INSERT INTO foo (num) VALUES (35);

EXPLAIN SELECT * FROM foo WHERE num = 27.0;
-- EXPLAIN: TABLE ":memory:".PUBLIC.FOO (NUM DOUBLE PRECISION)
-- EXPLAIN: WHERE ":memory:".PUBLIC.FOO.NUM = 27
-- EXPLAIN: WHERE ":memory:".PUBLIC.FOO.NUM = 27.0
-- EXPLAIN: EXPR (":memory:".PUBLIC.FOO.NUM DOUBLE PRECISION)

SELECT * FROM foo WHERE num = 27.0;
Expand All @@ -28,7 +28,7 @@ SELECT * FROM foo WHERE num < 27.0;

EXPLAIN SELECT * FROM foo WHERE num <= 27.0;
-- EXPLAIN: TABLE ":memory:".PUBLIC.FOO (NUM DOUBLE PRECISION)
-- EXPLAIN: WHERE ":memory:".PUBLIC.FOO.NUM <= 27
-- EXPLAIN: WHERE ":memory:".PUBLIC.FOO.NUM <= 27.0
-- EXPLAIN: EXPR (":memory:".PUBLIC.FOO.NUM DOUBLE PRECISION)

SELECT * FROM foo WHERE num <= 27.0;
Expand All @@ -37,7 +37,7 @@ SELECT * FROM foo WHERE num <= 27.0;

EXPLAIN SELECT * FROM foo WHERE foo.num = 27.0;
-- EXPLAIN: TABLE ":memory:".PUBLIC.FOO (NUM DOUBLE PRECISION)
-- EXPLAIN: WHERE ":memory:".PUBLIC.FOO.NUM = 27
-- EXPLAIN: WHERE ":memory:".PUBLIC.FOO.NUM = 27.0
-- EXPLAIN: EXPR (":memory:".PUBLIC.FOO.NUM DOUBLE PRECISION)

SELECT * FROM foo WHERE foo.num = 27.0;
Expand Down
Loading

0 comments on commit e423a6e

Please sign in to comment.