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"

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to