diff --git a/Jenkinsfile b/Jenkinsfile index c06320dc..5a10bca3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,28 +1,16 @@ def NODE_NAME = 'AWS_Instance_CentOS' def MAIL_TO = '$DEFAULT_RECIPIENTS' -def MAIL_SUBJECT = '[CI PGSpider] SQLite FDW Test FAILED ' + BRANCH_NAME -def BUILD_INFO = 'Jenkins job: ' + env.BUILD_URL def BRANCH_NAME = 'Branch [' + env.BRANCH_NAME + ']' +def BUILD_INFO = 'Jenkins job: ' + env.BUILD_URL + '\n' + +def POSTGRES_DOCKER_PATH = '/home/jenkins/Docker/Server/Postgres' +def ENHANCE_TEST_DOCKER_PATH = '/home/jenkins/Docker' +def TEST_TYPE = 'SQLITE' + +START_EXISTED_TEST = '' +START_ENHANCE_TEST = '' +INIT_ENHANCE_TEST = '' -def retrySh(String shCmd) { - def MAX_RETRY = 10 - script { - int status = 1; - for (int i = 0; i < MAX_RETRY; i++) { - status = sh(returnStatus: true, script: shCmd) - if (status == 0) { - echo "SUCCESS: " + shCmd - break - } else { - echo "RETRY: " + shCmd - sleep 5 - } - } - if (status != 0) { - sh(shCmd) - } - } -} pipeline { agent { @@ -33,7 +21,7 @@ pipeline { options { gitLabConnection('GitLabConnection') } - triggers { + triggers { gitlab( triggerOnPush: true, triggerOnMergeRequest: false, @@ -46,76 +34,184 @@ pipeline { ) } stages { - stage('Build') { + stage('Start_containers_Existed_Test') { steps { - sh ''' - rm -rf postgresql-13beta2 || true - tar -zxvf /home/jenkins/Postgres/postgresql-13beta2.tar.gz > /dev/null - cd postgresql-13beta2 - ./configure --prefix=$(pwd)/install > /dev/null - make clean && make > /dev/null - ''' - dir("postgresql-13beta2/contrib") { - sh 'rm -rf sqlite_fdw || true' - retrySh('git clone -b ' + env.GIT_BRANCH + ' ' + env.GIT_URL) + script { + if (env.GIT_URL != null) { + BUILD_INFO = BUILD_INFO + "Git commit: " + env.GIT_URL.replace(".git", "/commit/") + env.GIT_COMMIT + "\n" + } + } + catchError() { + sh """ + cd ${POSTGRES_DOCKER_PATH} + docker build -t postgresserver . + docker run -d --name postgresserver_for_sqlite_existed_test postgresserver + """ } } post { failure { - echo '** BUILD FAILED !!! NEXT STAGE WILL BE SKIPPED **' - emailext subject: "${MAIL_SUBJECT}", body: BUILD_INFO + "\nGit commit: " + env.GIT_URL.replace(".git", "/commit/") + env.GIT_COMMIT + "\n" + '${BUILD_LOG, maxLines=200, escapeHtml=false}', to: "${MAIL_TO}", attachLog: false + script { + START_EXISTED_TEST = 'FAILED' + } updateGitlabCommitStatus name: 'Build', state: 'failed' } success { + script { + START_EXISTED_TEST = 'SUCCESS' + } updateGitlabCommitStatus name: 'Build', state: 'success' } } } - stage('sqlite_fdw_test') { + stage('make_check_Existed_Test') { steps { - dir("postgresql-13beta2/contrib/sqlite_fdw") { - catchError() { - sh ''' - chmod +x *.sh - ./test.sh - ''' + catchError() { + sh """ + rm -rf make_check_existed_test.out || true + docker exec postgresserver_for_sqlite_existed_test /bin/bash -c 'su -c "/tmp/sqlite_existed_test.sh ${env.GIT_BRANCH}" postgres' + docker cp postgresserver_for_sqlite_existed_test:/home/postgres/postgresql-13beta2/contrib/sqlite_fdw/make_check.out make_check_existed_test.out + """ + } + script { + status = sh(returnStatus: true, script: "grep -q 'All [0-9]* tests passed' 'make_check_existed_test.out'") + if (status != 0) { + unstable(message: "Set UNSTABLE result") + sh 'docker cp postgresserver_for_sqlite_existed_test:/home/postgres/postgresql-13beta2/contrib/sqlite_fdw/regression.diffs regression.diffs' + sh 'cat regression.diffs || true' + updateGitlabCommitStatus name: 'make_check', state: 'failed' + } else { + updateGitlabCommitStatus name: 'make_check', state: 'success' } + } + } + } + stage('Start_containers_Enhance_Test') { + steps { + catchError() { + sh """ + cd ${ENHANCE_TEST_DOCKER_PATH} + docker-compose up --build -d + """ + } + } + post { + failure { script { - status = sh(returnStatus: true, script: "grep -q 'All [0-9]* tests passed' 'make_check.out'") - if (status != 0) { - unstable(message: "Set UNSTABLE result") - emailext subject: "${MAIL_SUBJECT}", body: BUILD_INFO + "\nGit commit: " + env.GIT_URL.replace(".git", "/commit/") + env.GIT_COMMIT + "\n" + '${FILE,path="make_check.out"}', to: "${MAIL_TO}", attachLog: false - sh 'cat regression.diffs || true' - updateGitlabCommitStatus name: 'sqlite_fdw_test', state: 'failed' - } else { - updateGitlabCommitStatus name: 'sqlite_fdw_test', state: 'success' - } + START_ENHANCE_TEST = 'FAILED' } + updateGitlabCommitStatus name: 'Build', state: 'failed' + } + success { + script { + START_ENHANCE_TEST = 'SUCCESS' + } + updateGitlabCommitStatus name: 'Build', state: 'success' } } } - stage('sqlite_fdw_test_extra') { + stage('Initialize_for_Enhance_Test') { steps { - dir("postgresql-13beta2/contrib/sqlite_fdw") { - catchError() { - sh ''' - chmod +x *.sh - ./test_extra.sh - ''' + catchError() { + sh """ + docker exec mysqlserver1_enhance_test /bin/bash -c '/tmp/start_enhance_test.sh' + docker exec mysqlserver2_enhance_test /bin/bash -c '/tmp/start_enhance_test.sh' + docker exec postgresserver1_enhance_test /bin/bash -c '/tmp/start_enhance_test_1.sh' + docker exec postgresserver2_enhance_test /bin/bash -c '/tmp/start_enhance_test_2.sh' + docker exec tinybraceserver1_enhance_test /bin/bash -c '/tmp/start_enhance_test_1.sh' + docker exec -d -w /usr/local/tinybrace tinybraceserver1_enhance_test /bin/bash -c 'bin/tbserver &' + docker exec tinybraceserver2_enhance_test /bin/bash -c '/tmp/start_enhance_test_2.sh' + docker exec -d -w /usr/local/tinybrace tinybraceserver2_enhance_test /bin/bash -c 'bin/tbserver &' + docker exec influxserver1_enhance_test /bin/bash -c '/tmp/start_enhance_test.sh' + docker exec influxserver2_enhance_test /bin/bash -c '/tmp/start_enhance_test.sh' + docker exec -d gridserver1_enhance_test /bin/bash -c '/tmp/start_enhance_test_1.sh' + sleep 10 + docker exec -d gridserver2_enhance_test /bin/bash -c '/tmp/start_enhance_test_2.sh' + sleep 10 + docker exec pgspiderserver1_enhance_test /bin/bash -c 'su -c "/tmp/start_enhance_test.sh ${env.GIT_BRANCH} ${TEST_TYPE}" pgspider' + """ + } + } + post { + failure { + script { + INIT_ENHANCE_TEST = 'FAILED' } + updateGitlabCommitStatus name: 'Init_Data', state: 'failed' + } + success { script { - status = sh(returnStatus: true, script: "grep -q 'All [0-9]* tests passed' 'make_check.out'") - if (status != 0) { - unstable(message: "Set UNSTABLE result") - emailext subject: "${MAIL_SUBJECT}", body: BUILD_INFO + "\nGit commit: " + env.GIT_URL.replace(".git", "/commit/") + env.GIT_COMMIT + "\n" + '${FILE,path="make_check.out"}', to: "${MAIL_TO}", attachLog: false - sh 'cat regression.diffs || true' - updateGitlabCommitStatus name: 'sqlite_fdw_test_extra', state: 'failed' - } else { - updateGitlabCommitStatus name: 'sqlite_fdw_test_extra', state: 'success' - } + INIT_ENHANCE_TEST = 'SUCCESS' + } + updateGitlabCommitStatus name: 'Init_Data', state: 'success' + } + } + } + stage('make_check_Enhance_Test') { + steps { + catchError() { + sh """ + rm -rf make_check_enhance_test.out regression.diffs || true + docker exec -w /home/pgspider/GIT/PGSpider/contrib/pgspider_core_fdw pgspiderserver1_enhance_test /bin/bash -c 'su -c "chmod a+x *.sh" pgspider' + docker exec -w /home/pgspider/GIT/PGSpider/contrib/pgspider_core_fdw pgspiderserver1_enhance_test /bin/bash -c "sed -i 's/enhance\\\\\\\\\\/BasicFeature1_File_4ARG enhance\\\\\\\\\\/BasicFeature1_File_AllARG enhance\\\\\\\\\\/BasicFeature1_GridDB_4ARG enhance\\\\\\\\\\/BasicFeature1_GridDB_AllARG enhance\\\\\\\\\\/BasicFeature1_InfluxDB_4ARG enhance\\\\\\\\\\/BasicFeature1_InfluxDB_AllARG enhance\\\\\\\\\\/BasicFeature1_MySQL_4ARG enhance\\\\\\\\\\/BasicFeature1_MySQL_AllARG enhance\\\\\\\\\\/BasicFeature1_PostgreSQL_4ARG enhance\\\\\\\\\\/BasicFeature1_PostgreSQL_AllARG enhance\\\\\\\\\\/BasicFeature1_SQLite_4ARG enhance\\\\\\\\\\/BasicFeature1_SQLite_AllARG enhance\\\\\\\\\\/BasicFeature1_TinyBrace_4ARG enhance\\\\\\\\\\/BasicFeature1_TinyBrace_AllARG enhance\\\\\\\\\\/BasicFeature1_t_max_range enhance\\\\\\\\\\/BasicFeature1_tmp_t15_4ARG enhance\\\\\\\\\\/BasicFeature1_tmp_t15_AllARG enhance\\\\\\\\\\/BasicFeature2_JOIN_Multi_Tbl enhance\\\\\\\\\\/BasicFeature2_SELECT_Muli_Tbl enhance\\\\\\\\\\/BasicFeature2_UNION_Multi_Tbl enhance\\\\\\\\\\/BasicFeature_Additional_Test enhance\\\\\\\\\\/BasicFeature_ComplexCommand enhance\\\\\\\\\\/BasicFeature_For_Bug_54 enhance\\\\\\\\\\/BasicFeature_For_Bug_60/enhance\\\\\\\\\\/BasicFeature1_SQLite_4ARG enhance\\\\\\\\\\/BasicFeature1_SQLite_AllARG/g' test_enhance.sh" + docker exec -w /home/pgspider/GIT/PGSpider/contrib/pgspider_core_fdw pgspiderserver1_enhance_test /bin/bash -c 'su -c "./test_enhance.sh" pgspider' + docker cp pgspiderserver1_enhance_test:/home/pgspider/GIT/PGSpider/contrib/pgspider_core_fdw/make_check.out make_check_enhance_test.out + """ + } + script { + status = sh(returnStatus: true, script: "grep -q 'All [0-9]* tests passed' 'make_check_enhance_test.out'") + if (status != 0) { + unstable(message: "Set UNSTABLE result") + sh 'docker cp pgspiderserver1_enhance_test:/home/pgspider/GIT/PGSpider/contrib/pgspider_core_fdw/regression.diffs regression.diffs' + sh 'cat regression.diffs || true' + updateGitlabCommitStatus name: 'make_check', state: 'failed' + } else { + updateGitlabCommitStatus name: 'make_check', state: 'success' } } } } } -} \ No newline at end of file + post { + success { + script { + prevResult = 'SUCCESS' + if (currentBuild.previousBuild != null) { + prevResult = currentBuild.previousBuild.result.toString() + } + if (prevResult != 'SUCCESS') { + emailext subject: '[CI SQLITE_FDW] InfluxDB_Test BACK TO NORMAL on ' + BRANCH_NAME, body: BUILD_INFO + '\n---------EXISTED_TEST---------\n' + '${FILE,path="make_check_existed_test.out"}' + '\n---------ENHANCE_TEST---------\n' + '${FILE,path="make_check_enhance_test.out"}', to: "${MAIL_TO}", attachLog: false + } + } + } + unsuccessful { + script { + if (START_EXISTED_TEST == 'FAILED') { + if (START_ENHANCE_TEST == 'FAILED') { + emailext subject: '[CI SQLITE_FDW] EXISTED_TEST: Start Containers FAILED | ENHANCE_TEST: Start Containers FAILED ' + BRANCH_NAME, body: BUILD_INFO + '${BUILD_LOG, maxLines=200, escapeHtml=false}', to: "${MAIL_TO}", attachLog: false + } else if (INIT_ENHANCE_TEST == 'FAILED') { + emailext subject: '[CI SQLITE_FDW] EXISTED_TEST: Start Containers FAILED | ENHANCE_TEST: Initialize FAILED ' + BRANCH_NAME, body: BUILD_INFO + '${BUILD_LOG, maxLines=200, escapeHtml=false}', to: "${MAIL_TO}", attachLog: false + } else { + emailext subject: '[CI SQLITE_FDW] EXISTED_TEST: Start Containers FAILED | ENHANCE_TEST: Result make check ' + BRANCH_NAME, body: BUILD_INFO + '${FILE,path="make_check_enhance_test.out"}', to: "${MAIL_TO}", attachLog: false + } + } else { + if (START_ENHANCE_TEST == 'FAILED') { + emailext subject: '[CI SQLITE_FDW] EXISTED_TEST: Result make check | ENHANCE_TEST: Start Containers FAILED ' + BRANCH_NAME, body: BUILD_INFO + '${FILE,path="make_check_existed_test.out"}', to: "${MAIL_TO}", attachLog: false + } else if (INIT_ENHANCE_TEST == 'FAILED') { + emailext subject: '[CI SQLITE_FDW] EXISTED_TEST: Result make check | ENHANCE_TEST: Initialize FAILED ' + BRANCH_NAME, body: BUILD_INFO + '${FILE,path="make_check_existed_test.out"}', to: "${MAIL_TO}", attachLog: false + } else { + emailext subject: '[CI SQLITE_FDW] EXISTED_TEST: Result make check | ENHANCE_TEST: Result make check ' + BRANCH_NAME, body: BUILD_INFO + '\n---------EXISTED_TEST---------\n' + '${FILE,path="make_check_existed_test.out"}' + '\n---------ENHANCE_TEST---------\n' + '${FILE,path="make_check_enhance_test.out"}', to: "${MAIL_TO}", attachLog: false + } + } + } + } + always { + sh """ + docker stop postgresserver_for_sqlite_existed_test + docker rm postgresserver_for_sqlite_existed_test + cd ${ENHANCE_TEST_DOCKER_PATH} + docker-compose down + """ + } + } +} diff --git a/META.json b/META.json index c4a6b9f4..abc57402 100644 --- a/META.json +++ b/META.json @@ -2,7 +2,7 @@ "name": "sqlite_fdw", "abstract": "Foreign Data Wrapper for SQLite databases", "description": "PostgreSQL extension which implements a Foreign Data Wrapper (FDW) for SQLite databases.", - "version": "1.2.0", + "version": "1.3.1", "maintainer": "mochizk", "license": "postgresql", "provides": { @@ -10,7 +10,7 @@ "abstract": "Foreign Data Wrapper for SQLite databases", "file": "sqlite_fdw.c", "docfile": "README.md", - "version": "1.2.0" + "version": "1.3.1" } }, "prereqs": { diff --git a/Makefile b/Makefile index 4d7ce347..579a91c6 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ OBJS = connection.o option.o deparse.o sqlite_query.o sqlite_fdw.o EXTENSION = sqlite_fdw DATA = sqlite_fdw--1.0.sql -REGRESS = extra/sqlite_fdw_post extra/float4 extra/float8 extra/int4 extra/int8 extra/numeric extra/join extra/limit extra/aggregates extra/prepare extra/select_having extra/select extra/insert extra/update extra/timestamp sqlite_fdw type aggregate +REGRESS = extra/sqlite_fdw_post extra/float4 extra/float8 extra/int4 extra/int8 extra/numeric extra/join extra/limit extra/aggregates extra/prepare extra/select_having extra/select extra/insert extra/update extra/timestamp sqlite_fdw type aggregate selectfunc SQLITE_LIB = sqlite3 diff --git a/deparse.c b/deparse.c index 8b9cf0cc..1e7b6054 100644 --- a/deparse.c +++ b/deparse.c @@ -38,6 +38,7 @@ #define QUOTE '"' static char *sqlite_quote_identifier(const char *s, char q); +static bool sqlite_contain_immutable_functions_walker(Node *node, void *context); /* * Global context for foreign_expr_walker's search of an expression tree. @@ -1023,6 +1024,7 @@ sqlite_deparse_select(List *tlist, List **retrieved_attrs, deparse_expr_cxt *con appendStringInfoString(buf, "SELECT "); if (foreignrel->reloptkind == RELOPT_JOINREL || + fpinfo->is_tlist_func_pushdown == true || foreignrel->reloptkind == RELOPT_UPPER_REL) { /* @@ -2691,3 +2693,130 @@ deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cx return (Node *) expr; } + +/***************************************************************************** + * Check clauses for immutable functions + *****************************************************************************/ + +/* + * contain_immutable_functions + * Recursively search for immutable functions within a clause. + * + * Returns true if any immutable function (or operator implemented by a + * immutable function) is found. + * + * We will recursively look into TargetEntry exprs. + */ +static bool +sqlite_contain_immutable_functions(Node *clause) +{ + return sqlite_contain_immutable_functions_walker(clause, NULL); +} + +static bool +sqlite_contain_immutable_functions_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + /* Check for mutable functions in node itself */ + if (nodeTag(node) == T_FuncExpr) + { + FuncExpr *expr = (FuncExpr *) node; + if (func_volatile(expr->funcid) == PROVOLATILE_IMMUTABLE) + return true; + } + + /* + * It should be safe to treat MinMaxExpr as immutable, because it will + * depend on a non-cross-type btree comparison function, and those should + * always be immutable. Treating XmlExpr as immutable is more dubious, + * and treating CoerceToDomain as immutable is outright dangerous. But we + * have done so historically, and changing this would probably cause more + * problems than it would fix. In practice, if you have a non-immutable + * domain constraint you are in for pain anyhow. + */ + + /* Recurse to check arguments */ + if (IsA(node, Query)) + { + /* Recurse into subselects */ + return query_tree_walker((Query *) node, + sqlite_contain_immutable_functions_walker, + context, 0); + } + return expression_tree_walker(node, sqlite_contain_immutable_functions_walker, + context); +} + +/* + * Returns true if given tlist is safe to evaluate on the foreign server. + */ +bool sqlite_is_foreign_function_tlist(PlannerInfo *root, + RelOptInfo *baserel, + List *tlist) +{ + foreign_glob_cxt glob_cxt; + foreign_loc_cxt loc_cxt; + ListCell *lc; + bool is_contain_function; + + if (!(baserel->reloptkind == RELOPT_BASEREL || + baserel->reloptkind == RELOPT_OTHER_MEMBER_REL)) + return false; + + /* + * Check that the expression consists of any immutable function. + */ + is_contain_function = false; + foreach(lc, tlist) + { + TargetEntry *tle = lfirst_node(TargetEntry, lc); + + if (sqlite_contain_immutable_functions((Node *) tle->expr)) + { + is_contain_function = true; + break; + } + } + + if (!is_contain_function) + return false; + + /* + * Check that the expression consists of nodes that are safe to execute + * remotely. + */ + foreach(lc, tlist) + { + TargetEntry *tle = lfirst_node(TargetEntry, lc); + + glob_cxt.root = root; + glob_cxt.foreignrel = baserel; + glob_cxt.relids = baserel->relids; + loc_cxt.collation = InvalidOid; + loc_cxt.state = FDW_COLLATE_NONE; + + if (!foreign_expr_walker((Node *) tle->expr, &glob_cxt, &loc_cxt)) + return false; + + /* + * If the expression has a valid collation that does not arise from a + * foreign var, the expression can not be sent over. + */ + if (loc_cxt.state == FDW_COLLATE_UNSAFE) + return false; + + /* + * An expression which includes any mutable functions can't be sent over + * because its result is not stable. For example, sending now() remote + * side could cause confusion from clock offsets. Future versions might + * be able to make this choice with more granularity. (We check this last + * because it requires a lot of expensive catalog lookups.) + */ + if (contain_mutable_functions((Node *) tle->expr)) + return false; + } + + /* OK for the target list with functions to evaluate on the remote server */ + return true; +} diff --git a/expected/aggregate.out b/expected/aggregate.out index f3320c13..d3f193e0 100644 --- a/expected/aggregate.out +++ b/expected/aggregate.out @@ -1,8 +1,11 @@ --SET log_min_messages TO DEBUG1; --SET client_min_messages TO DEBUG1; +--Testcase 16: CREATE EXTENSION sqlite_fdw; +--Testcase 17: CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw OPTIONS (database '/tmp/sqlitefdw_test.db'); +--Testcase 18: CREATE FOREIGN TABLE multiprimary(a int, b int OPTIONS (key 'true'), c int OPTIONS(key 'true')) SERVER sqlite_svr; -- test for aggregate pushdown --Testcase 8: @@ -93,6 +96,97 @@ explain (costs off, verbose) select sum(a) from multiprimary group by b having v --Testcase 13: DROP FOREIGN TABLE multiprimary; +--Testcase 16: +CREATE FOREIGN TABLE limittest(id serial OPTIONS (key 'true'), x int, y text) SERVER sqlite_svr; +--Testcase 17: +INSERT INTO limittest(x, y) VALUES (1, 'x'), (2, 'x'), (3, 'x'), (4, 'x'); +--Testcase 18: +INSERT INTO limittest(x, y) VALUES (1, 'y'), (2, 'y'), (3, 'y'), (4, 'y'); +--Testcase 19: +INSERT INTO limittest(x, y) VALUES (1, 'z'), (2, 'z'), (3, 'z'), (4, 'z'); +--Testcase 20: +EXPLAIN VERBOSE +SELECT avg(x) FROM limittest GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- + Limit (cost=1.00..1.00 rows=1 width=64) + Output: (avg(x)), y + -> Foreign Scan (cost=1.00..1.00 rows=1 width=64) + Output: (avg(x)), y + SQLite query: SELECT avg(`x`), `y` FROM main."limittest" GROUP BY 2 ORDER BY avg(`x`) DESC NULLS FIRST +(5 rows) + +--Testcase 21: +SELECT avg(x) FROM limittest GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; + avg +----- + 2.5 + 2.5 + 2.5 +(3 rows) + +--Testcase 22: +EXPLAIN VERBOSE +SELECT avg(x) FROM limittest WHERE x >= 0 GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------- + Limit (cost=1.00..1.00 rows=1 width=64) + Output: (avg(x)), y + -> Foreign Scan (cost=1.00..1.00 rows=1 width=64) + Output: (avg(x)), y + SQLite query: SELECT avg(`x`), `y` FROM main."limittest" WHERE ((`x` >= 0)) GROUP BY 2 ORDER BY avg(`x`) DESC NULLS FIRST +(5 rows) + +--Testcase 23: +SELECT avg(x) FROM limittest WHERE x >= 0 GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; + avg +----- + 2.5 + 2.5 + 2.5 +(3 rows) + +--Testcase 24: +EXPLAIN VERBOSE +SELECT x FROM limittest WHERE x > 0 ORDER BY 1 FETCH FIRST 2 ROWS WITH TIES; + QUERY PLAN +------------------------------------------------------------------------------------------------------ + Limit (cost=10.00..10.00 rows=2 width=4) + Output: x + -> Foreign Scan on public.limittest (cost=10.00..10.00 rows=10 width=4) + Output: x + SQLite query: SELECT `x` FROM main."limittest" WHERE ((`x` > 0)) ORDER BY `x` ASC NULLS LAST +(5 rows) + +--Testcase 25: +SELECT x FROM limittest WHERE x > 0 ORDER BY 1 FETCH FIRST 2 ROWS WITH TIES; + x +--- + 1 + 1 + 1 +(3 rows) + +--Testcase 26: +EXPLAIN VERBOSE +SELECT x FROM limittest ORDER BY 1 FETCH FIRST 2 ROWS ONLY; + QUERY PLAN +-------------------------------------------------------------------------------------- + Foreign Scan on public.limittest (cost=1.00..1.00 rows=1 width=4) + Output: x + SQLite query: SELECT `x` FROM main."limittest" ORDER BY `x` ASC NULLS LAST LIMIT 2 +(3 rows) + +--Testcase 27: +SELECT x FROM limittest ORDER BY 1 FETCH FIRST 2 ROWS ONLY; + x +--- + 1 + 1 +(2 rows) + +--Testcase 28: +DROP FOREIGN TABLE limittest; --Testcase 14: DROP SERVER sqlite_svr; --Testcase 15: diff --git a/expected/extra/aggregates.out b/expected/extra/aggregates.out index d0209ecf..c1f39bf2 100644 --- a/expected/extra/aggregates.out +++ b/expected/extra/aggregates.out @@ -451,14 +451,14 @@ select avg(null::float8) from agg_t8; select sum('NaN'::numeric) from agg_t8; sum ----- - 0.0 + 0 (1 row) --Testcase 330: select avg('NaN'::numeric) from agg_t8; avg ----- - 0.0 + 0 (1 row) -- verify correct results for infinite inputs @@ -1582,38 +1582,44 @@ from agg_t1 inner join agg_t2 on agg_t1.a = agg_t2.x and agg_t1.b = agg_t2.y group by agg_t1.a,agg_t1.b,agg_t1.c,agg_t1.d,agg_t2.x,agg_t2.y,agg_t2.z; QUERY PLAN ----------------------------------------------------------------------------------- - HashAggregate + Group Group Key: agg_t1.a, agg_t1.b, agg_t1.c, agg_t1.d, agg_t2.x, agg_t2.y, agg_t2.z - -> Merge Join - Merge Cond: ((agg_t1.a = agg_t2.x) AND (agg_t1.b = agg_t2.y)) - -> Sort - Sort Key: agg_t1.a, agg_t1.b - -> Foreign Scan on agg_t1 - -> Materialize + -> Incremental Sort + Sort Key: agg_t1.a, agg_t1.b, agg_t1.c, agg_t1.d, agg_t2.z + Presorted Key: agg_t1.a, agg_t1.b + -> Merge Join + Merge Cond: ((agg_t1.a = agg_t2.x) AND (agg_t1.b = agg_t2.y)) -> Sort - Sort Key: agg_t2.x, agg_t2.y - -> Foreign Scan on agg_t2 -(11 rows) + Sort Key: agg_t1.a, agg_t1.b + -> Foreign Scan on agg_t1 + -> Materialize + -> Sort + Sort Key: agg_t2.x, agg_t2.y + -> Foreign Scan on agg_t2 +(14 rows) -- Test case where agg_t1 can be optimized but not agg_t2 --Testcase 92: explain (costs off) select agg_t1.*,agg_t2.x,agg_t2.z from agg_t1 inner join agg_t2 on agg_t1.a = agg_t2.x and agg_t1.b = agg_t2.y group by agg_t1.a,agg_t1.b,agg_t1.c,agg_t1.d,agg_t2.x,agg_t2.z; - QUERY PLAN -------------------------------------------------------------------------- - HashAggregate + QUERY PLAN +----------------------------------------------------------------------------- + Group Group Key: agg_t1.a, agg_t1.b, agg_t1.c, agg_t1.d, agg_t2.x, agg_t2.z - -> Merge Join - Merge Cond: ((agg_t1.a = agg_t2.x) AND (agg_t1.b = agg_t2.y)) - -> Sort - Sort Key: agg_t1.a, agg_t1.b - -> Foreign Scan on agg_t1 - -> Materialize + -> Incremental Sort + Sort Key: agg_t1.a, agg_t1.b, agg_t1.c, agg_t1.d, agg_t2.z + Presorted Key: agg_t1.a, agg_t1.b + -> Merge Join + Merge Cond: ((agg_t1.a = agg_t2.x) AND (agg_t1.b = agg_t2.y)) -> Sort - Sort Key: agg_t2.x, agg_t2.y - -> Foreign Scan on agg_t2 -(11 rows) + Sort Key: agg_t1.a, agg_t1.b + -> Foreign Scan on agg_t1 + -> Materialize + -> Sort + Sort Key: agg_t2.x, agg_t2.y + -> Foreign Scan on agg_t2 +(14 rows) -- Cannot optimize when PK is deferrable --Testcase 422: diff --git a/expected/extra/limit.out b/expected/extra/limit.out index 47a76aa4..550f09a2 100644 --- a/expected/extra/limit.out +++ b/expected/extra/limit.out @@ -56,6 +56,7 @@ CREATE FOREIGN TABLE tenk1 ( stringu2 name, string4 name ) SERVER sqlite_svr; +--Testcase 88: CREATE TABLE parent_table ( unique1 int4 PRIMARY KEY, unique2 int4, @@ -74,6 +75,7 @@ CREATE TABLE parent_table ( stringu2 name, string4 name ); +--Testcase 89: CREATE FOREIGN table inherited_table () INHERITS (parent_table) SERVER sqlite_svr options (table 'tenk1'); @@ -517,6 +519,7 @@ select unique1, unique2, nextval('testseq') 3043 | 9 | 10 (10 rows) +--Testcase 90: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by unique2 limit 10 offset 5; @@ -527,6 +530,7 @@ select unique1, unique2, nextval('testseq') SQLite query: SELECT `unique1`, `unique2` FROM main."tenk1" ORDER BY `unique2` ASC NULLS LAST LIMIT 10 OFFSET 5 (3 rows) +--Testcase 91: select unique1, unique2, nextval('testseq') from tenk1 order by unique2 limit 10 offset 5; unique1 | unique2 | nextval @@ -550,6 +554,7 @@ select currval('testseq'); 20 (1 row) +--Testcase 92: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10; @@ -560,6 +565,7 @@ select unique1, unique2, nextval('testseq') SQLite query: SELECT `unique1`, `unique2` FROM main."tenk1" ORDER BY `unique2` DESC NULLS FIRST LIMIT 10 (3 rows) +--Testcase 93: select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10; unique1 | unique2 | nextval @@ -576,6 +582,7 @@ select unique1, unique2, nextval('testseq') 4773 | 9990 | 30 (10 rows) +--Testcase 94: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10 offset 5; @@ -586,6 +593,7 @@ select unique1, unique2, nextval('testseq') SQLite query: SELECT `unique1`, `unique2` FROM main."tenk1" ORDER BY `unique2` DESC NULLS FIRST LIMIT 10 OFFSET 5 (3 rows) +--Testcase 95: select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10 offset 5; unique1 | unique2 | nextval @@ -602,6 +610,7 @@ select unique1, unique2, nextval('testseq') 2406 | 9985 | 40 (10 rows) +--Testcase 96: select currval('testseq'); currval --------- @@ -636,6 +645,7 @@ select unique1, unique2, nextval('testseq') 9 | 4463 | 50 (10 rows) +--Testcase 97: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by tenthous limit 10 offset 5; @@ -646,6 +656,7 @@ select unique1, unique2, nextval('testseq') SQLite query: SELECT `unique1`, `unique2`, `tenthous` FROM main."tenk1" ORDER BY `tenthous` ASC NULLS LAST LIMIT 10 OFFSET 5 (3 rows) +--Testcase 98: select unique1, unique2, nextval('testseq') from tenk1 order by tenthous limit 10 offset 5; unique1 | unique2 | nextval @@ -670,6 +681,7 @@ select currval('testseq'); (1 row) -- test for limit and offset when querying table and foreign table inherited +--Testcase 99: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10; @@ -691,6 +703,7 @@ select unique1, unique2, nextval('testseq') SQLite query: SELECT `unique1`, `unique2`, `tenthous` FROM main."tenk1" ORDER BY `tenthous` ASC NULLS LAST LIMIT 10 (14 rows) +--Testcase 100: select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10; unique1 | unique2 | nextval @@ -708,6 +721,7 @@ select unique1, unique2, nextval('testseq') (10 rows) -- when querying regular tables with inherited tables, only limit is pushed-down when no offset is specified +--Testcase 101: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10 offset 5; @@ -729,6 +743,7 @@ select unique1, unique2, nextval('testseq') SQLite query: SELECT `unique1`, `unique2`, `tenthous` FROM main."tenk1" ORDER BY `tenthous` ASC NULLS LAST (14 rows) +--Testcase 102: select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10 offset 5; unique1 | unique2 | nextval @@ -745,6 +760,7 @@ select unique1, unique2, nextval('testseq') 14 | 4341 | 85 (10 rows) +--Testcase 103: select currval('testseq'); currval --------- @@ -888,7 +904,15 @@ SELECT thousand ---------- 0 0 -(2 rows) + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +(10 rows) --Testcase 73: SELECT thousand @@ -897,7 +921,16 @@ SELECT thousand thousand ---------- 0 -(1 row) + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +(10 rows) --Testcase 74: SELECT thousand @@ -906,7 +939,16 @@ SELECT thousand thousand ---------- 0 -(1 row) + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +(10 rows) --Testcase 75: SELECT thousand @@ -923,7 +965,7 @@ SELECT thousand SELECT ''::text AS two, unique1, unique2, stringu1 FROM onek WHERE unique1 > 50 FETCH FIRST 2 ROW WITH TIES; -ERROR: WITH TIES options can not be specified without ORDER BY clause +ERROR: WITH TIES cannot be specified without ORDER BY clause -- test ruleutils --Testcase 77: CREATE VIEW limit_thousand_v_1 AS SELECT thousand FROM onek WHERE thousand < 995 @@ -962,7 +1004,7 @@ View definition: --Testcase 81: CREATE VIEW limit_thousand_v_3 AS SELECT thousand FROM onek WHERE thousand < 995 ORDER BY thousand FETCH FIRST NULL ROWS WITH TIES; -- fails -ERROR: row count cannot be NULL in FETCH FIRST ... WITH TIES clause +ERROR: row count cannot be null in FETCH FIRST ... WITH TIES clause --Testcase 82: CREATE VIEW limit_thousand_v_3 AS SELECT thousand FROM onek WHERE thousand < 995 ORDER BY thousand FETCH FIRST (NULL+1) ROWS WITH TIES; diff --git a/expected/extra/numeric.out b/expected/extra/numeric.out index 594400f1..3829aa0a 100644 --- a/expected/extra/numeric.out +++ b/expected/extra/numeric.out @@ -978,18 +978,15 @@ SELECT t1.id1, t1.id2, t1.result, t2.expected FROM num_result t1, num_exp_add t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != t2.expected; - id1 | id2 | result | expected ------+-----+-------------------+------------------- - 2 | 2 | -68676984.430794 | -68676984.4307941 - 2 | 3 | -34338487.905397 | -34338487.9053971 - 2 | 6 | -34244590.6377667 | -34244590.6377668 - 2 | 9 | -59265296.2604444 | -59265296.2604445 - 3 | 2 | -34338487.905397 | -34338487.9053971 - 6 | 2 | -34244590.6377667 | -34244590.6377668 - 6 | 9 | -24832902.4674171 | -24832902.4674172 - 9 | 2 | -59265296.2604444 | -59265296.2604445 - 9 | 6 | -24832902.4674171 | -24832902.4674172 -(9 rows) + id1 | id2 | result | expected +-----+-----+--------------------+-------------------- + 2 | 3 | -34338487.90539704 | -34338487.90539705 + 2 | 5 | -34322095.17690604 | -34322095.17690605 + 2 | 9 | -59265296.26044446 | -59265296.26044447 + 3 | 2 | -34338487.90539704 | -34338487.90539705 + 5 | 2 | -34322095.17690604 | -34322095.17690605 + 9 | 2 | -59265296.26044446 | -59265296.26044447 +(6 rows) --Testcase 454: DELETE FROM num_result; @@ -1001,18 +998,15 @@ SELECT t1.id1, t1.id2, t1.result, round(t2.expected, 10) as expected FROM num_result t1, num_exp_add t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != round(t2.expected, 10); - id1 | id2 | result | expected ------+-----+-------------------+---------------------- - 2 | 2 | -68676984.430794 | -68676984.4307941000 - 2 | 3 | -34338487.905397 | -34338487.9053971000 - 2 | 6 | -34244590.6377667 | -34244590.6377668000 - 2 | 9 | -59265296.2604444 | -59265296.2604445000 - 3 | 2 | -34338487.905397 | -34338487.9053971000 - 6 | 2 | -34244590.6377667 | -34244590.6377668000 - 6 | 9 | -24832902.4674171 | -24832902.4674172000 - 9 | 2 | -59265296.2604444 | -59265296.2604445000 - 9 | 6 | -24832902.4674171 | -24832902.4674172000 -(9 rows) + id1 | id2 | result | expected +-----+-----+--------------------+---------------------- + 2 | 3 | -34338487.90539704 | -34338487.9053970500 + 2 | 5 | -34322095.17690604 | -34322095.1769060500 + 2 | 9 | -59265296.26044446 | -59265296.2604444700 + 3 | 2 | -34338487.90539704 | -34338487.9053970500 + 5 | 2 | -34322095.17690604 | -34322095.1769060500 + 9 | 2 | -59265296.26044446 | -59265296.2604444700 +(6 rows) -- ****************************** -- * Subtraction check @@ -1027,10 +1021,10 @@ SELECT t1.id1, t1.id2, t1.result, t2.expected FROM num_result t1, num_exp_sub t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != t2.expected; - id1 | id2 | result | expected ------+-----+------------------+------------------- - 2 | 9 | -9411688.1703496 | -9411688.17034963 - 9 | 2 | 9411688.1703496 | 9411688.17034963 + id1 | id2 | result | expected +-----+-----+--------------------+-------------------- + 2 | 9 | -9411688.170349626 | -9411688.170349628 + 9 | 2 | 9411688.170349626 | 9411688.170349628 (2 rows) --Testcase 460: @@ -1043,10 +1037,10 @@ SELECT t1.id1, t1.id2, t1.result, round(t2.expected, 40) FROM num_result t1, num_exp_sub t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != round(t2.expected, 40); - id1 | id2 | result | round ------+-----+------------------+--------------------------------------------------- - 2 | 9 | -9411688.1703496 | -9411688.1703496300000000000000000000000000000000 - 9 | 2 | 9411688.1703496 | 9411688.1703496300000000000000000000000000000000 + id1 | id2 | result | round +-----+-----+--------------------+--------------------------------------------------- + 2 | 9 | -9411688.170349626 | -9411688.1703496280000000000000000000000000000000 + 9 | 2 | 9411688.170349626 | 9411688.1703496280000000000000000000000000000000 (2 rows) -- ****************************** @@ -1062,22 +1056,19 @@ SELECT t1.id1, t1.id2, t1.result, t2.expected FROM num_result t1, num_exp_mul t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != t2.expected; - id1 | id2 | result | expected ------+-----+--------------------+-------------------- - 2 | 4 | -267821744976817.0 | -267821744976818.0 - 2 | 5 | -563049578578.768 | -563049578578.769 - 2 | 8 | -2571300635581.14 | -2571300635581.15 - 2 | 9 | 855948866655587.0 | 855948866655589.0 - 4 | 2 | -267821744976817.0 | -267821744976818.0 - 5 | 2 | -563049578578.768 | -563049578578.769 - 7 | 9 | 2069634775752160 | 2069634775752159 - 8 | 2 | -2571300635581.14 | -2571300635581.15 - 8 | 9 | -1866544013697.19 | -1866544013697.2 - 9 | 2 | 855948866655587.0 | 855948866655589.0 - 9 | 7 | 2069634775752160 | 2069634775752159 - 9 | 8 | -1866544013697.19 | -1866544013697.2 - 9 | 9 | 621345559900191.0 | 621345559900192.0 -(13 rows) + id1 | id2 | result | expected +-----+-----+---------------------+--------------------- + 2 | 4 | -267821744976817.78 | -267821744976817.8 + 2 | 5 | -563049578578.7692 | -563049578578.7693 + 2 | 6 | -3224438592470.184 | -3224438592470.1846 + 2 | 8 | -2571300635581.146 | -2571300635581.1465 + 2 | 9 | 855948866655588.4 | 855948866655588.5 + 4 | 2 | -267821744976817.78 | -267821744976817.8 + 5 | 2 | -563049578578.7692 | -563049578578.7693 + 6 | 2 | -3224438592470.184 | -3224438592470.1846 + 8 | 2 | -2571300635581.146 | -2571300635581.1465 + 9 | 2 | 855948866655588.4 | 855948866655588.5 +(10 rows) --Testcase 466: DELETE FROM num_result; @@ -1089,22 +1080,19 @@ SELECT t1.id1, t1.id2, t1.result, round(t2.expected, 30) as expected FROM num_result t1, num_exp_mul t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != round(t2.expected, 30); - id1 | id2 | result | expected ------+-----+--------------------+------------------------------------------------- - 2 | 4 | -267821744976817.0 | -267821744976818.000000000000000000000000000000 - 2 | 5 | -563049578578.768 | -563049578578.769000000000000000000000000000 - 2 | 8 | -2571300635581.14 | -2571300635581.150000000000000000000000000000 - 2 | 9 | 855948866655587.0 | 855948866655589.000000000000000000000000000000 - 4 | 2 | -267821744976817.0 | -267821744976818.000000000000000000000000000000 - 5 | 2 | -563049578578.768 | -563049578578.769000000000000000000000000000 - 7 | 9 | 2069634775752160 | 2069634775752159.000000000000000000000000000000 - 8 | 2 | -2571300635581.14 | -2571300635581.150000000000000000000000000000 - 8 | 9 | -1866544013697.19 | -1866544013697.200000000000000000000000000000 - 9 | 2 | 855948866655587.0 | 855948866655589.000000000000000000000000000000 - 9 | 7 | 2069634775752160 | 2069634775752159.000000000000000000000000000000 - 9 | 8 | -1866544013697.19 | -1866544013697.200000000000000000000000000000 - 9 | 9 | 621345559900191.0 | 621345559900192.000000000000000000000000000000 -(13 rows) + id1 | id2 | result | expected +-----+-----+---------------------+------------------------------------------------- + 2 | 4 | -267821744976817.78 | -267821744976817.800000000000000000000000000000 + 2 | 5 | -563049578578.7692 | -563049578578.769300000000000000000000000000 + 2 | 6 | -3224438592470.184 | -3224438592470.184600000000000000000000000000 + 2 | 8 | -2571300635581.146 | -2571300635581.146500000000000000000000000000 + 2 | 9 | 855948866655588.4 | 855948866655588.500000000000000000000000000000 + 4 | 2 | -267821744976817.78 | -267821744976817.800000000000000000000000000000 + 5 | 2 | -563049578578.7692 | -563049578578.769300000000000000000000000000 + 6 | 2 | -3224438592470.184 | -3224438592470.184600000000000000000000000000 + 8 | 2 | -2571300635581.146 | -2571300635581.146500000000000000000000000000 + 9 | 2 | 855948866655588.4 | 855948866655588.500000000000000000000000000000 +(10 rows) -- ****************************** -- * Division check @@ -1120,11 +1108,9 @@ SELECT t1.id1, t1.id2, t1.result, t2.expected FROM num_result t1, num_exp_div t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != t2.expected; - id1 | id2 | result | expected ------+-----+-------------------+------------------- - 2 | 3 | -7967167.56737749 | -7967167.5673775 - 9 | 3 | -5783481.21694835 | -5783481.21694836 -(2 rows) + id1 | id2 | result | expected +-----+-----+--------+---------- +(0 rows) --Testcase 472: DELETE FROM num_result; @@ -1137,11 +1123,9 @@ SELECT t1.id1, t1.id2, t1.result, round(t2.expected, 80) as expected FROM num_result t1, num_exp_div t2 WHERE t1.id1 = t2.id1 AND t1.id2 = t2.id2 AND t1.result != round(t2.expected, 80); - id1 | id2 | result | expected ------+-----+-------------------+------------------------------------------------------------------------------------------- - 2 | 3 | -7967167.56737749 | -7967167.56737750000000000000000000000000000000000000000000000000000000000000000000000000 - 9 | 3 | -5783481.21694835 | -5783481.21694836000000000000000000000000000000000000000000000000000000000000000000000000 -(2 rows) + id1 | id2 | result | expected +-----+-----+--------+---------- +(0 rows) -- ****************************** -- * Square root check @@ -1212,9 +1196,8 @@ SELECT t1.id1, t1.result, t2.expected AND t1.result != t2.expected; id1 | result | expected -----+--------------------+-------------------- - 2 | 224790267919917248 | 224790267919917952 - 9 | 107511333880051808 | 107511333880052000 -(2 rows) + 2 | 224790267919917920 | 224790267919917950 +(1 row) -- ****************************** -- * miscellaneous checks for things that have been broken in the past... @@ -1222,23 +1205,23 @@ SELECT t1.id1, t1.result, t2.expected -- numeric AVG used to fail on some platforms --Testcase 487: SELECT AVG(val) FROM num_data; - avg -------------------- - -13430913.5922423 + avg +--------------------- + -13430913.592242321 (1 row) --Testcase 488: SELECT STDDEV(val) FROM num_data; - stddev ---------------------------- - 27791203.2875883484501033 + stddev +----------------------------- + 27791203.287588353130876346 (1 row) --Testcase 489: SELECT VARIANCE(val) FROM num_data; - variance ----------------------------------- - 772350980172061.4271301683648535 + variance +------------------------------------ + 772350980172061.687298801053312091 (1 row) -- Check for appropriate rounding and overflow @@ -1352,15 +1335,15 @@ INSERT INTO ceil_floor_round VALUES ('0.0000001'); INSERT INTO ceil_floor_round VALUES ('-0.000001'); --Testcase 506: SELECT a, ceil(a), ceiling(a), floor(a), round(a) FROM ceil_floor_round ORDER BY a; - a | ceil | ceiling | floor | round -------------+------+---------+-------+------- - -5.5 | -5 | -5 | -6 | -6 - -5.499999 | -5 | -5 | -6 | -5 - -0.0000010 | 0 | 0 | -1 | 0 - 0 | 0 | 0 | 0 | 0 - 0.00000010 | 1 | 1 | 0 | 0 - 9.4999999 | 10 | 10 | 9 | 9 - 9.5 | 10 | 10 | 9 | 10 + a | ceil | ceiling | floor | round +-----------+------+---------+-------+------- + -5.5 | -5 | -5 | -6 | -6 + -5.499999 | -5 | -5 | -6 | -5 + -0.000001 | 0 | 0 | -1 | 0 + 0 | 0 | 0 | 0 | 0 + 0.0000001 | 1 | 1 | 0 | 0 + 9.4999999 | 10 | 10 | 9 | 9 + 9.5 | 10 | 10 | 9 | 10 (7 rows) -- Check rounding, it should round ties away from zero. @@ -1516,8 +1499,8 @@ SELECT operand_num | wb_1 | wb_1f | wb_2 | wb_2f | wb_3 | wb_3f | wb_4 | wb_4f | wb_5 | wb_5f ------------------+------+-------+------+-------+------+-------+------+-------+------+------- -5.2 | 0 | 0 | 6 | 6 | 0 | 0 | 0 | 0 | 4 | 4 - -0.00000000010 | 0 | 0 | 6 | 6 | 0 | 0 | 0 | 0 | 5 | 5 - 0.0000000000010 | 1 | 1 | 5 | 5 | 0 | 0 | 0 | 0 | 6 | 6 + -0.0000000001 | 0 | 0 | 6 | 6 | 0 | 0 | 0 | 0 | 5 | 5 + 0.000000000001 | 1 | 1 | 5 | 5 | 0 | 0 | 0 | 0 | 6 | 6 1 | 1 | 1 | 5 | 5 | 0 | 0 | 0 | 0 | 6 | 6 1.99999999999999 | 1 | 1 | 5 | 5 | 0 | 0 | 0 | 0 | 6 | 6 2 | 2 | 2 | 5 | 5 | 1 | 1 | 0 | 0 | 6 | 6 @@ -1592,14 +1575,14 @@ SELECT '' AS to_char_2, to_char(val, '9G999G999G999G999G999D999G999G999G999G999' -----------+-------------------------------------------- | .000,000,000,000,000 | .000,000,000,000,000 - | -34,338,492.215,397,000,000,000 + | -34,338,492.215,397,045,000,000 | 4.310,000,000,000,000 | 7,799,461.411,900,000,000,000 | 16,397.038,491,000,000,000 | 93,901.577,630,260,000,000 | -83,028,485.000,000,000,000,000 | 74,881.000,000,000,000,000 - | -24,926,804.045,047,400,000,000 + | -24,926,804.045,047,420,000,000 (10 rows) --Testcase 515: @@ -1609,14 +1592,14 @@ SELECT '' AS to_char_3, to_char(val, '9999999999999999.999999999999999PR') -----------+------------------------------------ | .000000000000000 | .000000000000000 - | <34338492.215397000000000> + | <34338492.215397045000000> | 4.310000000000000 | 7799461.411900000000000 | 16397.038491000000000 | 93901.577630260000000 | <83028485.000000000000000> | 74881.000000000000000 - | <24926804.045047400000000> + | <24926804.045047420000000> (10 rows) --Testcase 516: @@ -1626,14 +1609,14 @@ SELECT '' AS to_char_4, to_char(val, '9999999999999999.999999999999999S') -----------+----------------------------------- | .000000000000000+ | .000000000000000+ - | 34338492.215397000000000- + | 34338492.215397045000000- | 4.310000000000000+ | 7799461.411900000000000+ | 16397.038491000000000+ | 93901.577630260000000+ | 83028485.000000000000000- | 74881.000000000000000+ - | 24926804.045047400000000- + | 24926804.045047420000000- (10 rows) --Testcase 517: @@ -1642,46 +1625,46 @@ SELECT '' AS to_char_5, to_char(val, 'MI9999999999999999.999999999999999') -----------+----------------------------------- | .000000000000000 | .000000000000000 - | - 34338492.215397000000000 + | - 34338492.215397045000000 | 4.310000000000000 | 7799461.411900000000000 | 16397.038491000000000 | 93901.577630260000000 | - 83028485.000000000000000 | 74881.000000000000000 - | - 24926804.045047400000000 + | - 24926804.045047420000000 (10 rows) --Testcase 518: SELECT '' AS to_char_6, to_char(val, 'FMS9999999999999999.999999999999999') FROM num_data; - to_char_6 | to_char ------------+------------------- + to_char_6 | to_char +-----------+--------------------- | +0. | +0. - | -34338492.215397 + | -34338492.215397045 | +4.31 | +7799461.4119 | +16397.038491 | +93901.57763026 | -83028485. | +74881. - | -24926804.0450474 + | -24926804.04504742 (10 rows) --Testcase 519: SELECT '' AS to_char_7, to_char(val, 'FM9999999999999999.999999999999999THPR') FROM num_data; - to_char_7 | to_char ------------+-------------------- + to_char_7 | to_char +-----------+---------------------- | 0. | 0. - | <34338492.215397> + | <34338492.215397045> | 4.31 | 7799461.4119 | 16397.038491 | 93901.57763026 | <83028485.> | 74881. - | <24926804.0450474> + | <24926804.04504742> (10 rows) --Testcase 520: @@ -1690,14 +1673,14 @@ SELECT '' AS to_char_8, to_char(val, 'SG9999999999999999.999999999999999th') -----------+----------------------------------- | + .000000000000000 | + .000000000000000 - | - 34338492.215397000000000 + | - 34338492.215397045000000 | + 4.310000000000000 | + 7799461.411900000000000 | + 16397.038491000000000 | + 93901.577630260000000 | - 83028485.000000000000000 | + 74881.000000000000000 - | - 24926804.045047400000000 + | - 24926804.045047420000000 (10 rows) --Testcase 521: @@ -1706,14 +1689,14 @@ SELECT '' AS to_char_9, to_char(val, '0999999999999999.999999999999999') -----------+----------------------------------- | 0000000000000000.000000000000000 | 0000000000000000.000000000000000 - | -0000000034338492.215397000000000 + | -0000000034338492.215397045000000 | 0000000000000004.310000000000000 | 0000000007799461.411900000000000 | 0000000000016397.038491000000000 | 0000000000093901.577630260000000 | -0000000083028485.000000000000000 | 0000000000074881.000000000000000 - | -0000000024926804.045047400000000 + | -0000000024926804.045047420000000 (10 rows) --Testcase 522: @@ -1722,94 +1705,94 @@ SELECT '' AS to_char_10, to_char(val, 'S0999999999999999.999999999999999') ------------+----------------------------------- | +0000000000000000.000000000000000 | +0000000000000000.000000000000000 - | -0000000034338492.215397000000000 + | -0000000034338492.215397045000000 | +0000000000000004.310000000000000 | +0000000007799461.411900000000000 | +0000000000016397.038491000000000 | +0000000000093901.577630260000000 | -0000000083028485.000000000000000 | +0000000000074881.000000000000000 - | -0000000024926804.045047400000000 + | -0000000024926804.045047420000000 (10 rows) --Testcase 523: SELECT '' AS to_char_11, to_char(val, 'FM0999999999999999.999999999999999') FROM num_data; - to_char_11 | to_char -------------+--------------------------- + to_char_11 | to_char +------------+----------------------------- | 0000000000000000. | 0000000000000000. - | -0000000034338492.215397 + | -0000000034338492.215397045 | 0000000000000004.31 | 0000000007799461.4119 | 0000000000016397.038491 | 0000000000093901.57763026 | -0000000083028485. | 0000000000074881. - | -0000000024926804.0450474 + | -0000000024926804.04504742 (10 rows) --Testcase 524: SELECT '' AS to_char_12, to_char(val, 'FM9999999999999999.099999999999999') FROM num_data; - to_char_12 | to_char -------------+------------------- + to_char_12 | to_char +------------+--------------------- | .0 | .0 - | -34338492.215397 + | -34338492.215397045 | 4.31 | 7799461.4119 | 16397.038491 | 93901.57763026 | -83028485.0 | 74881.0 - | -24926804.0450474 + | -24926804.04504742 (10 rows) --Testcase 525: SELECT '' AS to_char_13, to_char(val, 'FM9999999999990999.990999999999999') FROM num_data; - to_char_13 | to_char -------------+------------------- + to_char_13 | to_char +------------+--------------------- | 0000.000 | 0000.000 - | -34338492.215397 + | -34338492.215397045 | 0004.310 | 7799461.4119 | 16397.038491 | 93901.57763026 | -83028485.000 | 74881.000 - | -24926804.0450474 + | -24926804.04504742 (10 rows) --Testcase 526: SELECT '' AS to_char_14, to_char(val, 'FM0999999999999999.999909999999999') FROM num_data; - to_char_14 | to_char -------------+--------------------------- + to_char_14 | to_char +------------+----------------------------- | 0000000000000000.00000 | 0000000000000000.00000 - | -0000000034338492.215397 + | -0000000034338492.215397045 | 0000000000000004.31000 | 0000000007799461.41190 | 0000000000016397.038491 | 0000000000093901.57763026 | -0000000083028485.00000 | 0000000000074881.00000 - | -0000000024926804.0450474 + | -0000000024926804.04504742 (10 rows) --Testcase 527: SELECT '' AS to_char_15, to_char(val, 'FM9999999990999999.099999999999999') FROM num_data; - to_char_15 | to_char -------------+------------------- + to_char_15 | to_char +------------+--------------------- | 0000000.0 | 0000000.0 - | -34338492.215397 + | -34338492.215397045 | 0000004.31 | 7799461.4119 | 0016397.038491 | 0093901.57763026 | -83028485.0 | 0074881.0 - | -24926804.0450474 + | -24926804.04504742 (10 rows) --Testcase 528: @@ -1818,30 +1801,30 @@ SELECT '' AS to_char_16, to_char(val, 'L9999999999999999.099999999999999') FROM ------------+------------------------------------ | .000000000000000 | .000000000000000 - | -34338492.215397000000000 + | -34338492.215397045000000 | 4.310000000000000 | 7799461.411900000000000 | 16397.038491000000000 | 93901.577630260000000 | -83028485.000000000000000 | 74881.000000000000000 - | -24926804.045047400000000 + | -24926804.045047420000000 (10 rows) --Testcase 529: SELECT '' AS to_char_17, to_char(val, 'FM9999999999999999.99999999999999') FROM num_data; - to_char_17 | to_char -------------+------------------- + to_char_17 | to_char +------------+--------------------- | 0. | 0. - | -34338492.215397 + | -34338492.215397045 | 4.31 | 7799461.4119 | 16397.038491 | 93901.57763026 | -83028485. | 74881. - | -24926804.0450474 + | -24926804.04504742 (10 rows) --Testcase 530: @@ -1850,30 +1833,30 @@ SELECT '' AS to_char_18, to_char(val, 'S 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 . 9 9 9 ------------+----------------------------------------------------------------------- | +. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | +. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - | -3 4 3 3 8 4 9 2 . 2 1 5 3 9 7 0 0 0 0 0 0 0 0 0 0 0 + | -3 4 3 3 8 4 9 2 . 2 1 5 3 9 7 0 4 5 0 0 0 0 0 0 0 0 | +4 . 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | +7 7 9 9 4 6 1 . 4 1 1 9 0 0 0 0 0 0 0 0 0 0 0 0 0 | +1 6 3 9 7 . 0 3 8 4 9 1 0 0 0 0 0 0 0 0 0 0 0 | +9 3 9 0 1 . 5 7 7 6 3 0 2 6 0 0 0 0 0 0 0 0 0 | -8 3 0 2 8 4 8 5 . 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | +7 4 8 8 1 . 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - | -2 4 9 2 6 8 0 4 . 0 4 5 0 4 7 4 0 0 0 0 0 0 0 0 0 0 + | -2 4 9 2 6 8 0 4 . 0 4 5 0 4 7 4 2 0 0 0 0 0 0 0 0 0 (10 rows) --Testcase 531: SELECT '' AS to_char_19, to_char(val, 'FMS 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 . 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9') FROM num_data; - to_char_19 | to_char -------------+----------------------------------------------------- + to_char_19 | to_char +------------+------------------------------------------------------- | +0 . | +0 . - | -3 4 3 3 8 4 9 2 . 2 1 5 3 9 7 + | -3 4 3 3 8 4 9 2 . 2 1 5 3 9 7 0 4 5 | +4 . 3 1 | +7 7 9 9 4 6 1 . 4 1 1 9 | +1 6 3 9 7 . 0 3 8 4 9 1 | +9 3 9 0 1 . 5 7 7 6 3 0 2 6 | -8 3 0 2 8 4 8 5 . | +7 4 8 8 1 . - | -2 4 9 2 6 8 0 4 . 0 4 5 0 4 7 4 + | -2 4 9 2 6 8 0 4 . 0 4 5 0 4 7 4 2 (10 rows) --Testcase 532: @@ -1910,18 +1893,18 @@ SELECT '' AS to_char_21, to_char(val, '999999SG9999999999') FROM num_data; --Testcase 534: SELECT '' AS to_char_22, to_char(val, 'FM9999999999999999.999999999999999') FROM num_data; - to_char_22 | to_char -------------+------------------- + to_char_22 | to_char +------------+--------------------- | 0. | 0. - | -34338492.215397 + | -34338492.215397045 | 4.31 | 7799461.4119 | 16397.038491 | 93901.57763026 | -83028485. | 74881. - | -24926804.0450474 + | -24926804.04504742 (10 rows) --Testcase 535: @@ -2491,28 +2474,28 @@ INSERT INTO num_tmp VALUES (12345678901234567890, 123); select n1 % n2 FROM num_tmp; ?column? ---------- - 85 + 49 (1 row) --Testcase 737: select n1 / n2 FROM num_tmp; ?column? -------------------- - 100371373180769106 + 100371373180768837 (1 row) --Testcase 738: select div(n1, n2) FROM num_tmp; div -------------------- - 100371373180769105 + 100371373180768837 (1 row) --Testcase 739: select div(n1, n2) * n2 + n1 % n2 FROM num_tmp; ?column? ---------------------- - 12345678901234600000 + 12345678901234567000 (1 row) -- @@ -2526,7 +2509,7 @@ INSERT INTO num_tmp VALUES (1.000000000000003::numeric); SELECT sqrt(n1) FROM num_tmp; sqrt ------------------- - 1.000000000000000 + 1.000000000000001 (1 row) --Testcase 743: @@ -2537,7 +2520,7 @@ INSERT INTO num_tmp VALUES (1.000000000000004::numeric); SELECT sqrt(n1) FROM num_tmp; sqrt ------------------- - 1.000000000000000 + 1.000000000000002 (1 row) --Testcase 746: @@ -2548,7 +2531,7 @@ INSERT INTO num_tmp VALUES (96627521408608.56340355805::numeric); SELECT sqrt(n1) FROM num_tmp; sqrt ------------------- - 9829929.878112488 + 9829929.878112486 (1 row) --Testcase 749: @@ -2559,7 +2542,7 @@ INSERT INTO num_tmp VALUES (96627521408608.56340355806::numeric); SELECT sqrt(n1) FROM num_tmp; sqrt ------------------- - 9829929.878112488 + 9829929.878112486 (1 row) --Testcase 752: @@ -2592,7 +2575,7 @@ INSERT INTO num_tmp VALUES (8015491789940783531003294973900306::numeric); SELECT sqrt(n1) FROM num_tmp; sqrt ------------------- - 89529278953539998 + 89529278953540020 (1 row) --Testcase 761: @@ -2603,7 +2586,7 @@ INSERT INTO num_tmp VALUES (8015491789940783531003294973900307::numeric); SELECT sqrt(n1) FROM num_tmp; sqrt ------------------- - 89529278953539998 + 89529278953540020 (1 row) -- @@ -3196,9 +3179,9 @@ DELETE FROM num_tmp; INSERT INTO num_tmp VALUES (0.349873948359354029493948309745709580730482050975); --Testcase 913: select ln(n1) from num_tmp; - ln ---------------------- - -1.0501823369120829 + ln +---------------------- + -1.05018233691208275 (1 row) --Testcase 914: @@ -3231,7 +3214,7 @@ INSERT INTO num_tmp VALUES (1234.567890123456789); select ln(n1) from num_tmp; ln -------------------- - 7.1184763012977922 + 7.1184763012977898 (1 row) --Testcase 923: @@ -3294,7 +3277,7 @@ INSERT INTO num_tmp VALUES (3.4634998359873254962349856073435545); select log(n1) from num_tmp; log -------------------- - 0.5395151714070140 + 0.5395151714070135 (1 row) --Testcase 941: @@ -3509,7 +3492,7 @@ INSERT INTO num_tmp VALUES (110123.12475871856128); select scale(n1) from num_tmp; scale ------- - 9 + 11 (1 row) --Testcase 1004: @@ -3722,9 +3705,9 @@ DELETE FROM num_tmp; INSERT INTO num_tmp VALUES (110123.12475871856128000); --Testcase 1060: select trim_scale(n1) from num_tmp; - trim_scale ------------------- - 110123.124758719 + trim_scale +-------------------- + 110123.12475871856 (1 row) --Testcase 1061: diff --git a/expected/extra/timestamp.out b/expected/extra/timestamp.out index c9607843..3b2931f6 100644 --- a/expected/extra/timestamp.out +++ b/expected/extra/timestamp.out @@ -1,15 +1,19 @@ -- -- TIMESTAMP -- +--Testcase 1: CREATE EXTENSION sqlite_fdw; +--Testcase 2: CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw OPTIONS (database '/tmp/sqlitefdw_test_core.db'); +--Testcase 3: CREATE FOREIGN TABLE dates1 ( name varchar(20), date_as_text timestamp without time zone, date_as_number timestamp without time zone OPTIONS (column_type 'INT')) SERVER sqlite_svr OPTIONS (table 'dates'); +--Testcase 4: CREATE FOREIGN TABLE dates2 ( name varchar(20), date_as_text timestamp without time zone, @@ -17,6 +21,7 @@ CREATE FOREIGN TABLE dates2 ( SERVER sqlite_svr OPTIONS (table 'dates'); -- Showing timestamp column from SQLite value as TEXT and as INTEGER/FLOAT has same value +--Testcase 5: SELECT name, to_char(date_as_text, 'YYYY-MM-DD HH24:MI:SS.MS') as date_as_text, to_char(date_as_number, 'YYYY-MM-DD HH24:MI:SS.MS') as date_as_number @@ -28,6 +33,7 @@ FROM dates1; ThirdDate | 2020-05-10 10:45:29.000 | 2020-05-10 10:45:29.000 (3 rows) +--Testcase 6: SELECT * FROM dates2; name | date_as_text | date_as_number ------------+--------------------------+---------------- @@ -37,6 +43,7 @@ SELECT * FROM dates2; (3 rows) -- Comparing exact values showing same results even comparing to a text source sqlite column or numerical source sqlite column +--Testcase 7: SELECT * FROM dates1 WHERE date_as_text = to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -44,6 +51,7 @@ WHERE date_as_text = to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 8: SELECT * FROM dates1 WHERE date_as_number = to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -51,6 +59,7 @@ WHERE date_as_number = to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24: ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 9: SELECT * FROM dates1 WHERE date_as_text = to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -58,6 +67,7 @@ WHERE date_as_text = to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS. ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 10: SELECT * FROM dates1 WHERE date_as_number = to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -66,6 +76,7 @@ WHERE date_as_number = to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:S (1 row) -- Comparing greater values showing same results even comparing to a text source sqlite column or numerical source sqlite column +--Testcase 11: SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -74,6 +85,7 @@ WHERE date_as_text > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 12: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); @@ -85,6 +97,7 @@ WHERE date_as_text > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" (4 rows) +--Testcase 13: SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -93,6 +106,7 @@ WHERE date_as_number > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24: SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 14: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); @@ -104,6 +118,7 @@ WHERE date_as_number > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24: SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" (4 rows) +--Testcase 15: SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -112,6 +127,7 @@ WHERE date_as_text > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS. SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 16: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); @@ -123,6 +139,7 @@ WHERE date_as_text > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS. SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" (4 rows) +--Testcase 17: SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); name | date_as_text | date_as_number @@ -131,6 +148,7 @@ WHERE date_as_number > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:S SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 18: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); @@ -143,6 +161,7 @@ WHERE date_as_number > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:S (4 rows) --- Comparing without using to_timestamp +--Testcase 19: SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29.000')::timestamp); name | date_as_text | date_as_number @@ -150,6 +169,7 @@ WHERE date_as_text = (('2020-05-10 10:45:29.000')::timestamp); ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 20: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29.000')::timestamp); @@ -160,6 +180,7 @@ WHERE date_as_text = (('2020-05-10 10:45:29.000')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_text` = '2020-05-10 10:45:29')) (3 rows) +--Testcase 21: SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29.000')::timestamp); name | date_as_text | date_as_number @@ -167,6 +188,7 @@ WHERE date_as_number = (('2020-05-10 10:45:29.000')::timestamp); ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 22: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29.000')::timestamp); @@ -177,6 +199,7 @@ WHERE date_as_number = (('2020-05-10 10:45:29.000')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_number` = strftime('%s', '2020-05-10 10:45:29'))) (3 rows) +--Testcase 23: SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29')::timestamp); name | date_as_text | date_as_number @@ -184,6 +207,7 @@ WHERE date_as_text = (('2020-05-10 10:45:29')::timestamp); ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 24: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29')::timestamp); @@ -194,6 +218,7 @@ WHERE date_as_text = (('2020-05-10 10:45:29')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_text` = '2020-05-10 10:45:29')) (3 rows) +--Testcase 25: SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); name | date_as_text | date_as_number @@ -201,6 +226,7 @@ WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); ThirdDate | Sun May 10 10:45:29 2020 | Sun May 10 10:45:29 2020 (1 row) +--Testcase 26: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); @@ -212,6 +238,7 @@ WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); (3 rows) -- Comparing greater values without using to_timestamp +--Testcase 27: SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29.000')::timestamp); name | date_as_text | date_as_number @@ -220,6 +247,7 @@ WHERE date_as_text > (('2020-05-10 10:45:29.000')::timestamp); SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 28: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29.000')::timestamp); @@ -230,6 +258,7 @@ WHERE date_as_text > (('2020-05-10 10:45:29.000')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_text` > '2020-05-10 10:45:29')) (3 rows) +--Testcase 29: SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29.000')::timestamp); name | date_as_text | date_as_number @@ -238,6 +267,7 @@ WHERE date_as_number > (('2020-05-10 10:45:29.000')::timestamp); SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 30: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29.000')::timestamp); @@ -248,6 +278,7 @@ WHERE date_as_number > (('2020-05-10 10:45:29.000')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_number` > strftime('%s', '2020-05-10 10:45:29'))) (3 rows) +--Testcase 31: SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29')::timestamp); name | date_as_text | date_as_number @@ -256,6 +287,7 @@ WHERE date_as_text > (('2020-05-10 10:45:29')::timestamp); SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 32: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29')::timestamp); @@ -266,6 +298,7 @@ WHERE date_as_text > (('2020-05-10 10:45:29')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_text` > '2020-05-10 10:45:29')) (3 rows) +--Testcase 33: SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29')::timestamp); name | date_as_text | date_as_number @@ -274,6 +307,7 @@ WHERE date_as_number > (('2020-05-10 10:45:29')::timestamp); SecondDate | Tue May 12 13:32:31 2020 | Tue May 12 13:32:31 2020 (2 rows) +--Testcase 34: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29')::timestamp); @@ -284,7 +318,11 @@ WHERE date_as_number > (('2020-05-10 10:45:29')::timestamp); SQLite query: SELECT `name`, `date_as_text`, `date_as_number` FROM main."dates" WHERE ((`date_as_number` > strftime('%s', '2020-05-10 10:45:29'))) (3 rows) +--Testcase 35: DROP FOREIGN TABLE dates1; +--Testcase 36: DROP FOREIGN TABLE dates2; +--Testcase 37: DROP SERVER sqlite_svr; +--Testcase 38: DROP EXTENSION sqlite_fdw CASCADE; diff --git a/expected/selectfunc.out b/expected/selectfunc.out new file mode 100644 index 00000000..8d86d0d7 --- /dev/null +++ b/expected/selectfunc.out @@ -0,0 +1,430 @@ +SET datestyle=ISO; +SET timezone='Japan'; +--Testcase 1: +CREATE EXTENSION sqlite_fdw; +--Testcase 2: +CREATE SERVER server1 FOREIGN DATA WRAPPER sqlite_fdw +OPTIONS (database '/tmp/sqlitefdw_test_selectfunc.db'); +--CREATE USER MAPPING FOR CURRENT_USER SERVER server1 OPTIONS(user 'user', password 'pass'); +--IMPORT FOREIGN SCHEMA public FROM SERVER server1 INTO public OPTIONS(import_time_text 'false'); +--Testcase 3: +CREATE FOREIGN TABLE s3(id text OPTIONS (key 'true'), time timestamp, tag1 text, value1 float, value2 int, value3 float, value4 int, str1 text, str2 text) SERVER server1; +-- s3 (value1 as float8, value2 as bigint) +--Testcase 4: +\d s3; + Foreign table "public.s3" + Column | Type | Collation | Nullable | Default | FDW options +--------+-----------------------------+-----------+----------+---------+-------------- + id | text | | | | (key 'true') + time | timestamp without time zone | | | | + tag1 | text | | | | + value1 | double precision | | | | + value2 | integer | | | | + value3 | double precision | | | | + value4 | integer | | | | + str1 | text | | | | + str2 | text | | | | +Server: server1 + +--Testcase 5: +SELECT * FROM s3; + id | time | tag1 | value1 | value2 | value3 | value4 | str1 | str2 +----+---------------------+------+--------+--------+--------+--------+-----------+----------- + 0 | 1970-01-01 00:00:00 | a | 0.1 | 100 | -0.1 | -100 | ---XYZ--- | XYZ + 1 | 1970-01-01 00:00:01 | a | 0.2 | 100 | -0.2 | -100 | ---XYZ--- | XYZ + 2 | 1970-01-01 00:00:02 | a | 0.3 | 100 | -0.3 | -100 | ---XYZ--- | XYZ + 3 | 1970-01-01 00:00:03 | b | 1.1 | 200 | -1.1 | -200 | ---XYZ--- | XYZ + 4 | 1970-01-01 00:00:04 | b | 2.2 | 200 | -2.2 | -200 | ---XYZ--- | XYZ + 5 | 1970-01-01 00:00:05 | b | 3.3 | 200 | -3.3 | -200 | ---XYZ--- | XYZ +(6 rows) + +-- select float8() (not pushdown, remove float8, explain) +-- EXPLAIN VERBOSE +-- SELECT float8(value1), float8(value2), float8(value3), float8(value4) FROM s3; +-- sqlite fdw does not support +-- select float8() (not pushdown, remove float8, result) +-- SELECT float8(value1), float8(value2), float8(value3), float8(value4) FROM s3; +-- sqlite fdw does not support +-- select sqrt (builtin function, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(value1), sqrt(value2) FROM s3; +-- sqlite fdw does not have sqrt() +-- select sqrt (buitin function, result) +-- SELECT sqrt(value1), sqrt(value2) FROM s3; +-- sqlite fdw does not have sqrt() +-- select sqrt (builtin function,, not pushdown constraints, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE to_hex(value2) != '64'; +-- sqlite fdw does not have sqrt() +-- select sqrt (builtin function, not pushdown constraints, result) +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE to_hex(value2) != '64'; +-- sqlite fdw does not have sqrt() +-- select sqrt (builtin function, pushdown constraints, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE value2 != 200; +-- sqlite fdw does not have sqrt() +-- select sqrt (builtin function, pushdown constraints, result) +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE value2 != 200; +-- sqlite fdw does not have sqrt() +-- select abs (builtin function, explain) +--Testcase 6: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3; + QUERY PLAN +------------------------------------------------------------------------------ + Foreign Scan on public.s3 (cost=10.00..1010000.00 rows=1000000 width=24) + Output: abs(value1), abs(value2), abs(value3), abs(value4) + SQLite query: SELECT `value1`, `value2`, `value3`, `value4` FROM main."s3" +(3 rows) + +-- select abs (buitin function, result) +--Testcase 7: +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3; + abs | abs | abs | abs +-----+-----+-----+----- + 0.1 | 100 | 0.1 | 100 + 0.2 | 100 | 0.2 | 100 + 0.3 | 100 | 0.3 | 100 + 1.1 | 200 | 1.1 | 200 + 2.2 | 200 | 2.2 | 200 + 3.3 | 200 | 3.3 | 200 +(6 rows) + +-- select abs (builtin function, not pushdown constraints, explain) +--Testcase 8: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE to_hex(value2) != '64'; + QUERY PLAN +------------------------------------------------------------------------------ + Foreign Scan on public.s3 (cost=10.00..1010000.00 rows=1000000 width=24) + Output: abs(value1), abs(value2), abs(value3), abs(value4) + Filter: (to_hex(s3.value2) <> '64'::text) + SQLite query: SELECT `value1`, `value2`, `value3`, `value4` FROM main."s3" +(4 rows) + +-- select abs (builtin function, not pushdown constraints, result) +--Testcase 9: +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE to_hex(value2) != '64'; + abs | abs | abs | abs +-----+-----+-----+----- + 1.1 | 200 | 1.1 | 200 + 2.2 | 200 | 2.2 | 200 + 3.3 | 200 | 3.3 | 200 +(3 rows) + +-- select abs (builtin function, pushdown constraints, explain) +--Testcase 10: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE value2 != 200; + QUERY PLAN +-------------------------------------------------------------------------------------------------------- + Foreign Scan on public.s3 (cost=10.00..1010000.00 rows=1000000 width=24) + Output: abs(value1), abs(value2), abs(value3), abs(value4) + SQLite query: SELECT `value1`, `value2`, `value3`, `value4` FROM main."s3" WHERE ((`value2` <> 200)) +(3 rows) + +-- select abs (builtin function, pushdown constraints, result) +--Testcase 11: +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE value2 != 200; + abs | abs | abs | abs +-----+-----+-----+----- + 0.1 | 100 | 0.1 | 100 + 0.2 | 100 | 0.2 | 100 + 0.3 | 100 | 0.3 | 100 +(3 rows) + +-- select log (builtin function, need to swap arguments, numeric cast, explain) +-- log_(v) : postgresql (base, v), sqlite (v, base) +-- EXPLAIN VERBOSE +-- SELECT log(value1::numeric, value2::numeric) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (builtin function, need to swap arguments, numeric cast, result) +-- SELECT log(value1::numeric, value2::numeric) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (stub function, need to swap arguments, float8, explain) +-- EXPLAIN VERBOSE +-- SELECT log(value1, 0.1) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (stub function, need to swap arguments, float8, result) +-- SELECT log(value1, 0.1) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (stub function, need to swap arguments, bigint, explain) +-- EXPLAIN VERBOSE +-- SELECT log(value2, 3) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (stub function, need to swap arguments, bigint, result) +-- SELECT log(value2, 3) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (stub function, need to swap arguments, mix type, explain) +-- EXPLAIN VERBOSE +-- SELECT log(value1, value2) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log (stub function, need to swap arguments, mix type, result) +-- SELECT log(value1, value2) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() +-- select log2 (stub function, explain) +-- EXPLAIN VERBOSE +-- SELECT log2(value1),log2(value2) FROM s3; +-- sqlite fdw does not have log2() +-- select log2 (stub function, result) +-- SELECT log2(value1),log2(value2) FROM s3; +-- sqlite fdw does not have log2() +-- select spread (stub agg function, explain) +-- EXPLAIN VERBOSE +-- SELECT spread(value1),spread(value2),spread(value3),spread(value4) FROM s3; +-- sqlite fdw does not have spread() +-- select spread (stub agg function, result) +-- SELECT spread(value1),spread(value2),spread(value3),spread(value4) FROM s3; +-- sqlite fdw does not have spread() +-- select spread (stub agg function, raise exception if not expected type) +-- SELECT spread(value1::numeric),spread(value2::numeric),spread(value3::numeric),spread(value4::numeric) FROM s3; +-- sqlite fdw does not have spread() +-- select abs as nest function with agg (pushdown, explain) +--Testcase 12: +EXPLAIN VERBOSE +SELECT sum(value3),abs(sum(value3)) FROM s3; + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan (cost=1.00..1.00 rows=1 width=16) + Output: (sum(value3)), (abs(sum(value3))) + SQLite query: SELECT sum(`value3`), abs(sum(`value3`)) FROM main."s3" +(3 rows) + +-- select abs as nest function with agg (pushdown, result) +--Testcase 13: +SELECT sum(value3),abs(sum(value3)) FROM s3; + sum | abs +------+----- + -7.2 | 7.2 +(1 row) + +-- select abs as nest with log2 (pushdown, explain) +-- EXPLAIN VERBOSE +-- SELECT abs(log2(value1)),abs(log2(1/value1)) FROM s3; +-- sqlite fdw does not have log2() +-- select abs as nest with log2 (pushdown, result) +-- SELECT abs(log2(value1)),abs(log2(1/value1)) FROM s3; +-- sqlite fdw does not have log2() +-- select abs with non pushdown func and explicit constant (explain) +--Testcase 14: +EXPLAIN VERBOSE +SELECT abs(value3), pi(), 4.1 FROM s3; + QUERY PLAN +--------------------------------------------------------------------------- + Foreign Scan on public.s3 (cost=10.00..1002500.00 rows=1000000 width=48) + Output: abs(value3), '3.141592653589793'::double precision, 4.1 + SQLite query: SELECT `value3` FROM main."s3" +(3 rows) + +-- select abs with non pushdown func and explicit constant (result) +--Testcase 15: +SELECT abs(value3), pi(), 4.1 FROM s3; + abs | pi | ?column? +-----+-------------------+---------- + 0.1 | 3.141592653589793 | 4.1 + 0.2 | 3.141592653589793 | 4.1 + 0.3 | 3.141592653589793 | 4.1 + 1.1 | 3.141592653589793 | 4.1 + 2.2 | 3.141592653589793 | 4.1 + 3.3 | 3.141592653589793 | 4.1 +(6 rows) + +-- select sqrt as nest function with agg and explicit constant (pushdown, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(count(value1)), pi(), 4.1 FROM s3; +-- sqlite fdw does not have sqrt() +-- select sqrt as nest function with agg and explicit constant (pushdown, result) +-- SELECT sqrt(count(value1)), pi(), 4.1 FROM s3; +-- sqlite fdw does not have sqrt() +-- select sqrt as nest function with agg and explicit constant and tag (error, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(count(value1)), pi(), 4.1, tag1 FROM s3; +-- sqlite fdw does not have sqrt() +-- select spread (stub agg function and group by influx_time() and tag) (explain) +-- EXPLAIN VERBOSE +-- SELECT spread("value1"),influx_time(time, interval '1s'),tag1 FROM s3 WHERE time >= to_timestamp(0) and time <= to_timestamp(4) GROUP BY influx_time(time, interval '1s'), tag1; +-- sqlite fdw does not have spread() and influx_time() +-- select spread (stub agg function and group by influx_time() and tag) (result) +-- SELECT spread("value1"),influx_time(time, interval '1s'),tag1 FROM s3 WHERE time >= to_timestamp(0) and time <= to_timestamp(4) GROUP BY influx_time(time, interval '1s'), tag1; +-- sqlite fdw does not have spread() and influx_time() +-- select spread (stub agg function and group by tag only) (result) +-- SELECT tag1,spread("value1") FROM s3 WHERE time >= to_timestamp(0) and time <= to_timestamp(4) GROUP BY tag1; +-- sqlite fdw does not have spread() +-- select spread (stub agg function and other aggs) (result) +-- SELECT sum("value1"),spread("value1"),count("value1") FROM s3; +-- sqlite fdw does not have spread() +-- select abs with order by (explain) +--Testcase 16: +EXPLAIN VERBOSE +SELECT value1, abs(1-value1) FROM s3 order by abs(1-value1); + QUERY PLAN +-------------------------------------------------------------------------------------------- + Foreign Scan on public.s3 (cost=10.00..10.05 rows=10 width=16) + Output: value1, abs(('1'::double precision - value1)) + SQLite query: SELECT `value1` FROM main."s3" ORDER BY abs((1 - `value1`)) ASC NULLS LAST +(3 rows) + +-- select abs with order by (result) +--Testcase 17: +SELECT value1, abs(1-value1) FROM s3 order by abs(1-value1); + value1 | abs +--------+--------------------- + 1.1 | 0.10000000000000009 + 0.3 | 0.7 + 0.2 | 0.8 + 0.1 | 0.9 + 2.2 | 1.2000000000000002 + 3.3 | 2.3 +(6 rows) + +-- select abs with order by index (result) +--Testcase 18: +SELECT value1, abs(1-value1) FROM s3 order by 2,1; + value1 | abs +--------+--------------------- + 1.1 | 0.10000000000000009 + 0.3 | 0.7 + 0.2 | 0.8 + 0.1 | 0.9 + 2.2 | 1.2000000000000002 + 3.3 | 2.3 +(6 rows) + +-- select abs with order by index (result) +--Testcase 19: +SELECT value1, abs(1-value1) FROM s3 order by 1,2; + value1 | abs +--------+--------------------- + 0.1 | 0.9 + 0.2 | 0.8 + 0.3 | 0.7 + 1.1 | 0.10000000000000009 + 2.2 | 1.2000000000000002 + 3.3 | 2.3 +(6 rows) + +-- select abs and as +--Testcase 20: +SELECT abs(value3) as abs1 FROM s3; + abs1 +------ + 0.1 + 0.2 + 0.3 + 1.1 + 2.2 + 3.3 +(6 rows) + +-- select spread over join query (explain) +-- EXPLAIN VERBOSE +-- SELECT spread(t1.value1), spread(t2.value1) FROM s3 t1 INNER JOIN s3 t2 ON (t1.value1 = t2.value1) where t1.value1 = 0.1; +-- sqlite fdw does not have spread() +-- select spread over join query (result, stub call error) +-- SELECT spread(t1.value1), spread(t2.value1) FROM s3 t1 INNER JOIN s3 t2 ON (t1.value1 = t2.value1) where t1.value1 = 0.1; +-- sqlite fdw does not have spread() +-- select spread with having (explain) +-- EXPLAIN VERBOSE +-- SELECT spread(value1) FROM s3 HAVING spread(value1) > 100; +-- sqlite fdw does not have spread() +-- select spread with having (explain, cannot pushdown, stub call error) +-- SELECT spread(value1) FROM s3 HAVING spread(value1) > 100; +-- sqlite fdw does not have spread() +-- select abs with arithmetic and tag in the middle (explain) +--Testcase 21: +EXPLAIN VERBOSE +SELECT abs(value1) + 1, value2, tag1, sqrt(value2) FROM s3; + QUERY PLAN +------------------------------------------------------------------------------------------------- + Foreign Scan on public.s3 (cost=10.00..1010000.00 rows=1000000 width=52) + Output: (abs(value1) + '1'::double precision), value2, tag1, sqrt((value2)::double precision) + SQLite query: SELECT `tag1`, `value1`, `value2` FROM main."s3" +(3 rows) + +-- select abs with arithmetic and tag in the middle (result) +--Testcase 22: +SELECT abs(value1) + 1, value2, tag1, sqrt(value2) FROM s3; + ?column? | value2 | tag1 | sqrt +----------+--------+------+-------------------- + 1.1 | 100 | a | 10 + 1.2 | 100 | a | 10 + 1.3 | 100 | a | 10 + 2.1 | 200 | b | 14.142135623730951 + 3.2 | 200 | b | 14.142135623730951 + 4.3 | 200 | b | 14.142135623730951 +(6 rows) + +-- select with order by limit (explain) +--Testcase 23: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value3), sqrt(value2) FROM s3 ORDER BY abs(value3) LIMIT 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ + Foreign Scan on public.s3 (cost=1.00..1.00 rows=1 width=24) + Output: abs(value1), abs(value3), sqrt((value2)::double precision) + SQLite query: SELECT `value1`, `value2`, `value3` FROM main."s3" ORDER BY abs(`value3`) ASC NULLS LAST LIMIT 1 +(3 rows) + +-- select with order by limit (explain) +--Testcase 24: +SELECT abs(value1), abs(value3), sqrt(value2) FROM s3 ORDER BY abs(value3) LIMIT 1; + abs | abs | sqrt +-----+-----+------ + 0.1 | 0.1 | 10 +(1 row) + +-- select mixing with non pushdown func (all not pushdown, explain) +--Testcase 25: +EXPLAIN VERBOSE +SELECT abs(value1), sqrt(value2), upper(tag1) FROM s3; + QUERY PLAN +--------------------------------------------------------------------------- + Foreign Scan on public.s3 (cost=10.00..1010000.00 rows=1000000 width=48) + Output: abs(value1), sqrt((value2)::double precision), upper(tag1) + SQLite query: SELECT `tag1`, `value1`, `value2` FROM main."s3" +(3 rows) + +-- select mixing with non pushdown func (result) +--Testcase 26: +SELECT abs(value1), sqrt(value2), upper(tag1) FROM s3; + abs | sqrt | upper +-----+--------------------+------- + 0.1 | 10 | A + 0.2 | 10 | A + 0.3 | 10 | A + 1.1 | 14.142135623730951 | B + 2.2 | 14.142135623730951 | B + 3.3 | 14.142135623730951 | B +(6 rows) + +-- sqlite data prep +-- sqlite pushdown supported functions (explain) +--Testcase 27: +EXPLAIN VERBOSE +SELECT abs(value3), length(tag1), lower(str1), ltrim(str2), ltrim(str1, '-'), replace(str1, 'XYZ', 'ABC'), round(value3), rtrim(str1, '-'), rtrim(str2), substr(str1, 4), substr(str1, 4, 3) FROM s3; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.s3 (cost=10.00..1027500.00 rows=1000000 width=276) + Output: abs(value3), length(tag1), lower(str1), ltrim(str2), ltrim(str1, '-'::text), replace(str1, 'XYZ'::text, 'ABC'::text), round(value3), rtrim(str1, '-'::text), rtrim(str2), substr(str1, 4), substr(str1, 4, 3) + SQLite query: SELECT `tag1`, `value3`, `str1`, `str2` FROM main."s3" +(3 rows) + +-- sqlite pushdown supported functions (result) +--Testcase 28: +SELECT abs(value3), length(tag1), lower(str1), ltrim(str2), ltrim(str1, '-'), replace(str1, 'XYZ', 'ABC'), round(value3), rtrim(str1, '-'), rtrim(str2), substr(str1, 4), substr(str1, 4, 3) FROM s3; + abs | length | lower | ltrim | ltrim | replace | round | rtrim | rtrim | substr | substr +-----+--------+-----------+--------+--------+-----------+-------+--------+--------+--------+-------- + 0.1 | 1 | ---xyz--- | XYZ | XYZ--- | ---ABC--- | -0 | ---XYZ | XYZ | XYZ--- | XYZ + 0.2 | 1 | ---xyz--- | XYZ | XYZ--- | ---ABC--- | -0 | ---XYZ | XYZ | XYZ--- | XYZ + 0.3 | 1 | ---xyz--- | XYZ | XYZ--- | ---ABC--- | -0 | ---XYZ | XYZ | XYZ--- | XYZ + 1.1 | 1 | ---xyz--- | XYZ | XYZ--- | ---ABC--- | -1 | ---XYZ | XYZ | XYZ--- | XYZ + 2.2 | 1 | ---xyz--- | XYZ | XYZ--- | ---ABC--- | -2 | ---XYZ | XYZ | XYZ--- | XYZ + 3.3 | 1 | ---xyz--- | XYZ | XYZ--- | ---ABC--- | -3 | ---XYZ | XYZ | XYZ--- | XYZ +(6 rows) + +--Testcase 29: +DROP FOREIGN TABLE s3; +--Testcase 30: +DROP SERVER server1; +--Testcase 31: +DROP EXTENSION sqlite_fdw; diff --git a/expected/type.out b/expected/type.out index fe0d7fab..29e4d177 100644 --- a/expected/type.out +++ b/expected/type.out @@ -247,8 +247,9 @@ SELECT * FROM "type_TIMESTAMP" WHERE col > b; 2017-11-06 12:34:56.789 | 2017-11-06 00:00:00 (1 row) +--Testcase 47: DROP EXTENSION sqlite_fdw CASCADE; -NOTICE: drop cascades to 25 other objects +NOTICE: drop cascades to 26 other objects DETAIL: drop cascades to server sqlite_svr drop cascades to foreign table department drop cascades to foreign table employee @@ -258,6 +259,7 @@ drop cascades to foreign table t drop cascades to foreign table multiprimary drop cascades to foreign table columntest drop cascades to foreign table noprimary +drop cascades to foreign table limittest drop cascades to foreign table "type_STRING" drop cascades to foreign table "type_BOOLEAN" drop cascades to foreign table "type_BYTE" diff --git a/sql/aggregate.sql b/sql/aggregate.sql index de980fb0..fcc162f5 100644 --- a/sql/aggregate.sql +++ b/sql/aggregate.sql @@ -1,8 +1,11 @@ --SET log_min_messages TO DEBUG1; --SET client_min_messages TO DEBUG1; +--Testcase 16: CREATE EXTENSION sqlite_fdw; +--Testcase 17: CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw OPTIONS (database '/tmp/sqlitefdw_test.db'); +--Testcase 18: CREATE FOREIGN TABLE multiprimary(a int, b int OPTIONS (key 'true'), c int OPTIONS(key 'true')) SERVER sqlite_svr; -- test for aggregate pushdown --Testcase 8: @@ -42,6 +45,43 @@ explain (costs off, verbose) select sum(a) from multiprimary group by b having v --Testcase 13: DROP FOREIGN TABLE multiprimary; +--Testcase 16: +CREATE FOREIGN TABLE limittest(id serial OPTIONS (key 'true'), x int, y text) SERVER sqlite_svr; + +--Testcase 17: +INSERT INTO limittest(x, y) VALUES (1, 'x'), (2, 'x'), (3, 'x'), (4, 'x'); +--Testcase 18: +INSERT INTO limittest(x, y) VALUES (1, 'y'), (2, 'y'), (3, 'y'), (4, 'y'); +--Testcase 19: +INSERT INTO limittest(x, y) VALUES (1, 'z'), (2, 'z'), (3, 'z'), (4, 'z'); + +--Testcase 20: +EXPLAIN VERBOSE +SELECT avg(x) FROM limittest GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; +--Testcase 21: +SELECT avg(x) FROM limittest GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; + +--Testcase 22: +EXPLAIN VERBOSE +SELECT avg(x) FROM limittest WHERE x >= 0 GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; +--Testcase 23: +SELECT avg(x) FROM limittest WHERE x >= 0 GROUP BY y ORDER BY 1 DESC FETCH FIRST 2 ROWS WITH TIES; + +--Testcase 24: +EXPLAIN VERBOSE +SELECT x FROM limittest WHERE x > 0 ORDER BY 1 FETCH FIRST 2 ROWS WITH TIES; +--Testcase 25: +SELECT x FROM limittest WHERE x > 0 ORDER BY 1 FETCH FIRST 2 ROWS WITH TIES; + +--Testcase 26: +EXPLAIN VERBOSE +SELECT x FROM limittest ORDER BY 1 FETCH FIRST 2 ROWS ONLY; +--Testcase 27: +SELECT x FROM limittest ORDER BY 1 FETCH FIRST 2 ROWS ONLY; + +--Testcase 28: +DROP FOREIGN TABLE limittest; + --Testcase 14: DROP SERVER sqlite_svr; --Testcase 15: diff --git a/sql/extra/limit.sql b/sql/extra/limit.sql index 58e439c2..e698a7b1 100644 --- a/sql/extra/limit.sql +++ b/sql/extra/limit.sql @@ -59,6 +59,7 @@ CREATE FOREIGN TABLE tenk1 ( string4 name ) SERVER sqlite_svr; +--Testcase 88: CREATE TABLE parent_table ( unique1 int4 PRIMARY KEY, unique2 int4, @@ -78,6 +79,7 @@ CREATE TABLE parent_table ( string4 name ); +--Testcase 89: CREATE FOREIGN table inherited_table () INHERITS (parent_table) SERVER sqlite_svr options (table 'tenk1'); @@ -236,31 +238,38 @@ select unique1, unique2, nextval('testseq') select unique1, unique2, nextval('testseq') from tenk1 order by unique2 limit 10; +--Testcase 90: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by unique2 limit 10 offset 5; +--Testcase 91: select unique1, unique2, nextval('testseq') from tenk1 order by unique2 limit 10 offset 5; --Testcase 17: select currval('testseq'); +--Testcase 92: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10; +--Testcase 93: select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10; +--Testcase 94: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10 offset 5; +--Testcase 95: select unique1, unique2, nextval('testseq') from tenk1 order by unique2 desc limit 10 offset 5; +--Testcase 96: select currval('testseq'); --Testcase 18: @@ -272,10 +281,12 @@ select unique1, unique2, nextval('testseq') select unique1, unique2, nextval('testseq') from tenk1 order by tenthous limit 10; +--Testcase 97: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from tenk1 order by tenthous limit 10 offset 5; +--Testcase 98: select unique1, unique2, nextval('testseq') from tenk1 order by tenthous limit 10 offset 5; @@ -283,21 +294,26 @@ select unique1, unique2, nextval('testseq') select currval('testseq'); -- test for limit and offset when querying table and foreign table inherited +--Testcase 99: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10; +--Testcase 100: select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10; -- when querying regular tables with inherited tables, only limit is pushed-down when no offset is specified +--Testcase 101: explain (verbose, costs off) select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10 offset 5; +--Testcase 102: select unique1, unique2, nextval('testseq') from parent_table order by tenthous limit 10 offset 5; +--Testcase 103: select currval('testseq'); --Testcase 21: diff --git a/sql/extra/numeric.sql b/sql/extra/numeric.sql index 4610f8cb..d57f9878 100644 --- a/sql/extra/numeric.sql +++ b/sql/extra/numeric.sql @@ -1324,6 +1324,7 @@ INSERT INTO width_bucket_tbl VALUES (0, 'NaN'::numeric, 4.0, 888); --Testcase 630: SELECT width_bucket(id1::float8, id2, id3::float8, id4) FROM width_bucket_tbl; + -- normal operation --Testcase 631: CREATE FOREIGN TABLE width_bucket_test ( diff --git a/sql/extra/timestamp.sql b/sql/extra/timestamp.sql index 5390f182..288bdd29 100644 --- a/sql/extra/timestamp.sql +++ b/sql/extra/timestamp.sql @@ -1,9 +1,12 @@ -- -- TIMESTAMP -- +--Testcase 1: CREATE EXTENSION sqlite_fdw; +--Testcase 2: CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw OPTIONS (database '/tmp/sqlitefdw_test_core.db'); +--Testcase 3: CREATE FOREIGN TABLE dates1 ( name varchar(20), date_as_text timestamp without time zone, @@ -11,6 +14,7 @@ CREATE FOREIGN TABLE dates1 ( SERVER sqlite_svr OPTIONS (table 'dates'); +--Testcase 4: CREATE FOREIGN TABLE dates2 ( name varchar(20), date_as_text timestamp without time zone, @@ -19,79 +23,101 @@ SERVER sqlite_svr OPTIONS (table 'dates'); -- Showing timestamp column from SQLite value as TEXT and as INTEGER/FLOAT has same value +--Testcase 5: SELECT name, to_char(date_as_text, 'YYYY-MM-DD HH24:MI:SS.MS') as date_as_text, to_char(date_as_number, 'YYYY-MM-DD HH24:MI:SS.MS') as date_as_number FROM dates1; +--Testcase 6: SELECT * FROM dates2; -- Comparing exact values showing same results even comparing to a text source sqlite column or numerical source sqlite column +--Testcase 7: SELECT * FROM dates1 WHERE date_as_text = to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 8: SELECT * FROM dates1 WHERE date_as_number = to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 9: SELECT * FROM dates1 WHERE date_as_text = to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 10: SELECT * FROM dates1 WHERE date_as_number = to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); -- Comparing greater values showing same results even comparing to a text source sqlite column or numerical source sqlite column +--Testcase 11: SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 12: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 13: SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 14: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29.000', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 15: SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 16: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 17: SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); +--Testcase 18: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > to_timestamp('2020-05-10 10:45:29', 'YYYY-MM-DD HH24:MI:SS.MS'); --- Comparing without using to_timestamp +--Testcase 19: SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 20: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 21: SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 22: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 23: SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29')::timestamp); +--Testcase 24: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text = (('2020-05-10 10:45:29')::timestamp); +--Testcase 25: SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); +--Testcase 26: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); @@ -99,35 +125,47 @@ WHERE date_as_number = (('2020-05-10 10:45:29')::timestamp); -- Comparing greater values without using to_timestamp +--Testcase 27: SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 28: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 29: SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 30: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29.000')::timestamp); +--Testcase 31: SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29')::timestamp); +--Testcase 32: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_text > (('2020-05-10 10:45:29')::timestamp); +--Testcase 33: SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29')::timestamp); +--Testcase 34: explain (verbose, costs off) SELECT * FROM dates1 WHERE date_as_number > (('2020-05-10 10:45:29')::timestamp); +--Testcase 35: DROP FOREIGN TABLE dates1; +--Testcase 36: DROP FOREIGN TABLE dates2; +--Testcase 37: DROP SERVER sqlite_svr; +--Testcase 38: DROP EXTENSION sqlite_fdw CASCADE; diff --git a/sql/init.sql b/sql/init.sql index 22707ac7..0dddde2c 100644 --- a/sql/init.sql +++ b/sql/init.sql @@ -3,6 +3,7 @@ DROP TABLE IF EXISTS department; DROP TABLE IF EXISTS employee; DROP TABLE IF EXISTS empdata; DROP TABLE IF EXISTS numbers; +DROP TABLE IF EXISTS limittest; CREATE TABLE department(department_id int primary key, department_name text); CREATE TABLE employee(emp_id int primary key, emp_name text, emp_dept_id int); CREATE TABLE empdata(emp_id int primary key, emp_dat bytea); @@ -11,7 +12,7 @@ CREATE TABLE t(a integer primary key, b integer); CREATE TABLE multiprimary(a integer, b integer, c integer, primary key(b,c)); CREATE TABLE columntest("a a" integer, "b b" integer,"c c" integer, primary key("a a","b b") ); CREATE TABLE noprimary(a integer, b text); - +CREATE TABLE limittest(id int primary key, x integer, y text); CREATE TABLE "type_STRING" (col text primary key); CREATE TABLE "type_BOOLEAN" (col boolean primary key); diff --git a/sql/init_selectfunc.sql b/sql/init_selectfunc.sql new file mode 100644 index 00000000..3bae29c0 --- /dev/null +++ b/sql/init_selectfunc.sql @@ -0,0 +1,11 @@ + +DROP TABLE IF EXISTS s3; +CREATE TABLE s3(id text primary key, time timestamp, tag1 text, value1 float, value2 int, value3 float, value4 int, str1 text, str2 text); +INSERT INTO 's3' VALUES (0, DATETIME('1970-01-01 00:00:00'), 'a', 0.1, 100, -0.1, -100, '---XYZ---', ' XYZ '); +INSERT INTO 's3' VALUES (1, DATETIME('1970-01-01 00:00:01'), 'a', 0.2, 100, -0.2, -100, '---XYZ---', ' XYZ '); +INSERT INTO 's3' VALUES (2, DATETIME('1970-01-01 00:00:02'), 'a', 0.3, 100, -0.3, -100, '---XYZ---', ' XYZ '); +INSERT INTO 's3' VALUES (3, DATETIME('1970-01-01 00:00:03'), 'b', 1.1, 200, -1.1, -200, '---XYZ---', ' XYZ '); +INSERT INTO 's3' VALUES (4, DATETIME('1970-01-01 00:00:04'), 'b', 2.2, 200, -2.2, -200, '---XYZ---', ' XYZ '); +INSERT INTO 's3' VALUES (5, DATETIME('1970-01-01 00:00:05'), 'b', 3.3, 200, -3.3, -200, '---XYZ---', ' XYZ '); + +analyze; diff --git a/sql/selectfunc.sql b/sql/selectfunc.sql new file mode 100644 index 00000000..adcdb0fa --- /dev/null +++ b/sql/selectfunc.sql @@ -0,0 +1,283 @@ +SET datestyle=ISO; +SET timezone='Japan'; + +--Testcase 1: +CREATE EXTENSION sqlite_fdw; +--Testcase 2: +CREATE SERVER server1 FOREIGN DATA WRAPPER sqlite_fdw +OPTIONS (database '/tmp/sqlitefdw_test_selectfunc.db'); +--CREATE USER MAPPING FOR CURRENT_USER SERVER server1 OPTIONS(user 'user', password 'pass'); + +--IMPORT FOREIGN SCHEMA public FROM SERVER server1 INTO public OPTIONS(import_time_text 'false'); +--Testcase 3: +CREATE FOREIGN TABLE s3(id text OPTIONS (key 'true'), time timestamp, tag1 text, value1 float, value2 int, value3 float, value4 int, str1 text, str2 text) SERVER server1; + +-- s3 (value1 as float8, value2 as bigint) +--Testcase 4: +\d s3; +--Testcase 5: +SELECT * FROM s3; + +-- select float8() (not pushdown, remove float8, explain) +-- EXPLAIN VERBOSE +-- SELECT float8(value1), float8(value2), float8(value3), float8(value4) FROM s3; +-- sqlite fdw does not support + +-- select float8() (not pushdown, remove float8, result) +-- SELECT float8(value1), float8(value2), float8(value3), float8(value4) FROM s3; +-- sqlite fdw does not support + +-- select sqrt (builtin function, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(value1), sqrt(value2) FROM s3; +-- sqlite fdw does not have sqrt() + +-- select sqrt (buitin function, result) +-- SELECT sqrt(value1), sqrt(value2) FROM s3; +-- sqlite fdw does not have sqrt() + +-- select sqrt (builtin function,, not pushdown constraints, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE to_hex(value2) != '64'; +-- sqlite fdw does not have sqrt() + +-- select sqrt (builtin function, not pushdown constraints, result) +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE to_hex(value2) != '64'; +-- sqlite fdw does not have sqrt() + +-- select sqrt (builtin function, pushdown constraints, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE value2 != 200; +-- sqlite fdw does not have sqrt() + +-- select sqrt (builtin function, pushdown constraints, result) +-- SELECT sqrt(value1), sqrt(value2) FROM s3 WHERE value2 != 200; +-- sqlite fdw does not have sqrt() + +-- select abs (builtin function, explain) +--Testcase 6: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3; + +-- select abs (buitin function, result) +--Testcase 7: +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3; + +-- select abs (builtin function, not pushdown constraints, explain) +--Testcase 8: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE to_hex(value2) != '64'; + +-- select abs (builtin function, not pushdown constraints, result) +--Testcase 9: +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE to_hex(value2) != '64'; + +-- select abs (builtin function, pushdown constraints, explain) +--Testcase 10: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE value2 != 200; + +-- select abs (builtin function, pushdown constraints, result) +--Testcase 11: +SELECT abs(value1), abs(value2), abs(value3), abs(value4) FROM s3 WHERE value2 != 200; + +-- select log (builtin function, need to swap arguments, numeric cast, explain) +-- log_(v) : postgresql (base, v), sqlite (v, base) +-- EXPLAIN VERBOSE +-- SELECT log(value1::numeric, value2::numeric) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (builtin function, need to swap arguments, numeric cast, result) +-- SELECT log(value1::numeric, value2::numeric) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (stub function, need to swap arguments, float8, explain) +-- EXPLAIN VERBOSE +-- SELECT log(value1, 0.1) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (stub function, need to swap arguments, float8, result) +-- SELECT log(value1, 0.1) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (stub function, need to swap arguments, bigint, explain) +-- EXPLAIN VERBOSE +-- SELECT log(value2, 3) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (stub function, need to swap arguments, bigint, result) +-- SELECT log(value2, 3) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (stub function, need to swap arguments, mix type, explain) +-- EXPLAIN VERBOSE +-- SELECT log(value1, value2) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log (stub function, need to swap arguments, mix type, result) +-- SELECT log(value1, value2) FROM s3 WHERE value1 != 1; +-- sqlite fdw does not have log() + +-- select log2 (stub function, explain) +-- EXPLAIN VERBOSE +-- SELECT log2(value1),log2(value2) FROM s3; +-- sqlite fdw does not have log2() + +-- select log2 (stub function, result) +-- SELECT log2(value1),log2(value2) FROM s3; +-- sqlite fdw does not have log2() + +-- select spread (stub agg function, explain) +-- EXPLAIN VERBOSE +-- SELECT spread(value1),spread(value2),spread(value3),spread(value4) FROM s3; +-- sqlite fdw does not have spread() + +-- select spread (stub agg function, result) +-- SELECT spread(value1),spread(value2),spread(value3),spread(value4) FROM s3; +-- sqlite fdw does not have spread() + +-- select spread (stub agg function, raise exception if not expected type) +-- SELECT spread(value1::numeric),spread(value2::numeric),spread(value3::numeric),spread(value4::numeric) FROM s3; +-- sqlite fdw does not have spread() + +-- select abs as nest function with agg (pushdown, explain) +--Testcase 12: +EXPLAIN VERBOSE +SELECT sum(value3),abs(sum(value3)) FROM s3; + +-- select abs as nest function with agg (pushdown, result) +--Testcase 13: +SELECT sum(value3),abs(sum(value3)) FROM s3; + +-- select abs as nest with log2 (pushdown, explain) +-- EXPLAIN VERBOSE +-- SELECT abs(log2(value1)),abs(log2(1/value1)) FROM s3; +-- sqlite fdw does not have log2() + +-- select abs as nest with log2 (pushdown, result) +-- SELECT abs(log2(value1)),abs(log2(1/value1)) FROM s3; +-- sqlite fdw does not have log2() + +-- select abs with non pushdown func and explicit constant (explain) +--Testcase 14: +EXPLAIN VERBOSE +SELECT abs(value3), pi(), 4.1 FROM s3; + +-- select abs with non pushdown func and explicit constant (result) +--Testcase 15: +SELECT abs(value3), pi(), 4.1 FROM s3; + +-- select sqrt as nest function with agg and explicit constant (pushdown, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(count(value1)), pi(), 4.1 FROM s3; +-- sqlite fdw does not have sqrt() + +-- select sqrt as nest function with agg and explicit constant (pushdown, result) +-- SELECT sqrt(count(value1)), pi(), 4.1 FROM s3; +-- sqlite fdw does not have sqrt() + +-- select sqrt as nest function with agg and explicit constant and tag (error, explain) +-- EXPLAIN VERBOSE +-- SELECT sqrt(count(value1)), pi(), 4.1, tag1 FROM s3; +-- sqlite fdw does not have sqrt() + +-- select spread (stub agg function and group by influx_time() and tag) (explain) +-- EXPLAIN VERBOSE +-- SELECT spread("value1"),influx_time(time, interval '1s'),tag1 FROM s3 WHERE time >= to_timestamp(0) and time <= to_timestamp(4) GROUP BY influx_time(time, interval '1s'), tag1; +-- sqlite fdw does not have spread() and influx_time() + +-- select spread (stub agg function and group by influx_time() and tag) (result) +-- SELECT spread("value1"),influx_time(time, interval '1s'),tag1 FROM s3 WHERE time >= to_timestamp(0) and time <= to_timestamp(4) GROUP BY influx_time(time, interval '1s'), tag1; +-- sqlite fdw does not have spread() and influx_time() + +-- select spread (stub agg function and group by tag only) (result) +-- SELECT tag1,spread("value1") FROM s3 WHERE time >= to_timestamp(0) and time <= to_timestamp(4) GROUP BY tag1; +-- sqlite fdw does not have spread() + +-- select spread (stub agg function and other aggs) (result) +-- SELECT sum("value1"),spread("value1"),count("value1") FROM s3; +-- sqlite fdw does not have spread() + +-- select abs with order by (explain) +--Testcase 16: +EXPLAIN VERBOSE +SELECT value1, abs(1-value1) FROM s3 order by abs(1-value1); + +-- select abs with order by (result) +--Testcase 17: +SELECT value1, abs(1-value1) FROM s3 order by abs(1-value1); + +-- select abs with order by index (result) +--Testcase 18: +SELECT value1, abs(1-value1) FROM s3 order by 2,1; + +-- select abs with order by index (result) +--Testcase 19: +SELECT value1, abs(1-value1) FROM s3 order by 1,2; + +-- select abs and as +--Testcase 20: +SELECT abs(value3) as abs1 FROM s3; + +-- select spread over join query (explain) +-- EXPLAIN VERBOSE +-- SELECT spread(t1.value1), spread(t2.value1) FROM s3 t1 INNER JOIN s3 t2 ON (t1.value1 = t2.value1) where t1.value1 = 0.1; +-- sqlite fdw does not have spread() + +-- select spread over join query (result, stub call error) +-- SELECT spread(t1.value1), spread(t2.value1) FROM s3 t1 INNER JOIN s3 t2 ON (t1.value1 = t2.value1) where t1.value1 = 0.1; +-- sqlite fdw does not have spread() + +-- select spread with having (explain) +-- EXPLAIN VERBOSE +-- SELECT spread(value1) FROM s3 HAVING spread(value1) > 100; +-- sqlite fdw does not have spread() + +-- select spread with having (explain, cannot pushdown, stub call error) +-- SELECT spread(value1) FROM s3 HAVING spread(value1) > 100; +-- sqlite fdw does not have spread() + +-- select abs with arithmetic and tag in the middle (explain) +--Testcase 21: +EXPLAIN VERBOSE +SELECT abs(value1) + 1, value2, tag1, sqrt(value2) FROM s3; + +-- select abs with arithmetic and tag in the middle (result) +--Testcase 22: +SELECT abs(value1) + 1, value2, tag1, sqrt(value2) FROM s3; + +-- select with order by limit (explain) +--Testcase 23: +EXPLAIN VERBOSE +SELECT abs(value1), abs(value3), sqrt(value2) FROM s3 ORDER BY abs(value3) LIMIT 1; + +-- select with order by limit (explain) +--Testcase 24: +SELECT abs(value1), abs(value3), sqrt(value2) FROM s3 ORDER BY abs(value3) LIMIT 1; + +-- select mixing with non pushdown func (all not pushdown, explain) +--Testcase 25: +EXPLAIN VERBOSE +SELECT abs(value1), sqrt(value2), upper(tag1) FROM s3; + +-- select mixing with non pushdown func (result) +--Testcase 26: +SELECT abs(value1), sqrt(value2), upper(tag1) FROM s3; + +-- sqlite data prep + +-- sqlite pushdown supported functions (explain) +--Testcase 27: +EXPLAIN VERBOSE +SELECT abs(value3), length(tag1), lower(str1), ltrim(str2), ltrim(str1, '-'), replace(str1, 'XYZ', 'ABC'), round(value3), rtrim(str1, '-'), rtrim(str2), substr(str1, 4), substr(str1, 4, 3) FROM s3; + +-- sqlite pushdown supported functions (result) +--Testcase 28: +SELECT abs(value3), length(tag1), lower(str1), ltrim(str2), ltrim(str1, '-'), replace(str1, 'XYZ', 'ABC'), round(value3), rtrim(str1, '-'), rtrim(str2), substr(str1, 4), substr(str1, 4, 3) FROM s3; + +--Testcase 29: +DROP FOREIGN TABLE s3; +--Testcase 30: +DROP SERVER server1; +--Testcase 31: +DROP EXTENSION sqlite_fdw; diff --git a/sql/type.sql b/sql/type.sql index d258ba43..fabfda1a 100644 --- a/sql/type.sql +++ b/sql/type.sql @@ -111,4 +111,5 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM "type_TIMESTAMP" WHERE col > b; --Testcase 43: SELECT * FROM "type_TIMESTAMP" WHERE col > b; +--Testcase 47: DROP EXTENSION sqlite_fdw CASCADE; diff --git a/sqlite_fdw.c b/sqlite_fdw.c index 2d4f1deb..0d752397 100644 --- a/sqlite_fdw.c +++ b/sqlite_fdw.c @@ -611,6 +611,9 @@ sqliteGetForeignPlan( elog(DEBUG1, "sqlite_fdw : %s", __func__); + /* Decide to execute function pushdown support in the target list. */ + fpinfo->is_tlist_func_pushdown = sqlite_is_foreign_function_tlist(root, baserel, tlist); + /* * Get FDW private data created by sqliteGetForeignUpperPaths(), if any. */ @@ -647,8 +650,9 @@ sqliteGetForeignPlan( * local_exprs list, since appendWhereClause expects a list of * RestrictInfos. */ - if (baserel->reloptkind == RELOPT_BASEREL || - baserel->reloptkind == RELOPT_OTHER_MEMBER_REL) + if ((baserel->reloptkind == RELOPT_BASEREL || + baserel->reloptkind == RELOPT_OTHER_MEMBER_REL) && + fpinfo->is_tlist_func_pushdown == false) { foreach(lc, scan_clauses) { @@ -694,7 +698,10 @@ sqliteGetForeignPlan( * parameterization right now, so there should be no scan_clauses for * a joinrel or an upper rel either. */ - Assert(!scan_clauses); + if (fpinfo->is_tlist_func_pushdown == false) + { + Assert(!scan_clauses); + } /* * Instead we get the conditions to apply from the fdw_private @@ -715,7 +722,39 @@ sqliteGetForeignPlan( */ /* Build the list of columns to be fetched from the foreign server. */ - fdw_scan_tlist = sqlite_build_tlist_to_deparse(baserel); + if (fpinfo->is_tlist_func_pushdown == true) + { + int next_resno = list_length(fdw_scan_tlist) + 1; + + foreach(lc, tlist) + { + TargetEntry *tlist_tle = lfirst_node(TargetEntry, lc); + + if (!IsA(tlist_tle->expr, Const)) + { + TargetEntry *tle; + + tle = makeTargetEntry(copyObject(tlist_tle->expr), + next_resno++, + NULL, + false); + fdw_scan_tlist = lappend(fdw_scan_tlist, tle); + } + } + + foreach(lc, fpinfo->local_conds) + { + RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc); + + fdw_scan_tlist = add_to_flat_tlist(fdw_scan_tlist, + pull_var_clause((Node *) rinfo->clause, + PVC_RECURSE_PLACEHOLDERS)); + } + } + else + { + fdw_scan_tlist = sqlite_build_tlist_to_deparse(baserel); + } /* * Ensure that the outer plan produces a tuple whose descriptor @@ -2409,6 +2448,13 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel, if (ifpinfo->local_conds) return; +#if PG_VERSION_NUM >= 130000 + /* Don't pushdown FETCH ... WITH TIES option */ + if (parse->limitCount + && parse->limitOption == LIMIT_OPTION_WITH_TIES) + return; +#endif + /* * Also, the LIMIT/OFFSET cannot be pushed down, if their expressions are * not safe to remote. diff --git a/sqlite_fdw.h b/sqlite_fdw.h index d20b689a..d6c8f4ef 100644 --- a/sqlite_fdw.h +++ b/sqlite_fdw.h @@ -156,11 +156,17 @@ typedef struct SqliteFdwRelationInfo /* Grouping information */ List *grouped_tlist; + + /* Function pushdown surppot in target list */ + bool is_tlist_func_pushdown; } SqliteFdwRelationInfo; extern bool sqlite_is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr); +extern bool sqlite_is_foreign_function_tlist(PlannerInfo *root, + RelOptInfo *baserel, + List *tlist); extern Expr *sqlite_find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel); extern Expr *sqlite_find_em_expr_for_input_target(PlannerInfo *root, diff --git a/sqlite_query.c b/sqlite_query.c index 5ecac40d..eb94e6d4 100644 --- a/sqlite_query.c +++ b/sqlite_query.c @@ -174,6 +174,13 @@ sqlite_convert_to_pg(Oid pgtyp, int pgtypmod, sqlite3_stmt * stmt, int attnum) } break; } + case NUMERICOID: + { + double value = sqlite3_column_double(stmt, attnum); + + valueDatum = CStringGetDatum((char *)DirectFunctionCall1(float8out, Float8GetDatum((float8) value))); + break; + } default: valueDatum = CStringGetDatum((char *) sqlite3_column_text(stmt, attnum)); } diff --git a/test.sh b/test.sh index 6cc73905..dfdcbf3e 100755 --- a/test.sh +++ b/test.sh @@ -6,8 +6,9 @@ cp -a sql/extra/*.data /tmp/ sqlite3 /tmp/sqlitefdw_test_post.db < sql/extra/init_post.sql sqlite3 /tmp/sqlitefdw_test_core.db < sql/extra/init_core.sql sqlite3 /tmp/sqlitefdw_test.db < sql/init.sql +sqlite3 /tmp/sqlitefdw_test_selectfunc.db < sql/init_selectfunc.sql -sed -i 's/REGRESS =.*/REGRESS = extra\/sqlite_fdw_post extra\/float4 extra\/float8 extra\/int4 extra\/int8 extra\/numeric extra\/join extra\/limit extra\/aggregates extra\/prepare extra\/select_having extra\/select extra\/insert extra\/update extra\/timestamp sqlite_fdw type aggregate /' Makefile +sed -i 's/REGRESS =.*/REGRESS = extra\/sqlite_fdw_post extra\/float4 extra\/float8 extra\/int4 extra\/int8 extra\/numeric extra\/join extra\/limit extra\/aggregates extra\/prepare extra\/select_having extra\/select extra\/insert extra\/update extra\/timestamp sqlite_fdw type aggregate selectfunc /' Makefile make clean make diff --git a/test_extra.sh b/test_extra.sh deleted file mode 100644 index 2a504f53..00000000 --- a/test_extra.sh +++ /dev/null @@ -1,14 +0,0 @@ -rm -rf /tmp/sqlitefdw_test*.db -rm -rf /tmp/*.data -cp -a sql/extra/*.data /tmp/ - -sqlite3 /tmp/sqlitefdw_test_post.db < sql/extra/init_post.sql -sqlite3 /tmp/sqlitefdw_test_core.db < sql/extra/init_core.sql - -export USE_PGXS=1 -sed -i 's/REGRESS =.*/REGRESS = extra\/sqlite_fdw_post extra\/float4 extra\/float8 extra\/int4 extra\/int8 extra\/numeric extra\/join extra\/limit extra\/aggregates extra\/prepare extra\/select_having extra\/select extra\/insert extra\/update extra\/timestamp /' Makefile - -make clean -make -mkdir -p results/extra || true -make check | tee make_check.out