--- /dev/null
+./run-test parse_schedule
+testcase insert: OK
+testcase update: OK
+testcase misc: OK
--- /dev/null
+#!/usr/bin/env bash
+#-------------------------------------------------------------------
+# test script for unit test of rewriting timestamp qeries.
+# requires Ruby
+
+cd timestamp
+make
+make test > result.txt
+cmp ../expected.txt result.txt
+if [ $? != 0 ];then
+ echo NG
+ exit 1
+fi
+make clean
+rm result.txt
+cd ..
+
+echo OK
+exit 0
--- /dev/null
+
+PROGRAM=timestamp-test
+topsrc_dir=../../../../..
+CPPFLAGS=-I$(topsrc_dir) -I$(shell pg_config --includedir)
+CFLAGS=-Wall -O0 -g
+
+OBJS=main.o \
+ $(topsrc_dir)/strlcpy.o \
+ $(topsrc_dir)/pool_timestamp.o \
+ $(topsrc_dir)/parser/libsql-parser.a
+
+all: all-pre $(PROGRAM)
+
+all-pre:
+ $(MAKE) -C $(topsrc_dir)/parser
+ $(MAKE) -C $(topsrc_dir) strlcpy.o
+ $(MAKE) -C $(topsrc_dir) pool_timestamp.o
+
+$(PROGRAM): $(OBJS)
+ $(CC) $(OBJS) -o $(PROGRAM)
+
+main.o: main.c
+
+test: $(PROGRAM)
+ ./run-test parse_schedule
+
+clean:
+ -rm *.o
+ -rm $(PROGRAM)
+ -rm result/*.out
+ -rm test.diff
+
+.PHONY: all all-pre test clean
--- /dev/null
+INSERT INTO "rel1" VALUES (DEFAULT,'2009-01-01 23:59:59.123456+09',DEFAULT,'2009-01-01 23:59:59.123456+09')
+INSERT INTO rel2 DEFAULT VALUES
+INSERT INTO rel2(c1) VALUES(1)
+INSERT INTO "rel1" VALUES (1,"pg_catalog"."timestamptz"('2009-01-01 23:59:59.123456+09'::text),2,'2009-01-01 23:59:59.123456+09'::text::date)
+INSERT INTO "rel1" VALUES (3,"pg_catalog"."timestamptz"('2009-01-01 23:59:59.123456+09'::text),4,'2009-01-01 23:59:59.123456+09'::text::timetz)
+INSERT INTO "rel1" VALUES (5,'2009-01-01 23:59:59.123456+09'::text::timestamptz(0),6,'2009-01-01 23:59:59.123456+09'::text::timetz(0))
+INSERT INTO "rel1" VALUES (7,'2009-01-01 23:59:59.123456+09'::text::timestamp,8,'2009-01-01 23:59:59.123456+09'::text::time)
+INSERT INTO "rel1" VALUES (9,'2009-01-01 23:59:59.123456+09'::text::timestamp(0),10,'2009-01-01 23:59:59.123456+09'::text::time(0))
+INSERT INTO "rel1" VALUES (11,'2009-01-01 23:59:59.123456+09',DEFAULT,'2009-01-01 23:59:59.123456+09')
+INSERT INTO "rel1"("c3", "c2", "c4") VALUES (1,'2009-01-01 23:59:59.123456+09','2009-01-01 23:59:59.123456+09')
+INSERT INTO "rel1"("c2", "c1", "c4") VALUES ('2000-1-1',1,'2009-01-01 23:59:59.123456+09')
+INSERT INTO "rel1"("c2", "c1", "c4") VALUES ('2009-01-01 23:59:59.123456+09',2,'2009-01-01 23:59:59.123456+09')
+INSERT INTO "rel1"("c2", "c1", "c4") VALUES ('2009-01-01 23:59:59.123456+09',3,'2009-01-01 23:59:59.123456+09'), ('2009-01-01 23:59:59.123456+09',4,'2009-01-01 23:59:59.123456+09'), ('2009-1-1',5,'2009-01-01 23:59:59.123456+09')
+INSERT INTO rel1(c1, c2, c4) VALUES(1, '2009-1-1', '2009-2-2')
+PREPARE "q" (timestamptz,timestamptz) AS INSERT INTO "rel1"("c3", "c2", "c4") VALUES (1,$1,$2)
+PREPARE "q" (int4,timestamptz,timestamptz) AS INSERT INTO "rel1"("c3", "c2", "c4") VALUES ($1,$2,$3)
--- /dev/null
+DELETE FROM "rel1" WHERE ("c1"='2009-01-01 23:59:59.123456+09'::text::date )
+PREPARE "q" ("date",timestamptz) AS DELETE FROM "rel1" WHERE ( ("c1"=$1 ) AND ("c3"=$2::text::date ))
+EXECUTE "q" ("pg_catalog"."timestamptz"('2009-01-01 23:59:59.123456+09'::text))
--- /dev/null
+UPDATE "rel1" SET "c1" = DEFAULT, "c2" = '2009-01-01 23:59:59.123456+09'
+UPDATE rel2 SET c1 = DEFAULT, c2 = DEFAULT
+UPDATE "rel1" SET "c1" = "pg_catalog"."timestamptz"('2009-01-01 23:59:59.123456+09'::text), "c2" = '2009-01-01 23:59:59.123456+09'::text::date
+UPDATE "rel1" SET "c3" = "pg_catalog"."timestamptz"('2009-01-01 23:59:59.123456+09'::text), "c4" = '2009-01-01 23:59:59.123456+09'::text::timetz
+UPDATE "rel1" SET "c1" = '2009-01-01 23:59:59.123456+09'::text::timestamp, "c2" = '2009-01-01 23:59:59.123456+09'::text::time
+PREPARE "q" (int4,timestamptz) AS UPDATE "rel1" SET "c1" = $1, "c2" = $2::text::date
--- /dev/null
+INSERT INTO rel1 DEFAULT VALUES
+INSERT INTO rel2 DEFAULT VALUES
+INSERT INTO rel2(c1) VALUES(1)
+INSERT INTO rel1 VALUES(1, now(), 2, CURRENT_DATE)
+INSERT INTO rel1 VALUES(3, CURRENT_TIMESTAMP, 4, CURRENT_TIME)
+INSERT INTO rel1 VALUES(5, CURRENT_TIMESTAMP(0), 6, CURRENT_TIME(0))
+INSERT INTO rel1 VALUES(7, LOCALTIMESTAMP, 8, LOCALTIME)
+INSERT INTO rel1 VALUES(9, LOCALTIMESTAMP(0), 10, LOCALTIME(0))
+INSERT INTO rel1 VALUES(11, DEFAULT);
+INSERT INTO rel1(c3) VALUES(1)
+INSERT INTO rel1(c2, c1) VALUES('2000-1-1', 1)
+INSERT INTO rel1(c2, c1) VALUES(DEFAULT, 2)
+INSERT INTO rel1(c2, c1) VALUES(DEFAULT, 3), (DEFAULT, 4), ('2009-1-1', 5)
+INSERT INTO rel1(c1, c2, c4) VALUES(1, '2009-1-1', '2009-2-2')
+PREPARE q AS INSERT INTO rel1(c3) VALUES(1)
+PREPARE q(int) AS INSERT INTO rel1(c3) VALUES($1)
--- /dev/null
+DELETE FROM rel1 WHERE c1 = CURRENT_DATE
+PREPARE q(date) AS DELETE FROM rel1 WHERE c1 = $1 AND c3 = CURRENT_DATE
+EXECUTE q(now())
--- /dev/null
+UPDATE rel1 SET c1 = DEFAULT, c2 = DEFAULT
+UPDATE rel2 SET c1 = DEFAULT, c2 = DEFAULT
+UPDATE rel1 SET c1 = now(), c2 = CURRENT_DATE
+UPDATE rel1 SET (c3, c4) = (CURRENT_TIMESTAMP, CURRENT_TIME)
+UPDATE rel1 SET c1 = LOCALTIMESTAMP, c2 = LOCALTIME
+PREPARE q(int) AS UPDATE rel1 SET c1 = $1, c2 = CURRENT_DATE
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "pool.h"
+#include "pool_config.h"
+#include "pool_relcache.h"
+#include "pool_timestamp.h"
+#include "parser/parser.h"
+
+/* for get_current_timestamp() (MASTER() macro) */
+POOL_REQUEST_INFO _req_info;
+POOL_REQUEST_INFO *Req_info = &_req_info;
+POOL_CONFIG _pool_config;
+POOL_CONFIG *pool_config = &_pool_config;
+
+typedef struct {
+ char *attrname; /* attribute name */
+ char *adsrc; /* default value expression */
+ int use_timestamp;
+} TSAttr;
+
+typedef struct {
+ int relnatts;
+ TSAttr attr[4];
+} TSRel;
+
+
+TSRel rc[2] = {
+ { 4, {
+ { "c1", "", 0 },
+ { "c2", "", 1 },
+ { "c3", "", 0 },
+ { "c4", "", 1 }
+ } },
+ { 4, {
+ { "c1", "", 0 },
+ { "c2", "", 0 },
+ { "c3", "", 0 },
+ { "c4", "", 0 }
+ } }
+};
+
+int pool_virtual_master_db_node_id(void)
+{
+ return 0;
+}
+
+bool pool_has_pgpool_regclass(void)
+{
+ return false;
+}
+
+bool pool_has_to_regclass(void)
+{
+ return false;
+}
+
+char *remove_quotes_and_schema_from_relname(char *table)
+{
+ return table;
+}
+
+POOL_RELCACHE *
+pool_create_relcache(int cachesize, char *sql, func_ptr register_func, func_ptr unregister_func, bool issessionlocal)
+{
+ return (POOL_RELCACHE *) 1;
+}
+
+void *
+pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, char *table)
+{
+ if (strcmp(table, "\"rel1\"") == 0)
+ return (void *) &(rc[0]);
+ else
+ return (void *) &(rc[1]);
+}
+
+POOL_STATUS
+do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major) {
+ static POOL_SELECT_RESULT res;
+ static char *data[1] = {
+ "2009-01-01 23:59:59.123456+09"
+ };
+
+ res.numrows = 1;
+ res.data = data;
+
+ *result = &res;
+ return POOL_CONTINUE;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *query;
+ List *tree;
+ ListCell *l;
+ StartupPacket sp;
+ POOL_CONNECTION_POOL backend;
+ POOL_CONNECTION_POOL_SLOT slot;
+ POOL_SENT_MESSAGE msg;
+ POOL_QUERY_CONTEXT ctx;
+ backend.slots[0] = &slot;
+ slot.sp = &sp;
+
+ pool_config->replication_mode = 1;
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "./timestmp-test query\n");
+ exit(1);
+ }
+
+ tree = raw_parser(argv[1]);
+ if (tree == NULL)
+ {
+ printf("syntax error: %s\n", argv[1]);
+ }
+ else
+ {
+ foreach(l, tree)
+ {
+ msg.num_tsparams = 0;
+ msg.query_context = &ctx;
+ Node *node = (Node *) lfirst(l);
+ query = rewrite_timestamp(&backend, node, false, &msg);
+ if (query)
+ printf("%s\n", query);
+ else
+ printf("%s\n", argv[1]);
+
+ }
+ }
+ return 0;
+}
+
+void child_exit(int code) { exit (code); }
+void pool_error(const char *fmt,...) {}
+void pool_debug(const char *fmt,...) {}
+void pool_log(const char *fmt,...) {}
+void free_select_result(POOL_SELECT_RESULT *result) {}
--- /dev/null
+insert
+update
+misc
--- /dev/null
+#! /usr/bin/env ruby
+
+# $Header$
+
+#
+# Usage¡§./run-test schedule
+# ignore a line at the beginning of '#'
+#
+
+INPUT_DIRECTORY="input"
+EXPECTED_DIRECTORY="expected"
+RESULT_DIRECTORY="result"
+TEST_PROGRAM="./timestamp-test"
+DIFF_FILE="test.diff"
+
+def escape_string str
+ str.gsub(/([\$\"\\])/) { "\\" + $1 }
+end
+
+if ARGV.size != 1
+ STDERR.puts "run-test schedule_file"
+ exit 1
+end
+
+file = ARGV.shift
+if !(File.exists? file)
+ STDERR.puts "run-test: file does not exist: #{file}"
+ exit 1
+end
+
+if !(File.exists? RESULT_DIRECTORY)
+ Dir.mkdir RESULT_DIRECTORY
+else
+ Dir["#{RESULT_DIRECTORY}/*.out"].each do |f|
+ File.unlink f
+ end
+end
+
+File.unlink DIFF_FILE if File.exists? DIFF_FILE
+
+begin
+ IO.foreach(file) do |testcase|
+ testcase.chomp!
+ if (/^\#/ =~ testcase or testcase == "")
+ next
+ end
+
+ print "testcase #{testcase}:\t"
+ begin
+ IO.foreach("#{INPUT_DIRECTORY}/#{testcase}.sql") do |test_sql|
+ test_sql.chomp!
+ system("#{TEST_PROGRAM} \"#{escape_string(test_sql)}\" >> #{RESULT_DIRECTORY}/#{testcase}.out\n")
+ end
+
+ system("diff -c #{EXPECTED_DIRECTORY}/#{testcase}.out #{RESULT_DIRECTORY}/#{testcase}.out >> #{DIFF_FILE}")
+
+ if ($? == 0)
+ print "OK\n"
+ else
+ print "FAILED\n"
+ end
+ rescue
+ print "FAILED\n"
+ end
+ end
+
+rescue
+ STDERR.puts "NG"
+end