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