Bison crashes postgresql - Mailing list pgsql-hackers
From | Werner Echezuria |
---|---|
Subject | Bison crashes postgresql |
Date | |
Msg-id | 2485a25e0908310643x4307c112u442292d747290df0@mail.gmail.com Whole thread Raw |
Responses |
Re: Bison crashes postgresql
|
List | pgsql-hackers |
Hi, I have a code in which I translate some code from sqlf to sql, but when it comes to yy_parse the server crashes, I have no idea why, because it works fine in other situations. This is the code (the problem is in parse_sqlf, when I call sqlf_yyparse): #include "postgres.h" #include "gram.h" #include "utils/builtins.h" #include "funcapi.h" #include "executor/spi.h" #include "access/heapam.h" #include "fmgr.h" #include "miscadmin.h" extern Datum sqlf(PG_FUNCTION_ARGS); char *parse_sqlf(); PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(sqlf); Datum sqlf(PG_FUNCTION_ARGS) { char *query = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *sql; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; Tuplestorestate *tupstore; TupleDesc tupdesc; int call_cntr; int max_calls; AttInMetadata *attinmeta; SPITupleTable *spi_tuptable; TupleDesc spi_tupdesc; bool firstpass; char *lastrowid; int i; int num_categories; MemoryContext per_query_ctx; MemoryContext oldcontext; int ret; int proc; sql=(char *)palloc(strlen(query)*sizeof(char *)); sql=parse_sqlf(query); /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valuedfunction called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; /* Connect to SPI manager */ if ((ret = SPI_connect()) < 0) /* internal error */ elog(ERROR, "SPI_connectreturned %d", ret); /* Retrieve the desired rows */ ret = SPI_execute(sql, true, 0); proc = SPI_processed; /* If no qualifying tuples, fall out early */ if (ret != SPI_OK_SELECT || proc <= 0) { SPI_finish(); rsinfo->isDone = ExprEndResult; PG_RETURN_NULL(); } spi_tuptable = SPI_tuptable; spi_tupdesc = spi_tuptable->tupdesc; /* get a tuple descriptor for our result type */ switch (get_call_result_type(fcinfo, NULL, &tupdesc)) { case TYPEFUNC_COMPOSITE: /* success */ break; case TYPEFUNC_RECORD: /* failed to determine actual type of RECORD */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); break; default: /* result type isn't composite */ elog(ERROR, "return type must be a rowtype"); break; } /* * switch to long-lived memory context */ oldcontext = MemoryContextSwitchTo(per_query_ctx); /* make sure we have a persistent copy of the result tupdesc */ tupdesc = CreateTupleDescCopy(tupdesc); /* initialize our tuplestore in long-lived context */ tupstore = tuplestore_begin_heap(rsinfo->allowedModes& SFRM_Materialize_Random, false, work_mem); MemoryContextSwitchTo(oldcontext); /* * Generate attribute metadata needed later to produce tuples from raw C * strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); /* total number of tuples to be examined */ max_calls = proc; /* the return tuple always must have 1 rowid + num_categories columns */ num_categories = tupdesc->natts; firstpass = true; lastrowid = NULL; for (call_cntr = 0; call_cntr < max_calls; call_cntr++) { char **values; HeapTuple spi_tuple; HeapTuple tuple; /* allocate and zero space */ values = (char **) palloc0((1 + num_categories) * sizeof(char *)); /* get the next sql result tuple */ spi_tuple = spi_tuptable->vals[call_cntr]; /* * now loop through the sql results and assign each value in sequence * to the next category */ for (i = 0; i < num_categories; i++) { /* see if we've gone too far already */ if (call_cntr >= max_calls) break; values[i] = SPI_getvalue(spi_tuple, spi_tupdesc, i+1); } /* build the tuple */ tuple = BuildTupleFromCStrings(attinmeta, values); /* switch to appropriate context while storing the tuple */ oldcontext = MemoryContextSwitchTo(per_query_ctx); tuplestore_puttuple(tupstore, tuple); MemoryContextSwitchTo(oldcontext); heap_freetuple(tuple); /* Clean up */ for (i = 0; i < num_categories + 1; i++) if (values[i] != NULL) pfree(values[i]); pfree(values); } /* let the caller know we're sending back a tuplestore */ rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult= tupstore; rsinfo->setDesc = tupdesc; /* release SPI related resources (and return to caller's context) */ SPI_finish(); pfree(sql); return (Datum) 0; } char *parse_sqlf(const char *query){ void *result; yy_scan_string(query); sqlf_yyparse(&result); return (char *)result; } Bison code: %{ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "postgres.h" #include "parsing.h" #define YYDEBUG 1 #define QUERY_LENGTH 4 #define YYPARSE_PARAM result /* need this to pass a pointer (void *) to yyparse */ int sqlf_yyparse(void *result); int real_length; char *field; char *fuzzy_query[QUERY_LENGTH]; %} %name-prefix="sqlf_yy" %union { int integer; char *text; } %token CREATE FUZZY PREDICATE ON AS COMMA DOTDOT LEFTP RIGHTP INFINIT DROP EQUAL SELECT WHERE FROM AND OR ORDER BYASC DESC WITH CALIBRATION %token <text> PARAMETER %type <text> Param Param_select Param_from List_where List_order SelectStmt %% query: /* empty string */ | query command ; command: '\n' | CreateFuzzyPredStmt | DropFuzzyPredStmt | SelectStmt { int i; *((void **)result) = fuzzy_query[real_length-1]; for (i=0;i<real_length;i++) pfree(fuzzy_query[i]); } | error '\n' { yyerrok;} ; CreateFuzzyPredStmt: CREATE FUZZY PREDICATE Param ON Param DOTDOT Param AS LEFTP Param COMMA Param COMMA Param COMMA Param RIGHTP { create_fuzzy_pred($4,$6,$8,$11,$13,$15,$17); } | CREATE FUZZY PREDICATE Param ON Param DOTDOTParam AS LEFTP INFINIT COMMA INFINIT COMMA Param COMMA Param RIGHTP { create_fuzzy_pred($4,$6,$8,"INFINIT","INFINIT",$15,$17); } | CREATE FUZZY PREDICATE Param ONParam DOTDOT Param AS LEFTP Param COMMA Param COMMA INFINIT COMMA INFINIT RIGHTP { create_fuzzy_pred($4,$6,$8,$11,$13,"INFINIT","INFINIT"); } ; DropFuzzyPredStmt: DROP FUZZY PREDICATE Param { drop_fuzzy_pred($4); } ; /**************SELECT STATEMENT**********************************/ /* [ WITH [ RECURSIVE ] with_query [, ...] ] SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] * | expression [ [ AS ] output_name ] [, ...] [ FROM from_item[, ...] ] [ WHERE condition ] [ GROUP BY expression [, ...] ] [ HAVING condition [, ...] ] [ WINDOW window_nameAS ( window_definition ) [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ] [ ORDER BY expression[ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] [ LIMIT { count | ALL } ] [ OFFSET start [ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [ count] { ROW | ROWS } ONLY ] [ FOR { UPDATE | SHARE } [ OF table_name [, ...] ] [ NOWAIT ] [...] ] where from_item can be one of: [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ] ( select ) [ AS ] alias [ ( column_alias [,...] ) ] with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ] function_name ( [ argument [, ...] ] ) [ AS] alias [ ( column_alias [, ...] | column_definition [, ...] ) ] function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...]) from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ] and with_query is: with_query_name [ ( column_name [, ...] ) ] AS ( select ) WITH CALIBRATION */ /* Missing pretty much everything, it parses the basic select */ SelectStmt: SELECT Param_select FROM Param_from { fuzzy_query[0]=(char *)palloc(sizeof(char)*(strlen($2)+strlen($4)+20)); snprintf(fuzzy_query[0],(strlen($2)+strlen($4)+20),"SELECT %s FROM %s",$2,$4); $$=fuzzy_query[0]; real_length=1; } | SelectStmt WHEREList_where { fuzzy_query[1]=(char *)palloc(sizeof(char)*(strlen($1)+strlen($3)+20)); snprintf(fuzzy_query[1],(strlen($1)+strlen($3)+20),"%s WHERE %s",$1,$3); $$=fuzzy_query[1]; real_length=2; } | SelectStmtORDER BY List_order { fuzzy_query[2]=(char *)palloc(sizeof(char)*(strlen($1)+strlen($4)+20)); snprintf(fuzzy_query[2],(strlen($1)+strlen($4)+20),"%s ORDER BY %s",$1,$4); $$=fuzzy_query[2]; real_length=3; } | SelectStmtWITH CALIBRATION Param { fuzzy_query[3]=(char *)palloc(sizeof(char)*(strlen($1)+strlen($4)+20)); snprintf(fuzzy_query[3],(strlen($1)+strlen($4)+20),"%s WITH CALIBRATION %s",$1,$4); $$=fuzzy_query[3]; real_length=4; } ; Param: PARAMETER { $$ = $1; }; Param_select: Param { $$ = $1; } | Param_select COMMA Param { strcat($$,", "); strcat($$,$3); } | Param_select AS Param { strcat($$," AS "); strcat($$,$3); } | Param_select Param { strcat($$," "); strcat($$,$2); } ; Param_from: Param { $$ = $1;} | Param_from COMMA Param { strcat($$,", "); strcat($$,$3); } | Param_from AS Param { strcat($$," AS "); strcat($$,$3); } | Param_from Param { strcat($$," "); strcat($$,$2); } ; List_where: Param { $$=$1; field=$1; } | LEFTP Param { strcat($$," ("); strcat($$,$2); field=$2; } | List_where EQUAL Param{ int len; char *str_result; len=strlen(field)+strlen($3)+15;//15 is the lengthof "%s > %f AND %s < %f" str_result=(char *)palloc(sizeof(char)*(len*2)); $$=translate_fuzzy_preds(str_result,field,$3); pfree(str_result); } | List_where AND Param{ strcat($$," AND "); strcat($$,$3); field=$3; } | List_whereRIGHTP AND Param { strcat($$,") AND "); strcat($$,$4); field=$4; } | List_where OR Param { strcat($$," OR "); strcat($$,$3); field=$3; } | List_where RIGHTP OR Param { strcat($$,") OR "); strcat($$,$4); field=$4; } ; List_order: Param { $$=$1; } | List_order COMMA Param { strcat($$,", "); strcat($$,$3); } | List_order ASC { strcat($$," ASC"); strcat($$,$1); } | List_order DESC { strcat($$," DESC"); strcat($$,$1); } ; %% void yyerror (char *s) {elog (ERROR, "%s\n", s);} #include "scan.c"
pgsql-hackers by date: