Bison crashes postgresql

Lists: pgsql-hackers
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
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: Andrew Dunstan <andrew(at)dunslane(dot)net>
To: Werner Echezuria <wercool(at)gmail(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Bison crashes postgresql
Date: 2009-08-31 14:00:50
Message-ID: 4A9BD792.1080007@dunslane.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Werner Echezuria wrote:
> 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.
>

I don't understand why you're doing what you're doing this way. Wouldn't
it be better to patch the main postgres parser and make your
functionality first class rather than having it run via an SQL string
and a function that calls a secondary parser?

cheers

andrew


From: Hans-Juergen Schoenig -- PostgreSQL <postgres(at)cybertec(dot)at>
To: Andrew Dunstan <andrew(at)dunslane(dot)net>
Cc: Werner Echezuria <wercool(at)gmail(dot)com>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Bison crashes postgresql
Date: 2009-08-31 14:07:40
Message-ID: 4A9BD92C.7020706@cybertec.at
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Andrew Dunstan wrote:
>
>
> Werner Echezuria wrote:
>> 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.
>>
>
> I don't understand why you're doing what you're doing this way.
> Wouldn't it be better to patch the main postgres parser and make your
> functionality first class rather than having it run via an SQL string
> and a function that calls a secondary parser?
>
> cheers
>
> andrew
>

yes, this is the thing i had in mind as well.
what is your ultimate goal?

many thanks,

hans

--
Cybertec Schoenig & Schoenig GmbH
Reyergasse 9 / 2
A-2700 Wiener Neustadt
Web: www.postgresql-support.de


From: Werner Echezuria <wercool(at)gmail(dot)com>
To: Hans-Juergen Schoenig -- PostgreSQL <postgres(at)cybertec(dot)at>
Cc: Andrew Dunstan <andrew(at)dunslane(dot)net>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Bison crashes postgresql
Date: 2009-09-01 12:39:57
Message-ID: 2485a25e0909010539l74287cf1r186f06a02fa6387f@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

The thing is I was in a project to develop a Fuzzy Database Management
System. We have to bring fuzzy logic to postgresql, there was a team
developing a software in java and the other developing in the
postgresql core. But I always think these were wrong, so I'm trying to
develop a library to do that, but I guess I'm moving forward, the bug
was solved and I have a google code project:
http://code.google.com/p/fuzzyquery/. Now I hope to give more features
and have a fully functional library.

2009/9/1 Hans-Juergen Schoenig -- PostgreSQL <postgres(at)cybertec(dot)at>:
> Andrew Dunstan wrote:
>>
>>
>> Werner Echezuria wrote:
>>>
>>> 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.
>>>
>>
>> I don't understand why you're doing what you're doing this way. Wouldn't
>> it be better to patch the main postgres parser and make your functionality
>> first class rather than having it run via an SQL string and a function that
>> calls a secondary parser?
>>
>> cheers
>>
>> andrew
>>
>
> yes, this is the thing i had in mind as well.
> what is your ultimate goal?
>
>   many thanks,
>
>      hans
>
>
> --
> Cybertec Schoenig & Schoenig GmbH
> Reyergasse 9 / 2
> A-2700 Wiener Neustadt
> Web: www.postgresql-support.de
>
>