Skip to content

Commit

Permalink
Various fixes for binary expressions (#165)
Browse files Browse the repository at this point in the history
The SQL standard states that arithmetic must result in the
"most specific type". This implementation is more correct, but is
incomplete. I'll keep the complete implementation for a later diff after
NUMERIC and DECIMAL has been included.

This also updates predicates to use the SQL-defined version instead of
the existing functions, adds some missing unary operators and fixes a
formatting error for some REAL values.
  • Loading branch information
elliotchance authored Oct 24, 2023
1 parent 6841be0 commit c05621f
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 524 deletions.
36 changes: 36 additions & 0 deletions docs/numbers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@ Numbers

.. contents::

Literals
--------

Different forms have implicit types:

.. list-table::
:header-rows: 1

* - Description
- Examples
- Type

* - Integers
- ``123``, ``0``, ``-1234``
- ``BIGINT``

* - Floating-point (contains ``.``)
- ``12.3``, ``0.0001``, ``-12.0``
- ``DOUBLE PRECISION``

Exact Numeric Types
-------------------

Expand Down Expand Up @@ -98,6 +118,22 @@ Casting
- ✅
- ✅

Arithmetic Operations
---------------------

Arithmetic operations (sometimes called binary operations) require the same type
for both operands and return this same type. For example ``INTEGER + INTEGER``
will result in an ``INTEGER``.

When the type of the operands are different it will implicitly cast to the
supertype of both. For numbers all supertypes are and in order: ``SMALLINT``,
``INTEGER``, ``BIGINT``, ``REAL`` and ``DOUBLE PRECISION``.

For example ``12 * 10.5`` is evaluated as the expression
``BIGINT * DOUBLE PRECISION``. Since ``DOUBLE PRECISION`` is the only supertype
for both, ``12`` must be implicitly cast to a ``DOUBLE PRECISION`` and the
operation will yield as result as ``DOUBLE PRECISION``.

Notes
-----

Expand Down
33 changes: 15 additions & 18 deletions tests/bigint.sql
Original file line number Diff line number Diff line change
Expand Up @@ -64,52 +64,49 @@ SELECT CAST(x AS BOOLEAN) FROM foo;
-- msg: INSERT 1
-- error 42846: cannot coerce BIGINT to BOOLEAN

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

VALUES CAST(-5000000000000000000 AS BIGINT) / 0;
Expand Down
6 changes: 3 additions & 3 deletions tests/double-precision.sql
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ 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
-- COL1: -6.000023e+10

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

VALUES CAST(1.23 AS DOUBLE PRECISION) / 53.7;
-- COL1: 0.022905
Expand All @@ -93,7 +93,7 @@ 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
-- COL1: -1.500000e+10

VALUES -90000.7 / CAST(3.2 AS DOUBLE PRECISION);
-- COL1: -28125.21875
Expand Down
41 changes: 19 additions & 22 deletions tests/integer.sql
Original file line number Diff line number Diff line change
Expand Up @@ -54,52 +54,49 @@ SELECT CAST(x AS DOUBLE PRECISION) FROM foo;
-- msg: INSERT 1
-- COL1: 123

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

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

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

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

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

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

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

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

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

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

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

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

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

VALUES -123.7 / CAST(53 AS INTEGER);
VALUES -123 / 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);
VALUES -90000 / CAST(3.2 AS INTEGER);
-- COL1: -30000

VALUES CAST(-30000 AS INTEGER) / 0;
Expand Down
42 changes: 21 additions & 21 deletions tests/real.sql
Original file line number Diff line number Diff line change
Expand Up @@ -47,61 +47,61 @@ SELECT CAST(x AS DOUBLE PRECISION) FROM foo;
-- msg: INSERT 1
-- COL1: 123

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

CREATE TABLE foo (x REAL);
Expand Down
46 changes: 20 additions & 26 deletions tests/smallint.sql
Original file line number Diff line number Diff line change
Expand Up @@ -47,56 +47,50 @@ SELECT CAST(x AS DOUBLE PRECISION) FROM foo;
-- msg: INSERT 1
-- COL1: 123

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

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

VALUES CAST(30000 AS SMALLINT) + 20000.7;
VALUES CAST(30000 AS SMALLINT) + CAST(20000 AS SMALLINT);
-- error 22003: numeric value out of range

VALUES 30000.7 + CAST(20000 AS SMALLINT);
VALUES CAST(30000 AS SMALLINT) + CAST(20000 AS SMALLINT);
-- error 22003: numeric value out of range

VALUES CAST(123 AS SMALLINT) - 53.7;
-- COL1: 69
VALUES CAST(123 AS SMALLINT) - CAST(53 AS SMALLINT);
-- COL1: 70

VALUES 53.7 - CAST(123 AS SMALLINT);
-- COL1: -69
VALUES CAST(53 AS SMALLINT) - CAST(123 AS SMALLINT);
-- COL1: -70

VALUES CAST(-30000 AS SMALLINT) - 20000.7;
VALUES CAST(-30000 AS SMALLINT) - CAST(20000 AS SMALLINT);
-- error 22003: numeric value out of range

VALUES -30000.7 - CAST(20000 AS SMALLINT);
VALUES CAST(-30000 AS SMALLINT) - CAST(20000 AS SMALLINT);
-- error 22003: numeric value out of range

VALUES CAST(123 AS SMALLINT) * 53.7;
-- COL1: 6605
VALUES CAST(123 AS SMALLINT) * CAST(53 AS SMALLINT);
-- COL1: 6519

VALUES -53.7 * CAST(123 AS SMALLINT);
-- COL1: -6605
VALUES CAST(-53 AS SMALLINT) * CAST(123 AS SMALLINT);
-- COL1: -6519

VALUES CAST(-30000 AS SMALLINT) * 20000.7;
VALUES CAST(-30000 AS SMALLINT) * CAST(20000 AS SMALLINT);
-- error 22003: numeric value out of range

VALUES -30000.7 * CAST(20000 AS SMALLINT);
VALUES CAST(-30000 AS SMALLINT) * CAST(20000 AS SMALLINT);
-- error 22003: numeric value out of range

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

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

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

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

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

VALUES -90000 / CAST(0.1 AS SMALLINT);
VALUES CAST(-30000 AS SMALLINT) / CAST(0.1 AS SMALLINT);
-- error 22012: division by zero
Loading

0 comments on commit c05621f

Please sign in to comment.