From: | Werner Echezuria <wercool(at)gmail(dot)com> |
---|---|
To: | pgsql-hackers(at)postgresql(dot)org |
Subject: | Bison crashes postgresql |
Date: | 2009-08-31 13:43:51 |
Message-ID: | 2485a25e0908310643x4307c112u442292d747290df0@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | 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-valued function 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_connect returned %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 row type");
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 BY ASC 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 DOTDOT Param AS
LEFTP INFINIT COMMA INFINIT COMMA Param COMMA Param RIGHTP
{
create_fuzzy_pred($4,$6,$8,"INFINIT","INFINIT",$15,$17);
}
|
CREATE FUZZY PREDICATE Param ON Param 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_name AS ( 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 WHERE List_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;
}
|
SelectStmt ORDER 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;
}
|
SelectStmt WITH 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 length of
"%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_where RIGHTP 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"
From | Date | Subject | |
---|---|---|---|
Next Message | Tom Lane | 2009-08-31 13:54:01 | Re: combined indexes with Gist - planner issues? |
Previous Message | Greg Sabino Mullane | 2009-08-31 13:43:13 | Re: Add YAML option to explain |