hawq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From foy...@apache.org
Subject [4/9] incubator-hawq git commit: HAWQ-149. Add orafce, gp_cancel_query, pgbench and extprotocol to HAWQ
Date Thu, 12 Nov 2015 20:25:21 GMT
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/e74af545/contrib/orafce/pipe.c
----------------------------------------------------------------------
diff --git a/contrib/orafce/pipe.c b/contrib/orafce/pipe.c
new file mode 100644
index 0000000..17c90ad
--- /dev/null
+++ b/contrib/orafce/pipe.c
@@ -0,0 +1,1230 @@
+#include "postgres.h"
+#include "funcapi.h"
+#include "fmgr.h"
+#include "storage/shmem.h"
+#include "utils/memutils.h"
+#include "utils/timestamp.h"
+#include "storage/lwlock.h"
+#include "miscadmin.h"
+#include "string.h"
+#include "lib/stringinfo.h"
+#include "catalog/pg_type.h"
+#include "utils/builtins.h"
+#include "utils/date.h"
+#include "utils/numeric.h"
+
+#include "shmmc.h"
+#include "pipe.h"
+#include "orafunc.h"
+#include "builtins.h"
+
+/*
+ * @ Pavel Stehule 2006
+ */
+
+#ifndef _GetCurrentTimestamp
+#define _GetCurrentTimestamp()	GetCurrentTimestamp()
+#endif
+
+#ifndef GetNowFloat
+#ifdef HAVE_INT64_TIMESTAMP
+#define GetNowFloat()   ((float8) _GetCurrentTimestamp() / 1000000.0)
+#else
+#define GetNowFloat()   _GetCurrentTimestamp()
+#endif
+#endif
+
+#define RESULT_DATA	0
+#define RESULT_WAIT	1
+
+#define NOT_INITIALIZED -1
+#define ONE_YEAR (60*60*24*365)
+
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_text);
+PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_text);
+PG_FUNCTION_INFO_V1(dbms_pipe_send_message);
+PG_FUNCTION_INFO_V1(dbms_pipe_receive_message);
+PG_FUNCTION_INFO_V1(dbms_pipe_unique_session_name);
+PG_FUNCTION_INFO_V1(dbms_pipe_list_pipes);
+PG_FUNCTION_INFO_V1(dbms_pipe_next_item_type);
+PG_FUNCTION_INFO_V1(dbms_pipe_create_pipe);
+PG_FUNCTION_INFO_V1(dbms_pipe_create_pipe_2);
+PG_FUNCTION_INFO_V1(dbms_pipe_create_pipe_1);
+PG_FUNCTION_INFO_V1(dbms_pipe_reset_buffer);
+PG_FUNCTION_INFO_V1(dbms_pipe_purge);
+PG_FUNCTION_INFO_V1(dbms_pipe_remove_pipe);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_date);
+PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_date);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_timestamp);
+PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_timestamp);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_number);
+PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_number);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_bytea);
+PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_bytea);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_record);
+PG_FUNCTION_INFO_V1(dbms_pipe_unpack_message_record);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_integer);
+PG_FUNCTION_INFO_V1(dbms_pipe_pack_message_bigint);
+
+typedef enum {
+	IT_NO_MORE_ITEMS = 0,
+	IT_NUMBER = 9,
+	IT_VARCHAR = 11,
+	IT_DATE = 12,
+	IT_TIMESTAMPTZ = 13,
+	IT_BYTEA = 23,
+	IT_RECORD = 24
+} message_data_type;
+
+typedef struct _queue_item {
+	void *ptr;
+	struct _queue_item *next_item;
+} queue_item;
+
+typedef struct {
+	bool is_valid;
+	bool registered;
+	char *pipe_name;
+	char *creator;
+	Oid  uid;
+	struct _queue_item *items;
+	int16 count;
+	int16 limit;
+	int size;
+} pipe;
+
+typedef struct {
+	int32 size;
+	message_data_type type;
+	Oid tupType;
+} message_data_item;
+
+typedef struct {
+	int32 size;
+	int32 items_count;
+	message_data_item *next;
+} message_buffer;
+
+#define message_buffer_size		(MAXALIGN(sizeof(message_buffer)))
+#define message_buffer_get_content(buf)	((message_data_item *) (((char*)buf)+message_buffer_size))
+
+
+#define message_data_item_size	(MAXALIGN(sizeof(message_data_item)))
+#define message_data_get_content(msg) (((char *)msg) + message_data_item_size)
+#define message_data_item_next(msg) \
+	((message_data_item *) (message_data_get_content(msg) + MAXALIGN(msg->size)))
+
+typedef struct PipesFctx {
+	int pipe_nth;
+} PipesFctx;
+
+typedef struct
+{
+	LWLockId shmem_lock;
+	pipe *pipes;
+	alert_event *events;
+	alert_lock *locks;
+	size_t size;
+	unsigned int sid;
+	vardata data[1]; /* flexible array member */
+} sh_memory;
+
+#define sh_memory_size			(offsetof(sh_memory, data))
+
+message_buffer *output_buffer = NULL;
+message_buffer *input_buffer = NULL;
+
+pipe* pipes = NULL;
+LWLockId shmem_lock = NOT_INITIALIZED;
+unsigned int sid;                                 /* session id */
+Oid uid;
+
+extern alert_event *events;
+extern alert_lock  *locks;
+
+/*
+ * write on writer size bytes from ptr
+ */
+
+static void
+pack_field(message_buffer *buffer, message_data_type type,
+			int32 size, void *ptr, Oid tupType)
+{
+	int len;
+	message_data_item *message;
+
+	len = MAXALIGN(size) + message_data_item_size;
+	if (MAXALIGN(buffer->size) + len > LOCALMSGSZ - message_buffer_size)
+		ereport(ERROR,
+				(errcode(ERRCODE_OUT_OF_MEMORY),
+				 errmsg("out of memory"),
+				 errdetail("Packed message is bigger than local buffer."),
+				 errhint("Increase LOCALMSGSZ in 'pipe.h' and recompile library.")));
+
+	if (buffer->next == NULL)
+		buffer->next =  message_buffer_get_content(buffer);
+
+	message = buffer->next;
+
+	message->size = size;
+	message->type = type;
+	message->tupType = tupType;
+
+	/* padding bytes have to be zeroed - buffer creator is responsible to clear memory */
+
+	memcpy(message_data_get_content(message), ptr, size);
+
+	buffer->size += len;
+	buffer->items_count++;
+	buffer->next = message_data_item_next(message);
+}
+
+
+static void*
+unpack_field(message_buffer *buffer, message_data_type *type,
+				int32 *size, Oid *tupType)
+{
+	void *ptr;
+	message_data_item *message;
+
+	Assert(buffer != NULL);
+	Assert(buffer->items_count > 0);
+	Assert(buffer->next != NULL);
+
+	message = buffer->next;
+	*size = message->size;
+	*type = message->type;
+	*tupType = message->tupType;
+	ptr = message_data_get_content(message);
+
+	buffer->next = --buffer->items_count > 0 ? message_data_item_next(message) : NULL;
+
+	return ptr;
+}
+
+
+/*
+ * Add ptr to queue. If pipe doesn't exist, register new pipe
+ */
+
+bool
+ora_lock_shmem(size_t size, int max_pipes, int max_events, int max_locks, bool reset)
+{
+	int i;
+	bool found;
+
+	sh_memory *sh_mem;
+
+	if (pipes == NULL)
+	{
+		sh_mem = ShmemInitStruct("dbms_pipe", size, &found);
+		uid = GetUserId();
+		if (sh_mem == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_OUT_OF_MEMORY),
+					 errmsg("out of memory"),
+					 errdetail("Failed while allocation block %lu bytes in shared memory.", (unsigned long) size)));
+
+		if (!found)
+		{
+			shmem_lock = sh_mem->shmem_lock = LWLockAssign();
+			LWLockAcquire(sh_mem->shmem_lock, LW_EXCLUSIVE);
+			sh_mem->size = size - sh_memory_size;
+			ora_sinit(sh_mem->data, size, true);
+			pipes = sh_mem->pipes = ora_salloc(max_pipes*sizeof(pipe));
+			sid = sh_mem->sid = 1;
+			for (i = 0; i < max_pipes; i++)
+				pipes[i].is_valid = false;
+
+			events = sh_mem->events = ora_salloc(max_events*sizeof(alert_event));
+			locks = sh_mem->locks = ora_salloc(max_locks*sizeof(alert_lock));
+
+			for (i = 0; i < max_events; i++)
+			{
+				events[i].event_name = NULL;
+				events[i].max_receivers = 0;
+				events[i].receivers = NULL;
+				events[i].messages = NULL;
+			}
+			for (i = 0; i < max_locks; i++)
+			{
+				locks[i].sid = -1;
+				locks[i].echo = NULL;
+			}
+
+		}
+		else if (sh_mem->shmem_lock != 0)
+		{
+			pipes = sh_mem->pipes;
+			shmem_lock = sh_mem->shmem_lock;
+			LWLockAcquire(sh_mem->shmem_lock, LW_EXCLUSIVE);
+			ora_sinit(sh_mem->data, sh_mem->size, reset);
+			sid = ++(sh_mem->sid);
+			events = sh_mem->events;
+			locks = sh_mem->locks;
+		}
+	}
+	else
+	{
+		LWLockAcquire(shmem_lock, LW_EXCLUSIVE);
+	}
+/*
+	if (reset && pipes == NULL)
+		elog(ERROR, "Can't purge memory");
+*/
+
+	return pipes != NULL;
+}
+
+
+/*
+ * can be enhanced access/hash.h
+ */
+
+static pipe*
+find_pipe(text* pipe_name, bool* created, bool only_check)
+{
+	int i;
+	pipe *result = NULL;
+
+	*created = false;
+	for (i = 0; i < MAX_PIPES; i++)
+	{
+		if (pipes[i].is_valid &&
+			strncmp((char*)VARDATA(pipe_name), pipes[i].pipe_name, VARSIZE(pipe_name) - VARHDRSZ) == 0
+			&& (strlen(pipes[i].pipe_name) == (VARSIZE(pipe_name) - VARHDRSZ)))
+		{
+			/* check owner if non public pipe */
+
+			if (pipes[i].creator != NULL && pipes[i].uid != uid)
+			{
+				LWLockRelease(shmem_lock);
+				ereport(ERROR,
+						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+						 errmsg("insufficient privilege"),
+						 errdetail("Insufficient privilege to access pipe")));
+			}
+
+			return &pipes[i];
+		}
+	}
+
+	if (only_check)
+		return result;
+
+	for (i = 0; i < MAX_PIPES; i++)
+		if (!pipes[i].is_valid)
+		{
+			if (NULL != (pipes[i].pipe_name = ora_scstring(pipe_name)))
+			{
+				pipes[i].is_valid = true;
+				pipes[i].registered = false;
+				pipes[i].creator = NULL;
+				pipes[i].uid = -1;
+				pipes[i].count = 0;
+				pipes[i].limit = -1;
+
+				*created = true;
+				result = &pipes[i];
+			}
+			break;
+		}
+
+	return result;
+}
+
+
+static bool
+new_last(pipe *p, void *ptr)
+{
+	queue_item *q, *aux_q;
+
+	if (p->count >= p->limit && p->limit != -1)
+		return false;
+
+	if (p->items == NULL)
+	{
+		if (NULL == (p->items = ora_salloc(sizeof(queue_item))))
+			return false;
+		p->items->next_item = NULL;
+		p->items->ptr = ptr;
+		p->count = 1;
+		return true;
+	}
+	q = p->items;
+	while (q->next_item != NULL)
+		q = q->next_item;
+
+
+	if (NULL == (aux_q = ora_salloc(sizeof(queue_item))))
+		return false;
+
+	q->next_item = aux_q;
+	aux_q->next_item = NULL;
+	aux_q->ptr = ptr;
+
+	p->count += 1;
+
+	return true;
+}
+
+
+static void*
+remove_first(pipe *p, bool *found)
+{
+	struct _queue_item *q;
+	void *ptr = NULL;
+
+	*found = false;
+
+	if (NULL != (q = p->items))
+	{
+		p->count -= 1;
+		ptr = q->ptr;
+		p->items = q->next_item;
+		*found = true;
+
+		ora_sfree(q);
+		if (p->items == NULL && !p->registered)
+		{
+			ora_sfree(p->pipe_name);
+			p->is_valid = false;
+		}
+
+	}
+
+	return ptr;
+}
+
+
+/* copy message to local memory, if exists */
+
+static message_buffer*
+get_from_pipe(text *pipe_name, bool *found)
+{
+	pipe *p;
+	bool created;
+	message_buffer *shm_msg;
+	message_buffer *result = NULL;
+
+	if (!ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false))
+		return NULL;
+
+	if (NULL != (p = find_pipe(pipe_name, &created,false)))
+	{
+		if (!created)
+		{
+			if (NULL != (shm_msg = remove_first(p, found)))
+			{
+				p->size -= shm_msg->size;
+
+				result = (message_buffer*) MemoryContextAlloc(TopMemoryContext, shm_msg->size);
+				memcpy(result, shm_msg, shm_msg->size);
+				ora_sfree(shm_msg);
+			}
+		}
+	}
+
+	LWLockRelease(shmem_lock);
+
+	return result;
+}
+
+
+/*
+ * if ptr is null, then only register pipe
+ */
+
+static bool
+add_to_pipe(text *pipe_name, message_buffer *ptr, int limit, bool limit_is_valid)
+{
+	pipe *p;
+	bool created;
+	bool result = false;
+	message_buffer *sh_ptr;
+
+	if (!ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS,false))
+		return false;
+
+	for (;;)
+	{
+		if (NULL != (p = find_pipe(pipe_name, &created, false)))
+		{
+			if (created)
+				p->registered = ptr == NULL;
+
+			if (limit_is_valid && (created || (p->limit < limit)))
+				p->limit = limit;
+
+			if (ptr != NULL)
+			{
+				if (NULL != (sh_ptr = ora_salloc(ptr->size)))
+				{
+					memcpy(sh_ptr,ptr,ptr->size);
+					if (new_last(p, sh_ptr))
+					{
+						p->size += ptr->size;
+						result = true;
+						break;
+					}
+					ora_sfree(sh_ptr);
+				}
+				if (created)
+				{
+					/* I created new pipe, but haven't memory for new value */
+					ora_sfree(p->pipe_name);
+					p->is_valid = false;
+					result = false;
+				}
+			}
+			else
+				result = true;
+		}
+		break;
+	}
+	LWLockRelease(shmem_lock);
+	return result;
+}
+
+
+static void
+remove_pipe(text *pipe_name, bool purge)
+{
+	pipe *p;
+	bool created;
+
+	if (NULL != (p = find_pipe(pipe_name, &created, true)))
+	{
+		queue_item *q = p->items;
+		while (q != NULL)
+		{
+			queue_item *aux_q;
+
+			aux_q = q->next_item;
+			if (q->ptr)
+				ora_sfree(q->ptr);
+			ora_sfree(q);
+			q = aux_q;
+		}
+		p->items = NULL;
+		p->size = 0;
+		p->count = 0;
+		if (!(purge && p->registered))
+		{
+			ora_sfree(p->pipe_name);
+			p->is_valid = false;
+		}
+	}
+}
+
+
+Datum
+dbms_pipe_next_item_type (PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT32(input_buffer != NULL ? input_buffer->next->type : IT_NO_MORE_ITEMS);
+}
+
+
+static void
+init_buffer(message_buffer *buffer, int32 size)
+{
+	memset(buffer, 0, size);
+	buffer->size = message_buffer_size;
+	buffer->items_count = 0;
+	buffer->next = message_buffer_get_content(buffer);
+}
+
+static message_buffer*
+check_buffer(message_buffer *buffer, int32 size)
+{
+	if (buffer == NULL)
+	{
+		buffer = (message_buffer*) MemoryContextAlloc(TopMemoryContext, size);
+		if (buffer == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_OUT_OF_MEMORY),
+					 errmsg("out of memory"),
+					 errdetail("Failed while allocation block %d bytes in memory.", size)));
+
+		init_buffer(buffer, size);
+	}
+
+	return buffer;
+}
+
+Datum
+dbms_pipe_pack_message_text(PG_FUNCTION_ARGS)
+{
+	text *str = PG_GETARG_TEXT_PP(0);
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+	pack_field(output_buffer, IT_VARCHAR,
+		VARSIZE_ANY_EXHDR(str), VARDATA_ANY(str), InvalidOid);
+
+	PG_RETURN_VOID();
+}
+
+
+Datum
+dbms_pipe_pack_message_date(PG_FUNCTION_ARGS)
+{
+	DateADT dt = PG_GETARG_DATEADT(0);
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+	pack_field(output_buffer, IT_DATE,
+			   sizeof(dt), &dt, InvalidOid);
+
+	PG_RETURN_VOID();
+}
+
+
+Datum
+dbms_pipe_pack_message_timestamp(PG_FUNCTION_ARGS)
+{
+	TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+	pack_field(output_buffer, IT_TIMESTAMPTZ,
+			   sizeof(dt), &dt, InvalidOid);
+
+	PG_RETURN_VOID();
+}
+
+
+Datum
+dbms_pipe_pack_message_number(PG_FUNCTION_ARGS)
+{
+	Numeric num = PG_GETARG_NUMERIC(0);
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+	pack_field(output_buffer, IT_NUMBER,
+			   VARSIZE(num) - VARHDRSZ, VARDATA(num), InvalidOid);
+
+	PG_RETURN_VOID();
+}
+
+
+Datum
+dbms_pipe_pack_message_bytea(PG_FUNCTION_ARGS)
+{
+	bytea *data = PG_GETARG_BYTEA_P(0);
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+	pack_field(output_buffer, IT_BYTEA,
+		VARSIZE_ANY_EXHDR(data), VARDATA_ANY(data), InvalidOid);
+
+	PG_RETURN_VOID();
+}
+
+
+/*
+ *  We can serialize only typed record
+ */
+
+Datum
+dbms_pipe_pack_message_record(PG_FUNCTION_ARGS)
+{
+	HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
+	Oid tupType;
+	bytea *data;
+	FunctionCallInfoData info;
+
+	tupType = HeapTupleHeaderGetTypeId(rec);
+
+	/*
+	 * Normally one would call record_send() using DirectFunctionCall3,
+	 * but that does not work since record_send wants to cache some data
+	 * using fcinfo->flinfo->fn_extra.  So we need to pass it our own
+	 * flinfo parameter.
+	 */
+	InitFunctionCallInfoData(info, fcinfo->flinfo, 3, NULL, NULL);
+
+	info.arg[0] = PointerGetDatum(rec);
+	info.arg[1] = ObjectIdGetDatum(tupType);
+	info.arg[2] = Int32GetDatum(-1);
+	info.argnull[0] = false;
+	info.argnull[1] = false;
+	info.argnull[2] = false;
+
+	data = (bytea*) DatumGetPointer(record_send(&info));
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+	pack_field(output_buffer, IT_RECORD,
+			   VARSIZE(data), VARDATA(data), tupType);
+
+	PG_RETURN_VOID();
+}
+
+
+static Datum
+dbms_pipe_unpack_message(PG_FUNCTION_ARGS, message_data_type dtype)
+{
+	Oid		tupType;
+	void *ptr;
+	message_data_type type;
+	int32 size;
+	Datum result;
+	message_data_type next_type;
+
+	if (input_buffer == NULL ||
+		input_buffer->items_count <= 0 ||
+		input_buffer->next == NULL ||
+		input_buffer->next->type == IT_NO_MORE_ITEMS)
+		PG_RETURN_NULL();
+
+	next_type = input_buffer->next->type;
+	if (next_type != dtype)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("datatype mismatch"),
+				 errdetail("unpack unexpected type: %d", next_type)));
+
+	ptr = unpack_field(input_buffer, &type, &size, &tupType);
+	Assert(ptr != NULL);
+
+	switch (type)
+	{
+		case IT_TIMESTAMPTZ:
+			result = TimestampTzGetDatum(*(TimestampTz*)ptr);
+			break;
+		case IT_DATE:
+			result = DateADTGetDatum(*(DateADT*)ptr);
+			break;
+		case IT_VARCHAR:
+		case IT_NUMBER:
+		case IT_BYTEA:
+			result = PointerGetDatum(cstring_to_text_with_len(ptr, size));
+			break;
+		case IT_RECORD:
+		{
+			FunctionCallInfoData	info;
+			StringInfoData	buf;
+			text		   *data = cstring_to_text_with_len(ptr, size);
+
+			buf.data = VARDATA(data);
+			buf.len = VARSIZE(data) - VARHDRSZ;
+			buf.maxlen = buf.len;
+			buf.cursor = 0;
+
+			/*
+			 * Normally one would call record_recv() using DirectFunctionCall3,
+			 * but that does not work since record_recv wants to cache some data
+			 * using fcinfo->flinfo->fn_extra.  So we need to pass it our own
+			 * flinfo parameter.
+			 */
+			InitFunctionCallInfoData(info, fcinfo->flinfo, 3, NULL, NULL);
+
+			info.arg[0] = PointerGetDatum(&buf);
+			info.arg[1] = ObjectIdGetDatum(tupType);
+			info.arg[2] = Int32GetDatum(-1);
+			info.argnull[0] = false;
+			info.argnull[1] = false;
+			info.argnull[2] = false;
+
+			result = record_recv(&info);
+			break;
+		}
+		default:
+			elog(ERROR, "unexpected type: %d", type);
+			result = (Datum) 0;	/* keep compiler quiet */
+	}
+
+	if (input_buffer->items_count == 0)
+	{
+		pfree(input_buffer);
+		input_buffer = NULL;
+	}
+
+	PG_RETURN_DATUM(result);
+}
+
+
+Datum
+dbms_pipe_unpack_message_text(PG_FUNCTION_ARGS)
+{
+	return dbms_pipe_unpack_message(fcinfo, IT_VARCHAR);
+}
+
+
+Datum
+dbms_pipe_unpack_message_date(PG_FUNCTION_ARGS)
+{
+	return dbms_pipe_unpack_message(fcinfo, IT_DATE);
+}
+
+Datum
+dbms_pipe_unpack_message_timestamp(PG_FUNCTION_ARGS)
+{
+	return dbms_pipe_unpack_message(fcinfo, IT_TIMESTAMPTZ);
+}
+
+
+Datum
+dbms_pipe_unpack_message_number(PG_FUNCTION_ARGS)
+{
+	return dbms_pipe_unpack_message(fcinfo, IT_NUMBER);
+}
+
+
+Datum
+dbms_pipe_unpack_message_bytea(PG_FUNCTION_ARGS)
+{
+	return dbms_pipe_unpack_message(fcinfo, IT_BYTEA);
+}
+
+
+Datum
+dbms_pipe_unpack_message_record(PG_FUNCTION_ARGS)
+{
+	return dbms_pipe_unpack_message(fcinfo, IT_RECORD);
+}
+
+
+#define WATCH_PRE(t, et, c) \
+et = GetNowFloat() + (float8)t; c = 0; \
+do \
+{ \
+
+#define WATCH_POST(t,et,c) \
+if (GetNowFloat() >= et) \
+PG_RETURN_INT32(RESULT_WAIT); \
+if (cycle++ % 100 == 0) \
+CHECK_FOR_INTERRUPTS(); \
+pg_usleep(10000L); \
+} while(true && t != 0);
+
+
+Datum
+dbms_pipe_receive_message(PG_FUNCTION_ARGS)
+{
+	text *pipe_name = NULL;
+	int timeout = ONE_YEAR;
+	int cycle = 0;
+	float8 endtime;
+	bool found = false;
+
+	if (PG_ARGISNULL(0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+				 errmsg("pipe name is NULL"),
+				 errdetail("Pipename may not be NULL.")));
+	else
+		pipe_name = PG_GETARG_TEXT_P(0);
+
+	if (!PG_ARGISNULL(1))
+		timeout = PG_GETARG_INT32(1);
+
+	if (input_buffer != NULL)
+	{
+		pfree(input_buffer);
+		input_buffer = NULL;
+	}
+
+	WATCH_PRE(timeout, endtime, cycle);
+	if (NULL != (input_buffer = get_from_pipe(pipe_name, &found)))
+	{
+		input_buffer->next = message_buffer_get_content(input_buffer);
+		break;
+	}
+/* found empty message */
+	if (found)
+		break;
+
+	WATCH_POST(timeout, endtime, cycle);
+	PG_RETURN_INT32(RESULT_DATA);
+}
+
+
+Datum
+dbms_pipe_send_message(PG_FUNCTION_ARGS)
+{
+	text *pipe_name = NULL;
+	int timeout = ONE_YEAR;
+	int limit = 0;
+	bool valid_limit;
+
+	int cycle = 0;
+	float8 endtime;
+
+	if (PG_ARGISNULL(0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+				 errmsg("pipe name is NULL"),
+				 errdetail("Pipename may not be NULL.")));
+	else
+		pipe_name = PG_GETARG_TEXT_P(0);
+
+	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
+
+	if (!PG_ARGISNULL(1))
+		timeout = PG_GETARG_INT32(1);
+
+	if (PG_ARGISNULL(2))
+		valid_limit = false;
+	else
+	{
+		limit = PG_GETARG_INT32(2);
+		valid_limit = true;
+	}
+
+	if (input_buffer != NULL) /* XXX Strange? */
+	{
+		pfree(input_buffer);
+		input_buffer = NULL;
+	}
+
+	WATCH_PRE(timeout, endtime, cycle);
+	if (add_to_pipe(pipe_name, output_buffer,
+					limit, valid_limit))
+		break;
+	WATCH_POST(timeout, endtime, cycle);
+
+	init_buffer(output_buffer, LOCALMSGSZ);
+
+	PG_RETURN_INT32(RESULT_DATA);
+}
+
+
+Datum
+dbms_pipe_unique_session_name (PG_FUNCTION_ARGS)
+{
+	StringInfoData strbuf;
+	text *result;
+
+	float8 endtime;
+	int cycle = 0;
+	int timeout = 10;
+
+	WATCH_PRE(timeout, endtime, cycle);
+	if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false))
+	{
+		initStringInfo(&strbuf);
+		appendStringInfo(&strbuf,"PG$PIPE$%d$%d",sid, MyProcPid);
+
+		result = cstring_to_text_with_len(strbuf.data, strbuf.len);
+		pfree(strbuf.data);
+		LWLockRelease(shmem_lock);
+
+		PG_RETURN_TEXT_P(result);
+	}
+	WATCH_POST(timeout, endtime, cycle);
+	LOCK_ERROR();
+
+	PG_RETURN_NULL();
+}
+
+#define DB_PIPES_COLS		6
+
+Datum
+dbms_pipe_list_pipes(PG_FUNCTION_ARGS)
+{
+	FuncCallContext *funcctx;
+	TupleDesc        tupdesc;
+	TupleTableSlot  *slot;
+	AttInMetadata   *attinmeta;
+	PipesFctx       *fctx;
+
+	float8 endtime;
+	int cycle = 0;
+	int timeout = 10;
+
+	if (SRF_IS_FIRSTCALL())
+	{
+		int		i;
+		MemoryContext  oldcontext;
+		bool has_lock = false;
+
+		WATCH_PRE(timeout, endtime, cycle);
+		if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false))
+		{
+			has_lock = true;
+			break;
+		}
+		WATCH_POST(timeout, endtime, cycle);
+		if (!has_lock)
+			LOCK_ERROR();
+
+		funcctx = SRF_FIRSTCALL_INIT();
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		fctx = palloc(sizeof(PipesFctx));
+		funcctx->user_fctx = fctx;
+		fctx->pipe_nth = 0;
+
+		tupdesc = CreateTemplateTupleDesc(DB_PIPES_COLS , false);
+		i = 0;
+		TupleDescInitEntry(tupdesc, ++i, "name",    VARCHAROID, -1, 0);
+		TupleDescInitEntry(tupdesc, ++i, "items",   INT4OID,    -1, 0);
+		TupleDescInitEntry(tupdesc, ++i, "size",    INT4OID,    -1, 0);
+		TupleDescInitEntry(tupdesc, ++i, "limit",   INT4OID,    -1, 0);
+		TupleDescInitEntry(tupdesc, ++i, "private", BOOLOID,    -1, 0);
+		TupleDescInitEntry(tupdesc, ++i, "owner",   VARCHAROID, -1, 0);
+		Assert(i == DB_PIPES_COLS);
+
+		slot = TupleDescGetSlot(tupdesc);
+		funcctx->slot = slot;
+
+		attinmeta = TupleDescGetAttInMetadata(tupdesc);
+		funcctx->attinmeta = attinmeta;
+
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	funcctx = SRF_PERCALL_SETUP();
+	fctx = (PipesFctx *) funcctx->user_fctx;
+
+	while (fctx->pipe_nth < MAX_PIPES)
+	{
+		if (pipes[fctx->pipe_nth].is_valid)
+		{
+			Datum		result;
+			HeapTuple	tuple;
+			char	   *values[DB_PIPES_COLS];
+			char		items[16];
+			char		size[16];
+			char		limit[16];
+
+			/* name */
+			values[0] = pipes[fctx->pipe_nth].pipe_name;
+			/* items */
+			snprintf(items, lengthof(items), "%d", pipes[fctx->pipe_nth].count);
+			values[1] = items;
+			/* items */
+			snprintf(size, lengthof(size), "%d", pipes[fctx->pipe_nth].size);
+			values[2] = size;
+			/* limit */
+			if (pipes[fctx->pipe_nth].limit != -1)
+			{
+				snprintf(limit, lengthof(limit), "%d", pipes[fctx->pipe_nth].limit);
+				values[3] = limit;
+			}
+			else
+				values[3] = NULL;
+			/* private */
+			values[4] = (pipes[fctx->pipe_nth].creator ? "true" : "false");
+			/* owner */
+			values[5] = pipes[fctx->pipe_nth].creator;
+
+			tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+			result = TupleGetDatum(funcctx->slot, tuple);
+
+			fctx->pipe_nth += 1;
+			SRF_RETURN_NEXT(funcctx, result);
+		}
+		fctx->pipe_nth += 1;
+	}
+
+	LWLockRelease(shmem_lock);
+	SRF_RETURN_DONE(funcctx);
+}
+
+/*
+ * secondary functions
+ */
+
+/*
+ * Registration explicit pipes
+ *   dbms_pipe.create_pipe(pipe_name varchar, limit := -1 int, private := false bool);
+ */
+
+Datum
+dbms_pipe_create_pipe (PG_FUNCTION_ARGS)
+{
+	text *pipe_name = NULL;
+	int   limit = 0;
+	bool  is_private;
+	bool  limit_is_valid = false;
+	bool  created;
+	float8 endtime;
+	int cycle = 0;
+	int timeout = 10;
+
+	if (PG_ARGISNULL(0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+				 errmsg("pipe name is NULL"),
+				 errdetail("Pipename may not be NULL.")));
+	else
+		pipe_name = PG_GETARG_TEXT_P(0);
+
+	if (!PG_ARGISNULL(1))
+	{
+		limit = PG_GETARG_INT32(1);
+		limit_is_valid = true;
+	}
+
+	is_private = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2);
+
+	WATCH_PRE(timeout, endtime, cycle);
+	if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false))
+	{
+		pipe *p;
+		if (NULL != (p = find_pipe(pipe_name, &created, false)))
+		{
+			if (!created)
+			{
+				LWLockRelease(shmem_lock);
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("pipe creation error"),
+						 errdetail("Pipe is registered.")));
+			}
+			if (is_private)
+			{
+				char *user;
+
+				p->uid = GetUserId();
+#ifdef GP_VERSION_NUM
+				user = (GetUserNameFromId(p->uid)); 
+#else
+				user = (char*)DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(p->uid)));
+#endif
+				p->creator = ora_sstrcpy(user);
+				pfree(user);
+			}
+			p->limit = limit_is_valid ? limit : -1;
+			p->registered = true;
+
+			LWLockRelease(shmem_lock);
+			PG_RETURN_VOID();
+		}
+	}
+	WATCH_POST(timeout, endtime, cycle);
+	LOCK_ERROR();
+
+	PG_RETURN_VOID();
+}
+
+
+/*
+ * Clean local input, output buffers
+ */
+
+Datum
+dbms_pipe_reset_buffer(PG_FUNCTION_ARGS)
+{
+	if (output_buffer != NULL)
+	{
+		pfree(output_buffer);
+		output_buffer = NULL;
+	}
+
+	if (input_buffer != NULL)
+	{
+		pfree(input_buffer);
+		input_buffer = NULL;
+	}
+
+	PG_RETURN_VOID();
+}
+
+
+/*
+ * Remove all stored messages in pipe. Remove implicit created
+ * pipe.
+ */
+
+Datum
+dbms_pipe_purge (PG_FUNCTION_ARGS)
+{
+	text *pipe_name = PG_GETARG_TEXT_P(0);
+
+	float8 endtime;
+	int cycle = 0;
+	int timeout = 10;
+
+	WATCH_PRE(timeout, endtime, cycle);
+	if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false))
+	{
+
+		remove_pipe(pipe_name, true);
+		LWLockRelease(shmem_lock);
+
+		PG_RETURN_VOID();
+	}
+	WATCH_POST(timeout, endtime, cycle);
+	LOCK_ERROR();
+
+	PG_RETURN_VOID();
+}
+
+/*
+ * Remove pipe if exists
+ */
+
+Datum
+dbms_pipe_remove_pipe (PG_FUNCTION_ARGS)
+{
+	text *pipe_name = PG_GETARG_TEXT_P(0);
+
+	float8 endtime;
+	int cycle = 0;
+	int timeout = 10;
+
+	WATCH_PRE(timeout, endtime, cycle);
+	if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false))
+	{
+
+		remove_pipe(pipe_name, false);
+		LWLockRelease(shmem_lock);
+
+		PG_RETURN_VOID();
+	}
+	WATCH_POST(timeout, endtime, cycle);
+	LOCK_ERROR();
+
+	PG_RETURN_VOID();
+}
+
+
+/*
+ * Some void udf which I can't wrap in sql
+ */
+
+Datum
+dbms_pipe_create_pipe_2 (PG_FUNCTION_ARGS)
+{
+	Datum arg1 = PG_GETARG_DATUM(0);
+	Datum arg2 = PG_GETARG_DATUM(1);
+
+	DirectFunctionCall3(dbms_pipe_create_pipe,
+						arg1,
+						arg2,
+						BoolGetDatum(false));
+
+	PG_RETURN_VOID();
+}
+
+Datum
+dbms_pipe_create_pipe_1 (PG_FUNCTION_ARGS)
+{
+	Datum arg1 = PG_GETARG_DATUM(0);
+
+	DirectFunctionCall3(dbms_pipe_create_pipe,
+						arg1,
+						(Datum)0,
+						BoolGetDatum(false));
+
+	PG_RETURN_VOID();
+}
+
+Datum
+dbms_pipe_pack_message_integer(PG_FUNCTION_ARGS)
+{
+	/* Casting from int4 to numeric */
+	DirectFunctionCall1(dbms_pipe_pack_message_number,
+				DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(0)));
+
+	PG_RETURN_VOID();
+}
+
+Datum
+dbms_pipe_pack_message_bigint(PG_FUNCTION_ARGS)
+{
+	/* Casting from int8 to numeric */
+	DirectFunctionCall1(dbms_pipe_pack_message_number,
+				DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(0)));
+
+	PG_RETURN_VOID();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/e74af545/contrib/orafce/pipe.h
----------------------------------------------------------------------
diff --git a/contrib/orafce/pipe.h b/contrib/orafce/pipe.h
new file mode 100644
index 0000000..00451c2
--- /dev/null
+++ b/contrib/orafce/pipe.h
@@ -0,0 +1,49 @@
+#ifndef __PIPE__
+#define __PIPE__
+
+#define LOCALMSGSZ (8*1024)
+#define SHMEMMSGSZ (30*1024)
+#define MAX_PIPES  30
+#define MAX_EVENTS 30
+#define MAX_LOCKS  256
+
+typedef struct _message_item {
+	char *message;
+	float8 timestamp;
+	struct _message_item *next_message;
+	struct _message_item *prev_message;
+	unsigned char message_id;
+	int *receivers;                     /* copy of array all registered receivers */
+	int receivers_number;
+} message_item;
+
+typedef struct _message_echo {
+	struct _message_item *message;
+	unsigned char message_id;
+	struct _message_echo *next_echo;
+} message_echo;
+
+typedef struct {
+	char *event_name;
+	unsigned char max_receivers;
+	int *receivers;
+	int receivers_number;
+	struct _message_item *messages;
+} alert_event;
+
+typedef struct {
+	unsigned int sid;
+	message_echo *echo;
+} alert_lock;
+
+bool ora_lock_shmem(size_t size, int max_pipes, int max_events, int max_locks, bool reset);
+
+#define ERRCODE_ORA_PACKAGES_LOCK_REQUEST_ERROR        MAKE_SQLSTATE('3','0', '0','0','1')
+
+#define LOCK_ERROR() \
+	ereport(ERROR, \
+	(errcode(ERRCODE_ORA_PACKAGES_LOCK_REQUEST_ERROR), \
+	 errmsg("lock request error"), \
+	 errdetail("Failed exclusive locking of shared memory."), \
+	 errhint("Restart PostgreSQL server.")));
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/e74af545/contrib/orafce/plunit.c
----------------------------------------------------------------------
diff --git a/contrib/orafce/plunit.c b/contrib/orafce/plunit.c
new file mode 100644
index 0000000..accab05
--- /dev/null
+++ b/contrib/orafce/plunit.c
@@ -0,0 +1,431 @@
+/*
+ * This API is subset plunit lib with http://www.apollo-pro.com/help/pl_unit_assertions.htm
+ *
+ */
+
+#include "postgres.h"
+#include "funcapi.h"
+#include "parser/parse_oper.h"
+#include "utils/builtins.h"
+#include "orafunc.h"
+#include "builtins.h"
+
+PG_FUNCTION_INFO_V1(plunit_assert_true);
+PG_FUNCTION_INFO_V1(plunit_assert_true_message);
+PG_FUNCTION_INFO_V1(plunit_assert_false);
+PG_FUNCTION_INFO_V1(plunit_assert_false_message);
+PG_FUNCTION_INFO_V1(plunit_assert_null);
+PG_FUNCTION_INFO_V1(plunit_assert_null_message);
+PG_FUNCTION_INFO_V1(plunit_assert_not_null);
+PG_FUNCTION_INFO_V1(plunit_assert_not_null_message);
+PG_FUNCTION_INFO_V1(plunit_assert_equals);
+PG_FUNCTION_INFO_V1(plunit_assert_equals_message);
+PG_FUNCTION_INFO_V1(plunit_assert_equals_range);
+PG_FUNCTION_INFO_V1(plunit_assert_equals_range_message);
+PG_FUNCTION_INFO_V1(plunit_assert_not_equals);
+PG_FUNCTION_INFO_V1(plunit_assert_not_equals_message);
+PG_FUNCTION_INFO_V1(plunit_assert_not_equals_range);
+PG_FUNCTION_INFO_V1(plunit_assert_not_equals_range_message);
+PG_FUNCTION_INFO_V1(plunit_fail);
+PG_FUNCTION_INFO_V1(plunit_fail_message);
+
+static bool assert_equals_base(FunctionCallInfo fcinfo);
+static bool assert_equals_range_base(FunctionCallInfo fcinfo);
+static char *assert_get_message(FunctionCallInfo fcinfo, int nargs, char *default_message);
+
+
+/****************************************************************
+ * plunit.assert_true
+ * plunit.assert_true_message
+ *
+ * Syntax:
+ *   PROCEDURE assert_true(condition boolean, message varchar default '');
+ *
+ * Purpouse:
+ *   Asserts that the condition is true.  The optional message will be
+ *   displayed if the assertion fails.  If not supplied, a default message
+ *   is displayed.
+ *
+ ****************************************************************/
+Datum
+plunit_assert_true(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_true_message(fcinfo);
+}
+
+Datum
+plunit_assert_true_message(PG_FUNCTION_ARGS)
+{
+	char	*message = assert_get_message(fcinfo, 2, "plunit.assert_true exception");
+	bool condition = PG_GETARG_BOOL(0);
+
+	if (PG_ARGISNULL(0) || !condition)
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_true).")));
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * plunit.assert_false
+ * plunit.assert_false_message
+ *
+ * Syntax:
+ *   PROCEDURE assert_false(condition boolean, message varchar default '');
+ *
+ * Purpouse:
+ *   Asserts that the condition is false.  The optional message will be
+ *   displayed if the assertion fails.  If not supplied, a default message
+ *   is displayed.
+ *
+ ****************************************************************/
+Datum
+plunit_assert_false(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_false_message(fcinfo);
+}
+
+Datum
+plunit_assert_false_message(PG_FUNCTION_ARGS)
+{
+	char	*message = assert_get_message(fcinfo, 2, "plunit.assert_false exception");
+	bool condition = PG_GETARG_BOOL(0);
+
+	if (PG_ARGISNULL(0) || condition)
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_false).")));
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * plunit.assert_null
+ * plunit.assert_null_message
+ *
+ * Syntax:
+ *   PROCEDURE assert_null(actual anyelement, message varchar default '');
+ *
+ * Purpouse:
+ *   Asserts that the actual is null.  The optional message will be
+ *   displayed if the assertion fails.  If not supplied, a default message
+ *   is displayed.
+ *
+ ****************************************************************/
+Datum
+plunit_assert_null(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_null_message(fcinfo);
+}
+
+Datum
+plunit_assert_null_message(PG_FUNCTION_ARGS)
+{
+	char	*message = assert_get_message(fcinfo, 2, "plunit.assert_null exception");
+
+	if (!PG_ARGISNULL(0))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_null).")));
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * plunit.assert_not_null
+ * plunit.assert_not_null_message
+ *
+ * Syntax:
+ *   PROCEDURE assert_not_null(actual anyelement, message varchar default '');
+ *
+ * Purpouse:
+ *   Asserts that the actual isn't null.  The optional message will be
+ *   displayed if the assertion fails.  If not supplied, a default message
+ *   is displayed.
+ *
+ ****************************************************************/
+Datum
+plunit_assert_not_null(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_not_null_message(fcinfo);
+}
+
+Datum
+plunit_assert_not_null_message(PG_FUNCTION_ARGS)
+{
+	char	*message = assert_get_message(fcinfo, 2, "plunit.assert_not_null exception");
+
+	if (PG_ARGISNULL(0))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_not_null).")));
+
+	PG_RETURN_VOID();
+}
+
+
+/****************************************************************
+ * plunit.assert_equals
+ * plunit.assert_equals_message
+ * plunit.assert_equals_range
+ * plunit.assert_equals_range_message
+ *
+ * Syntax:
+ *   PROCEDURE assert_equals(expected anyelement,actual anyelement,
+ *                           message varchar default '');
+ *   PROCEDURE assert_equals(expected double precision, actual double precision,
+ *                           range double precision, message varchar default '');
+ *
+ * Purpouse:
+ *    Asserts that expected and actual are equal.  The optional message will be
+ *    displayed if the assertion fails.  If not supplied, a default
+ *    message is displayed.
+ *    Asserts that expected and actual are within the specified range.
+ *    The optional message will be displayed if the assertion fails.
+ *    If not supplied, a default message is displayed.
+ *
+ ****************************************************************/
+static char *
+assert_get_message(FunctionCallInfo fcinfo, int nargs, char *message)
+{
+	char *result;
+
+	if (PG_NARGS() == nargs)
+	{
+		text	*msg;
+
+		if (PG_ARGISNULL(nargs - 1))
+			ereport(ERROR,
+					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+					 errmsg("message is NULL"),
+					 errdetail("Message may not be NULL.")));
+
+		msg = PG_GETARG_TEXT_P(nargs - 1);
+		result = text_to_cstring(msg);
+	}
+	else
+		result = message;
+
+	return result;
+}
+
+
+static bool
+assert_equals_base(FunctionCallInfo fcinfo)
+{
+	Datum 		value1 = PG_GETARG_DATUM(0);
+	Datum		value2 = PG_GETARG_DATUM(1);
+	Oid		*ptr;
+
+	ptr = (Oid *) fcinfo->flinfo->fn_extra;
+	if (ptr == NULL)
+	{
+		Oid	  valtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
+		Oid eqopfcid;
+
+		if (!OidIsValid(valtype))
+	    		elog(ERROR, "could not determine data type of input");
+
+		eqopfcid = equality_oper_funcid(valtype);
+
+		if (!OidIsValid(eqopfcid))
+			ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("unknown equal operand for datatype")));
+
+    		/* First time calling for current query: allocate storage */
+        	fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+            						                    sizeof(Oid));
+                ptr = (Oid *) fcinfo->flinfo->fn_extra;
+                *ptr = eqopfcid;
+        }
+
+	return DatumGetBool(OidFunctionCall2(*ptr, value1, value2));
+}
+
+Datum
+plunit_assert_equals(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_equals_message(fcinfo);
+}
+
+Datum
+plunit_assert_equals_message(PG_FUNCTION_ARGS)
+{
+	char *message = assert_get_message(fcinfo, 3, "plunit.assert_equal exception");
+
+	/* skip all tests for NULL value */
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_equals).")));
+
+	if (!assert_equals_base(fcinfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_equals).")));
+
+	PG_RETURN_VOID();
+}
+
+Datum
+plunit_assert_equals_range(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_equals_range_message(fcinfo);
+}
+
+static bool
+assert_equals_range_base(FunctionCallInfo fcinfo)
+{
+	float8	expected_value;
+	float8	actual_value;
+	float8	range_value;
+
+        range_value = PG_GETARG_FLOAT8(2);
+	if (range_value < 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("cannot set range to negative number")));
+
+	expected_value = PG_GETARG_FLOAT8(0);
+	actual_value = PG_GETARG_FLOAT8(1);
+
+	return fabs(expected_value - actual_value) < range_value;
+}
+
+Datum
+plunit_assert_equals_range_message(PG_FUNCTION_ARGS)
+{
+	char *message = assert_get_message(fcinfo, 4, "plunit.assert_equal exception");
+
+	/* skip all tests for NULL value */
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_equals).")));
+
+	if (!assert_equals_range_base(fcinfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_equals).")));
+
+	PG_RETURN_VOID();
+}
+
+
+/****************************************************************
+ * plunit.assert_not_equals
+ * plunit.assert_not_equals_message
+ * plunit.assert_not_equals_range
+ * plunit.assert_not_equals_range_message
+ *
+ * Syntax:
+ *   PROCEDURE assert_not_equals(expected anyelement,actual anyelement,
+ *                           message varchar default '');
+ *   PROCEDURE assert_not_equals(expected double precision, expected double precision,
+ *                           range double precision, message varchar default '');
+ *
+ * Purpouse:
+ *    Asserts that expected and actual are equal.  The optional message will be
+ *    displayed if the assertion fails.  If not supplied, a default
+ *    message is displayed.
+ *    Asserts that expected and actual are within the specified range.
+ *    The optional message will be displayed if the assertion fails.
+ *    If not supplied, a default message is displayed.
+ *
+ ****************************************************************/
+Datum
+plunit_assert_not_equals(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_not_equals_message(fcinfo);
+}
+
+Datum
+plunit_assert_not_equals_message(PG_FUNCTION_ARGS)
+{
+	char *message = assert_get_message(fcinfo, 3, "plunit.assert_not_equal exception");
+
+	/* skip all tests for NULL value */
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_not_equals).")));
+
+	if (assert_equals_base(fcinfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s",message),
+				 errdetail("Plunit.assertation fails (assert_not_equals).")));
+
+	PG_RETURN_VOID();
+}
+
+Datum
+plunit_assert_not_equals_range(PG_FUNCTION_ARGS)
+{
+	return plunit_assert_not_equals_range_message(fcinfo);
+}
+
+Datum
+plunit_assert_not_equals_range_message(PG_FUNCTION_ARGS)
+{
+	char *message = assert_get_message(fcinfo, 3, "plunit.assert_not_equal exception");
+
+	/* skip all tests for NULL value */
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s", message),
+				 errdetail("Plunit.assertation fails (assert_not_equals).")));
+
+	if (assert_equals_range_base(fcinfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s", message),
+				 errdetail("Plunit.assertation fails (assert_not_equals).")));
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * plunit.fail
+ * plunit.fail_message
+ *
+ * Syntax:
+ *   PROCEDURE fail(message varchar default '');
+ *
+ * Purpouse:
+ *    Fail can be used to cause a test procedure to fail
+ *    immediately using the supplied message.
+ *
+ ****************************************************************/
+
+Datum
+plunit_fail(PG_FUNCTION_ARGS)
+{
+	return plunit_fail_message(fcinfo);
+}
+
+Datum
+plunit_fail_message(PG_FUNCTION_ARGS)
+{
+	char *message = assert_get_message(fcinfo, 1, "plunit.assert_fail exception");
+
+	ereport(ERROR,
+				(errcode(ERRCODE_CHECK_VIOLATION),
+				 errmsg("%s", message),
+				 errdetail("Plunit.assertation (assert_fail).")));
+
+	PG_RETURN_VOID();
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/e74af545/contrib/orafce/plvdate.c
----------------------------------------------------------------------
diff --git a/contrib/orafce/plvdate.c b/contrib/orafce/plvdate.c
new file mode 100644
index 0000000..79fb2d5
--- /dev/null
+++ b/contrib/orafce/plvdate.c
@@ -0,0 +1,875 @@
+/*
+  This code implements one part of functonality of
+  free available library PL/Vision. Please look www.quest.com
+
+  This library isn't optimalized for big numbers, for working
+  with n days (n > 10000), can be slow (on my P4 31ms).
+
+  Original author: Steven Feuerstein, 1996 - 2002
+  PostgreSQL implementation author: Pavel Stehule, 2006
+
+  This module is under BSD Licence
+
+  History:
+    1.0. first public version 13. March 2006
+*/
+
+#define PLVDATE_VERSION  "PostgreSQL PLVdate, version 1.0, March 2006"
+
+#include "postgres.h"
+#include "utils/date.h"
+#include "utils/builtins.h"
+#include "utils/nabstime.h"
+#include <sys/time.h>
+#include <stdlib.h>
+#include "orafunc.h"
+
+
+/*
+ * External (defined in PgSQL datetime.c (timestamp utils))
+ */
+
+extern PGDLLIMPORT char *days[];
+
+Datum plvdate_add_bizdays (PG_FUNCTION_ARGS);
+Datum plvdate_nearest_bizday (PG_FUNCTION_ARGS);
+Datum plvdate_next_bizday (PG_FUNCTION_ARGS);
+Datum plvdate_bizdays_between (PG_FUNCTION_ARGS);
+Datum plvdate_prev_bizday (PG_FUNCTION_ARGS);
+Datum plvdate_isbizday (PG_FUNCTION_ARGS);
+
+Datum plvdate_set_nonbizday_dow (PG_FUNCTION_ARGS);
+Datum plvdate_unset_nonbizday_dow (PG_FUNCTION_ARGS);
+Datum plvdate_set_nonbizday_day (PG_FUNCTION_ARGS);
+Datum plvdate_unset_nonbizday_day (PG_FUNCTION_ARGS);
+
+Datum plvdate_use_easter (PG_FUNCTION_ARGS);
+Datum plvdate_using_easter (PG_FUNCTION_ARGS);
+Datum plvdate_include_start (PG_FUNCTION_ARGS);
+Datum plvdate_including_start (PG_FUNCTION_ARGS);
+
+Datum plvdate_default_holidays (PG_FUNCTION_ARGS);
+
+Datum plvdate_version (PG_FUNCTION_ARGS);
+
+Datum plvdate_days_inmonth (PG_FUNCTION_ARGS);
+Datum plvdate_isleapyear (PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(plvdate_add_bizdays);
+PG_FUNCTION_INFO_V1(plvdate_nearest_bizday);
+PG_FUNCTION_INFO_V1(plvdate_next_bizday);
+PG_FUNCTION_INFO_V1(plvdate_bizdays_between);
+PG_FUNCTION_INFO_V1(plvdate_prev_bizday);
+PG_FUNCTION_INFO_V1(plvdate_isbizday);
+
+PG_FUNCTION_INFO_V1(plvdate_set_nonbizday_dow);
+PG_FUNCTION_INFO_V1(plvdate_unset_nonbizday_dow);
+PG_FUNCTION_INFO_V1(plvdate_set_nonbizday_day);
+PG_FUNCTION_INFO_V1(plvdate_unset_nonbizday_day);
+
+PG_FUNCTION_INFO_V1(plvdate_use_easter);
+PG_FUNCTION_INFO_V1(plvdate_using_easter);
+PG_FUNCTION_INFO_V1(plvdate_include_start);
+PG_FUNCTION_INFO_V1(plvdate_including_start);
+
+PG_FUNCTION_INFO_V1(plvdate_default_holidays);
+
+PG_FUNCTION_INFO_V1(plvdate_version);
+
+PG_FUNCTION_INFO_V1(plvdate_days_inmonth);
+PG_FUNCTION_INFO_V1(plvdate_isleapyear);
+
+
+#define CHECK_SEQ_SEARCH(_l, _s) \
+do { \
+     if ((_l) < 0) {                                                 \
+               ereport(ERROR,                                        \
+                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),      \
+                      errmsg("invalid value for %s", (_s))));        \
+              }                                                      \
+} while (0)
+
+extern int ora_seq_search(const char *name, /*const*/ char **array, int max);
+
+#define SUNDAY     (1 << 0)
+#define SATURDAY   (1 << 6)
+
+static unsigned char nonbizdays = SUNDAY | SATURDAY;
+static bool use_easter = true;
+static bool include_start = true;
+
+#define MAX_holidays   30
+#define MAX_EXCEPTIONS 50
+
+typedef struct {
+	char day;
+	char month;
+} holiday_desc;
+
+typedef struct {
+	unsigned char nonbizdays;
+	bool use_easter;
+	holiday_desc *holidays;
+	int holidays_c;
+} cultural_info;
+
+static holiday_desc holidays[MAX_holidays];  /* sorted array */
+static DateADT exceptions[MAX_EXCEPTIONS];   /* sorted array */
+
+static int holidays_c = 0;
+static int exceptions_c = 0;
+
+static holiday_desc czech_holidays[] = {
+	{1,1}, // Novy rok
+	{1,5}, // Svatek prace
+	{8,5}, // Den osvobozeni
+	{5,7}, // Den slovanskych verozvestu
+	{6,7}, // Den upaleni mistra Jana Husa
+	{28,9}, // Den ceske statnosti
+	{28,10}, // Den vzniku samostatneho ceskoslovenskeho statu
+	{17,11}, // Den boje za svobodu a demokracii
+	{24,12}, // Stedry den
+	{25,12}, // 1. svatek vanocni
+	{26,12}  // 2. svatek vanocni
+};
+
+
+static holiday_desc germany_holidays[] = {
+	{1,1},{1,5},{25,5},{4,6},{5,6},
+	{15,8},{3,10},{25,12},{26,12}
+};
+
+static holiday_desc poland_holidays[] = {
+	{1,1},{1,5},{3,5},{15,6},{15,8},
+	{1,11},{11,11},{25,12},{26,12}
+};
+
+static holiday_desc austria_holidays[] = {
+	{1,1},{6,1},{1,5},{25,5},{4,6},
+	{5,6},{15,6},{15,8},{26,10},{1,11},
+	{8,12},{25,12},{26,12}
+};
+
+static holiday_desc slovakia_holidays[] = {
+	{1,1},{6,1},{1,5},{8,5},{5,7},
+	{29,8},{1,9},{15,9},{1,11},{17,11},
+	{24,12},{25,12},{26,12}
+};
+
+static holiday_desc russian_holidays[] = {
+	{1,1},{2,1},{3,1},{4,1},{5,1},
+	{7,1},{23,2},{8,3},{1,5},{9,5},
+	{12,6}, {4,11}
+};
+
+static holiday_desc england_holidays[] = {
+	{1,1},{2,1},{1,5},{29,5},{28,8},
+	{25,12},{26,12}
+};
+
+static holiday_desc usa_holidays[] = {
+	{1,1},{16,1},{20,2},{29,5},{4,7},
+	{4,9},{9,10},{11,11},{23,11},{25,12}
+};
+
+cultural_info defaults_ci[] = {
+	{SUNDAY | SATURDAY, true, czech_holidays, 11},
+	{SUNDAY | SATURDAY, true, germany_holidays, 9},
+	{SUNDAY | SATURDAY, true, poland_holidays, 9},
+	{SUNDAY | SATURDAY, true, austria_holidays, 13},
+	{SUNDAY | SATURDAY, true, slovakia_holidays, 13},
+	{SUNDAY | SATURDAY, false, russian_holidays, 12},
+	{SUNDAY | SATURDAY, true, england_holidays, 7},
+	{SUNDAY | SATURDAY, false, usa_holidays, 10}
+};
+
+static char *states[] = {
+	"Czech", "Germany", "Poland",
+	"Austria", "Slovakia", "Russia",
+	"Gb", "Usa",
+	NULL,
+};
+
+static int
+dateadt_comp(const void* a, const void* b)
+{
+	DateADT *_a = (DateADT*)a;
+	DateADT *_b = (DateADT*)b;
+
+	return *_a - *_b;
+}
+
+static int
+holiday_desc_comp(const void* a, const void* b)
+{
+	int result;
+	if (0 == (result = ((holiday_desc*)a)->month - ((holiday_desc*)b)->month))
+		result = ((holiday_desc*)a)->day - ((holiday_desc*)b)->day;
+
+	return result;
+}
+
+
+static void
+easter_sunday(int year, int* dd, int* mm)
+{
+	int b, d, e, q;
+
+	if (year < 1900 || year > 2099)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+				 errmsg("date is out of range"),
+				 errdetail("Easter is defined only for years between 1900 and 2099")));
+
+	b = 255 - 11 * (year % 19);
+	d = ((b - 21) % 30) + 21;
+	if (d > 38) d -= 1;
+	e = (year + year/4 + d + 1) % 7;
+	q = d + 7 - e;
+	if (q < 32)
+	{
+		*dd = q; *mm = 3;
+	}
+	else
+	{
+		*dd = q - 31; *mm = 4;
+	}
+}
+
+static Datum
+ora_add_bizdays(DateADT day, int days)
+{
+	int d, dx;
+	int y, m, auxd;
+	holiday_desc hd;
+
+	d = j2day(day+POSTGRES_EPOCH_JDATE);
+	dx = days > 0? 1 : -1;
+
+	while (days != 0)
+	{
+		d = (d+dx) % 7;
+		d = (d < 0) ? 6:d;
+		day += dx;
+		if ((1 << d) & nonbizdays)
+			continue;
+
+		if (NULL != bsearch(&day, exceptions, exceptions_c,
+							sizeof(DateADT), dateadt_comp))
+			continue;
+
+		j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &auxd);
+		hd.day = (char) auxd;
+		hd.month = (char) m;
+
+		if (use_easter && (m == 3 || m == 4))
+		{
+			easter_sunday(y, &auxd, &m);
+			if (m == hd.month && (auxd == hd.day || d+1 == hd.day))
+				continue;
+		}
+		if (NULL != bsearch(&hd, holidays, holidays_c,
+							sizeof(holiday_desc), holiday_desc_comp))
+			continue;
+
+		days -= dx;
+	}
+
+	return day;
+}
+
+
+static int
+ora_diff_bizdays(DateADT day1, DateADT day2)
+{
+	int d, days;
+	int y, m, auxd;
+	holiday_desc hd;
+
+	int cycle_c = 0;
+	bool start_is_bizday = false;
+
+	DateADT aux_day;
+	if (day1 > day2)
+	{
+		aux_day = day1;
+		day1 = day2; day2 = aux_day;
+	}
+
+
+	d = j2day(day1+POSTGRES_EPOCH_JDATE);
+	days = 0;
+
+	while (day1 <= day2)
+	{
+		++ cycle_c;
+		d = (d+1) % 7;
+		d = (d < 0) ? 6:d;
+		day1 += 1;
+		if ((1 << d) & nonbizdays)
+			continue;
+
+		if (NULL != bsearch(&day1, exceptions, exceptions_c,
+							sizeof(DateADT), dateadt_comp))
+			continue;
+
+		j2date(day1 + POSTGRES_EPOCH_JDATE, &y, &m, &auxd);
+		hd.day = (char) auxd;
+		hd.month = (char) m;
+
+		if (use_easter && (m == 3 || m == 4))
+		{
+			easter_sunday(y, &auxd, &m);
+			if (m == hd.month && (auxd == hd.day || d+1 == hd.day))
+				continue;
+		}
+		if (NULL != bsearch(&hd, holidays, holidays_c,
+							sizeof(holiday_desc), holiday_desc_comp))
+			continue;
+
+		days += 1;
+		if (cycle_c == 1)
+			start_is_bizday = true;
+	}
+	if (include_start && start_is_bizday && days >= 1)
+		days -= 1;
+
+	return days;
+}
+
+
+/****************************************************************
+ * PLVdate.add_bizdays
+ *
+ * Syntax:
+ *   FUNCTION add_bizdays(IN dt DATE, IN days int) RETURNS DATE;
+ *
+ * Purpouse:
+ *   Get the date created by adding <n> business days to a date
+ *
+ ****************************************************************/
+
+
+Datum
+plvdate_add_bizdays (PG_FUNCTION_ARGS)
+{
+	DateADT day = PG_GETARG_DATEADT(0);
+	int days = PG_GETARG_INT32(1);
+
+	PG_RETURN_DATEADT(ora_add_bizdays(day,days));
+}
+
+
+/****************************************************************
+ * PLVdate.nearest_bizday
+ *
+ * Syntax:
+ *   FUNCTION nearest_bizday(IN dt DATE) RETURNS DATE;
+ *
+ * Purpouse:
+ *   Get the nearest business date to a given date, user defined
+ *
+ ****************************************************************/
+
+Datum
+plvdate_nearest_bizday (PG_FUNCTION_ARGS)
+{
+	DateADT dt = PG_GETARG_DATEADT(0);
+	DateADT d1, d2, res;
+
+	d1 = ora_add_bizdays(dt, -1);
+	d2 = ora_add_bizdays(dt, 1);
+
+	if ((dt - d1) > (d2 - dt))
+		res = d2;
+	else
+		res = d1;
+
+	PG_RETURN_DATEADT(res);
+}
+
+
+/****************************************************************
+ * PLVdate.next_bizday
+ *
+ * Syntax:
+ *   FUNCTION next_bizday(IN dt DATE) RETURNS DATE;
+ *
+ * Purpouse:
+ *   Get the next business date from a given date, user defined
+ *
+ ****************************************************************/
+
+Datum
+plvdate_next_bizday (PG_FUNCTION_ARGS)
+{
+	DateADT day = PG_GETARG_DATEADT(0);
+
+	PG_RETURN_DATEADT(ora_add_bizdays(day,1));
+}
+
+
+/****************************************************************
+ * PLVdate.bizdays_between
+ *
+ * Syntax:
+ *   FUNCTION bizdays_between(IN dt1 DATE, IN dt2 DATE)
+ *     RETURNS int;
+ *
+ * Purpouse:
+ *   Get the number of business days between two dates
+ *
+ ****************************************************************/
+
+Datum
+plvdate_bizdays_between (PG_FUNCTION_ARGS)
+{
+	DateADT day1 = PG_GETARG_DATEADT(0);
+	DateADT day2 = PG_GETARG_DATEADT(1);
+
+	PG_RETURN_INT32(ora_diff_bizdays(day1,day2));
+}
+
+
+/****************************************************************
+ * PLVdate.prev_bizday
+ *
+ * Syntax:
+ *   FUNCTION prev_bizday(IN dt DATE) RETURNS date;
+ *
+ * Purpouse:
+ *   Get the previous business date from a given date, user
+ * defined
+ *
+ ****************************************************************/
+
+Datum
+plvdate_prev_bizday (PG_FUNCTION_ARGS)
+{
+	DateADT day = PG_GETARG_DATEADT(0);
+
+	PG_RETURN_DATEADT(ora_add_bizdays(day,-1));
+}
+
+
+/****************************************************************
+ * PLVdate.isbizday
+ *
+ * Syntax:
+ *   FUNCTION isbizday(IN dt DATE) RETURNS bool;
+ *
+ * Purpouse:
+ *   Call this function to determine if a date is a business day
+ *
+ ****************************************************************/
+
+Datum
+plvdate_isbizday (PG_FUNCTION_ARGS)
+{
+	DateADT day = PG_GETARG_DATEADT(0);
+	int y, m, d;
+	holiday_desc hd;
+
+	if (0 != ((1 << j2day(day+POSTGRES_EPOCH_JDATE)) & nonbizdays))
+		return false;
+
+	if (NULL != bsearch(&day, exceptions, exceptions_c,
+						sizeof(DateADT), dateadt_comp))
+		return false;
+
+	j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+	hd.month = m; hd.day = d;
+
+ 	if (use_easter && (m == 3 || m == 4))
+	{
+		easter_sunday(y, &d, &m);
+		if (m == hd.month && (d == hd.day || d+1 == hd.day))
+			return false;
+	}
+
+	PG_RETURN_BOOL (NULL == bsearch(&hd, holidays, holidays_c,
+									sizeof(holiday_desc), holiday_desc_comp));
+}
+
+
+/****************************************************************
+ * PLVdate.set_nonbizday
+ *
+ * Syntax:
+ *   FUNCTION set_nonbizday(IN dow VARCHAR) RETURNS void;
+ *
+ * Purpouse:
+ *   Set day of week as non bussines day
+ *
+ ****************************************************************/
+
+Datum
+plvdate_set_nonbizday_dow (PG_FUNCTION_ARGS)
+{
+	unsigned char check;
+
+	text *day_txt = PG_GETARG_TEXT_PP(0);
+
+	int d = ora_seq_search(VARDATA_ANY(day_txt), days, VARSIZE_ANY_EXHDR(day_txt));
+	CHECK_SEQ_SEARCH(d, "DAY/Day/day");
+
+	check = nonbizdays | (1 << d);
+	if (check == 0x7f)
+                ereport(ERROR,
+                        (errcode(ERRCODE_DATA_EXCEPTION),
+                         errmsg("nonbizday registeration error"),
+                         errdetail("Constraint violation."),
+                         errhint("One day in week have to be bizday.")));
+
+	nonbizdays = nonbizdays | (1 << d);
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * PLVdate.unset_nonbizday
+ *
+ * Syntax:
+ *   FUNCTION unset_nonbizday(IN dow VARCHAR) RETURNS void;
+ *
+ * Purpouse:
+ *   Unset day of week as non bussines day
+ *
+ ****************************************************************/
+
+Datum
+plvdate_unset_nonbizday_dow (PG_FUNCTION_ARGS)
+{
+	text *day_txt = PG_GETARG_TEXT_PP(0);
+
+	int d = ora_seq_search(VARDATA_ANY(day_txt), days, VARSIZE_ANY_EXHDR(day_txt));
+	CHECK_SEQ_SEARCH(d, "DAY/Day/day");
+
+	nonbizdays = (nonbizdays | (1 << d)) ^ (1 << d);
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * PLVdate.set_nonbizday
+ *
+ * Syntax:
+ *   FUNCTION set_nonbizday(IN day DATE) RETURNS void;
+ *   FUNCTION set_nonbizday(IN day DATE, IN repeat := false BOOL) RETURNS void;
+ *
+ * Purpouse:
+ *   Set day as non bussines day, second arg specify year's
+ * periodicity
+ *
+ ****************************************************************/
+
+Datum
+plvdate_set_nonbizday_day (PG_FUNCTION_ARGS)
+{
+	DateADT arg1 = PG_GETARG_DATEADT(0);
+	bool arg2 = PG_GETARG_BOOL(1);
+	int y, m, d;
+	holiday_desc hd;
+
+	if (arg2)
+	{
+		if (holidays_c == MAX_holidays)
+                        ereport(ERROR,
+                                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                 errmsg("nonbizday registeration error"),
+                                 errdetail("Too much registered nonbizdays."),
+                                 errhint("Increase MAX_holidays in 'plvdate.c'.")));
+
+		j2date(arg1 + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+		hd.month = m; hd.day = d;
+
+		if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp))
+                        ereport(ERROR,
+                                (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                 errmsg("nonbizday registeration error"),
+                                 errdetail("Date is registered.")));
+
+		holidays[holidays_c].month = m;
+		holidays[holidays_c].day = d;
+		holidays_c += 1;
+
+		qsort(holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp);
+	}
+	else
+	{
+		if (exceptions_c == MAX_EXCEPTIONS)
+                        ereport(ERROR,
+                                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                 errmsg("nonbizday registeration error"),
+                                 errdetail("Too much registered nonrepeated nonbizdays."),
+                                 errhint("Increase MAX_EXCEPTIONS in 'plvdate.c'.")));
+
+		if (NULL != bsearch(&arg1, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp))
+                        ereport(ERROR,
+                                (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                 errmsg("nonbizday registeration error"),
+                                 errdetail("Date is registered.")));
+
+		exceptions[exceptions_c++] = arg1;
+		qsort(exceptions, exceptions_c, sizeof(DateADT), dateadt_comp);
+	}
+
+	PG_RETURN_VOID();
+}
+
+/****************************************************************
+ * PLVdate.unset_nonbizday
+ *
+ * Syntax:
+ *   FUNCTION unset_nonbizday(IN day DATE) RETURNS void;
+ *   FUNCTION unset_nonbizday(IN day DATE, IN repeat := false BOOL) RETURNS void;
+ *
+ * Purpouse:
+ *   Unset day as non bussines day, second arg specify year's
+ * periodicity
+ *
+ ****************************************************************/
+
+Datum
+plvdate_unset_nonbizday_day (PG_FUNCTION_ARGS)
+{
+	DateADT arg1 = PG_GETARG_DATEADT(0);
+	bool arg2 = PG_GETARG_BOOL(1);
+	int y, m, d;
+	bool found = false;
+	int i;
+
+	if (arg2)
+	{
+		j2date(arg1 + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+		for (i = 0; i < holidays_c; i++)
+		{
+			if (!found && holidays[i].month == m && holidays[i].day == d)
+				found = true;
+			else if (found)
+			{
+				holidays[i-1].month = holidays[i].month;
+				holidays[i-1].day = holidays[i].day;
+			}
+		}
+		if (found)
+			holidays_c -= 1;
+	}
+	else
+	{
+		for (i = 0; i < exceptions_c; i++)
+			if (!found && exceptions[i] == arg1)
+				found = true;
+			else if (found)
+				exceptions[i-1] = exceptions[i];
+		if (found)
+			exceptions_c -= 1;
+	}
+	if (!found)
+                ereport(ERROR,
+                        (errcode(ERRCODE_UNDEFINED_OBJECT),
+                         errmsg("nonbizday unregisteration error"),
+                         errdetail("Nonbizday not found.")));
+
+	PG_RETURN_VOID();
+}
+
+
+/****************************************************************
+ * PLVdate.use_easter
+ *
+ * Syntax:
+ *   FUNCTION unuse_easter() RETURNS void;
+ *   FUNCTION use_easter() RETURNS void;
+ *   FUNCTION use_easter(IN bool) RETURNS void
+ *
+ * Purpouse:
+ *   Have to use easter as nonbizday?
+ *
+ ****************************************************************/
+
+Datum
+plvdate_use_easter (PG_FUNCTION_ARGS)
+{
+	use_easter = PG_GETARG_BOOL(0);
+
+	PG_RETURN_VOID();
+}
+
+
+/****************************************************************
+ * PLVdate.using_easter
+ *
+ * Syntax:
+ *   FUNCTION using_easter() RETURNS bool
+ *
+ * Purpouse:
+ *   Use it easter as nonbizday?
+ *
+ ****************************************************************/
+
+Datum
+plvdate_using_easter (PG_FUNCTION_ARGS)
+{
+	PG_RETURN_BOOL(use_easter);
+}
+
+
+/****************************************************************
+ * PLVdate.include_start
+ *
+ * Syntax:
+ *   FUNCTION include_start() RETURNS void;
+ *   FUNCTION noinclude_start() RETURNS void;
+ *   FUNCTION include_start(IN bool) RETURNS void
+ *
+ * Purpouse:
+ *   Have to include current day in bizdays_between calculation?
+ *
+ ****************************************************************/
+
+Datum
+plvdate_include_start (PG_FUNCTION_ARGS)
+{
+	include_start = PG_GETARG_BOOL(0);
+
+	PG_RETURN_VOID();
+}
+
+
+/****************************************************************
+ * PLVdate.including_start
+ *
+ * Syntax:
+ *   FUNCTION including_start() RETURNS bool
+ *
+ * Purpouse:
+ *   include current day in bizdays_between calculation?
+ *
+ ****************************************************************/
+
+Datum
+plvdate_including_start (PG_FUNCTION_ARGS)
+{
+	PG_RETURN_BOOL(include_start);
+}
+
+
+/*
+ * Load some national configurations
+ *
+ */
+
+Datum
+plvdate_default_holidays (PG_FUNCTION_ARGS)
+{
+	text *country = PG_GETARG_TEXT_PP(0);
+
+	int c = ora_seq_search(VARDATA_ANY(country), states, VARSIZE_ANY_EXHDR(country));
+	CHECK_SEQ_SEARCH(c, "STATE/State/state");
+
+	nonbizdays = defaults_ci[c].nonbizdays;
+	use_easter = defaults_ci[c].use_easter;
+	exceptions_c = 0;
+
+	holidays_c = defaults_ci[c].holidays_c;
+	memcpy(holidays, defaults_ci[c].holidays, holidays_c*sizeof(holiday_desc));
+
+	PG_RETURN_VOID();
+}
+
+/*
+ * helper maintaince functions
+ */
+
+Datum
+plvdate_version (PG_FUNCTION_ARGS)
+{
+	PG_RETURN_CSTRING(PLVDATE_VERSION);
+}
+
+
+/****************************************************************
+ * PLVdate.days_inmonth
+ *
+ * Syntax:
+ *   FUNCTION days_inmonth(date) RETURNS integer
+ *
+ * Purpouse:
+ *   Returns month's length
+ *
+ ****************************************************************/
+
+Datum
+plvdate_days_inmonth(PG_FUNCTION_ARGS)
+{
+	DateADT day = PG_GETARG_DATEADT(0);
+	int result;
+	int y, m, d;
+
+	j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+
+	result = date2j(y, m+1, 1) - date2j(y, m, 1);
+
+	PG_RETURN_INT32(result);
+}
+
+
+/****************************************************************
+ * PLVdate.isleapyear
+ *
+ * Syntax:
+ *   FUNCTION isleapyear() RETURNS bool
+ *
+ * Purpouse:
+ *   Returns true, if year is leap
+ *
+ ****************************************************************/
+
+Datum
+plvdate_isleapyear(PG_FUNCTION_ARGS)
+{
+	DateADT day = PG_GETARG_DATEADT(0);
+	int y, m, d;
+	bool result;
+
+	j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+	result = ((( y % 4) == 0) && ((y % 100) != 0)) || ((y / 400) == 0);
+
+	PG_RETURN_BOOL(result);
+}
+
+/****************************************************************
+ * PLVdate.set_nonbizdays
+ *
+ * Syntax:
+ *   FUNCTION set_nonbizdays(IN dow bool[7]) RETURNS void;
+ *
+ * Purpouse:
+ *   Set pattern bussines/nonbussines days in week
+ *
+ ****************************************************************/
+
+/****************************************************************
+ * PLVdate.set_nonbizday
+ *
+ * Syntax:
+ *   FUNCTION set_nonbizdays(IN days DATE[]) RETURNS void;
+ *   FUNCTION set_nonbizdays(IN days DATE[], IN repeat := false BOOL) RETURNS void;
+ *
+ * Purpouse:
+ *   Set days as non bussines day, second arg specify year's
+ * periodicity
+ *
+ ****************************************************************/
+
+/****************************************************************
+ * PLVdate.display
+ *
+ * Syntax:
+ *   FUNCTION display() RETURNS void;
+ *
+ * Purpouse:
+ *   Show current calendar
+ *
+ ****************************************************************/

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/e74af545/contrib/orafce/plvlex.c
----------------------------------------------------------------------
diff --git a/contrib/orafce/plvlex.c b/contrib/orafce/plvlex.c
new file mode 100644
index 0000000..fbde660
--- /dev/null
+++ b/contrib/orafce/plvlex.c
@@ -0,0 +1,290 @@
+/*
+  This code implements one part of functonality of
+  free available library PL/Vision. Please look www.quest.com
+
+  Original author: Steven Feuerstein, 1996 - 2002
+  PostgreSQL implementation author: Pavel Stehule, 2006
+
+  This module is under BSD Licence
+
+  History:
+    1.0. first public version 13. March 2006
+*/
+
+#include "postgres.h"
+#include "utils/date.h"
+#include "utils/builtins.h"
+#include "utils/nabstime.h"
+#include <sys/time.h>
+#include <stdlib.h>
+#include "lib/stringinfo.h"
+
+#include "plvlex.h"
+#include "sqlparse.h"
+#include "nodes/pg_list.h"
+#include "funcapi.h"
+#include "catalog/pg_type.h"
+#include "orafunc.h"
+#include "builtins.h"
+
+typedef struct {
+	List	*nodes;
+	int 	nnodes;
+	int	cnode;
+	char **values;
+} tokensFctx;
+
+PG_FUNCTION_INFO_V1(plvlex_tokens);
+
+extern int      orafce_sql_yyparse(void *);
+extern void orafce_sql_yyerror(const char *message);
+extern void orafce_sql_scanner_init(const char *str);
+extern void orafce_sql_scanner_finish(void);
+
+static orafce_lexnode *__node;
+
+static char *__result;
+static int __len;
+
+#define CSTRING(txt) \
+	( \
+    __len = VARSIZE(txt) - VARHDRSZ, \
+    __result = palloc(__len + 1), \
+    memcpy(__result, VARDATA(txt), __len), \
+    __result[__len] = '\0', \
+    __result)
+
+
+#define COPY_TO_S(src,dest,col)	(dest->col = (src->col ? pstrdup(src->col) : NULL))
+#define COPY_TO(src,dest,col)	(dest->col = src->col)
+
+#define COPY_FIELDS(src,dest) \
+	COPY_TO(src, dest, typenode), \
+	COPY_TO_S(src,dest,str), \
+	COPY_TO(src,dest,keycode), \
+	COPY_TO(src,dest,lloc), \
+	COPY_TO_S(src,dest,sep), \
+	COPY_TO(src,dest,modificator), \
+	COPY_TO(src,dest,classname)
+
+
+#define COPY_NODE(src)   \
+  ( \
+    __node = (orafce_lexnode*) palloc(sizeof(orafce_lexnode)),  \
+    COPY_FIELDS(src,__node), \
+    __node)
+
+
+/* Finding triplet a.b --> a */
+
+#define IsType(node, type)	(node->typenode == X_##type)
+#define APPEND_NODE(list,nd)	\
+	if (nd) \
+	{ \
+		list = lappend(list, nd); \
+		nd = NULL; \
+	}
+
+#define mod(a)  (a->modificator)
+#define SF(a)	(a ? a : "")
+
+#define NEWNODE(type) \
+	( \
+	__node = (orafce_lexnode *) palloc(sizeof(orafce_lexnode)), \
+	__node->typenode = X_##type, \
+	__node->modificator = NULL, \
+	__node->sep = NULL, \
+	__node->keycode = -1, \
+	__node->classname = #type, \
+	__node->lloc = 0, \
+	__node )
+
+
+
+static orafce_lexnode *
+compose(orafce_lexnode *a, orafce_lexnode *b)
+{
+	orafce_lexnode *result;
+	StringInfo sinfo;
+
+	sinfo = makeStringInfo();
+	result = NEWNODE(IDENT);
+	result->lloc = a->lloc;
+
+	if (strcmp(SF(mod(a)), "dq") == 0)
+		appendStringInfo(sinfo, "\"%s\".", a->str);
+	else
+	{
+		appendStringInfoString(sinfo, a->str);
+		appendStringInfoChar(sinfo, '.');
+	}
+
+	if (strcmp(SF(mod(b)), "dq") == 0)
+		appendStringInfo(sinfo, "\"%s\"", b->str);
+	else
+		appendStringInfoString(sinfo, b->str);
+
+	result->str = sinfo->data;
+
+	return result;
+}
+
+static List *
+filterList(List *list, bool skip_spaces, bool qnames)
+{
+	List *result = NIL;
+	ListCell *cell;
+	bool isdot = false;
+	orafce_lexnode *a = NULL;
+	orafce_lexnode *dot = NULL;
+
+	foreach(cell, list)
+	{
+		orafce_lexnode *nd = (orafce_lexnode *) lfirst(cell);
+
+		if (qnames)
+		{
+			isdot = (IsType(nd, OTHERS) && (nd->str[0] == '.'));
+
+			if (IsType(nd, IDENT) && dot && a)
+			{
+				a = compose(a, nd);
+				dot = NULL;
+				continue;
+			}
+			else if (isdot && !dot && a)
+			{
+				dot = COPY_NODE(nd);
+				continue;
+			}
+			else if (IsType(nd, IDENT) && !a)
+			{
+				a = COPY_NODE(nd);
+				continue;
+			}
+		}
+
+		/* clean buffered values */
+		APPEND_NODE(result,a);
+		APPEND_NODE(result,dot);
+
+		if (!(skip_spaces && IsType(nd, WHITESPACE)))
+		{
+			result = lappend(result, COPY_NODE(nd));
+		}
+	}
+
+	/* clean buffered values */
+	APPEND_NODE(result,a);
+	APPEND_NODE(result,dot);
+
+	return result;
+}
+
+Datum plvlex_tokens(PG_FUNCTION_ARGS)
+{
+	FuncCallContext	   *funcctx;
+	TupleDesc			tupdesc;
+	TupleTableSlot	   *slot;
+	AttInMetadata	   *attinmeta;
+	tokensFctx		   *fctx;
+
+
+	if (SRF_IS_FIRSTCALL ())
+	{
+		MemoryContext  oldcontext;
+		List *lexems;
+		text *src = PG_GETARG_TEXT_P(0);
+		bool skip_spaces = PG_GETARG_BOOL(1);
+		bool qnames = PG_GETARG_BOOL(2);
+
+		orafce_sql_scanner_init(CSTRING(src));
+		if (orafce_sql_yyparse(&lexems) != 0)
+			orafce_sql_yyerror("bogus input");
+
+		orafce_sql_scanner_finish();
+
+		funcctx = SRF_FIRSTCALL_INIT ();
+		oldcontext = MemoryContextSwitchTo (funcctx->multi_call_memory_ctx);
+
+		fctx = (tokensFctx*) palloc (sizeof (tokensFctx));
+		funcctx->user_fctx = (void *)fctx;
+
+		fctx->nodes = filterList(lexems, skip_spaces, qnames);
+		fctx->nnodes = list_length(fctx->nodes);
+		fctx->cnode = 0;
+
+		fctx->values = (char **) palloc (6 * sizeof (char *));
+		fctx->values  [0] = (char*) palloc (16 * sizeof (char));
+		fctx->values  [1] = (char*) palloc (1024 * sizeof (char));
+		fctx->values  [2] = (char*) palloc (16 * sizeof (char));
+		fctx->values  [3] = (char*) palloc (16 * sizeof (char));
+		fctx->values  [4] = (char*) palloc (255 * sizeof (char));
+		fctx->values  [5] = (char*) palloc (255 * sizeof (char));
+
+		tupdesc = CreateTemplateTupleDesc (6 , false);
+
+		TupleDescInitEntry (tupdesc,  1, "start_pos", INT4OID, -1, 0);
+		TupleDescInitEntry (tupdesc,  2, "token",     TEXTOID, -1, 0);
+		TupleDescInitEntry (tupdesc,  3, "keycode",   INT4OID, -1, 0);
+		TupleDescInitEntry (tupdesc,  4, "class",     TEXTOID, -1, 0);
+		TupleDescInitEntry (tupdesc,  5, "separator", TEXTOID, -1, 0);
+		TupleDescInitEntry (tupdesc,  6, "mod",       TEXTOID, -1, 0);
+
+		slot = TupleDescGetSlot (tupdesc);
+		funcctx -> slot = slot;
+
+		attinmeta = TupleDescGetAttInMetadata (tupdesc);
+		funcctx -> attinmeta = attinmeta;
+
+		MemoryContextSwitchTo (oldcontext);
+	}
+
+
+	funcctx = SRF_PERCALL_SETUP ();
+	fctx = (tokensFctx*) funcctx->user_fctx;
+
+	while (fctx->cnode < fctx->nnodes)
+	{
+		char **values;
+		Datum result;
+		HeapTuple tuple;
+		char *back_vals[6];
+
+		orafce_lexnode *nd = (orafce_lexnode*) list_nth(fctx->nodes, fctx->cnode++);
+		values = fctx->values;
+
+		back_vals[2] = values[2];
+		back_vals[4] = values[4];
+		back_vals[5] = values[5];
+
+		snprintf(values[0],    16, "%d", nd->lloc);
+		snprintf(values[1], 10000, "%s", SF(nd->str));
+		snprintf(values[2],    16, "%d", nd->keycode);
+		snprintf(values[3],    16, "%s", nd->classname);
+		snprintf(values[4],   255, "%s", SF(nd->sep));
+		snprintf(values[5],    48, "%s", SF(nd->modificator));
+
+		if (nd->keycode == -1)
+			values[2] = NULL;
+
+		if (!nd->sep)
+			values[4] = NULL;
+
+		if (!nd->modificator)
+			values[5] = NULL;
+
+		tuple = BuildTupleFromCStrings (funcctx -> attinmeta,
+							fctx -> values);
+		result = TupleGetDatum (funcctx -> slot, tuple);
+
+		values[2] = back_vals[2];
+		values[4] = back_vals[4];
+		values[5] = back_vals[5];
+
+		SRF_RETURN_NEXT (funcctx, result);
+	}
+
+	SRF_RETURN_DONE (funcctx);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/e74af545/contrib/orafce/plvlex.h
----------------------------------------------------------------------
diff --git a/contrib/orafce/plvlex.h b/contrib/orafce/plvlex.h
new file mode 100644
index 0000000..5ada34d
--- /dev/null
+++ b/contrib/orafce/plvlex.h
@@ -0,0 +1,10 @@
+typedef struct 
+{
+	int		typenode;
+	char   *str;
+	int		keycode;
+	int		lloc;
+	char   *sep;
+	char   *modificator;
+	char   *classname;
+} orafce_lexnode;


Mime
View raw message