Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse CREATE FUNCTION into runnable functions #1174

Merged
merged 4 commits into from
Feb 7, 2025

Conversation

Hydrocharged
Copy link
Collaborator

This implements parsing of CREATE FUNCTION into the same expected set of operations as the handcoded examples. This means that we are able to write CREATE FUNCTION statements that are runnable, and the interpreter is able to properly execute said functions.

At the moment, the function provider used in GMS does not allow for adding new functions, so the test is skipped. I've confirmed it does work though if we hack around the provider limitation. It's also worth noting that we have to rely on the new pg_analyze package in order to handle PL/pgSQL. I attempted to add support within our parser, but the syntax conflicts with regular SQL syntax in ways that can't really be reconciled, so this was the only choice.

@Hydrocharged Hydrocharged requested a review from zachmu February 5, 2025 17:56
@fulghum
Copy link
Contributor

fulghum commented Feb 6, 2025

Conflicts are due to #1169, which my PR does not currently address.

I resolved the conflicts and skipped the new ALIAS test. I'm happy to take a look at the parsing and OpCode conversion for ALIAS next.

Copy link
Contributor

github-actions bot commented Feb 6, 2025

Main PR
covering_index_scan_postgres 362.62/s 363.40/s +0.2%
index_join_postgres 154.47/s 153.03/s -1.0%
index_join_scan_postgres 183.57/s 184.15/s +0.3%
index_scan_postgres 12.69/s 12.53/s -1.3%
oltp_point_select 2797.41/s 2796.67/s -0.1%
oltp_read_only 1870.69/s 1886.56/s +0.8%
select_random_points 111.85/s 114.55/s +2.4%
select_random_ranges 128.02/s 129.80/s +1.3%
table_scan_postgres 11.93/s 11.88/s -0.5%
types_table_scan_postgres 5.57/s 5.55/s -0.4%

Copy link
Contributor

github-actions bot commented Feb 6, 2025

Main PR
Total 42090 42090
Successful 15537 15557
Failures 26553 26533
Partial Successes1 5226 5216
Main PR
Successful 36.9138% 36.9613%
Failures 63.0862% 63.0387%

${\color{red}Regressions (5)}$

indexing

QUERY:          select indexrelid::regclass, indrelid::regclass
  from pg_index where indexrelid::regclass::text like 'idxpart%';
RECEIVED ERROR: DoltgresHandler caught panic: function 'echo_me' is already registered (errno 1105) (sqlstate HY000)

regproc

QUERY:          SELECT to_regclass('pg_catalog.pg_class');
RECEIVED ERROR: DoltgresHandler caught panic: function 'echo_me' is already registered (errno 1105) (sqlstate HY000)

sequence

QUERY:          SELECT nextval('sequence_test'::regclass);
RECEIVED ERROR: DoltgresHandler caught panic: function 'echo_me' is already registered (errno 1105) (sqlstate HY000)
QUERY:          SELECT nextval('sequence_test'::regclass);
RECEIVED ERROR: DoltgresHandler caught panic: function 'echo_me' is already registered (errno 1105) (sqlstate HY000)
QUERY:          SELECT nextval('sequence_test'::regclass);
RECEIVED ERROR: DoltgresHandler caught panic: function 'echo_me' is already registered (errno 1105) (sqlstate HY000)

${\color{lightgreen}Progressions (26)}$

case

QUERY: CREATE FUNCTION vol(text) returns text as
  'begin return $1; end' language plpgsql volatile;
QUERY: CREATE FUNCTION volfoo(text) returns foodomain as
  'begin return $1::foodomain; end' language plpgsql volatile;
QUERY: CREATE FUNCTION ad_eq(arrdomain, arrdomain) returns boolean as
  'begin return array_eq($1, $2); end' language plpgsql;

collate.icu.utf8

QUERY: CREATE FUNCTION mylt_plpgsql (text, text) RETURNS boolean LANGUAGE plpgsql
    AS $$ begin return $1 < $2; end $$;
QUERY: CREATE FUNCTION mylt2 (x text, y text) RETURNS boolean LANGUAGE plpgsql AS $$
declare
  xx text := x;
  yy text := y;
begin
  return xx < yy;
end
$$;
QUERY: CREATE OR REPLACE FUNCTION
  mylt2 (x text, y text) RETURNS boolean LANGUAGE plpgsql AS $$
declare
  xx text COLLATE "POSIX" := x;
  yy text := y;
begin
  return xx < yy;
end
$$;

dependency

QUERY: CREATE FUNCTION deptest_func() RETURNS void LANGUAGE plpgsql
  AS $$ BEGIN END; $$;

domain

QUERY: create function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int;
begin
    return p1;
end$$ language plpgsql;
QUERY: create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int := 0;
begin
    return p1;
end$$ language plpgsql;
QUERY: create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int := 1;
begin
    v := p1 - 1;
    return v - 1;
end$$ language plpgsql;

enum

QUERY: CREATE FUNCTION echo_me(anyenum) RETURNS text AS $$
BEGIN
RETURN $1::text || 'omg';
END
$$ LANGUAGE plpgsql;
QUERY: CREATE FUNCTION echo_me(rainbow) RETURNS text AS $$
BEGIN
RETURN $1::text || 'wtf';
END
$$ LANGUAGE plpgsql;

expressions

QUERY: create function return_text_input(text) returns text as $$
begin
	return $1;
end;
$$ language plpgsql stable;
QUERY: create function myinteq(myint, myint) returns bool as $$
begin
  if $1 is null and $2 is null then
    return true;
  else
    return $1::int = $2::int;
  end if;
end;
$$ language plpgsql immutable;
QUERY: create function myintne(myint, myint) returns bool as $$
begin
  return not myinteq($1, $2);
end;
$$ language plpgsql immutable;

plpgsql

QUERY: create function f1(x anyelement) returns anyelement as $$
begin
  return x + 1;
end$$ language plpgsql;
QUERY: create or replace function shadowtest()
	returns void as $$
declare
f1 int;
c1 cursor (f1 int) for select 1;
begin
end$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
declare
  v compostype;
begin
  v := (1, 'hello');
  return v;
end;
$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
declare
  v record;
begin
  v := (1, 'hello'::varchar);
  return v;
end;
$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
begin
  return (1, 'hello'::varchar);
end;
$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
begin
  return (1, 'hello');
end;
$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
begin
  return (1, 'hello')::compostype;
end;
$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
begin
  return 1 + 1;
end;
$$ language plpgsql;
QUERY: create or replace function compos() returns compostype as $$
declare x int := 42;
begin
  return x;
end;
$$ language plpgsql;
QUERY: create function error2(p_name_table text) returns text language plpgsql as $$
begin
  return error1(p_name_table);
end$$;

updatable_views

QUERY: CREATE OR REPLACE FUNCTION leakproof(anyelement)
RETURNS boolean AS
$$
BEGIN
  RETURN true;
END;
$$
LANGUAGE plpgsql STRICT IMMUTABLE LEAKPROOF;

Footnotes

  1. These are tests that we're marking as Successful, however they do not match the expected output in some way. This is due to small differences, such as different wording on the error messages, or the column names being incorrect while the data itself is correct.

Copy link
Contributor

@fulghum fulghum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read through this one to ramp up on the create function changes and left a couple minor comments. Overall, seems like a good base to keep building on.

server/plpgsql/interpreter_logic.go Show resolved Hide resolved
server/plpgsql/interpreter_logic.go Outdated Show resolved Hide resolved
server/plpgsql/statements.go Show resolved Hide resolved
server/plpgsql/statements.go Show resolved Hide resolved
Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No major feedback on top of what Jason already said, but worth asking if there's a true parser out there that might be better supported. Surely somebody has a yacc grammar for parsing this language somewhere.

server/plpgsql/interpreter_logic.go Outdated Show resolved Hide resolved
server/plpgsql/parse.go Show resolved Hide resolved
@Hydrocharged Hydrocharged merged commit b8fd58f into main Feb 7, 2025
14 checks passed
@Hydrocharged Hydrocharged deleted the daylon/create-function-conversion branch February 7, 2025 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants