| /* |
| 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); |
| } |
| |