Thread: Bison crashes postgresql

Bison crashes postgresql

From
Werner Echezuria
Date:
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"


Re: Bison crashes postgresql

From
Andrew Dunstan
Date:

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




Re: Bison crashes postgresql

From
Hans-Juergen Schoenig -- PostgreSQL
Date:
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



Re: Bison crashes postgresql

From
Werner Echezuria
Date:
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@cybertec.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
>
>