blob: e703cbda455daa370c797c5816f8e3bf6560882b [file] [log] [blame]
/*
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 "nodes/pg_list.h"
#include "funcapi.h"
#include "catalog/pg_type.h"
#include "orafunc.h"
#include "builtins.h"
#define YYPARSE_PARAM
#include "sqlparse.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);
}