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  (Andrew Dunstan <andrew@dunslane.net>)
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:

Previous
From: Greg Sabino Mullane
Date:
Subject: Re: Add YAML option to explain
Next
From: Tom Lane
Date:
Subject: Re: combined indexes with Gist - planner issues?