Skip to content

Commit 53629d2

Browse files
committed
Merge branch 'DBTOOLS-1601-add-records-processing' into 'master'
DBTOOLS-1601 added records processing See merge request codekeeper/pgcodekeeper-core!76
2 parents 1e2b53e + 479e366 commit 53629d2

7 files changed

Lines changed: 143 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Added analysis of functions returning the RECORD type.
13+
1214
### Changed
1315

1416
### Fixed

CHANGELOG.ru.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
### Добавлено
1111

12+
- Добавлен анализ функций, возвращающих тип RECORD.
13+
1214
### Изменено
1315

1416
### Исправлено

src/main/antlr4/org/pgcodekeeper/core/parsers/antlr/pg/generated/SQLParser.g4

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,8 +3853,12 @@ from_primary
38533853
(AS from_function_column_def
38543854
| AS? alias=identifier (LEFT_PAREN column_alias+=identifier (COMMA column_alias+=identifier)* RIGHT_PAREN | from_function_column_def)?
38553855
)?
3856-
| LATERAL? ROWS FROM LEFT_PAREN function_call (AS from_function_column_def)? (COMMA function_call (AS from_function_column_def)?)* RIGHT_PAREN
3857-
(WITH ORDINALITY)? (AS? identifier (LEFT_PAREN identifier (COMMA identifier)* RIGHT_PAREN)?)?
3856+
| from_rows_with_alias
3857+
;
3858+
3859+
from_rows_with_alias
3860+
: LATERAL? ROWS FROM LEFT_PAREN function_call (AS from_function_column_def)? (COMMA function_call (AS from_function_column_def)?)* RIGHT_PAREN
3861+
(WITH ORDINALITY)? (AS? alias=identifier (LEFT_PAREN column_alias+=identifier (COMMA column_alias+=identifier)* RIGHT_PAREN)?)?
38583862
;
38593863

38603864
alias_clause

src/main/java/org/pgcodekeeper/core/parsers/antlr/pg/expr/Select.java

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -530,13 +530,11 @@ private void from(From_itemContext fromItem) {
530530
}
531531
} else if ((primary = fromItem.from_primary()) != null) {
532532
Alias_clauseContext alias = primary.alias_clause();
533-
List<Function_callContext> functions = primary.function_call();
534533
Schema_qualified_nameContext table;
535534
Table_subqueryContext subquery;
536535

537-
if (!functions.isEmpty()) {
538-
functions.forEach(e -> function(e, primary.alias));
539-
} else if ((table = primary.schema_qualified_name()) != null) {
536+
fromFunctionCommon(primary);
537+
if ((table = primary.schema_qualified_name()) != null) {
540538
addNameReference(table, alias);
541539
if (primary.TABLESAMPLE() != null) {
542540
ValueExpr vex = new ValueExpr(this);
@@ -571,20 +569,62 @@ private void from(From_itemContext fromItem) {
571569
}
572570
}
573571

574-
private void function(Function_callContext function, IdentifierContext alias) {
572+
private void fromFunctionCommon(From_primaryContext from) {
575573
boolean oldLateral = lateralAllowed;
576574
try {
577-
lateralAllowed = true;
575+
if (from.function_call() != null) {
576+
function(from.function_call(), from.alias, from.from_function_column_def());
577+
} else if (from.from_rows_with_alias() != null) {
578+
fromRowsFunction(from.from_rows_with_alias());
579+
}
580+
} finally {
581+
lateralAllowed = oldLateral;
582+
}
583+
}
584+
585+
private void fromRowsFunction(From_rows_with_aliasContext fromRows) {
586+
for (var function : fromRows.function_call()) {
578587
ValueExpr vexFunc = new ValueExpr(this);
579588
Pair<String, String> func = vexFunc.function(function);
580589
if (func.getFirst() != null) {
581-
String funcAlias = alias == null ? func.getFirst() : alias.getText();
582-
addReference(funcAlias, null);
583-
complexNamespace.put(funcAlias,
584-
List.of(new Pair<>(funcAlias, func.getSecond())));
590+
String funcName = func.getFirst();
591+
addReference(funcName, null);
585592
}
586-
} finally {
587-
lateralAllowed = oldLateral;
593+
}
594+
595+
List<Pair<String, String>> colPairs = new ArrayList<>();
596+
fromRows.column_alias
597+
.forEach(identifier -> colPairs.add(new ModPair<>(identifier.getText(), TypesSetManually.COLUMN)));
598+
599+
if (!fromRows.from_function_column_def().isEmpty()) {
600+
// safe to take any since they all must have the same types
601+
var cols = fromRows.from_function_column_def(0);
602+
for (int i = 0; i < cols.column_alias.size() && i < colPairs.size(); i++) {
603+
colPairs.set(i, new Pair<>(colPairs.get(i).getFirst(), cols.data_type().get(i).getText()));
604+
}
605+
}
606+
607+
var alias = fromRows.alias.getText();
608+
addReference(alias, null);
609+
complexNamespace.put(alias, colPairs);
610+
}
611+
612+
private void function(Function_callContext function, IdentifierContext alias,
613+
From_function_column_defContext definition) {
614+
ValueExpr vexFunc = new ValueExpr(this);
615+
Pair<String, String> func = vexFunc.function(function);
616+
if (func.getFirst() != null) {
617+
String funcAlias = alias == null ? func.getFirst() : alias.getText();
618+
addReference(funcAlias, null);
619+
List<Pair<String, String>> colPairs = new ArrayList<>();
620+
if (definition != null) {
621+
for (int i = 0; i < definition.column_alias.size(); i++) {
622+
colPairs.add(new Pair<>(definition.column_alias.get(i).getText(), definition.data_type().get(i).getText()));
623+
}
624+
} else {
625+
colPairs.add(new Pair<>(funcAlias, func.getSecond()));
626+
}
627+
complexNamespace.put(funcAlias, colPairs);
588628
}
589629
}
590630
}

src/main/java/org/pgcodekeeper/core/parsers/antlr/pg/rulectx/Vex.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626

2727
/**
2828
* Merging wrapper for vex/vex_b.
29-
* Provides a unified interface for working with PostgreSQL value expressions
30-
* that can be either regular expressions (vex) or boolean expressions (vex_b).
29+
* Provides a unified interface for working with PostgreSQL value expressions.
3130
*
3231
* @author levsha_aa
3332
*/

src/test/resources/org/pgcodekeeper/core/it/parser/pg/check_types_cols_view_extended_diff.sql

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,35 @@ Schema: public
8989
c2 - public.test_composite1
9090
c3 - public.test_composite
9191
c4 - public.complex
92-
c5 - double precision
92+
c5 - double precision
93+
94+
View: test_record_view1
95+
RelationColumns :
96+
id - INT
97+
desc - TEXT
98+
data - NUMERIC
99+
id_test - INT
100+
description - TEXT
101+
value - NUMERIC
102+
103+
View: test_record_view2
104+
RelationColumns :
105+
id_test - INT
106+
description_test - TEXT
107+
value_test - NUMERIC
108+
id - INT
109+
110+
View: test_record_view3
111+
RelationColumns :
112+
id - INT
113+
new_id - INT
114+
new_description - TEXT
115+
new_value - NUMERIC
116+
117+
View: test_record_view4
118+
RelationColumns :
119+
id - INT
120+
descr - TEXT
121+
new_id - INT
122+
new_description - TEXT
123+
new_value - NUMERIC

src/test/resources/org/pgcodekeeper/core/it/parser/pg/check_types_cols_view_extended_new.sql

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,30 @@ CREATE FUNCTION tester.f2(p double precision) RETURNS real
5151
CREATE FUNCTION tester.f2(p text) RETURNS integer
5252
LANGUAGE plpgsql
5353
AS $$begin return 'text'; end;$$;
54+
55+
CREATE FUNCTION public.get_simple_record() RETURNS RECORD
56+
LANGUAGE plpgsql
57+
AS $$
58+
declare
59+
result RECORD;
60+
begin
61+
result.id := 1;
62+
result.name := 'Test User';
63+
result.score := 100.5;
64+
return result;
65+
end;$$;
66+
67+
CREATE FUNCTION public.get_another_record() RETURNS RECORD
68+
LANGUAGE plpgsql
69+
AS $$
70+
declare
71+
rec RECORD;
72+
begin
73+
result.intt := 25;
74+
result.str := 'str';
75+
result.numm := 100.5;
76+
return rec;
77+
end;$$;
5478

5579
CREATE TABLE public.mytable (
5680
col1 integer,
@@ -241,4 +265,27 @@ CREATE VIEW public.testview AS
241265
(item).test.t as c3,
242266
(item).test.t.r as c4,
243267
(item).test.t.r.r AS c5
244-
FROM public.on_hand;
268+
FROM public.on_hand;
269+
270+
CREATE VIEW public.test_record_view1 AS
271+
SELECT simple_data.id_test as id,
272+
simple_data.description as desc,
273+
simple_data.value as data,
274+
*
275+
FROM public.get_simple_record() AS simple_data(id_test INT, description TEXT, value NUMERIC);
276+
277+
CREATE VIEW public.test_record_view2 AS
278+
SELECT *, get_simple_record.id_test as id
279+
FROM public.get_simple_record() AS (id_test INT, description_test TEXT, value_test NUMERIC);
280+
281+
CREATE VIEW public.test_record_view3 AS
282+
SELECT t.new_id as id, * FROM ROWS FROM (
283+
public.get_simple_record() AS (id_test INT, description_test TEXT, value_test NUMERIC),
284+
public.get_another_record() AS (id INT, description TEXT, value NUMERIC)
285+
) AS t(new_id, new_description, new_value);
286+
287+
CREATE VIEW public.test_record_view4 AS
288+
SELECT t.new_id as id, t.new_description as descr, t.* FROM ROWS FROM (
289+
public.get_simple_record() AS (id_test INT, description_test TEXT, value_test NUMERIC),
290+
public.get_another_record() AS (id INT, description TEXT, value NUMERIC)
291+
) AS t(new_id, new_description, new_value);

0 commit comments

Comments
 (0)