lelit / pglast

PostgreSQL Languages AST and statements prettifier: master branch covers PG10, v2 branch covers PG12, v3 covers PG13, v4 covers PG14, v5 covers PG15, v6 covers PG16
347 stars 41 forks source link

Unknown variable errors with plpgsql composite types #156

Open pauldzy opened 2 weeks ago

pauldzy commented 2 weeks ago

Hi Lele, great project,

When parsing a plpgsql function with a composite type, the parse fails with an unknown variable error.

Example:

  CREATE TYPE public.dz_sumthing
  AS(sumattribute INTEGER);

  CREATE FUNCTION public.dz_sumfunc(
      IN  p_in  INTEGER
     ,OUT p_out public.dz_sumthing
  )
  AS $BODY$ 
  DECLARE
  BEGIN
     p_out.sumattribute := p_in;
  END;
  $BODY$
  LANGUAGE plpgsql;

  SELECT * FROM public.dz_sumfunc(123);

In this case I'd like to parse the function code:

from pglast import parse_plpgsql

str_sql = """
    CREATE FUNCTION public.dz_sumfunc(
        IN  p_in  INTEGER
       ,OUT p_out public.dz_sumthing
    )
    AS $BODY$ 
    DECLARE
    BEGIN
       p_out.sumattribute := p_in;
    END;
    $BODY$
    LANGUAGE plpgsql;
""";

root = parse_plpgsql(str_sql);

This returns

ParseError: "p_out.sumattribute" is not a known variable

I assume the code does not currently support cross-referencing the attributes of the type when variables are checked? Is there a way to avoid the check and just accept that p_out.sumattribute is valid?

Thanks! Paul

lelit commented 2 weeks ago

Hi, I cannot check since I'm away for a brief vacation, but this could be related to #154, that is, a problem in the underlying libpg_query, possibly solved by a not-yet-merged PR.

lelit commented 1 week ago

Hi! Re-reading your report I see that it is clearly unrelated to #154, and indeed the following C program

#include <pg_query.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
  PgQueryPlpgsqlParseResult result;

  result = pg_query_parse_plpgsql(" \
    CREATE FUNCTION public.dz_sumfunc(\
        IN  p_in  INTEGER\
       ,OUT p_out public.dz_sumthing\
    )\
    AS $BODY$\
    DECLARE\
    BEGIN\
       p_out.sumattribute := p_in;\
    END;\
    $BODY$\
    LANGUAGE plpgsql;");

  if (result.error) {
    printf("error: %s at %d\n", result.error->message, result.error->cursorpos);
  } else {
    printf("%s\n", result.plpgsql_funcs);
  }

  pg_query_free_plpgsql_parse_result(result);

  // Optional, this ensures all memory is freed upon program exit (useful when running Valgrind)
  pg_query_exit();

  return 0;
}

fails even with svenklemm's branch.

So I'm afraid there's little I can do on the pglast side. Maybe you could post the question on the libpg_query issues?

pauldzy commented 1 week ago

Thanks for your help, I passed the problem over to libpg_query as https://github.com/pganalyze/libpg_query/issues/260 Looking at the history of such issues its might be useful to tag these errors more clearly as coming from libpg_query. Cheers!