HAWQ-808. Refactor feature test for external_oid with new framework.
Project: http://git-wip-us.apache.org/repos/asf/incubator-hawq/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-hawq/commit/0e6fe7a4 Tree: http://git-wip-us.apache.org/repos/asf/incubator-hawq/tree/0e6fe7a4 Diff: http://git-wip-us.apache.org/repos/asf/incubator-hawq/diff/0e6fe7a4 Branch: refs/heads/2.0.0.0-incubating Commit: 0e6fe7a4f1431ed5d01f0fdc8b48e648869c177e Parents: e308af6 Author: xunzhang <xunzhang...@gmail.com> Authored: Tue Jul 12 14:14:08 2016 +0800 Committer: rlei <r...@pivotal.io> Committed: Tue Jul 19 10:49:42 2016 +0800 ---------------------------------------------------------------------- .../ExternalSource/ans/external_oid.ans.source | 209 ++++++ .../ExternalSource/data/multi_table.json | 1 + .../ExternalSource/data/single_table.json | 1 + src/test/feature/ExternalSource/lib/Makefile | 44 ++ src/test/feature/ExternalSource/lib/function.c | 727 +++++++++++++++++++ .../ExternalSource/sql/external_oid.sql.source | 108 +++ .../ExternalSource/test_external_oid.cpp | 35 + src/test/feature/Makefile | 2 + src/test/regress/input/external_oid.source | 118 --- src/test/regress/known_good_schedule | 1 - src/test/regress/output/external_oid.source | 211 ------ 11 files changed, 1127 insertions(+), 330 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/ans/external_oid.ans.source ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/ans/external_oid.ans.source b/src/test/feature/ExternalSource/ans/external_oid.ans.source new file mode 100644 index 0000000..3f3f3ae --- /dev/null +++ b/src/test/feature/ExternalSource/ans/external_oid.ans.source @@ -0,0 +1,209 @@ +-- -------------------------------------- +-- test first external Oid initialization +-- -------------------------------------- +-- start_matchsubs +-- +-- # create a match/subs expression to handle ip addresses that change +-- +-- m/.*inserted tuple to heap table pg_class \(oid \d+, relname table_xl\).*/ +-- s/oid \d+/oid SOME_OID/ +-- +-- m/.*deleted tuple oid=\d+ from heap table pg_class.*/ +-- s/oid=\d+/oid=OID/ +-- +-- end_matchsubs +-- Create function that returns the first external Oid boundary +CREATE OR REPLACE FUNCTION min_external_oid() RETURNS oid + AS '@SHARE_LIBRARY_PATH@', 'min_external_oid' + LANGUAGE C; +CREATE FUNCTION +-- Create function that returns the current external Oid +CREATE OR REPLACE FUNCTION get_next_external_oid() RETURNS oid + AS '@SHARE_LIBRARY_PATH@', 'get_next_external_oid' + LANGUAGE C; +CREATE FUNCTION +-- Create function that sets the current external Oid +CREATE OR REPLACE FUNCTION set_next_external_oid(ext_oid oid) RETURNS oid + AS '@SHARE_LIBRARY_PATH@', 'set_next_external_oid' + LANGUAGE C; +CREATE FUNCTION +-- Create function to insert and scan in-memory data to pg_class +CREATE OR REPLACE FUNCTION load_json_data(filename text) RETURNS text + AS '@SHARE_LIBRARY_PATH@', 'load_json_data' + LANGUAGE C; +CREATE FUNCTION +-- Create function that inserts tuple with given Oid +CREATE OR REPLACE FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text) RETURNS text + AS '@SHARE_LIBRARY_PATH@', 'caql_insert_into_heap_pg_class' + LANGUAGE C; +CREATE FUNCTION +-- Create function that inserts tuple with given Oid +CREATE OR REPLACE FUNCTION caql_delete_from_heap_pg_class(relid oid) RETURNS text + AS '@SHARE_LIBRARY_PATH@', 'caql_delete_from_heap_pg_class' + LANGUAGE C; +CREATE FUNCTION +-- -------------------------------------- +-- Test hcat table external oid initialization +-- -------------------------------------- +-- Boundary should be at FirstExternalObjectId +--SELECT min_external_oid(); +-- NextExternalObjectId is uninitialized +SELECT get_next_external_oid(); + get_next_external_oid +----------------------- + 0 +(1 row) + +SELECT load_json_data('@abs_datadir@/single_table.json'); + load_json_data +------------------ + default.mytable +(1 row) + +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 0 +(1 row) + +BEGIN TRANSACTION; +BEGIN +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 0 +(1 row) + +-- load default.mytable -> +3 oids +-- 1 oid for namespace 'default', 1 oid for relation 'mytable', 1 oid for reltype +SELECT load_json_data('@abs_datadir@/single_table.json'); + load_json_data +------------------ + default.mytable +(1 row) + +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 3 +(1 row) + +-- load db1.ht1, db2.ht1, db2.ht2 -> +8 oids +-- oids: db1, ht1(db1), db2, ht1(db2), ht2, reltype(ht1, ht1, ht2) +SELECT load_json_data('@abs_datadir@/multi_table.json'); + load_json_data +-------------------------- + db1.ht1 db2.ht1 db2.ht2 +(1 row) + +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 11 +(1 row) + +END TRANSACTION; +COMMIT +-- New transaction will reset external Oid start point +-- Yields the same result as previous transaction +BEGIN TRANSACTION; +BEGIN +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 0 +(1 row) + +SELECT load_json_data('@abs_datadir@/single_table.json'); + load_json_data +------------------ + default.mytable +(1 row) + +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 3 +(1 row) + +SELECT load_json_data('@abs_datadir@/multi_table.json'); + load_json_data +-------------------------- + db1.ht1 db2.ht1 db2.ht2 +(1 row) + +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 11 +(1 row) + +END TRANSACTION; +COMMIT +-- -------------------------------------- +-- Test external oid rollover +-- -------------------------------------- +BEGIN TRANSACTION; +BEGIN +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + ?column? +---------- + 0 +(1 row) + +SELECT set_next_external_oid( oid(min_external_oid()::bigint + (10*power(2,20))::bigint - 8 + 1) ) > 0; + ?column? +---------- + t +(1 row) + +SELECT load_json_data('@abs_datadir@/multi_table.json'); + load_json_data +-------------------------- + db1.ht1 db2.ht1 db2.ht2 +(1 row) + +-- Used up external Oids result in Oid overflow +SELECT get_next_external_oid(); + get_next_external_oid +----------------------- + 0 +(1 row) + +-- Rollover disallowed! +SELECT load_json_data('@abs_datadir@/single_table.json'); +psql:/tmp/TestExternalOid_TestExternalOidAll.sql:92: ERROR: number of external objects from HCatalog exceeded 10M during transaction +HINT: Separate HCatalog queries into different transactions to process. +END TRANSACTION; +ROLLBACK +-- -------------------------------------- +-- Test external Oid boundary +-- -------------------------------------- +-- Create a tuple with Oid larger than FirstExternalObjectId +-- Will fail during next session when try to query HCatalog +-- Because external Oid boundary is violated +SELECT caql_insert_into_heap_pg_class(min_external_oid()::bigint + 20, 'table_xl'); + caql_insert_into_heap_pg_class +-------------------------------------------------------------------------- + inserted tuple to heap table pg_class (oid 4284481555, relname table_xl) +(1 row) + +-- cleanup +SELECT caql_delete_from_heap_pg_class(min_external_oid()::bigint + 20); + caql_delete_from_heap_pg_class +------------------------------------------------------- + deleted tuple oid=4284481555 from heap table pg_class +(1 row) + +DROP FUNCTION caql_delete_from_heap_pg_class(relid oid); +DROP FUNCTION +DROP FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text); +DROP FUNCTION +DROP FUNCTION load_json_data(filename text); +DROP FUNCTION +DROP FUNCTION get_next_external_oid(); +DROP FUNCTION +DROP FUNCTION set_next_external_oid(ext_oid oid); +DROP FUNCTION +DROP FUNCTION min_external_oid(); +DROP FUNCTION http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/data/multi_table.json ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/data/multi_table.json b/src/test/feature/ExternalSource/data/multi_table.json new file mode 100644 index 0000000..82e70b0 --- /dev/null +++ b/src/test/feature/ExternalSource/data/multi_table.json @@ -0,0 +1 @@ +{"PXFMetadata":[{"item":{"path":"db1","name":"ht1"},"fields":[{"name":"c1","type":"bpchar","modifiers":["3"],"sourceType":"char"},{"name":"vc2","type":"varchar","modifiers":["3"],"sourceType":"varchar"}]},{"item":{"path":"db2","name":"ht1"},"fields":[{"name":"c1","type":"bpchar","modifiers":["3"],"sourceType":"char"},{"name":"vc2","type":"varchar","modifiers":["3"],"sourceType":"varchar"}]},{"item":{"path":"db2","name":"ht2"},"fields":[{"name":"c1","type":"bpchar","modifiers":["3"],"sourceType":"char"},{"name":"vc2","type":"varchar","modifiers":["3"],"sourceType":"varchar"}]}]} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/data/single_table.json ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/data/single_table.json b/src/test/feature/ExternalSource/data/single_table.json new file mode 100644 index 0000000..b571e5d --- /dev/null +++ b/src/test/feature/ExternalSource/data/single_table.json @@ -0,0 +1 @@ +{"PXFMetadata":[{"item":{"path":"default","name":"mytable"},"fields":[{"name":"s1","type":"text","sourceType":"string"},{"name":"s2","type":"text","sourceType":"string"},{"name":"n1","type":"int4","sourceType":"int"},{"name":"d1","type":"float8","sourceType":"double"},{"name":"dc1","type":"numeric","modifiers":["38","18"],"sourceType":"decimal"},{"name":"tm","type":"timestamp","sourceType":"timestamp"},{"name":"f","type":"float4","sourceType":"float"},{"name":"bg","type":"int8","sourceType":"bigint"},{"name":"b","type":"bool","sourceType":"boolean"},{"name":"tn","type":"int2","sourceType":"tinyint"},{"name":"sml","type":"int2","sourceType":"tinyint"},{"name":"dt","type":"date","sourceType":"date"},{"name":"vc1","type":"varchar","modifiers":["5"],"sourceType":"varchar"},{"name":"c1","type":"bpchar","modifiers":["3"],"sourceType":"char"},{"name":"bin","type":"bytea","sourceType":"binary"}]}]} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/lib/Makefile ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/lib/Makefile b/src/test/feature/ExternalSource/lib/Makefile new file mode 100644 index 0000000..46f6c20 --- /dev/null +++ b/src/test/feature/ExternalSource/lib/Makefile @@ -0,0 +1,44 @@ +top_builddir = ../../../../.. +include $(top_builddir)/src/Makefile.global + +OS = $(shell uname) + +CXX = gcc +CXXFLAGS = -Wall -O1 -g -std=gnu99 -Wmissing-prototypes -Wpointer-arith -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv -fPIC + +CC = gcc +CFLAGS = -Wall -O1 -g -std=gnu99 -Wmissing-prototypes -Wpointer-arith -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv -fPIC + +CPPFLAGS = -I$(abs_top_srcdir)/src/include +CPPFLAGS += -I$(abs_top_srcdir)/depends/libhdfs3/build/install$(prefix)/include +CPPFLAGS += -I$(abs_top_srcdir)/depends/libyarn/build/install$(prefix)/include + +LDFLAGS = -L$(libdir) +LDFLAGS += -L$(abs_top_srcdir)/src/port +LDFLAGS += -L$(abs_top_builddir)/src/port +LDFLAGS += -L$(abs_top_srcdir)/depends/libhdfs3/build/install$(prefix)/lib +LDFLAGS += -L$(abs_top_srcdir)/depends/libyarn/build/install$(prefix)/lib + +POSTGRES = $(abs_top_srcdir)/src/backend/postgres + +PROG = function.c +OBJS = function.o +TARGET = function.so + +RM = rm -rf + +all: $(TARGET) + +$(OBJS): $(PROG) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $(OBJS) $(PROG) + +$(TARGET): $(OBJS) +ifeq ($(OS),Darwin) + $(CXX) $(CXXFLAGS) -bundle $(OBJS) -bundle_loader $(POSTGRES) $(LDFLAGS) -o $@ +else + $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LDFLAGS) -Wl,-rpath,'$(abs_top_builddir)/lib' -o $@ +endif + +clean: + $(RM) *.o + $(RM) *.so http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/lib/function.c ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/lib/function.c b/src/test/feature/ExternalSource/lib/function.c new file mode 100644 index 0000000..4275edc --- /dev/null +++ b/src/test/feature/ExternalSource/lib/function.c @@ -0,0 +1,727 @@ +/* + * json_utils.c + * + * Created on: Mar 5, 2015 + * Author: antova + */ + +#include "catalog/external/externalmd.h" +#include "postgres.h" +#include "access/hd_work_mgr.h" +#include "funcapi.h" +#include "catalog/catquery.h" +#include "catalog/gp_policy.h" +#include "catalog/namespace.h" +#include "catalog/pg_database.h" +#include "catalog/pg_exttable.h" +#include "catalog/pg_namespace.h" +#include "cdb/cdbinmemheapam.h" +#include "nodes/makefuncs.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "access/transam.h" + +/* + * number of output columns for the UDFs for scanning in memory catalog tables + */ +#define NUM_COLS 3 + +#ifdef PG_MODULE_MAGIC +PG_MODULE_MAGIC; +#endif + +static +char *read_file(const char *filename); + +static +Oid GetRelationOid(char *tableName); + +/* utility functions for loading json files */ +extern Datum load_json_data(PG_FUNCTION_ARGS); +extern Datum caql_scan_in_memory_pg_namespace(PG_FUNCTION_ARGS); +extern Datum caql_scan_in_memory_pg_type(PG_FUNCTION_ARGS); +extern Datum caql_scan_in_memory_gp_distribution_policy(PG_FUNCTION_ARGS); +extern Datum caql_scan_in_memory_pg_exttable(PG_FUNCTION_ARGS); +extern Datum caql_scan_in_memory_pg_attribute(PG_FUNCTION_ARGS); +extern Datum caql_insert_into_heap_pg_class(PG_FUNCTION_ARGS); +extern Datum caql_delete_from_heap_pg_class(PG_FUNCTION_ARGS); +extern Datum get_next_external_oid(PG_FUNCTION_ARGS); +extern Datum set_next_external_oid(PG_FUNCTION_ARGS); +extern Datum min_external_oid(PG_FUNCTION_ARGS); + +PG_FUNCTION_INFO_V1(load_json_data); +PG_FUNCTION_INFO_V1(caql_scan_in_memory_pg_namespace); +PG_FUNCTION_INFO_V1(caql_scan_in_memory_pg_type); +PG_FUNCTION_INFO_V1(caql_scan_in_memory_gp_distribution_policy); +PG_FUNCTION_INFO_V1(caql_scan_in_memory_pg_exttable); +PG_FUNCTION_INFO_V1(caql_scan_in_memory_pg_attribute); +PG_FUNCTION_INFO_V1(caql_insert_into_heap_pg_class); +PG_FUNCTION_INFO_V1(caql_delete_from_heap_pg_class); +PG_FUNCTION_INFO_V1(get_next_external_oid); +PG_FUNCTION_INFO_V1(set_next_external_oid); +PG_FUNCTION_INFO_V1(min_external_oid); + +Datum +load_json_data(PG_FUNCTION_ARGS) +{ + text *filename = PG_GETARG_TEXT_P(0); + char *filenameStr = text_to_cstring(filename); + + char *pcbuf = read_file(filenameStr); + StringInfoData buf; + initStringInfo(&buf); + appendStringInfo(&buf, "%s", pcbuf); + + List *items = ParsePxfEntries(&buf, HiveProfileName, HcatalogDbOid); + pfree(buf.data); + + StringInfoData tblNames; + initStringInfo(&tblNames); + ListCell *lc = NULL; + foreach (lc, items) + { + PxfItem *item = (PxfItem *) lfirst(lc); + appendStringInfo(&tblNames, "%s.%s ", item->path, item->name); + } + + PG_RETURN_TEXT_P(cstring_to_text(tblNames.data)); +} + +char * +read_file(const char *filename) +{ + FILE *pf = fopen(filename, "r"); + if (NULL == pf) + { + elog(ERROR, "Could not open file %s for reading", filename); + } + + StringInfoData strinfo; + initStringInfo(&strinfo); + + const int len = 1024; + char buf[len]; + + while (NULL != fgets(buf, len, pf)) + { + appendStringInfo(&strinfo, "%s", buf); + } + + fclose(pf); + return strinfo.data; +} + +Datum +caql_scan_in_memory_pg_namespace(PG_FUNCTION_ARGS) +{ + text *namespaceNameText = PG_GETARG_TEXT_P(0); + char *namespaceNameStr = text_to_cstring(namespaceNameText); + + FuncCallContext *funcctx; + Datum result; + MemoryContext oldcontext; + TupleDesc tupdesc; + HeapTuple restuple; + HeapTuple readtup = NULL; + cqContext *pcqCtx; + StringInfoData buf; + initStringInfo(&buf); + + if (SRF_IS_FIRSTCALL()) + { + funcctx = SRF_FIRSTCALL_INIT(); + /* switch context when allocating stuff to be used in later calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(NUM_COLS, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "nspname", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "nspdboid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "oid", + OIDOID, -1, 0); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + /* create tuples for pg_namespace table */ + pcqCtx = caql_beginscan( + NULL, + cql("SELECT * FROM pg_namespace " + " WHERE nspname = :1 and nspdboid = :2", + CStringGetDatum((char *) namespaceNameStr), ObjectIdGetDatum(HcatalogDbOid))); + + funcctx->user_fctx = pcqCtx; + + /* return to original context when allocating transient memory */ + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + pcqCtx = (cqContext *)funcctx->user_fctx; + + if (NULL != (readtup = caql_getnext(pcqCtx))) + { + Datum values[NUM_COLS]; + bool nulls[NUM_COLS]; + + Relation relation = RelationIdGetRelation(NamespaceRelationId); + TupleDesc tupleDesc = RelationGetDescr(relation); + + char *nspname = DatumGetCString(tuple_getattr(readtup, tupleDesc, Anum_pg_namespace_nspname)); + text *t = cstring_to_text(nspname); + + values[0] = PointerGetDatum(t); + nulls[0] = false; + + values[1] = tuple_getattr(readtup, tupleDesc, Anum_pg_namespace_nspdboid); + nulls[1] = false; + + values[2] = ObjectIdGetDatum(HeapTupleGetOid(readtup)); + nulls[2] = false; + + elog(DEBUG1, "Namespace oid: %d", HeapTupleGetOid(readtup)); + + /* build tuple */ + restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + /* make the tuple into a datum */ + result = HeapTupleGetDatum(restuple); + + RelationClose(relation); + SRF_RETURN_NEXT(funcctx, result); + } + else + { + caql_endscan(pcqCtx); + SRF_RETURN_DONE(funcctx); + } +} + +Datum +caql_scan_in_memory_pg_type(PG_FUNCTION_ARGS) +{ + text *relNameText = PG_GETARG_TEXT_P(0); + char *relNameStr = text_to_cstring(relNameText); + + FuncCallContext *funcctx; + Datum result; + MemoryContext oldcontext; + TupleDesc tupdesc; + HeapTuple restuple; + HeapTuple readtup = NULL; + cqContext *pcqCtx; + StringInfoData buf; + initStringInfo(&buf); + + if (SRF_IS_FIRSTCALL()) + { + funcctx = SRF_FIRSTCALL_INIT(); + /* switch context when allocating stuff to be used in later calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(NUM_COLS, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "typoid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "typname", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "typnamespace", + OIDOID, -1, 0); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + /* create tuples for pg_type table */ + pcqCtx = caql_beginscan( + NULL, + cql("SELECT * FROM pg_type " + " WHERE typname = :1", + CStringGetDatum((char *) relNameStr))); + + funcctx->user_fctx = pcqCtx; + + /* return to original context when allocating transient memory */ + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + pcqCtx = (cqContext *)funcctx->user_fctx; + + if (NULL != (readtup = caql_getnext(pcqCtx))) + { + Datum values[NUM_COLS]; + bool nulls[NUM_COLS]; + + Relation relation = RelationIdGetRelation(TypeRelationId); + TupleDesc tupleDesc = RelationGetDescr(relation); + + values[0] = ObjectIdGetDatum(HeapTupleGetOid(readtup)); + nulls[0] = false; + + elog(DEBUG1, "Type oid: %d", HeapTupleGetOid(readtup)); + + char *typname = DatumGetCString(tuple_getattr(readtup, tupleDesc, Anum_pg_type_typname)); + text *t = cstring_to_text(typname); + + values[1] = PointerGetDatum(t); + nulls[1] = false; + + values[2] = tuple_getattr(readtup, tupleDesc, Anum_pg_type_typnamespace); + nulls[2] = false; + + /* build tuple */ + restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + /* make the tuple into a datum */ + result = HeapTupleGetDatum(restuple); + + RelationClose(relation); + SRF_RETURN_NEXT(funcctx, result); + } + else + { + caql_endscan(pcqCtx); + SRF_RETURN_DONE(funcctx); + } +} + +Datum +caql_scan_in_memory_gp_distribution_policy(PG_FUNCTION_ARGS) +{ + text *tableName = PG_GETARG_TEXT_P(0); + char *tableNameStr = text_to_cstring(tableName); + Oid reloid = InvalidOid; + + FuncCallContext *funcctx; + Datum result; + MemoryContext oldcontext; + TupleDesc tupdesc; + HeapTuple restuple; + HeapTuple pgclasstup = NULL; + HeapTuple readtup = NULL; + cqContext *pcqCtx; + StringInfoData buf; + initStringInfo(&buf); + + if (SRF_IS_FIRSTCALL()) + { + funcctx = SRF_FIRSTCALL_INIT(); + /* switch context when allocating stuff to be used in later calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(NUM_COLS, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tableoid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "tablename", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "distpolicy", + TEXTOID, -1, 0); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + /* iterate on pg_class and query + * gp_distribution_policy by given oid */ + pcqCtx = caql_beginscan( + NULL, + cql("SELECT oid FROM pg_class " + " WHERE relname = :1", + CStringGetDatum(tableNameStr))); + + funcctx->user_fctx = pcqCtx; + + /* return to original context when allocating transient memory */ + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + pcqCtx = (cqContext *)funcctx->user_fctx; + + if (NULL != (pgclasstup = caql_getnext(pcqCtx))) + { + Datum values[NUM_COLS]; + bool nulls[NUM_COLS]; + + /* create tuples for pg_exttable table */ + cqContext* pcqCtx1 = caql_beginscan( + NULL, + cql("SELECT * FROM gp_distribution_policy " + " WHERE localoid = :1", + ObjectIdGetDatum(HeapTupleGetOid(pgclasstup)))); + + Relation relation = RelationIdGetRelation(GpPolicyRelationId); + TupleDesc tupleDesc = RelationGetDescr(relation); + + readtup = caql_getnext(pcqCtx1); + + values[0] = ObjectIdGetDatum(reloid); + nulls[0] = false; + + text *t1 = cstring_to_text(tableNameStr); + + values[1] = PointerGetDatum(t1); + nulls[1] = false; + + text *t2 = NULL; + bool isnull; + Datum policy = heap_getattr(readtup, Anum_gp_policy_attrnums, tupleDesc, &isnull); + if (isnull) + { + t2 = cstring_to_text("null"); + } + else + { + /* not tested! */ + Datum* elems = NULL; + int nelems; + deconstruct_array(DatumGetArrayTypeP(policy), + INT2OID, -1, false, 'i', + &elems, NULL, &nelems); + Assert(nelems > 0); + StringInfoData elems_str; + initStringInfo(&elems_str); + for (int i = 0; i < nelems; i++) + { + appendStringInfo(&elems_str, "%d", DatumGetInt16(elems[0])); + if (i != nelems) + { + appendStringInfo(&elems_str, ", "); + } + } + t2 = cstring_to_text(elems_str.data); + pfree(elems_str.data); + } + + values[2] = PointerGetDatum(t2); + nulls[2] = false; + + /* build tuple */ + restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + /* make the tuple into a datum */ + result = HeapTupleGetDatum(restuple); + + RelationClose(relation); + /* there should be only one value per oid */ + Assert(NULL == caql_getnext(pcqCtx1)) ; + caql_endscan(pcqCtx1); + + SRF_RETURN_NEXT(funcctx, result); + } + else + { + caql_endscan(pcqCtx); + SRF_RETURN_DONE(funcctx); + } +} + +Datum +caql_scan_in_memory_pg_exttable(PG_FUNCTION_ARGS) +{ + text *tableName = PG_GETARG_TEXT_P(0); + char *tableNameStr = text_to_cstring(tableName); + Oid reloid = InvalidOid; + + FuncCallContext *funcctx; + Datum result; + MemoryContext oldcontext; + TupleDesc tupdesc; + HeapTuple restuple; + HeapTuple pgclasstup = NULL; + HeapTuple readtup = NULL; + cqContext *pcqCtx; + StringInfoData buf; + initStringInfo(&buf); + + if (SRF_IS_FIRSTCALL()) + { + funcctx = SRF_FIRSTCALL_INIT(); + /* switch context when allocating stuff to be used in later calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(NUM_COLS, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "exttableoid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "exttablename", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "exttablelocation", + TEXTOID, -1, 0); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + /* iterate on pg_class and query + * pg_exttable by given oid */ + pcqCtx = caql_beginscan( + NULL, + cql("SELECT oid FROM pg_class " + " WHERE relname = :1", + CStringGetDatum(tableNameStr))); + + funcctx->user_fctx = pcqCtx; + + /* return to original context when allocating transient memory */ + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + pcqCtx = (cqContext *)funcctx->user_fctx; + + if (NULL != (pgclasstup = caql_getnext(pcqCtx))) + { + Datum values[NUM_COLS]; + bool nulls[NUM_COLS]; + + /* create tuples for pg_exttable table */ + cqContext* pcqCtx1 = caql_beginscan( + NULL, + cql("SELECT * FROM pg_exttable " + " WHERE reloid = :1", + ObjectIdGetDatum(HeapTupleGetOid(pgclasstup)))); + + Relation relation = RelationIdGetRelation(ExtTableRelationId); + TupleDesc tupleDesc = RelationGetDescr(relation); + + readtup = caql_getnext(pcqCtx1); + + values[0] = ObjectIdGetDatum(reloid); + nulls[0] = false; + + text *t1 = cstring_to_text(tableNameStr); + + values[1] = PointerGetDatum(t1); + nulls[1] = false; + + Datum locations = tuple_getattr(readtup, tupleDesc, Anum_pg_exttable_location); + Datum* elems = NULL; + int nelems; + deconstruct_array(DatumGetArrayTypeP(locations), + TEXTOID, -1, false, 'i', + &elems, NULL, &nelems); + Assert(nelems > 0); + char *loc_str = DatumGetCString(DirectFunctionCall1(textout, elems[0])); + text *t2 = cstring_to_text(loc_str); + + values[2] = PointerGetDatum(t2); + nulls[2] = false; + + /* build tuple */ + restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + /* make the tuple into a datum */ + result = HeapTupleGetDatum(restuple); + + RelationClose(relation); + /* there should be only one value per oid */ + Assert(NULL == caql_getnext(pcqCtx1)) ; + caql_endscan(pcqCtx1); + + SRF_RETURN_NEXT(funcctx, result); + } + else + { + caql_endscan(pcqCtx); + SRF_RETURN_DONE(funcctx); + } +} + +Datum +caql_scan_in_memory_pg_attribute(PG_FUNCTION_ARGS) +{ + text *tableNameText = PG_GETARG_TEXT_P(0); + char *tableNameStr = text_to_cstring(tableNameText); + + FuncCallContext *funcctx; + Datum result; + MemoryContext oldcontext; + TupleDesc tupdesc; + HeapTuple restuple; + HeapTuple readtup = NULL; + cqContext *pcqCtx; + StringInfoData buf; + initStringInfo(&buf); + + Oid relid = GetRelationOid(tableNameStr); + if (SRF_IS_FIRSTCALL()) + { + funcctx = SRF_FIRSTCALL_INIT(); + /* switch context when allocating stuff to be used in later calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(NUM_COLS, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "attname", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "atttype", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "atttypmod", + INT4OID, -1, 0); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + /* create tuples for pg_attribute table */ + pcqCtx = caql_beginscan( + NULL, + cql("SELECT * FROM pg_attribute " + " WHERE attrelid = :1", + ObjectIdGetDatum(relid))); + funcctx->user_fctx = pcqCtx; + + /* return to original context when allocating transient memory */ + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + pcqCtx = (cqContext *)funcctx->user_fctx; + + if (NULL != (readtup = caql_getnext(pcqCtx))) + { + Datum values[NUM_COLS]; + bool nulls[NUM_COLS]; + + Relation relation = RelationIdGetRelation(AttributeRelationId); + TupleDesc tupleDesc = RelationGetDescr(relation); + + char *attname = DatumGetCString(tuple_getattr(readtup, tupleDesc, Anum_pg_attribute_attname)); + text *t = cstring_to_text(attname); + + values[0] = PointerGetDatum(t); + nulls[0] = false; + + values[1] = tuple_getattr(readtup, tupleDesc, Anum_pg_attribute_atttypid); + nulls[1] = false; + + values[2] = tuple_getattr(readtup, tupleDesc, Anum_pg_attribute_atttypmod); + nulls[2] = false; + + /* build tuple */ + restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + /* make the tuple into a datum */ + result = HeapTupleGetDatum(restuple); + + RelationClose(relation); + SRF_RETURN_NEXT(funcctx, result); + } + else + { + caql_endscan(pcqCtx); + SRF_RETURN_DONE(funcctx); + } +} + +Oid GetRelationOid(char *tableName) +{ + cqContext *pcqCtx = caql_beginscan( + NULL, + cql("SELECT * FROM pg_class " + " WHERE relname = :1", + CStringGetDatum((char *) tableName))); + + HeapTuple ht = caql_getnext(pcqCtx); + Oid result = InvalidOid; + if (NULL != ht) + { + result = HeapTupleGetOid(ht); + } + + elog(DEBUG1, "Found relname %s, oid: %d", tableName, result); + caql_endscan(pcqCtx); + return result; +} + +/* + * This function must be used in conjunction with + * caql_delete_from_heap_pg_class + * and exclusively for testing external Oid setting + */ +Datum +caql_insert_into_heap_pg_class(PG_FUNCTION_ARGS) + { + Oid relid = PG_GETARG_OID(0); + char *tblname = text_to_cstring(PG_GETARG_TEXT_P(1)); + + Datum values[Natts_pg_class]; + bool nulls[Natts_pg_class]; + + for (int i = 0; i < Natts_pg_class; i++) + { + nulls[i] = true; + values[i] = (Datum) 0; + } + + NameData name; + namestrcpy(&name, tblname); + + values[Anum_pg_class_relname - 1] = NameGetDatum(&name); + values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum((Oid) NSPDBOID_CURRENT); + nulls[Anum_pg_class_relname - 1] = false; + nulls[Anum_pg_class_relnamespace - 1] = false; + + cqContext *pcqCtx = caql_beginscan( + NULL, + cql("INSERT INTO pg_class", NULL)); + + HeapTuple tup = caql_form_tuple(pcqCtx, values, nulls); + HeapTupleSetOid(tup, relid); + + caql_insert(pcqCtx, tup); + caql_endscan(pcqCtx); + + StringInfoData buf; + initStringInfo(&buf); + + appendStringInfo(&buf, "inserted tuple to heap table pg_class (oid %u, relname %s)", relid, tblname); + + PG_RETURN_TEXT_P(cstring_to_text(buf.data)); +} + +/* + * This function must be used in conjunction with + * caql_insert_into_heap_pg_class + * and exclusively for testing external Oid setting + */ +Datum +caql_delete_from_heap_pg_class(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + cqContext *pcqCtx = caql_beginscan( + NULL, + cql("SELECT * FROM pg_class " + " WHERE oid = :1 " + " FOR UPDATE ", + ObjectIdGetDatum(relid))); + + HeapTuple tuple = caql_getnext(pcqCtx); + + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("pg_class table relid=%u does not exist", relid))); + + /* Delete the pg_class table entry from the catalog (pg_class) */ + caql_delete_current(pcqCtx); + + /* Finish up scan and close pg_class catalog */ + caql_endscan(pcqCtx); + + StringInfoData buf; + initStringInfo(&buf); + + appendStringInfo(&buf, "deleted tuple oid=%u from heap table pg_class", relid); + + PG_RETURN_TEXT_P(cstring_to_text(buf.data)); +} + +Datum +get_next_external_oid(PG_FUNCTION_ARGS) +{ + PG_RETURN_OID(GetCurrentExternalObjectId()); +} + +Datum +set_next_external_oid(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + SetCurrentExternalObjectId(oid); + + PG_RETURN_OID(GetCurrentExternalObjectId()); +} + +Datum +min_external_oid(PG_FUNCTION_ARGS) +{ + PG_RETURN_OID(FirstExternalObjectId); +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/sql/external_oid.sql.source ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/sql/external_oid.sql.source b/src/test/feature/ExternalSource/sql/external_oid.sql.source new file mode 100644 index 0000000..bded23e --- /dev/null +++ b/src/test/feature/ExternalSource/sql/external_oid.sql.source @@ -0,0 +1,108 @@ +-- -------------------------------------- +-- test first external Oid initialization +-- -------------------------------------- + +-- start_matchsubs +-- +-- # create a match/subs expression to handle ip addresses that change +-- +-- m/.*inserted tuple to heap table pg_class \(oid \d+, relname table_xl\).*/ +-- s/oid \d+/oid SOME_OID/ +-- +-- m/.*deleted tuple oid=\d+ from heap table pg_class.*/ +-- s/oid=\d+/oid=OID/ +-- +-- end_matchsubs + +-- Create function that returns the first external Oid boundary +CREATE OR REPLACE FUNCTION min_external_oid() RETURNS oid + AS '@SHARE_LIBRARY_PATH@', 'min_external_oid' + LANGUAGE C; + +-- Create function that returns the current external Oid +CREATE OR REPLACE FUNCTION get_next_external_oid() RETURNS oid + AS '@SHARE_LIBRARY_PATH@', 'get_next_external_oid' + LANGUAGE C; + +-- Create function that sets the current external Oid +CREATE OR REPLACE FUNCTION set_next_external_oid(ext_oid oid) RETURNS oid + AS '@SHARE_LIBRARY_PATH@', 'set_next_external_oid' + LANGUAGE C; + +-- Create function to insert and scan in-memory data to pg_class +CREATE OR REPLACE FUNCTION load_json_data(filename text) RETURNS text + AS '@SHARE_LIBRARY_PATH@', 'load_json_data' + LANGUAGE C; + +-- Create function that inserts tuple with given Oid +CREATE OR REPLACE FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text) RETURNS text + AS '@SHARE_LIBRARY_PATH@', 'caql_insert_into_heap_pg_class' + LANGUAGE C; + +-- Create function that inserts tuple with given Oid +CREATE OR REPLACE FUNCTION caql_delete_from_heap_pg_class(relid oid) RETURNS text + AS '@SHARE_LIBRARY_PATH@', 'caql_delete_from_heap_pg_class' + LANGUAGE C; + +-- -------------------------------------- +-- Test hcat table external oid initialization +-- -------------------------------------- +-- Boundary should be at FirstExternalObjectId +--SELECT min_external_oid(); +-- NextExternalObjectId is uninitialized +SELECT get_next_external_oid(); +SELECT load_json_data('@abs_datadir@/single_table.json'); +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; + +BEGIN TRANSACTION; +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +-- load default.mytable -> +3 oids +-- 1 oid for namespace 'default', 1 oid for relation 'mytable', 1 oid for reltype +SELECT load_json_data('@abs_datadir@/single_table.json'); +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +-- load db1.ht1, db2.ht1, db2.ht2 -> +8 oids +-- oids: db1, ht1(db1), db2, ht1(db2), ht2, reltype(ht1, ht1, ht2) +SELECT load_json_data('@abs_datadir@/multi_table.json'); +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +END TRANSACTION; + +-- New transaction will reset external Oid start point +-- Yields the same result as previous transaction +BEGIN TRANSACTION; +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +SELECT load_json_data('@abs_datadir@/single_table.json'); +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +SELECT load_json_data('@abs_datadir@/multi_table.json'); +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +END TRANSACTION; + +-- -------------------------------------- +-- Test external oid rollover +-- -------------------------------------- +BEGIN TRANSACTION; +SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; +SELECT set_next_external_oid( oid(min_external_oid()::bigint + (10*power(2,20))::bigint - 8 + 1) ) > 0; +SELECT load_json_data('@abs_datadir@/multi_table.json'); +-- Used up external Oids result in Oid overflow +SELECT get_next_external_oid(); +-- Rollover disallowed! +SELECT load_json_data('@abs_datadir@/single_table.json'); +END TRANSACTION; + +-- -------------------------------------- +-- Test external Oid boundary +-- -------------------------------------- +-- Create a tuple with Oid larger than FirstExternalObjectId +-- Will fail during next session when try to query HCatalog +-- Because external Oid boundary is violated +SELECT caql_insert_into_heap_pg_class(min_external_oid()::bigint + 20, 'table_xl'); + +-- cleanup +SELECT caql_delete_from_heap_pg_class(min_external_oid()::bigint + 20); + +DROP FUNCTION caql_delete_from_heap_pg_class(relid oid); +DROP FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text); +DROP FUNCTION load_json_data(filename text); +DROP FUNCTION get_next_external_oid(); +DROP FUNCTION set_next_external_oid(ext_oid oid); +DROP FUNCTION min_external_oid(); http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/ExternalSource/test_external_oid.cpp ---------------------------------------------------------------------- diff --git a/src/test/feature/ExternalSource/test_external_oid.cpp b/src/test/feature/ExternalSource/test_external_oid.cpp new file mode 100644 index 0000000..3326514 --- /dev/null +++ b/src/test/feature/ExternalSource/test_external_oid.cpp @@ -0,0 +1,35 @@ +#include <string> +#include <iostream> +#include "gtest/gtest.h" + +#include "lib/sql_util.h" +#include "lib/file_replace.h" + +using hawq::test::SQLUtility; +using hawq::test::FileReplace; + +class TestExternalOid : public ::testing::Test { + public: + TestExternalOid() {} + ~TestExternalOid() {} +}; + +TEST_F(TestExternalOid, TestExternalOidAll) { + SQLUtility util; + FileReplace frep; + auto test_root = util.getTestRootPath(); + std::cout << test_root << std::endl; + + std::unordered_map<std::string, std::string> D; + D["@SHARE_LIBRARY_PATH@"] = test_root + "/ExternalSource/lib/function.so"; + D["@abs_datadir@"] = test_root + "/ExternalSource/data"; + frep.replace(test_root + "/ExternalSource/sql/external_oid.sql.source", + test_root + "/ExternalSource/sql/external_oid.sql", + D); + frep.replace(test_root + "/ExternalSource/ans/external_oid.ans.source", + test_root + "/ExternalSource/ans/external_oid.ans", + D); + + util.execSQLFile("ExternalSource/sql/external_oid.sql", + "ExternalSource/ans/external_oid.ans"); +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/feature/Makefile ---------------------------------------------------------------------- diff --git a/src/test/feature/Makefile b/src/test/feature/Makefile index adc6acc..f393a76 100644 --- a/src/test/feature/Makefile +++ b/src/test/feature/Makefile @@ -27,9 +27,11 @@ all: $(OBJS) sharelib sharelib: cd UDF/lib || exit 1; $(MAKE) || exit 2 + cd ExternalSource/lib || exit 1; $(MAKE) || exit 2 sharelibclean: cd UDF/lib || exit 1; $(RM) *.o *.so || exit 2 + cd ExternalSource/lib || exit 1; $(MAKE) || exit 2 doc: doxygen doxygen_template http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/regress/input/external_oid.source ---------------------------------------------------------------------- diff --git a/src/test/regress/input/external_oid.source b/src/test/regress/input/external_oid.source deleted file mode 100644 index bd4724a..0000000 --- a/src/test/regress/input/external_oid.source +++ /dev/null @@ -1,118 +0,0 @@ --- -------------------------------------- --- test first external Oid initialization --- -------------------------------------- - --- start_matchsubs --- --- # create a match/subs expression to handle ip addresses that change --- --- m/.*inserted tuple to heap table pg_class \(oid \d+, relname table_xl\).*/ --- s/oid \d+/oid SOME_OID/ --- --- m/.*deleted tuple oid=\d+ from heap table pg_class.*/ --- s/oid=\d+/oid=OID/ --- --- end_matchsubs - --- Create function that returns the first external Oid boundary -CREATE OR REPLACE FUNCTION min_external_oid() RETURNS oid - AS '@abs_builddir@/regress@DLSUFFIX@', 'min_external_oid' - LANGUAGE C; - --- Create function that returns the current external Oid -CREATE OR REPLACE FUNCTION get_next_external_oid() RETURNS oid - AS '@abs_builddir@/regress@DLSUFFIX@', 'get_next_external_oid' - LANGUAGE C; - --- Create function that sets the current external Oid -CREATE OR REPLACE FUNCTION set_next_external_oid(ext_oid oid) RETURNS oid - AS '@abs_builddir@/regress@DLSUFFIX@', 'set_next_external_oid' - LANGUAGE C; - --- Create function to insert and scan in-memory data to pg_class -CREATE OR REPLACE FUNCTION load_json_data(filename text) RETURNS text - AS '@abs_builddir@/regress@DLSUFFIX@', 'load_json_data' - LANGUAGE C; - --- Create function that inserts tuple with given Oid -CREATE OR REPLACE FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text) RETURNS text - AS '@abs_builddir@/regress@DLSUFFIX@', 'caql_insert_into_heap_pg_class' - LANGUAGE C; - --- Create function that inserts tuple with given Oid -CREATE OR REPLACE FUNCTION caql_delete_from_heap_pg_class(relid oid) RETURNS text - AS '@abs_builddir@/regress@DLSUFFIX@', 'caql_delete_from_heap_pg_class' - LANGUAGE C; - --- -------------------------------------- --- Test hcat table external oid initialization --- -------------------------------------- --- Boundary should be at FirstExternalObjectId ---SELECT min_external_oid(); --- NextExternalObjectId is uninitialized -SELECT get_next_external_oid(); -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - -BEGIN TRANSACTION; -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; --- load default.mytable -> +3 oids --- 1 oid for namespace 'default', 1 oid for relation 'mytable', 1 oid for reltype -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; --- load db1.ht1, db2.ht1, db2.ht2 -> +8 oids --- oids: db1, ht1(db1), db2, ht1(db2), ht2, reltype(ht1, ht1, ht2) -SELECT load_json_data('@abs_builddir@/data/hcatalog/multi_table.json'); -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; -END TRANSACTION; - --- New transaction will reset external Oid start point --- Yields the same result as previous transaction -BEGIN TRANSACTION; -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; -SELECT load_json_data('@abs_builddir@/data/hcatalog/multi_table.json'); -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; -END TRANSACTION; - --- -------------------------------------- --- Test external oid rollover --- -------------------------------------- -BEGIN TRANSACTION; -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; -SELECT set_next_external_oid( oid(min_external_oid()::bigint + (10*power(2,20))::bigint - 8 + 1) ) > 0; -SELECT load_json_data('@abs_builddir@/data/hcatalog/multi_table.json'); --- Used up external Oids result in Oid overflow -SELECT get_next_external_oid(); --- Rollover disallowed! -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); -END TRANSACTION; - --- -------------------------------------- --- Test external Oid boundary --- -------------------------------------- --- Create a tuple with Oid larger than FirstExternalObjectId --- Will fail during next session when try to query HCatalog --- Because external Oid boundary is violated -SELECT caql_insert_into_heap_pg_class(min_external_oid()::bigint + 20, 'table_xl'); - --- Fresh session -\c --- NextExternalObjectId is uninitialized -SELECT get_next_external_oid(); --- Should fail -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); --- NextExternalObjectId is still uninitialized -SELECT get_next_external_oid(); - --- cleanup -SELECT caql_delete_from_heap_pg_class(min_external_oid()::bigint + 20); - -DROP FUNCTION caql_delete_from_heap_pg_class(relid oid); -DROP FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text); -DROP FUNCTION load_json_data(filename text); -DROP FUNCTION get_next_external_oid(); -DROP FUNCTION set_next_external_oid(ext_oid oid); -DROP FUNCTION min_external_oid(); - http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/regress/known_good_schedule ---------------------------------------------------------------------- diff --git a/src/test/regress/known_good_schedule b/src/test/regress/known_good_schedule index 0cd48f3..1f95e49 100755 --- a/src/test/regress/known_good_schedule +++ b/src/test/regress/known_good_schedule @@ -202,5 +202,4 @@ ignore: co_disabled test: caqlinmem test: hcatalog_lookup test: json_load -test: external_oid test: validator_function http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/0e6fe7a4/src/test/regress/output/external_oid.source ---------------------------------------------------------------------- diff --git a/src/test/regress/output/external_oid.source b/src/test/regress/output/external_oid.source deleted file mode 100644 index d0a3730..0000000 --- a/src/test/regress/output/external_oid.source +++ /dev/null @@ -1,211 +0,0 @@ --- -------------------------------------- --- test first external Oid initialization --- -------------------------------------- --- start_matchsubs --- --- # create a match/subs expression to handle ip addresses that change --- --- m/.*inserted tuple to heap table pg_class \(oid \d+, relname table_xl\).*/ --- s/oid \d+/oid SOME_OID/ --- --- m/.*deleted tuple oid=\d+ from heap table pg_class.*/ --- s/oid=\d+/oid=OID/ --- --- end_matchsubs --- Create function that returns the first external Oid boundary -CREATE OR REPLACE FUNCTION min_external_oid() RETURNS oid - AS '@abs_builddir@/regress@DLSUFFIX@', 'min_external_oid' - LANGUAGE C; --- Create function that returns the current external Oid -CREATE OR REPLACE FUNCTION get_next_external_oid() RETURNS oid - AS '@abs_builddir@/regress@DLSUFFIX@', 'get_next_external_oid' - LANGUAGE C; --- Create function that sets the current external Oid -CREATE OR REPLACE FUNCTION set_next_external_oid(ext_oid oid) RETURNS oid - AS '@abs_builddir@/regress@DLSUFFIX@', 'set_next_external_oid' - LANGUAGE C; --- Create function to insert and scan in-memory data to pg_class -CREATE OR REPLACE FUNCTION load_json_data(filename text) RETURNS text - AS '@abs_builddir@/regress@DLSUFFIX@', 'load_json_data' - LANGUAGE C; --- Create function that inserts tuple with given Oid -CREATE OR REPLACE FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text) RETURNS text - AS '@abs_builddir@/regress@DLSUFFIX@', 'caql_insert_into_heap_pg_class' - LANGUAGE C; --- Create function that inserts tuple with given Oid -CREATE OR REPLACE FUNCTION caql_delete_from_heap_pg_class(relid oid) RETURNS text - AS '@abs_builddir@/regress@DLSUFFIX@', 'caql_delete_from_heap_pg_class' - LANGUAGE C; --- -------------------------------------- --- Test hcat table external oid initialization --- -------------------------------------- --- Boundary should be at FirstExternalObjectId ---SELECT min_external_oid(); --- NextExternalObjectId is uninitialized -SELECT get_next_external_oid(); - get_next_external_oid ------------------------ - 0 -(1 row) - -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); - load_json_data ------------------- - default.mytable -(1 row) - -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 0 -(1 row) - -BEGIN TRANSACTION; -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 0 -(1 row) - --- load default.mytable -> +3 oids --- 1 oid for namespace 'default', 1 oid for relation 'mytable', 1 oid for reltype -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); - load_json_data ------------------- - default.mytable -(1 row) - -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 3 -(1 row) - --- load db1.ht1, db2.ht1, db2.ht2 -> +8 oids --- oids: db1, ht1(db1), db2, ht1(db2), ht2, reltype(ht1, ht1, ht2) -SELECT load_json_data('@abs_builddir@/data/hcatalog/multi_table.json'); - load_json_data --------------------------- - db1.ht1 db2.ht1 db2.ht2 -(1 row) - -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 11 -(1 row) - -END TRANSACTION; --- New transaction will reset external Oid start point --- Yields the same result as previous transaction -BEGIN TRANSACTION; -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 0 -(1 row) - -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); - load_json_data ------------------- - default.mytable -(1 row) - -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 3 -(1 row) - -SELECT load_json_data('@abs_builddir@/data/hcatalog/multi_table.json'); - load_json_data --------------------------- - db1.ht1 db2.ht1 db2.ht2 -(1 row) - -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 11 -(1 row) - -END TRANSACTION; --- -------------------------------------- --- Test external oid rollover --- -------------------------------------- -BEGIN TRANSACTION; -SELECT get_next_external_oid()::bigint - min_external_oid()::bigint; - ?column? ----------- - 0 -(1 row) - -SELECT set_next_external_oid( oid(min_external_oid()::bigint + (10*power(2,20))::bigint - 8 + 1) ) > 0; - ?column? ----------- - t -(1 row) - -SELECT load_json_data('@abs_builddir@/data/hcatalog/multi_table.json'); - load_json_data --------------------------- - db1.ht1 db2.ht1 db2.ht2 -(1 row) - --- Used up external Oids result in Oid overflow -SELECT get_next_external_oid(); - get_next_external_oid ------------------------ - 0 -(1 row) - --- Rollover disallowed! -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); -ERROR: number of external objects from HCatalog exceeded 10M during transaction -HINT: Separate HCatalog queries into different transactions to process. -END TRANSACTION; --- -------------------------------------- --- Test external Oid boundary --- -------------------------------------- --- Create a tuple with Oid larger than FirstExternalObjectId --- Will fail during next session when try to query HCatalog --- Because external Oid boundary is violated -SELECT caql_insert_into_heap_pg_class(min_external_oid()::bigint + 20, 'table_xl'); - caql_insert_into_heap_pg_class --------------------------------------------------------------------------- - inserted tuple to heap table pg_class (oid 4293918750, relname table_xl) -(1 row) - --- Fresh session -\c --- NextExternalObjectId is uninitialized -SELECT get_next_external_oid(); - get_next_external_oid ------------------------ - 0 -(1 row) - --- Should fail -SELECT load_json_data('@abs_builddir@/data/hcatalog/single_table.json'); -ERROR: database does not have enough available Oids to support HCatalog queries -HINT: Database VACUUM may recycle unused Oids. --- NextExternalObjectId is still uninitialized -SELECT get_next_external_oid(); - get_next_external_oid ------------------------ - 0 -(1 row) - --- cleanup -SELECT caql_delete_from_heap_pg_class(min_external_oid()::bigint + 20); - caql_delete_from_heap_pg_class -------------------------------------------------------- - deleted tuple oid=4293918750 from heap table pg_class -(1 row) - -DROP FUNCTION caql_delete_from_heap_pg_class(relid oid); -DROP FUNCTION caql_insert_into_heap_pg_class(relid oid, tblname text); -DROP FUNCTION load_json_data(filename text); -DROP FUNCTION get_next_external_oid(); -DROP FUNCTION set_next_external_oid(ext_oid oid); -DROP FUNCTION min_external_oid();