Skip to content

Implement pure floating numbers mode #113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,7 @@ Array support is experimental. Please be careful.
- SQLite does not support `numeric` type as PostgreSQL. Therefore, it does not allow to store numbers with too high precision and scale. Error out of range occurs.
- SQLite does not support `NaN` special value for IEEE 754-2008 numbers. Please use this special value very cerefully because there is no such conception in SQLite at all and `NaN` value treated in SQLite as `NULL`.
- SQLite support `+Infinity` and `-Infinity` special values for IEEE 754-2008 numbers in SQL expressions with numeric context. This values can be readed with both `text` and `real` affiniy, but can be writed to SQLite only with `real` affinity (as signed out of range value `9.0e999`).
- Please note you can turn off processing of IEEE 754-2008 values with `text` affiniy thorough `real` value of `column_type` option. This can increase `SELECT` or `ORDER` speed, becasuse there will be no normalize function wrapping, but in this case any query will have unsuccessfilly result in case of any value with `text` affiniy.

### Boolean values
- `sqlite_fdw` boolean values support exists only for `bool` columns in foreign table. SQLite documentation recommends to store boolean as value with `integer` [affinity](https://www.sqlite.org/datatype3.html). `NULL` isn't converted, 1 converted to `true`, all other `NOT NULL` values converted to `false`. During `SELECT ... WHERE condition_column` condition converted only to `condition_column`.
Expand Down
42 changes: 32 additions & 10 deletions deparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -2384,12 +2384,22 @@ sqlite_deparse_column_ref(StringInfo buf, int varno, int varattno, PlannerInfo *
case FLOAT4OID:
case NUMERICOID:
{
elog(DEBUG2, "floatN unification for \"%s\"", colname);
appendStringInfoString(buf, "sqlite_fdw_float(");
if (qualify_col)
ADD_REL_QUALIFIER(buf, varno);
appendStringInfoString(buf, sqlite_quote_identifier(colname, '`'));
appendStringInfoString(buf, ")");
if (colaff != SQLITE_FLOAT)
{
elog(DEBUG2, "floatN unification for \"%s\"", colname);
appendStringInfoString(buf, "sqlite_fdw_float(");
if (qualify_col)
ADD_REL_QUALIFIER(buf, varno);
appendStringInfoString(buf, sqlite_quote_identifier(colname, '`'));
appendStringInfoString(buf, ")");
}
else
{
elog(DEBUG2, "floatN real affinity only for \"%s\"", colname);
if (qualify_col)
ADD_REL_QUALIFIER(buf, varno);
appendStringInfoString(buf, sqlite_quote_identifier(colname, '`'));
}
break;
}
case BOOLOID:
Expand Down Expand Up @@ -3048,6 +3058,21 @@ get_complementary_var_node(Expr *node)
}
}

/* IEEE 754-2008 : ∞ and NaN */
const char * CHAR_INF_SHORT = "Inf";
const char * CHAR_INF_LONG = "Infinity";
const char * CHAR_NAN = "NaN";

bool
isInfinity (const char * s)
{
return strcasecmp(s, CHAR_INF_SHORT) == 0 ||
strcasecmp(s, CHAR_INF_LONG) == 0 ||
strcasecmp(s + sizeof(char), CHAR_INF_SHORT) == 0 ||
strcasecmp(s + sizeof(char), CHAR_INF_LONG) == 0;
}


/*
* Deparse given constant value into context->buf.
*
Expand Down Expand Up @@ -3127,10 +3152,7 @@ sqlite_deparse_const(Const *node, deparse_expr_cxt *context, int showtype)
else
appendStringInfoString(buf, extval);
}
else if (strcasecmp(extval, infs) == 0 ||
strcasecmp(extval, infl) == 0 ||
strcasecmp(extval + 1, infs) == 0 ||
strcasecmp(extval + 1, infl) == 0)
else if (isInfinity(extval))
{
bool is_negative_or_positive = false;
if (extval[0] == '-' || extval[0] == '+')
Expand Down
77 changes: 73 additions & 4 deletions expected/13.15/types/float4.out
Original file line number Diff line number Diff line change
Expand Up @@ -1885,12 +1885,81 @@ SELECT * FROM "type_FLOAT_INF+" WHERE f = 'NaN' ORDER BY i;
(6 rows)

--Testcase 351:
DELETE FROM "type_FLOAT_INF" WHERE i >= 10;
ALTER FOREIGN TABLE "type_FLOAT_INF" ALTER COLUMN f OPTIONS (ADD column_type 'real');
--Testcase 352:
DROP FOREIGN TABLE "type_FLOAT_INF";
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM "type_FLOAT_INF";
QUERY PLAN
------------------------------------------------------------
Foreign Scan on public."type_FLOAT_INF"
Output: i, f
SQLite query: SELECT `i`, `f` FROM main."type_FLOAT_INF"
(3 rows)

--Testcase 353:
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM "type_FLOAT_INF+";
QUERY PLAN
-----------------------------------------------------------------------------------------
Foreign Scan on public."type_FLOAT_INF+"
Output: i, f, t, l
SQLite query: SELECT `i`, sqlite_fdw_float(`f`), `t`, `l` FROM main."type_FLOAT_INF+"
(3 rows)

--Testcase 354: ERR - remove real
SELECT * FROM "type_FLOAT_INF";
ERROR: you should disable column_type = real for this column for infinity value processing
HINT: SQLite value with "text" affinity (8 bytes) : 'Infinity'
CONTEXT: foreign table "type_FLOAT_INF" foreign column "f" have data type "double precision" (usual affinity "real"), in query there is reference to foreign column
--Testcase 355:
DELETE FROM "type_FLOAT_INF" WHERE i IN (SELECT i FROM "type_FLOAT_INF+" WHERE t = 'text');
--Testcase 356:
SELECT * FROM "type_FLOAT_INF";
i | f
----+-----------
1 | -Infinity
2 | Infinity
3 | -Infinity
4 | Infinity
5 | -1e+308
6 | 0
7 | 1e+308
10 | Infinity
11 | Infinity
12 | -Infinity
13 | Infinity
14 | Infinity
15 | -Infinity
16 |
(14 rows)

--Testcase 357:
SELECT * FROM "type_FLOAT_INF+";
i | f | t | l
----+-----------+------+---
1 | -Infinity | real | 4
2 | Infinity | real | 3
3 | -Infinity | real | 4
4 | Infinity | real | 3
5 | -1e+308 | real | 9
6 | 0 | real | 3
7 | 1e+308 | real | 8
10 | Infinity | real | 3
11 | Infinity | real | 3
12 | -Infinity | real | 4
13 | Infinity | real | 3
14 | Infinity | real | 3
15 | -Infinity | real | 4
16 | | null |
(14 rows)

--Testcase 358:
DELETE FROM "type_FLOAT_INF" WHERE i >= 10;
--Testcase 359:
DROP FOREIGN TABLE "type_FLOAT_INF";
--Testcase 360:
DROP FOREIGN TABLE "type_FLOAT_INF+";
--Testcase 270:
--Testcase 390:
DROP SERVER sqlite_svr;
--Testcase 271:
--Testcase 391:
DROP EXTENSION sqlite_fdw CASCADE;
77 changes: 73 additions & 4 deletions expected/13.15/types/float8.out
Original file line number Diff line number Diff line change
Expand Up @@ -2304,12 +2304,81 @@ SELECT * FROM "type_FLOAT_INF+" WHERE f = 'NaN' ORDER BY i;
(6 rows)

--Testcase 351:
DELETE FROM "type_FLOAT_INF" WHERE i >= 10;
ALTER FOREIGN TABLE "type_FLOAT_INF" ALTER COLUMN f OPTIONS (ADD column_type 'real');
--Testcase 352:
DROP FOREIGN TABLE "type_FLOAT_INF";
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM "type_FLOAT_INF";
QUERY PLAN
------------------------------------------------------------
Foreign Scan on public."type_FLOAT_INF"
Output: i, f
SQLite query: SELECT `i`, `f` FROM main."type_FLOAT_INF"
(3 rows)

--Testcase 353:
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM "type_FLOAT_INF+";
QUERY PLAN
-----------------------------------------------------------------------------------------
Foreign Scan on public."type_FLOAT_INF+"
Output: i, f, t, l
SQLite query: SELECT `i`, sqlite_fdw_float(`f`), `t`, `l` FROM main."type_FLOAT_INF+"
(3 rows)

--Testcase 354: ERR - remove real
SELECT * FROM "type_FLOAT_INF";
ERROR: you should disable column_type = real for this column for infinity value processing
HINT: SQLite value with "text" affinity (8 bytes) : 'Infinity'
CONTEXT: foreign table "type_FLOAT_INF" foreign column "f" have data type "double precision" (usual affinity "real"), in query there is reference to foreign column
--Testcase 355:
DELETE FROM "type_FLOAT_INF" WHERE i IN (SELECT i FROM "type_FLOAT_INF+" WHERE t = 'text');
--Testcase 356:
SELECT * FROM "type_FLOAT_INF";
i | f
----+-----------
1 | -Infinity
2 | Infinity
3 | -Infinity
4 | Infinity
5 | -1e+308
6 | 0
7 | 1e+308
10 | Infinity
11 | Infinity
12 | -Infinity
13 | Infinity
14 | Infinity
15 | -Infinity
16 |
(14 rows)

--Testcase 357:
SELECT * FROM "type_FLOAT_INF+";
i | f | t | l
----+-----------+------+---
1 | -Infinity | real | 4
2 | Infinity | real | 3
3 | -Infinity | real | 4
4 | Infinity | real | 3
5 | -1e+308 | real | 9
6 | 0 | real | 3
7 | 1e+308 | real | 8
10 | Infinity | real | 3
11 | Infinity | real | 3
12 | -Infinity | real | 4
13 | Infinity | real | 3
14 | Infinity | real | 3
15 | -Infinity | real | 4
16 | | null |
(14 rows)

--Testcase 358:
DELETE FROM "type_FLOAT_INF" WHERE i >= 10;
--Testcase 359:
DROP FOREIGN TABLE "type_FLOAT_INF";
--Testcase 360:
DROP FOREIGN TABLE "type_FLOAT_INF+";
--Testcase 270:
--Testcase 390:
DROP SERVER sqlite_svr;
--Testcase 271:
--Testcase 391:
DROP EXTENSION sqlite_fdw CASCADE;
77 changes: 73 additions & 4 deletions expected/14.12/types/float4.out
Original file line number Diff line number Diff line change
Expand Up @@ -1907,12 +1907,81 @@ SELECT * FROM "type_FLOAT_INF+" WHERE f = 'NaN' ORDER BY i;
(6 rows)

--Testcase 351:
DELETE FROM "type_FLOAT_INF" WHERE i >= 10;
ALTER FOREIGN TABLE "type_FLOAT_INF" ALTER COLUMN f OPTIONS (ADD column_type 'real');
--Testcase 352:
DROP FOREIGN TABLE "type_FLOAT_INF";
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM "type_FLOAT_INF";
QUERY PLAN
------------------------------------------------------------
Foreign Scan on public."type_FLOAT_INF"
Output: i, f
SQLite query: SELECT `i`, `f` FROM main."type_FLOAT_INF"
(3 rows)

--Testcase 353:
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM "type_FLOAT_INF+";
QUERY PLAN
-----------------------------------------------------------------------------------------
Foreign Scan on public."type_FLOAT_INF+"
Output: i, f, t, l
SQLite query: SELECT `i`, sqlite_fdw_float(`f`), `t`, `l` FROM main."type_FLOAT_INF+"
(3 rows)

--Testcase 354: ERR - remove real
SELECT * FROM "type_FLOAT_INF";
ERROR: you should disable column_type = real for this column for infinity value processing
HINT: SQLite value with "text" affinity (8 bytes) : 'Infinity'
CONTEXT: foreign table "type_FLOAT_INF" foreign column "f" have data type "double precision" (usual affinity "real"), in query there is reference to foreign column
--Testcase 355:
DELETE FROM "type_FLOAT_INF" WHERE i IN (SELECT i FROM "type_FLOAT_INF+" WHERE t = 'text');
--Testcase 356:
SELECT * FROM "type_FLOAT_INF";
i | f
----+-----------
1 | -Infinity
2 | Infinity
3 | -Infinity
4 | Infinity
5 | -1e+308
6 | 0
7 | 1e+308
10 | Infinity
11 | Infinity
12 | -Infinity
13 | Infinity
14 | Infinity
15 | -Infinity
16 |
(14 rows)

--Testcase 357:
SELECT * FROM "type_FLOAT_INF+";
i | f | t | l
----+-----------+------+---
1 | -Infinity | real | 4
2 | Infinity | real | 3
3 | -Infinity | real | 4
4 | Infinity | real | 3
5 | -1e+308 | real | 9
6 | 0 | real | 3
7 | 1e+308 | real | 8
10 | Infinity | real | 3
11 | Infinity | real | 3
12 | -Infinity | real | 4
13 | Infinity | real | 3
14 | Infinity | real | 3
15 | -Infinity | real | 4
16 | | null |
(14 rows)

--Testcase 358:
DELETE FROM "type_FLOAT_INF" WHERE i >= 10;
--Testcase 359:
DROP FOREIGN TABLE "type_FLOAT_INF";
--Testcase 360:
DROP FOREIGN TABLE "type_FLOAT_INF+";
--Testcase 270:
--Testcase 390:
DROP SERVER sqlite_svr;
--Testcase 271:
--Testcase 391:
DROP EXTENSION sqlite_fdw CASCADE;
Loading