Skip to content

Commit c8fa698

Browse files
committed
sql: portable SHOW CREATE routine output
Previously, the `SHOW CREATE <FUNCTION | PROCEDURE>` statements would include the fully qualified table names. The database component of the table name made it unportable. This change uses the unqualified table name to make the output portable. Fixes: #125936 Epic: CRDB-39674 Release note (sql change): The `SHOW CREATE FUNCTION` and `SHOW CREATE PROCEDURE` statements produce the 2-part table names rather than qualifying with the current database.
1 parent 1ded868 commit c8fa698

File tree

12 files changed

+171
-27
lines changed

12 files changed

+171
-27
lines changed

pkg/backup/testdata/backup-restore/plpgsql_procedures

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
9999
DECLARE
100100
foobar sc1.enum1;
101101
BEGIN
102-
SELECT a FROM db1.sc1.tbl1;
102+
SELECT a FROM sc1.tbl1;
103103
SELECT 'Good':::sc1.enum1;
104104
SELECT nextval('sc1.sq1'::REGCLASS);
105105
END;
@@ -140,7 +140,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
140140
DECLARE
141141
foobar sc1.enum1;
142142
BEGIN
143-
SELECT a FROM db1_new.sc1.tbl1;
143+
SELECT a FROM sc1.tbl1;
144144
SELECT 'Good':::sc1.enum1;
145145
SELECT nextval('sc1.sq1'::REGCLASS);
146146
END;
@@ -307,7 +307,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
307307
DECLARE
308308
foobar sc1.enum1;
309309
BEGIN
310-
SELECT a FROM db1.sc1.tbl1;
310+
SELECT a FROM sc1.tbl1;
311311
SELECT 'Good':::sc1.enum1;
312312
SELECT nextval('sc1.sq1'::REGCLASS);
313313
END;
@@ -349,7 +349,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
349349
DECLARE
350350
foobar sc1.enum1;
351351
BEGIN
352-
SELECT a FROM db1.sc1.tbl1;
352+
SELECT a FROM sc1.tbl1;
353353
SELECT 'Good':::sc1.enum1;
354354
SELECT nextval('sc1.sq1'::REGCLASS);
355355
END;

pkg/backup/testdata/backup-restore/plpgsql_user_defined_functions

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
121121
x INT8 := 0;
122122
foobar sc1.enum1;
123123
BEGIN
124-
SELECT a FROM db1.sc1.tbl1;
124+
SELECT a FROM sc1.tbl1;
125125
SELECT 'Good':::sc1.enum1;
126126
RETURN nextval('sc1.sq1'::REGCLASS);
127127
END;
@@ -146,7 +146,7 @@ CREATE FUNCTION sc2.f2()
146146
DECLARE
147147
x INT8;
148148
BEGIN
149-
SELECT a FROM db1.sc2.tbl2 LIMIT 1 INTO x;
149+
SELECT a FROM sc2.tbl2 LIMIT 1 INTO x;
150150
SELECT sc1.f1('Good':::sc1.enum1);
151151
CALL public.p_nested('Good':::sc1.enum1);
152152
RETURN x;
@@ -184,7 +184,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
184184
x INT8 := 0;
185185
foobar sc1.enum1;
186186
BEGIN
187-
SELECT a FROM db1_new.sc1.tbl1;
187+
SELECT a FROM sc1.tbl1;
188188
SELECT 'Good':::sc1.enum1;
189189
RETURN nextval('sc1.sq1'::REGCLASS);
190190
END;
@@ -204,7 +204,7 @@ CREATE FUNCTION sc2.f2()
204204
DECLARE
205205
x INT8;
206206
BEGIN
207-
SELECT a FROM db1_new.sc2.tbl2 LIMIT 1 INTO x;
207+
SELECT a FROM sc2.tbl2 LIMIT 1 INTO x;
208208
SELECT sc1.f1('Good':::sc1.enum1);
209209
CALL public.p_nested('Good':::sc1.enum1);
210210
RETURN x;
@@ -376,7 +376,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
376376
x INT8;
377377
foobar sc1.enum1;
378378
BEGIN
379-
SELECT a FROM db1.sc1.tbl1;
379+
SELECT a FROM sc1.tbl1;
380380
SELECT 'Good':::sc1.enum1;
381381
SELECT nextval('sc1.sq1'::REGCLASS) INTO x;
382382
RETURN x;
@@ -420,7 +420,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
420420
x INT8;
421421
foobar sc1.enum1;
422422
BEGIN
423-
SELECT a FROM db1.sc1.tbl1;
423+
SELECT a FROM sc1.tbl1;
424424
SELECT 'Good':::sc1.enum1;
425425
SELECT nextval('sc1.sq1'::REGCLASS) INTO x;
426426
RETURN x;

pkg/backup/testdata/backup-restore/procedures

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
9090
LANGUAGE SQL
9191
SECURITY INVOKER
9292
AS $$
93-
SELECT a FROM db1.sc1.tbl1;
93+
SELECT a FROM sc1.tbl1;
9494
SELECT 'Good':::sc1.enum1;
9595
SELECT nextval('sc1.sq1'::REGCLASS);
9696
$$
@@ -127,7 +127,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
127127
LANGUAGE SQL
128128
SECURITY INVOKER
129129
AS $$
130-
SELECT a FROM db1_new.sc1.tbl1;
130+
SELECT a FROM sc1.tbl1;
131131
SELECT 'Good':::sc1.enum1;
132132
SELECT nextval('sc1.sq1'::REGCLASS);
133133
$$
@@ -284,7 +284,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
284284
LANGUAGE SQL
285285
SECURITY INVOKER
286286
AS $$
287-
SELECT a FROM db1.sc1.tbl1;
287+
SELECT a FROM sc1.tbl1;
288288
SELECT 'Good':::sc1.enum1;
289289
SELECT nextval('sc1.sq1'::REGCLASS);
290290
$$
@@ -322,7 +322,7 @@ CREATE PROCEDURE sc1.p1(a sc1.enum1)
322322
LANGUAGE SQL
323323
SECURITY INVOKER
324324
AS $$
325-
SELECT a FROM db1.sc1.tbl1;
325+
SELECT a FROM sc1.tbl1;
326326
SELECT 'Good':::sc1.enum1;
327327
SELECT nextval('sc1.sq1'::REGCLASS);
328328
$$

pkg/backup/testdata/backup-restore/user-defined-functions

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
9393
LANGUAGE SQL
9494
SECURITY INVOKER
9595
AS $$
96-
SELECT a FROM db1.sc1.tbl1;
96+
SELECT a FROM sc1.tbl1;
9797
SELECT 'Good':::sc1.enum1;
9898
SELECT nextval('sc1.sq1'::REGCLASS);
9999
$$
@@ -130,7 +130,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
130130
LANGUAGE SQL
131131
SECURITY INVOKER
132132
AS $$
133-
SELECT a FROM db1_new.sc1.tbl1;
133+
SELECT a FROM sc1.tbl1;
134134
SELECT 'Good':::sc1.enum1;
135135
SELECT nextval('sc1.sq1'::REGCLASS);
136136
$$
@@ -279,7 +279,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
279279
LANGUAGE SQL
280280
SECURITY INVOKER
281281
AS $$
282-
SELECT a FROM db1.sc1.tbl1;
282+
SELECT a FROM sc1.tbl1;
283283
SELECT 'Good':::sc1.enum1;
284284
SELECT nextval('sc1.sq1'::REGCLASS);
285285
$$
@@ -317,7 +317,7 @@ CREATE FUNCTION sc1.f1(a sc1.enum1)
317317
LANGUAGE SQL
318318
SECURITY INVOKER
319319
AS $$
320-
SELECT a FROM db1.sc1.tbl1;
320+
SELECT a FROM sc1.tbl1;
321321
SELECT 'Good':::sc1.enum1;
322322
SELECT nextval('sc1.sq1'::REGCLASS);
323323
$$

pkg/sql/crdb_internal.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,6 +3555,11 @@ func createRoutinePopulate(
35553555
if err != nil {
35563556
return err
35573557
}
3558+
bodyStr, err = formatUnqualifyTableNames(bodyStr, fnIDToDBName[fnDesc.GetID()], fnDesc.GetLanguage())
3559+
if err != nil {
3560+
return err
3561+
}
3562+
35583563
bodyStr = strings.TrimSpace(bodyStr)
35593564
stmtStrs := strings.Split(bodyStr, "\n")
35603565
for i := range stmtStrs {

pkg/sql/logictest/testdata/logic_test/show_create_all_routines

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,52 @@ CREATE FUNCTION s.add_one(x INT8)
162162
AS $$
163163
SELECT x + 1;
164164
$$;
165+
166+
subtest trigger_invalid_reference
167+
# ensure the lazily evaluated function bodies parse
168+
169+
statement ok
170+
CREATE FUNCTION select_invalid() RETURNS TRIGGER AS $$
171+
BEGIN
172+
SELECT 1 FROM a.b.c;
173+
END;
174+
$$ LANGUAGE PLpgSQL;
175+
176+
query T colnames,nosort
177+
SHOW CREATE ALL ROUTINES;
178+
----
179+
create_statement
180+
CREATE FUNCTION public.add_one(x INT8)
181+
RETURNS INT8
182+
VOLATILE
183+
NOT LEAKPROOF
184+
CALLED ON NULL INPUT
185+
LANGUAGE SQL
186+
SECURITY INVOKER
187+
AS $$
188+
SELECT x + 1;
189+
$$;
190+
CREATE FUNCTION public.select_invalid()
191+
RETURNS TRIGGER
192+
VOLATILE
193+
NOT LEAKPROOF
194+
CALLED ON NULL INPUT
195+
LANGUAGE plpgsql
196+
SECURITY INVOKER
197+
AS $$
198+
BEGIN
199+
SELECT 1 FROM a.b.c;
200+
END;
201+
$$;
202+
CREATE FUNCTION s.add_one(x INT8)
203+
RETURNS INT8
204+
VOLATILE
205+
NOT LEAKPROOF
206+
CALLED ON NULL INPUT
207+
LANGUAGE SQL
208+
SECURITY INVOKER
209+
AS $$
210+
SELECT x + 1;
211+
$$;
212+
213+
subtest end

pkg/sql/logictest/testdata/logic_test/udf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ CREATE FUNCTION public.f(a public.notmyworkday)
106106
LANGUAGE SQL
107107
SECURITY INVOKER
108108
AS $$
109-
SELECT a FROM test.public.t;
110-
SELECT b FROM test.public.t@t_idx_b;
111-
SELECT c FROM test.public.t@t_idx_c;
109+
SELECT a FROM public.t;
110+
SELECT b FROM public.t@t_idx_b;
111+
SELECT c FROM public.t@t_idx_c;
112112
SELECT nextval('public.sq1'::REGCLASS);
113113
$$
114114

pkg/sql/logictest/testdata/logic_test/udf_record

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ f_table CREATE FUNCTION public.f_table()
8282
LANGUAGE SQL
8383
SECURITY INVOKER
8484
AS $$
85-
SELECT t.a, t.b FROM test.public.t ORDER BY a LIMIT 1;
85+
SELECT t.a, t.b FROM public.t ORDER BY a LIMIT 1;
8686
$$
8787

8888
query T
@@ -130,6 +130,39 @@ SELECT f_table();
130130
----
131131
(1,5)
132132

133+
subtest unqualifying_table_names
134+
# test case-sensitive and unicode database names
135+
136+
statement ok
137+
CREATE DATABASE interesting⨄DbName;
138+
USE interesting⨄DbName;
139+
CREATE TABLE t1 (c1 int);
140+
141+
statement ok
142+
CREATE FUNCTION f() RETURNS INT VOLATILE LANGUAGE SQL AS
143+
$$
144+
SELECT * FROM t1;
145+
$$;
146+
147+
query TT
148+
SHOW CREATE FUNCTION f;
149+
----
150+
f CREATE FUNCTION public.f()
151+
RETURNS INT8
152+
VOLATILE
153+
NOT LEAKPROOF
154+
CALLED ON NULL INPUT
155+
LANGUAGE SQL
156+
SECURITY INVOKER
157+
AS $$
158+
SELECT t1.c1 FROM public.t1;
159+
$$
160+
161+
162+
statement ok
163+
USE test;
164+
165+
subtest end
133166

134167
subtest datasource
135168

pkg/sql/logictest/testdata/logic_test/udf_regressions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ CREATE FUNCTION public.func104242()
520520
LANGUAGE SQL
521521
SECURITY INVOKER
522522
AS $$
523-
SELECT 1 FROM test.public.tab104242 WHERE NULL IN ();
523+
SELECT 1 FROM public.tab104242 WHERE NULL IN ();
524524
$$
525525

526526
statement ok
@@ -539,7 +539,7 @@ CREATE FUNCTION public.func104242_not_null()
539539
LANGUAGE SQL
540540
SECURITY INVOKER
541541
AS $$
542-
SELECT 1 FROM test.public.tab104242 WHERE 'foo':::public.typ104242 IN ();
542+
SELECT 1 FROM public.tab104242 WHERE 'foo':::public.typ104242 IN ();
543543
$$
544544

545545
subtest end

pkg/sql/logictest/testdata/logic_test/udf_star

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ f_subquery CREATE FUNCTION public.f_subquery()
113113
LANGUAGE SQL
114114
SECURITY INVOKER
115115
AS $$
116-
SELECT bar.a FROM (SELECT a FROM (SELECT t_onecol.a FROM test.public.t_onecol) AS foo) AS bar;
116+
SELECT bar.a FROM (SELECT a FROM (SELECT t_onecol.a FROM public.t_onecol) AS foo) AS bar;
117117
$$
118118

119119
query TT
@@ -127,7 +127,7 @@ f_allcolsel_alias CREATE FUNCTION public.f_allcolsel_alias()
127127
LANGUAGE SQL
128128
SECURITY INVOKER
129129
AS $$
130-
SELECT t1.a, t1.b FROM test.public.t_twocol AS t1, test.public.t_twocol AS t2 WHERE t1.a = t2.a;
130+
SELECT t1.a, t1.b FROM public.t_twocol AS t1, public.t_twocol AS t2 WHERE t1.a = t2.a;
131131
$$
132132

133133
query I

pkg/sql/sem/tree/format.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ func (ctx *FmtCtx) SetLocation(loc *time.Location) *time.Location {
430430
return old
431431
}
432432

433-
// WithReformatTableNames modifies FmtCtx to to substitute the printing of table
433+
// WithReformatTableNames modifies FmtCtx to substitute the printing of table
434434
// names using the provided function, calls fn, then restores the original table
435435
// formatting.
436436
func (ctx *FmtCtx) WithReformatTableNames(tableNameFmt func(*FmtCtx, *TableName), fn func()) {

pkg/sql/show_create_clauses.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,63 @@ func formatQuerySequencesForDisplay(
273273
return fmtCtx.CloseAndGetString(), nil
274274
}
275275

276+
// Drops the database component of the table names (i.e. unqualifies) when it matches the name provided.
277+
func formatUnqualifyTableNames(
278+
queries string, databaseName string, lang catpb.Function_Language,
279+
) (string, error) {
280+
281+
// walking the table names using the reformat option. the buffer is simply discarded
282+
unqualifyTableNamesCtx := tree.NewFmtCtx(tree.FmtSimple, tree.FmtReformatTableNames(func(ctx *tree.FmtCtx, tn *tree.TableName) {
283+
if string(tn.CatalogName) == databaseName {
284+
tn.ExplicitCatalog = false
285+
}
286+
}))
287+
defer unqualifyTableNamesCtx.Close()
288+
289+
// a fresh buffer to rebuild the queries string
290+
prettyPrintCtx := tree.NewFmtCtx(tree.FmtSimple)
291+
292+
switch lang {
293+
case catpb.Function_SQL:
294+
parsedStmts, err := parser.Parse(queries)
295+
if err != nil {
296+
return "", err
297+
}
298+
299+
stmts := make(tree.Statements, len(parsedStmts))
300+
for i, stmt := range parsedStmts {
301+
stmts[i] = stmt.AST
302+
}
303+
304+
for _, stmt := range stmts {
305+
unqualifyTableNamesCtx.FormatNode(stmt)
306+
}
307+
308+
for i, stmt := range stmts {
309+
if i > 0 {
310+
prettyPrintCtx.WriteString("\n")
311+
}
312+
prettyPrintCtx.FormatNode(stmt)
313+
prettyPrintCtx.WriteString(";")
314+
}
315+
case catpb.Function_PLPGSQL:
316+
var stmts plpgsqltree.Statement
317+
plstmt, err := plpgsql.Parse(queries)
318+
if err != nil {
319+
return "", err
320+
}
321+
stmts = plstmt.AST
322+
323+
unqualifyTableNamesCtx.FormatNode(stmts)
324+
325+
prettyPrintCtx.FormatNode(stmts)
326+
default:
327+
return "", fmt.Errorf("routine language %v not supported", lang)
328+
}
329+
330+
return prettyPrintCtx.CloseAndGetString(), nil
331+
}
332+
276333
// formatViewQueryTypesForDisplay walks the view query and
277334
// look for serialized user-defined types. If it finds any,
278335
// it will deserialize it to display its name.

0 commit comments

Comments
 (0)