Bison crashes postgresql

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"

Responses

Browse pgsql-hackers by date

  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