From 848fe2d142451cd03068f1c3f888c130ba913015 Mon Sep 17 00:00:00 2001 From: Yahor Yuzefovich Date: Wed, 28 Feb 2024 18:06:03 -0800 Subject: [PATCH 1/6] tree: propagate all routine parameters into the overload This allows us to remove some of the recently introduced fields and this information will be used by the follow up work. Epic: None Release note: None --- pkg/sql/catalog/funcdesc/func_desc.go | 25 +++++++++++----------- pkg/sql/catalog/funcdesc/func_desc_test.go | 15 +++++++++++++ pkg/sql/opt/optbuilder/routine.go | 21 ++++++++++++++++-- pkg/sql/opt/optbuilder/srfs.go | 17 +++++++++++++-- pkg/sql/opt/testutils/testcat/function.go | 25 ++++++++-------------- pkg/sql/sem/tree/overload.go | 12 +++++------ 6 files changed, 76 insertions(+), 39 deletions(-) diff --git a/pkg/sql/catalog/funcdesc/func_desc.go b/pkg/sql/catalog/funcdesc/func_desc.go index 6641df199240..e8dcbdb8ff01 100644 --- a/pkg/sql/catalog/funcdesc/func_desc.go +++ b/pkg/sql/catalog/funcdesc/func_desc.go @@ -708,15 +708,15 @@ func (desc *immutable) ToOverload() (ret *tree.Overload, err error) { routineType = tree.ProcedureRoutine } ret = &tree.Overload{ - Oid: catid.FuncIDToOID(desc.ID), - Body: desc.FunctionBody, - Type: routineType, - Version: uint64(desc.Version), - Language: desc.getCreateExprLang(), + Oid: catid.FuncIDToOID(desc.ID), + Body: desc.FunctionBody, + Type: routineType, + Version: uint64(desc.Version), + Language: desc.getCreateExprLang(), + RoutineParams: make(tree.RoutineParams, 0, len(desc.Params)), } signatureTypes := make(tree.ParamTypes, 0, len(desc.Params)) - var firstOutParamName string var outParamNames []string for _, param := range desc.Params { class := ToTreeRoutineParamClass(param.Class) @@ -727,14 +727,17 @@ func (desc *immutable) ToOverload() (ret *tree.Overload, err error) { } if tree.IsOutParamClass(class) { paramName := param.Name - if len(outParamNames) == 0 { - firstOutParamName = paramName - } if paramName == "" { paramName = fmt.Sprintf("column%d", len(outParamNames)+1) } outParamNames = append(outParamNames, paramName) } + ret.RoutineParams = append(ret.RoutineParams, tree.RoutineParam{ + Name: tree.Name(param.Name), + Type: param.Type, + Class: class, + // TODO(100962): populate DefaultVal. + }) } returnType := desc.ReturnType.Type if types.IsRecordType(returnType) { @@ -743,10 +746,6 @@ func (desc *immutable) ToOverload() (ret *tree.Overload, err error) { } ret.ReturnType = tree.FixedReturnType(returnType) ret.Types = signatureTypes - if len(outParamNames) == 1 { - ret.NamedReturnColumn = firstOutParamName - } - ret.HasNamedReturnColumns = len(outParamNames) > 1 ret.Volatility, err = desc.getOverloadVolatility() if err != nil { return nil, err diff --git a/pkg/sql/catalog/funcdesc/func_desc_test.go b/pkg/sql/catalog/funcdesc/func_desc_test.go index d26e29966d58..276ca64ace9e 100644 --- a/pkg/sql/catalog/funcdesc/func_desc_test.go +++ b/pkg/sql/catalog/funcdesc/func_desc_test.go @@ -673,6 +673,9 @@ func TestToOverload(t *testing.T) { Body: "ANY QUERIES", Type: tree.UDFRoutine, Language: tree.RoutineLangSQL, + RoutineParams: tree.RoutineParams{ + {Name: "arg1", Type: types.Int}, + }, }, }, { @@ -697,6 +700,9 @@ func TestToOverload(t *testing.T) { Body: "ANY QUERIES", Type: tree.UDFRoutine, Language: tree.RoutineLangSQL, + RoutineParams: tree.RoutineParams{ + {Name: "arg1", Type: types.Int}, + }, }, }, { @@ -722,6 +728,9 @@ func TestToOverload(t *testing.T) { Body: "ANY QUERIES", Type: tree.UDFRoutine, Language: tree.RoutineLangSQL, + RoutineParams: tree.RoutineParams{ + {Name: "arg1", Type: types.Int}, + }, }, }, { @@ -748,6 +757,9 @@ func TestToOverload(t *testing.T) { Type: tree.UDFRoutine, CalledOnNullInput: true, Language: tree.RoutineLangSQL, + RoutineParams: tree.RoutineParams{ + {Name: "arg1", Type: types.Int}, + }, }, }, { @@ -772,6 +784,9 @@ func TestToOverload(t *testing.T) { Body: "ANY QUERIES", Type: tree.UDFRoutine, Language: tree.RoutineLangSQL, + RoutineParams: tree.RoutineParams{ + {Name: "arg1", Type: types.Int}, + }, }, err: "function 1 is leakproof but not immutable", }, diff --git a/pkg/sql/opt/optbuilder/routine.go b/pkg/sql/opt/optbuilder/routine.go index 4433130f541d..e626ecfa35fd 100644 --- a/pkg/sql/opt/optbuilder/routine.go +++ b/pkg/sql/opt/optbuilder/routine.go @@ -73,8 +73,25 @@ func (b *Builder) buildUDF( if outScope != nil { outCol = b.synthesizeColumn(outScope, scopeColName(""), f.ResolvedType(), nil /* expr */, routine) } - } else if o.NamedReturnColumn != "" && b.insideDataSource { - outCol.name = scopeColName(tree.Name(o.NamedReturnColumn)) + } else if b.insideDataSource { + // When we have a single OUT parameter, it becomes the output column + // name. + var firstOutParamName tree.Name + var numOutParams int + for _, param := range o.RoutineParams { + if param.IsOutParam() { + numOutParams++ + if numOutParams == 1 { + firstOutParamName = param.Name + } + } + if numOutParams == 2 { + break + } + } + if numOutParams == 1 && firstOutParamName != "" { + outCol.name = scopeColName(firstOutParamName) + } } return b.finishBuildScalar(f, routine, inScope, outScope, outCol) diff --git a/pkg/sql/opt/optbuilder/srfs.go b/pkg/sql/opt/optbuilder/srfs.go index 4ebf2f450202..5ef4dbdbe801 100644 --- a/pkg/sql/opt/optbuilder/srfs.go +++ b/pkg/sql/opt/optbuilder/srfs.go @@ -197,8 +197,21 @@ func (b *Builder) finishBuildGeneratorFunction( ) (out opt.ScalarExpr) { lastAlias := inScope.alias if def.ReturnsRecordType { - if lastAlias == nil && !def.HasNamedReturnColumns { - panic(pgerror.New(pgcode.Syntax, "a column definition list is required for functions returning \"record\"")) + if lastAlias == nil { + var numOutParams int + for _, param := range def.RoutineParams { + if param.IsOutParam() { + numOutParams++ + } + if numOutParams == 2 { + break + } + } + // If we have at least two OUT parameters, they specify an implicit + // alias for the RECORD return type. + if numOutParams < 2 { + panic(pgerror.New(pgcode.Syntax, "a column definition list is required for functions returning \"record\"")) + } } } else if lastAlias != nil { // Non-record type return with a table alias that includes types is not diff --git a/pkg/sql/opt/testutils/testcat/function.go b/pkg/sql/opt/testutils/testcat/function.go index 060edf042129..857ff41c091f 100644 --- a/pkg/sql/opt/testutils/testcat/function.go +++ b/pkg/sql/opt/testutils/testcat/function.go @@ -84,7 +84,6 @@ func (tc *Catalog) CreateRoutine(c *tree.CreateRoutine) { // Resolve the parameter names and types. paramTypes := make(tree.ParamTypes, len(c.Params)) var outParamTypes []*types.T - var firstOutParamName string var outParamNames []string for i := range c.Params { param := &c.Params[i] @@ -96,9 +95,6 @@ func (tc *Catalog) CreateRoutine(c *tree.CreateRoutine) { if param.IsOutParam() { outParamTypes = append(outParamTypes, typ) paramName := string(param.Name) - if len(outParamNames) == 0 { - firstOutParamName = paramName - } if paramName == "" { paramName = fmt.Sprintf("column%d", len(outParamTypes)) } @@ -157,23 +153,20 @@ func (tc *Catalog) CreateRoutine(c *tree.CreateRoutine) { } tc.currUDFOid++ overload := &tree.Overload{ - Oid: tc.currUDFOid, - Types: paramTypes, - ReturnType: tree.FixedReturnType(retType), - Body: body, - Volatility: v, - CalledOnNullInput: calledOnNullInput, - HasNamedReturnColumns: len(outParamNames) > 1, - Language: language, - Type: routineType, + Oid: tc.currUDFOid, + Types: paramTypes, + ReturnType: tree.FixedReturnType(retType), + Body: body, + Volatility: v, + CalledOnNullInput: calledOnNullInput, + Language: language, + Type: routineType, + RoutineParams: c.Params, } overload.ReturnsRecordType = types.IsRecordType(retType) if c.ReturnType != nil && c.ReturnType.SetOf { overload.Class = tree.GeneratorClass } - if len(outParamNames) == 1 { - overload.NamedReturnColumn = firstOutParamName - } prefixedOverload := tree.MakeQualifiedOverload("public", overload) def := &tree.ResolvedFunctionDefinition{ Name: name, diff --git a/pkg/sql/sem/tree/overload.go b/pkg/sql/sem/tree/overload.go index 2cb236958ecf..4476e6bf8650 100644 --- a/pkg/sql/sem/tree/overload.go +++ b/pkg/sql/sem/tree/overload.go @@ -262,18 +262,18 @@ type Overload struct { // in a Schema descriptor, which means that the full UDF descriptor need to be // fetched to get more info, e.g. function Body. UDFContainsOnlySignature bool - // NamedReturnColumn is non-empty when a user-defined function returns a - // single column of non-RECORD type and has named OUT parameter. - NamedReturnColumn string - // HasNamedReturnColumns is set when a user-defined function has multiple - // OUT parameters that specify an implicit alias for the RECORD return type. - HasNamedReturnColumns bool // Version is the descriptor version of the descriptor used to construct // this version of the function overload. Only used for UDFs. Version uint64 // Language is the function language that was used to define the UDF. // This is currently either SQL or PL/pgSQL. Language RoutineLanguage + // RoutineParams contains all parameter information of the routine. + // + // Note that unlike Types (which only contains input parameters and defines + // the signature of the function), RoutineParams contains all parameters as + // well as their class. + RoutineParams RoutineParams } // params implements the overloadImpl interface. From 1bc152e7ba9c3b726dd2ae7794ba8a7e698a3232 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Sat, 2 Mar 2024 01:24:57 +0000 Subject: [PATCH 2/6] restore: limit restore spans to 200 files Previously we would limit restore spans to 384MB, but if a backup contained many small files, a large number of these files could be grouped into such a span before it hit the 384MB target. Unfortunately this meant opening a all of those files to process the restore span, leading to very large numbers of concurrent connections when restoring a backup consisting of tiny files. This patch limits the restore spans to 384MB or 200 files, whichever is hit first. Restores of backups with large numbers of tiny files may thus be slightly slower but will better limit their concurrent outbound connections. This breaks the test cases for experimental/disabled support for memory-monitored restores. Given we have no plans to actually enable this at this time, for the sake of ease of backporting this bugfix, these tests are simply skipped rather than introducing churn to them. #119836 tracks removing them and that functionality entirely instead, but again for the same of backporting is not done here. Release note (bug fix): fix a bug where RESTORE on certain backups would open a very large number of connections to the backup storage provider. Epic: none. --- pkg/ccl/backupccl/bench_covering_test.go | 4 +-- pkg/ccl/backupccl/restore_span_covering.go | 20 +++++++++++--- .../backupccl/restore_span_covering_test.go | 26 +++++++++++++++---- pkg/ccl/backupccl/utils_test.go | 2 ++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/pkg/ccl/backupccl/bench_covering_test.go b/pkg/ccl/backupccl/bench_covering_test.go index 42cf0695a2f4..e9750e21bfb1 100644 --- a/pkg/ccl/backupccl/bench_covering_test.go +++ b/pkg/ccl/backupccl/bench_covering_test.go @@ -39,7 +39,7 @@ func BenchmarkCoverageChecks(b *testing.B) { b.Run(fmt.Sprintf("numFiles=%d", baseFiles), func(b *testing.B) { for _, hasExternalFilesList := range []bool{true, false} { b.Run(fmt.Sprintf("slim=%t", hasExternalFilesList), func(b *testing.B) { - backups, err := MockBackupChain(ctx, numBackups, numSpans, baseFiles, r, hasExternalFilesList, execCfg) + backups, err := MockBackupChain(ctx, numBackups, numSpans, baseFiles, 1<<20, r, hasExternalFilesList, execCfg) require.NoError(b, err) b.ResetTimer() @@ -75,7 +75,7 @@ func BenchmarkRestoreEntryCover(b *testing.B) { for _, hasExternalFilesList := range []bool{true, false} { b.Run(fmt.Sprintf("hasExternalFilesList=%t", hasExternalFilesList), func(b *testing.B) { - backups, err := MockBackupChain(ctx, numBackups, numSpans, baseFiles, r, hasExternalFilesList, execCfg) + backups, err := MockBackupChain(ctx, numBackups, numSpans, baseFiles, 1<<20, r, hasExternalFilesList, execCfg) require.NoError(b, err) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/pkg/ccl/backupccl/restore_span_covering.go b/pkg/ccl/backupccl/restore_span_covering.go index 3f38773b72e8..754c6779054c 100644 --- a/pkg/ccl/backupccl/restore_span_covering.go +++ b/pkg/ccl/backupccl/restore_span_covering.go @@ -307,6 +307,7 @@ func generateAndSendImportSpans( // lastCovSpanSize is the size of files added to the right-most span of // the cover so far. var lastCovSpanSize int64 + var lastCovSpanCount int var lastCovSpan roachpb.Span var covFilesByLayer [][]*backuppb.BackupManifest_File var firstInSpan bool @@ -389,8 +390,8 @@ func generateAndSendImportSpans( } var filesByLayer [][]*backuppb.BackupManifest_File - var covSize int64 - var newCovFilesSize int64 + var covSize, newCovFilesSize int64 + var covCount, newCovFilesCount int for layer := range newFilesByLayer { for _, file := range newFilesByLayer[layer] { @@ -400,6 +401,7 @@ func generateAndSendImportSpans( } newCovFilesSize += sz } + newCovFilesCount += len(newFilesByLayer[layer]) filesByLayer = append(filesByLayer, newFilesByLayer[layer]) } @@ -412,6 +414,7 @@ func generateAndSendImportSpans( if fsc.overlaps(coverSpan, file.Span) { covSize += sz + covCount++ filesByLayer[layer] = append(filesByLayer[layer], file) } } @@ -421,8 +424,17 @@ func generateAndSendImportSpans( covFilesByLayer = newFilesByLayer lastCovSpan = coverSpan lastCovSpanSize = newCovFilesSize + lastCovSpanCount = newCovFilesCount } else { - if (newCovFilesSize == 0 || lastCovSpanSize+newCovFilesSize <= filter.targetSize) && !firstInSpan { + // We have room to add to the last span if doing so would remain below + // both the target byte size and 200 total files. We limit the number + // of files since we default to running multiple concurrent workers so + // we want to bound sum total open files across all of them to <= 1k. + // We bound the span byte size to improve work distribution and make + // the progress more granular. + fits := lastCovSpanSize+newCovFilesSize <= filter.targetSize && lastCovSpanCount+newCovFilesCount <= 200 + + if (newCovFilesCount == 0 || fits) && !firstInSpan { // If there are no new files that cover this span or if we can add the // files in the new span's cover to the last span's cover and still stay // below targetSize, then we should merge the two spans. @@ -431,6 +443,7 @@ func generateAndSendImportSpans( } lastCovSpan.EndKey = coverSpan.EndKey lastCovSpanSize = lastCovSpanSize + newCovFilesSize + lastCovSpanCount = lastCovSpanCount + newCovFilesCount } else { if err := flush(ctx); err != nil { return err @@ -438,6 +451,7 @@ func generateAndSendImportSpans( lastCovSpan = coverSpan covFilesByLayer = filesByLayer lastCovSpanSize = covSize + lastCovSpanCount = covCount } } firstInSpan = false diff --git a/pkg/ccl/backupccl/restore_span_covering_test.go b/pkg/ccl/backupccl/restore_span_covering_test.go index 0ef4a3327301..41e81a39c90e 100644 --- a/pkg/ccl/backupccl/restore_span_covering_test.go +++ b/pkg/ccl/backupccl/restore_span_covering_test.go @@ -46,7 +46,7 @@ import ( // Files spans are ordered by start key but may overlap. func MockBackupChain( ctx context.Context, - length, spans, baseFiles int, + length, spans, baseFiles, fileSize int, r *rand.Rand, hasExternalFilesList bool, execCfg sql.ExecutorConfig, @@ -108,7 +108,7 @@ func MockBackupChain( backups[i].Files[f].Span.Key = encoding.EncodeVarintAscending(k, int64(start)) backups[i].Files[f].Span.EndKey = encoding.EncodeVarintAscending(k, int64(end)) backups[i].Files[f].Path = fmt.Sprintf("12345-b%d-f%d.sst", i, f) - backups[i].Files[f].EntryCounts.DataSize = 1 << 20 + backups[i].Files[f].EntryCounts.DataSize = int64(fileSize) } es, err := execCfg.DistSQLSrv.ExternalStorageFromURI(ctx, @@ -225,6 +225,9 @@ func checkRestoreCovering( } var spanIdx int for _, c := range cov { + if len(c.Files) > 500 { + return errors.Errorf("%d files in span %v", len(c.Files), c.Span) + } for _, f := range c.Files { if requireSpan, ok := required[f.Path]; ok { requireSpan.Sub(c.Span) @@ -721,8 +724,21 @@ func sanityCheckFileIterator( } } +func TestRestoreEntryCoverTinyFiles(t *testing.T) { + defer leaktest.AfterTest(t)() + runTestRestoreEntryCoverForSpanAndFileCounts(t, 5, 5<<10, []int{5}, []int{1000, 5000}) +} + //lint:ignore U1000 unused func runTestRestoreEntryCover(t *testing.T, numBackups int) { + spans := []int{1, 2, 3, 5, 9, 11, 12} + files := []int{0, 1, 2, 3, 4, 10, 12, 50} + runTestRestoreEntryCoverForSpanAndFileCounts(t, numBackups, 1<<20, spans, files) +} + +func runTestRestoreEntryCoverForSpanAndFileCounts( + t *testing.T, numBackups, fileSize int, spanCounts, fileCounts []int, +) { r, _ := randutil.NewTestRand() ctx := context.Background() tc, _, _, cleanupFn := backupRestoreTestSetup(t, singleNode, 1, InitManualReplication) @@ -752,10 +768,10 @@ func runTestRestoreEntryCover(t *testing.T, numBackups int) { return merged } - for _, spans := range []int{1, 2, 3, 5, 9, 11, 12} { - for _, files := range []int{0, 1, 2, 3, 4, 10, 12, 50} { + for _, spans := range spanCounts { + for _, files := range fileCounts { for _, hasExternalFilesList := range []bool{true, false} { - backups, err := MockBackupChain(ctx, numBackups, spans, files, r, hasExternalFilesList, execCfg) + backups, err := MockBackupChain(ctx, numBackups, spans, files, fileSize, r, hasExternalFilesList, execCfg) require.NoError(t, err) layerToIterFactory, err := backupinfo.GetBackupManifestIterFactories(ctx, execCfg.DistSQLSrv.ExternalStorage, backups, nil, nil) diff --git a/pkg/ccl/backupccl/utils_test.go b/pkg/ccl/backupccl/utils_test.go index fae97bf6f3f0..e0f38a269dc8 100644 --- a/pkg/ccl/backupccl/utils_test.go +++ b/pkg/ccl/backupccl/utils_test.go @@ -44,6 +44,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/testutils" "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" + "github.com/cockroachdb/cockroach/pkg/testutils/skip" "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" "github.com/cockroachdb/cockroach/pkg/util/hlc" @@ -577,6 +578,7 @@ func requireRecoveryEvent( // //lint:ignore U1000 unused func runTestRestoreMemoryMonitoring(t *testing.T, numSplits, numInc, restoreProcessorMaxFiles int) { + skip.WithIssue(t, 119836, "this functionality was never enabled and will likely be removed rather than enabled") const splitSize = 10 numAccounts := numSplits * splitSize var expectedNumFiles int From bcaf414a0a73377f0d5e77161a8f0994c21791c5 Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Fri, 1 Mar 2024 13:50:54 -0500 Subject: [PATCH 3/6] sql: redact queries in SHOW SESSIONS when needed Release note (bug fix): If a user has the VIEWACTIVITYREDACTED privilege, then they should not be able to see constants inside of queries that originate from other users in the SHOW SESSIONS result. This redaction was not occurring, but now this is fixed. --- pkg/sql/crdb_internal.go | 53 +++++++++++-- pkg/sql/show_test.go | 164 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 211 insertions(+), 6 deletions(-) diff --git a/pkg/sql/crdb_internal.go b/pkg/sql/crdb_internal.go index 98f4a9191f97..d13f0cd01cc7 100644 --- a/pkg/sql/crdb_internal.go +++ b/pkg/sql/crdb_internal.go @@ -2856,7 +2856,7 @@ var crdbInternalLocalSessionsTable = virtualSchemaTable{ if err != nil { return err } - return populateSessionsTable(ctx, addRow, response) + return populateSessionsTable(ctx, p, addRow, response) }, } @@ -2874,14 +2874,49 @@ var crdbInternalClusterSessionsTable = virtualSchemaTable{ if err != nil { return err } - return populateSessionsTable(ctx, addRow, response) + return populateSessionsTable(ctx, p, addRow, response) }, } func populateSessionsTable( - ctx context.Context, addRow func(...tree.Datum) error, response *serverpb.ListSessionsResponse, + ctx context.Context, + p *planner, + addRow func(...tree.Datum) error, + response *serverpb.ListSessionsResponse, ) error { + shouldRedactOtherUserQuery := false + canViewOtherUser := false + // Check if the user is admin. + if isAdmin, err := p.HasAdminRole(ctx); err != nil { + return err + } else if isAdmin { + canViewOtherUser = true + } else if !isAdmin { + // If the user is not admin, check the VIEWACTIVITYREDACTED privilege to + // see if constants need to be redacted. + if hasViewActivityRedacted, err := p.HasViewActivityRedacted(ctx); err != nil { + return err + } else if hasViewActivityRedacted { + // If the user has VIEWACTIVITYREDACTED, redact the query as it takes precedence + // over VIEWACTIVITY. + shouldRedactOtherUserQuery = true + canViewOtherUser = true + } else if !hasViewActivityRedacted { + if hasViewActivity, err := p.HasViewActivity(ctx); err != nil { + return err + } else if hasViewActivity { + canViewOtherUser = true + } + } + } for _, session := range response.Sessions { + normalizedUser, err := username.MakeSQLUsernameFromUserInput(session.Username, username.PurposeValidation) + if err != nil { + return err + } + if !canViewOtherUser && normalizedUser != p.User() { + continue + } // Generate active_queries and active_query_start var activeQueries bytes.Buffer var activeQueryStart time.Time @@ -2893,10 +2928,18 @@ func populateSessionsTable( // queries to be executed at once in a session. activeQueryStart = query.Start sql := formatActiveQuery(query) + // Never redact queries made by the same user. + if shouldRedactOtherUserQuery && session.Username != p.User().Normalized() { + sql = query.SqlNoConstants + } activeQueries.WriteString(sql) } + lastActiveQuery := session.LastActiveQuery + // Never redact queries made by the same user. + if shouldRedactOtherUserQuery && session.Username != p.User().Normalized() { + lastActiveQuery = session.LastActiveQueryNoConstants + } - var err error if activeQueryStart.IsZero() { activeQueryStartDatum = tree.DNull } else { @@ -2930,7 +2973,7 @@ func populateSessionsTable( tree.NewDString(session.ClientAddress), tree.NewDString(session.ApplicationName), tree.NewDString(activeQueries.String()), - tree.NewDString(session.LastActiveQuery), + tree.NewDString(lastActiveQuery), tree.NewDInt(tree.DInt(session.NumTxnsExecuted)), startTSDatum, activeQueryStartDatum, diff --git a/pkg/sql/show_test.go b/pkg/sql/show_test.go index 8fe3e642a5cd..edfab798bc74 100644 --- a/pkg/sql/show_test.go +++ b/pkg/sql/show_test.go @@ -1052,7 +1052,8 @@ func TestShowSessionPrivileges(t *testing.T) { } } -// TestShowRedactedActiveStatements tests the crdb_internal.cluster_queries table for system permissions. +// TestShowRedactedActiveStatements tests the crdb_internal.cluster_queries +// table for system permissions. func TestShowRedactedActiveStatements(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) @@ -1191,6 +1192,167 @@ func TestShowRedactedActiveStatements(t *testing.T) { <-waiter } +// TestShowRedactedSessions tests the crdb_internal.cluster_sessions +// table for system permissions. +func TestShowRedactedSessions(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + + params, _ := createTestServerParams() + params.Insecure = true + ctx, cancel := context.WithCancel(context.Background()) + s, rawSQLDBroot, _ := serverutils.StartServer(t, params) + sqlDBroot := sqlutils.MakeSQLRunner(rawSQLDBroot) + defer s.Stopper().Stop(context.Background()) + + // Create four users: one with no special permissions, one with the + // VIEWACTIVITY role option, one with VIEWACTIVITYREDACTED option, + // and one with both permissions. + _ = sqlDBroot.Exec(t, `CREATE USER noperms`) + _ = sqlDBroot.Exec(t, `CREATE USER onlyviewactivity`) + _ = sqlDBroot.Exec(t, `CREATE USER onlyviewactivityredacted`) + _ = sqlDBroot.Exec(t, `CREATE USER bothperms`) + _ = sqlDBroot.Exec(t, `GRANT SYSTEM VIEWACTIVITY TO onlyviewactivity`) + _ = sqlDBroot.Exec(t, `GRANT SYSTEM VIEWACTIVITYREDACTED TO onlyviewactivityredacted`) + _ = sqlDBroot.Exec(t, `GRANT SYSTEM VIEWACTIVITY TO bothperms`) + _ = sqlDBroot.Exec(t, `GRANT SYSTEM VIEWACTIVITYREDACTED TO bothperms`) + + type user struct { + username string + canViewOtherRows bool // Can the user view other users' rows in the table? + isQueryRedacted bool // Are the other userss queries redacted? + sqlRunner *sqlutils.SQLRunner + } + + // A user with no permissions should only be able to see their own rows + // in the table. + // A user with only VIEWACTIVITY should be able to see the whole query. + // A user with only VIEWACTIVITYREDACTED should see a redacted query. + // A user with both should see the redacted query, as VIEWACTIVITYREDACTED + // takes precedence. + users := []user{ + {"onlyviewactivityredacted", true, true, nil}, + {"onlyviewactivity", true, false, nil}, + {"noperms", false, false, nil}, + {"bothperms", true, true, nil}, + } + for i, tc := range users { + pgURL := url.URL{ + Scheme: "postgres", + User: url.User(tc.username), + Host: s.AdvSQLAddr(), + RawQuery: "sslmode=disable", + } + db, err := gosql.Open("postgres", pgURL.String()) + if err != nil { + t.Fatal(err) + } + defer db.Close() + users[i].sqlRunner = sqlutils.MakeSQLRunner(db) + + // Ensure the session is open. + users[i].sqlRunner.Exec(t, `SELECT version()`) + } + + // Run a long-running sleep query in the background. + startSignal := make(chan struct{}) + waiter := make(chan struct{}) + go func() { + // Signal that we have started the query. + close(startSignal) + _, _ = rawSQLDBroot.ExecContext(ctx, `SELECT pg_sleep(30)`) + // Signal that we have finished the query. + close(waiter) + }() + + // Wait for the start signal. + <-startSignal + + selectRootQuery := `SELECT active_queries FROM [SHOW CLUSTER SESSIONS] WHERE active_queries LIKE 'SELECT pg_sleep%' AND user_name = 'root'` + + testutils.SucceedsSoon(t, func() error { + rows := sqlDBroot.Query(t, selectRootQuery) + defer rows.Close() + count := 0 + for rows.Next() { + count++ + var query string + if err := rows.Scan(&query); err != nil { + return err + } + if query != "SELECT pg_sleep(30)" { + return errors.Errorf("Expected `SELECT pg_sleep(30)`, got %s", query) + } + } + if count != 1 { + return errors.Errorf("expected 1 row, got %d", count) + } + return nil + }) + + for _, u := range users { + t.Run(u.username, func(t *testing.T) { + rootRows := u.sqlRunner.Query(t, selectRootQuery) + defer func() { require.NoError(t, rootRows.Close()) }() + + count := 0 + for rootRows.Next() { + count++ + + var query string + if err := rootRows.Scan(&query); err != nil { + t.Fatal(err) + } + + t.Log(query) + // Make sure that if the user is supposed to see a redacted query, they do. + if u.isQueryRedacted { + if !strings.HasPrefix(query, "SELECT pg_sleep(_)") { + t.Fatalf("Expected `SELECT pg_sleep(_)`, got %s", query) + } + // Make sure that if the user is supposed to see the full query, they do. + } else { + if !strings.HasPrefix(query, "SELECT pg_sleep(30)") { + t.Fatalf("Expected `SELECT pg_sleep(30)`, got %s", query) + } + } + } + if u.canViewOtherRows { + require.Equalf(t, 1, count, "expected 1 row, got %d", count) + } else { + require.Equalf(t, 0, count, "expected 0 rows, got %d", count) + } + + selectOwnQuery := fmt.Sprintf( + `SELECT active_queries FROM [SHOW CLUSTER SESSIONS] WHERE active_queries LIKE 'SELECT active_queries FROM%%' AND user_name = '%s'`, + u.username, + ) + ownRows := u.sqlRunner.Query(t, selectOwnQuery) + defer func() { require.NoError(t, ownRows.Close()) }() + + count = 0 + for ownRows.Next() { + count++ + + var query string + if err := ownRows.Scan(&query); err != nil { + t.Fatal(err) + } + + t.Log(query) + // Any user can always see their own unredacted queries. + if !strings.Contains(query, fmt.Sprintf("user_name = '%s'", u.username)) { + t.Fatalf("Expected unredacted query, got %s", query) + } + } + require.Equalf(t, 1, count, "expected 1 row, got %d", count) + }) + } + + cancel() + <-waiter +} + // TestCancelQueriesRace can be stressed to try and reproduce a race // between SHOW QUERIES and currently executing statements. For // more details, see #28033. From 3cd24e8377c219b1dd05ef612e0366bd5c3c3dad Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Fri, 1 Mar 2024 13:53:43 -0500 Subject: [PATCH 4/6] sql: allow user to see their own queries without needing a privilege Release note (bug fix): The SHOW QUERIES and SHOW STATEMENTS commands were incorrectly requiring that the user has the VIEWACTIVITY or VIEWACTIVITYREDACTED privilege. However, a user always should be able to view their own queries, even without this privilege. This is fixed now. --- pkg/sql/crdb_internal.go | 32 +++++++++----- pkg/sql/show_test.go | 95 ++++++++++++++++++++++++---------------- 2 files changed, 80 insertions(+), 47 deletions(-) diff --git a/pkg/sql/crdb_internal.go b/pkg/sql/crdb_internal.go index d13f0cd01cc7..31db03c41dfe 100644 --- a/pkg/sql/crdb_internal.go +++ b/pkg/sql/crdb_internal.go @@ -2674,10 +2674,13 @@ func populateQueriesTable( addRow func(...tree.Datum) error, response *serverpb.ListSessionsResponse, ) error { - shouldRedactQuery := false + shouldRedactOtherUserQuery := false + canViewOtherUser := false // Check if the user is admin. if isAdmin, err := p.HasAdminRole(ctx); err != nil { return err + } else if isAdmin { + canViewOtherUser = true } else if !isAdmin { // If the user is not admin, check the individual VIEWACTIVITY and VIEWACTIVITYREDACTED // privileges. @@ -2686,16 +2689,24 @@ func populateQueriesTable( } else if hasViewActivityRedacted { // If the user has VIEWACTIVITYREDACTED, redact the query as it takes precedence // over VIEWACTIVITY. - shouldRedactQuery = true - } else if hasViewActivity, err := p.HasViewActivity(ctx); err != nil { - return err - } else if !hasViewActivity { - // If the user is not admin and does not have VIEWACTIVITY or VIEWACTIVITYREDACTED, - // return insufficient privileges error. - return noViewActivityOrViewActivityRedactedRoleError(p.User()) + shouldRedactOtherUserQuery = true + canViewOtherUser = true + } else if !hasViewActivityRedacted { + if hasViewActivity, err := p.HasViewActivity(ctx); err != nil { + return err + } else if hasViewActivity { + canViewOtherUser = true + } } } for _, session := range response.Sessions { + normalizedUser, err := username.MakeSQLUsernameFromUserInput(session.Username, username.PurposeValidation) + if err != nil { + return err + } + if !canViewOtherUser && normalizedUser != p.User() { + continue + } sessionID := getSessionID(session) for _, query := range session.ActiveQueries { isDistributedDatum := tree.DNull @@ -2739,8 +2750,9 @@ func populateQueriesTable( // Interpolate placeholders into the SQL statement. sql := formatActiveQuery(query) - // If the user does not have the correct privileges, show the query without literals or constants. - if shouldRedactQuery { + // If the user does not have the correct privileges, show the query + // without literals or constants. + if shouldRedactOtherUserQuery && session.Username != p.SessionData().User().Normalized() { sql = query.SqlNoConstants } if err := addRow( diff --git a/pkg/sql/show_test.go b/pkg/sql/show_test.go index edfab798bc74..214d8e61fc0a 100644 --- a/pkg/sql/show_test.go +++ b/pkg/sql/show_test.go @@ -1078,16 +1078,18 @@ func TestShowRedactedActiveStatements(t *testing.T) { _ = sqlDBroot.Exec(t, `GRANT SYSTEM VIEWACTIVITYREDACTED TO bothperms`) type user struct { - username string - canViewTable bool // Can the user view the `cluster_queries` table? - isQueryRedacted bool // Is the user's query redacted? - sqlRunner *sqlutils.SQLRunner + username string + canViewOtherRows bool // Can the user view other users' rows in the table? + isQueryRedacted bool // Are the other userss queries redacted? + sqlRunner *sqlutils.SQLRunner } - // A user with no permissions should not see the table. A user with only - // VIEWACTIVITY should be able to see the whole query. A user with only - // VIEWACTIVITYREDACTED should see a redacted query. A user with both should - // see the redacted query, as VIEWACTIVITYREDACTED takes precedence. + // A user with no permissions should only be able to see their own rows + // in the table. + // A user with only VIEWACTIVITY should be able to see the whole query. + // A user with only VIEWACTIVITYREDACTED should see a redacted query. + // A user with both should see the redacted query, as VIEWACTIVITYREDACTED + // takes precedence. users := []user{ {"onlyviewactivityredacted", true, true, nil}, {"onlyviewactivity", true, false, nil}, @@ -1126,10 +1128,10 @@ func TestShowRedactedActiveStatements(t *testing.T) { // Wait for the start signal. <-startSignal - selectQuery := `SELECT query FROM [SHOW CLUSTER QUERIES] WHERE query LIKE 'SELECT pg_sleep%'` + selectRootQuery := `SELECT query FROM [SHOW CLUSTER QUERIES] WHERE query LIKE 'SELECT pg_sleep%' AND user_name = 'root'` testutils.SucceedsSoon(t, func() error { - rows := sqlDBroot.Query(t, selectQuery) + rows := sqlDBroot.Query(t, selectRootQuery) defer rows.Close() count := 0 for rows.Next() { @@ -1150,41 +1152,60 @@ func TestShowRedactedActiveStatements(t *testing.T) { for _, u := range users { t.Run(u.username, func(t *testing.T) { - // Make sure that if the user can't view the table, they get an error. - if !u.canViewTable { - u.sqlRunner.ExpectErr(t, "does not have VIEWACTIVITY or VIEWACTIVITYREDACTED privilege", selectQuery) - } else { - rows := u.sqlRunner.Query(t, selectQuery) - defer rows.Close() - if err := rows.Err(); err != nil { + rootRows := u.sqlRunner.Query(t, selectRootQuery) + defer func() { require.NoError(t, rootRows.Close()) }() + + count := 0 + for rootRows.Next() { + count++ + + var query string + if err := rootRows.Scan(&query); err != nil { t.Fatal(err) } - count := 0 - for rows.Next() { - count++ - var query string - if err := rows.Scan(&query); err != nil { - t.Fatal(err) + t.Log(query) + // Make sure that if the user is supposed to see a redacted query, they do. + if u.isQueryRedacted { + if !strings.HasPrefix(query, "SELECT pg_sleep(_)") { + t.Fatalf("Expected `SELECT pg_sleep(_)`, got %s", query) } - - t.Log(query) - // Make sure that if the user is supposed to see a redacted query, they do. - if u.isQueryRedacted { - if !strings.HasPrefix(query, "SELECT pg_sleep(_)") { - t.Fatalf("Expected `SELECT pg_sleep(_)`, got %s", query) - } - // Make sure that if the user is supposed to see the full query, they do. - } else { - if !strings.HasPrefix(query, "SELECT pg_sleep(30)") { - t.Fatalf("Expected `SELECT pg_sleep(30)`, got %s", query) - } + // Make sure that if the user is supposed to see the full query, they do. + } else { + if !strings.HasPrefix(query, "SELECT pg_sleep(30)") { + t.Fatalf("Expected `SELECT pg_sleep(30)`, got %s", query) } } - if count != 1 { - t.Fatalf("expected 1 row, got %d", count) + } + if u.canViewOtherRows { + require.Equalf(t, 1, count, "expected 1 row, got %d", count) + } else { + require.Equalf(t, 0, count, "expected 0 rows, got %d", count) + } + + selectOwnQuery := fmt.Sprintf( + `SELECT query FROM [SHOW CLUSTER QUERIES] WHERE query LIKE 'SELECT query FROM%%' AND user_name = '%s'`, + u.username, + ) + ownRows := u.sqlRunner.Query(t, selectOwnQuery) + defer func() { require.NoError(t, ownRows.Close()) }() + + count = 0 + for ownRows.Next() { + count++ + + var query string + if err := ownRows.Scan(&query); err != nil { + t.Fatal(err) + } + + t.Log(query) + // Any user can always see their own unredacted queries. + if !strings.Contains(query, fmt.Sprintf("user_name = '%s'", u.username)) { + t.Fatalf("Expected unredacted query, got %s", query) } } + require.Equalf(t, 1, count, "expected 1 row, got %d", count) }) } From 9b32d40fb95b3985a85938481615c04c5823a7db Mon Sep 17 00:00:00 2001 From: Yahor Yuzefovich Date: Wed, 28 Feb 2024 19:57:52 -0800 Subject: [PATCH 5/6] sql: support OUT parameters in PLpgSQL UDFs This commit (mostly) adds the support for INOUT / OUT parameters in PLpgSQL UDFs. OUT parameters are not included into the signature (for overload resolution), but they result in uninitialized variables. Any parameter can be left unnamed but can still be referenced via `$i` notation which is unsupported so far. Unlike for SQL UDFs, in PLpgSQL input and output parameters share the same namespace for duplication check. Additionally, this commit fixes a few issues: - for UDFs only input parameters need to be added to the scope of the body - for procedures, all parameters (including OUT) are used for overload resolution - UDF returning VOID with empty body previously would hit an index out of bounds internal error. Release note: None --- .../testdata/logic_test/udf_params | 547 +++++++++++++++++- .../testdata/logic_test/udf_plpgsql | 8 + .../testdata/logic_test/udf_rewrite | 67 +++ pkg/cmd/roachtest/tests/pgjdbc_blocklist.go | 2 - pkg/sql/alter_function.go | 2 +- pkg/sql/catalog/descpb/structured.proto | 6 +- pkg/sql/catalog/funcdesc/func_desc.go | 4 +- pkg/sql/catalog/schemadesc/schema_desc.go | 3 + pkg/sql/create_function.go | 2 +- .../logictest/testdata/logic_test/udf_params | 65 ++- .../logictest/testdata/logic_test/udf_rewrite | 28 + pkg/sql/opt/optbuilder/create_function.go | 51 +- pkg/sql/opt/optbuilder/plpgsql.go | 50 +- pkg/sql/opt/optbuilder/routine.go | 72 ++- pkg/sql/opt/optbuilder/scope_column.go | 3 + pkg/sql/opt/testutils/testcat/function.go | 11 +- pkg/sql/opt/testutils/testcat/testdata/udf | 6 +- .../scexec/scmutationexec/references.go | 6 +- pkg/sql/sem/plpgsqltree/statements.go | 3 + pkg/sql/sem/tree/create_routine.go | 11 + pkg/sql/sem/tree/overload.go | 6 - 21 files changed, 861 insertions(+), 92 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/udf_params b/pkg/ccl/logictestccl/testdata/logic_test/udf_params index 323cf7ddb37f..12bb220bc2ea 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/udf_params +++ b/pkg/ccl/logictestccl/testdata/logic_test/udf_params @@ -2,6 +2,7 @@ subtest types +# PLpgSQL UDFs statement error pgcode 42P13 pq: function result type must be int because of OUT parameters CREATE FUNCTION f(OUT param INT) RETURNS FLOAT AS $$ BEGIN SELECT 1; END $$ LANGUAGE PLpgSQL; @@ -15,25 +16,128 @@ statement error pgcode 42P13 pq: function result type must be int because of OUT CREATE FUNCTION f(OUT param INT) RETURNS RECORD AS $$ BEGIN SELECT 1; END $$ LANGUAGE PLpgSQL; statement ok -CREATE FUNCTION f(OUT param INT) RETURNS INT AS $$ BEGIN SELECT 1; END $$ LANGUAGE PLpgSQL; +CREATE FUNCTION f(OUT param INT) RETURNS INT AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL; + +query I colnames +SELECT f(); +---- +f +1 + +query I colnames +SELECT * FROM f(); +---- +param +1 statement ok DROP FUNCTION f; +statement error RETURN cannot have a parameter in function with OUT parameters +CREATE FUNCTION f(OUT INT) AS $$ BEGIN RETURN NULL; END $$ LANGUAGE PLpgSQL; + +statement error RETURN cannot have a parameter in function with OUT parameters +CREATE FUNCTION f(OUT INT, OUT INT) AS $$ BEGIN RETURN NULL; END $$ LANGUAGE PLpgSQL; + +statement error RETURN cannot have a parameter in function with OUT parameters +CREATE FUNCTION f(INOUT INT) AS $$ BEGIN RETURN NULL; END $$ LANGUAGE PLpgSQL; + statement ok -CREATE FUNCTION f(INOUT param1 INT, OUT param2 INT) RETURNS RECORD AS $$ BEGIN SELECT 1, 2; END $$ LANGUAGE PLpgSQL; +CREATE FUNCTION f(INOUT param1 INT, OUT param2 INT) RETURNS RECORD AS $$ +BEGIN + param2 := 2; + RAISE NOTICE '%', param2; +END +$$ LANGUAGE PLpgSQL; + +query T colnames +SELECT f(3); +---- +f +(3,2) + +query T noticetrace +SELECT f(3); +---- +NOTICE: 2 + +# TODO(100405): figure out why this causes an internal error. +# query II colnames +# SELECT * FROM f(3); +# ---- +# param1 param2 +# 3 2 + +# query T noticetrace +# SELECT * FROM f(3); +# ---- +# NOTICE: 2 + +# query I colnames +# SELECT param1 FROM f(3); +# ---- +# param1 +# 3 + +# query I colnames +# SELECT param2 FROM f(3); +# ---- +# param2 +# 2 statement ok DROP FUNCTION f; -# TODO(#100405) Executing this function results in 42601: query has no destination for result data statement ok -CREATE FUNCTION f(INOUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1, 2, 3; END $$ LANGUAGE PLpgSQL; +CREATE FUNCTION f(INOUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 3 INTO param1; END $$ LANGUAGE PLpgSQL; + +query II colnames +SELECT * FROM f(1); +---- +param1 param2 +3 NULL + +statement ok +CREATE OR REPLACE FUNCTION f(INOUT param1 INT, OUT param2 INT) AS $$ +BEGIN + RAISE NOTICE '% %', param1, param2; + param1 = 3; + RAISE NOTICE '% %', param1, param2; + SELECT 4 INTO param2; + RAISE NOTICE '% %', param1, param2; +END +$$ LANGUAGE PLpgSQL; + +query T colnames +SELECT f(1); +---- +f +(3,4) + +query T noticetrace +SELECT f(1); +---- +NOTICE: 1 +NOTICE: 3 +NOTICE: 3 4 + +# TODO(100405): figure this out. +# query II colnames +# SELECT * FROM f(1); +# ---- +# param1 param2 +# 3 4 + +# query T noticetrace +# SELECT * FROM f(1); +# ---- +# NOTICE: 1 +# NOTICE: 3 +# NOTICE: 3 4 statement ok DROP FUNCTION f; -# TODO(#100405) Executing this function results in 42601: query has no destination for result data statement ok CREATE FUNCTION f(INOUT param INT) AS $$ BEGIN SELECT 'hello'; END $$ LANGUAGE PLpgSQL; @@ -48,9 +152,54 @@ BEGIN END $$ LANGUAGE PLpgSQL; +query II +SELECT * FROM f(3) +---- +1 2 + +statement ok +DROP FUNCTION f; + +# Verify that function resolution works correctly when dropping functions (OUT +# arguments are ignored). +statement ok +CREATE FUNCTION f(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL; + statement ok DROP FUNCTION f; +statement ok +CREATE FUNCTION f(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL; + +statement ok +DROP FUNCTION f(OUT INT); + +statement ok +CREATE FUNCTION f(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO param1; END $$ LANGUAGE PLpgSQL; + +statement ok +DROP FUNCTION f(OUT INT); + +# TODO(119502): uncomment this and invoke the function when $i notation is +# supported. +# statement ok +# CREATE FUNCTION f(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO $2; END $$ LANGUAGE PLpgSQL; + +statement ok +CREATE FUNCTION f(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO param2; END $$ LANGUAGE PLpgSQL; + +statement error pq: function f\(int\) does not exist +DROP FUNCTION f(INT); + +statement ok +DROP FUNCTION f; + +statement ok +CREATE FUNCTION f(OUT param INT) RETURNS INT AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL; + +statement ok +DROP FUNCTION f(OUT INT, OUT text, OUT INT); + # Stored Procedures statement ok CREATE PROCEDURE p(OUT param INT) AS $$ BEGIN SELECT 1; END $$ LANGUAGE PLpgSQL; @@ -64,14 +213,12 @@ CREATE PROCEDURE p(IN param1 INT, INOUT param2 INT, OUT param3 INT) AS $$ BEGIN statement ok DROP PROCEDURE p; -# TODO(#100405) Executing this procedure results in 42601: query has no destination for result data statement ok CREATE PROCEDURE p(INOUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1, 2, 3; END $$ LANGUAGE PLpgSQL; statement ok DROP PROCEDURE p; -# TODO(#100405) Executing this procedure results in 42601: query has no destination for result data statement ok CREATE PROCEDURE p(INOUT param INT) AS $$ BEGIN SELECT 'hello'; END $$ LANGUAGE PLpgSQL; @@ -133,3 +280,389 @@ statement ok DROP FUNCTION f_param_types; subtest end + +subtest parameter_names + +# Unlike for SQL UDFs, sharing of parameter names is not allowed across +# different "parameter namespaces" (IN vs OUT). + +statement error pgcode 42P13 pq: parameter name "a" used more than once +CREATE FUNCTION f_same_name(IN a INT, IN a INT) RETURNS INT AS $$ BEGIN RETURN a + a; END $$ LANGUAGE PLpgSQL; + +statement error pgcode 42P13 pq: parameter name "a" used more than once +CREATE FUNCTION f_same_name(IN a INT, INOUT a INT) RETURNS INT AS $$ BEGIN RETURN a + a; END $$ LANGUAGE PLpgSQL; + +statement error pgcode 42P13 pq: parameter name "a" used more than once +CREATE FUNCTION f_same_name(OUT a INT, INOUT a INT) RETURNS INT AS $$ BEGIN RETURN a + a; END $$ LANGUAGE PLpgSQL; + +statement error pgcode 42P13 pq: parameter name "a" used more than once +CREATE FUNCTION f_same_name(IN a INT, OUT a INT) RETURNS INT AS $$ BEGIN RETURN a; END $$ LANGUAGE PLpgSQL; + +statement ok +CREATE FUNCTION f_names(IN param_in INT, OUT param_out INT) AS $$ BEGIN SELECT param_in INTO param_out; END $$ LANGUAGE PLpgSQL; + +query I colnames +SELECT f_names(2); +---- +f_names +2 + +query I colnames +SELECT * FROM f_names(2); +---- +param_out +2 + +statement ok +CREATE FUNCTION f_in_int(IN param INT) RETURNS INT AS $$ BEGIN RETURN param; END; $$ LANGUAGE PLpgSQL; + +query I colnames +SELECT f_in_int(2); +---- +f_in_int +2 + +query I colnames +SELECT * FROM f_in_int(2); +---- +f_in_int +2 + +# Changing OUT parameter name is ok. +statement ok +CREATE FUNCTION f_out_int(OUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL; + +statement ok +CREATE OR REPLACE FUNCTION f_out_int(OUT param_new INT) AS $$ BEGIN param_new = 2; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_out_int]; +---- +CREATE FUNCTION public.f_out_int(OUT param_new INT8) + RETURNS INT8 + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param_new := 2; + END; +$$ + +query I colnames +SELECT f_out_int(); +---- +f_out_int +2 + +query I colnames +SELECT * FROM f_out_int(); +---- +param_new +2 + +# But changing IN or INOUT parameter name is not allowed. +statement error pgcode 42P13 pq: cannot change name of input parameter "param" +CREATE OR REPLACE FUNCTION f_in_int(IN param_new INT) RETURNS INT AS $$ BEGIN RETURN param_new; END; $$ LANGUAGE PLpgSQL; + +statement ok +CREATE FUNCTION f_inout_int(INOUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL; + +statement error pgcode 42P13 pq: cannot change name of input parameter "param" +CREATE OR REPLACE FUNCTION f_inout_int(INOUT param_new INT) AS $$ BEGIN param_new = 2; END; $$ LANGUAGE PLpgSQL; + +subtest end + +subtest changing_parameters + +statement ok +CREATE FUNCTION f_int(IN param INT) RETURNS INT AS $$ BEGIN RETURN param; END; $$ LANGUAGE PLpgSQL; + +query I colnames +SELECT * FROM f_int(2); +---- +f_int +2 + +# We can change the parameter class from IN to INOUT without introducing new +# overload. +statement ok +CREATE OR REPLACE FUNCTION f_int(INOUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_int]; +---- +CREATE FUNCTION public.f_int(INOUT param INT8) + RETURNS INT8 + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param := 2; + END; +$$ + +query I colnames +SELECT * FROM f_int(2); +---- +param +2 + +# We can add and remove an OUT parameter too without introducing another +# overload (but must preserve the original parameter name for IN / INOUT +# parameter). +statement error pgcode 42P13 pq: cannot change name of input parameter "param" +CREATE OR REPLACE FUNCTION f_int(IN param_in INT, OUT param_out INT) AS $$ BEGIN param_out = param_in; END; $$ LANGUAGE PLpgSQL; + +statement ok +CREATE OR REPLACE FUNCTION f_int(IN param INT, OUT param_out INT) AS $$ BEGIN SELECT param INTO param_out; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_int]; +---- +CREATE FUNCTION public.f_int(IN param INT8, OUT param_out INT8) + RETURNS INT8 + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + SELECT param INTO param_out; + END; +$$ + +query I colnames +SELECT * FROM f_int(2); +---- +param_out +2 + +statement ok +CREATE OR REPLACE FUNCTION f_int(OUT param_out INT, IN param INT) AS $$ BEGIN SELECT param INTO param_out; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_int]; +---- +CREATE FUNCTION public.f_int(OUT param_out INT8, IN param INT8) + RETURNS INT8 + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + SELECT param INTO param_out; + END; +$$ + +query I colnames +SELECT * FROM f_int(2); +---- +param_out +2 + +statement ok +CREATE OR REPLACE FUNCTION f_int(INOUT param INT) AS $$ BEGIN param = param; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_int]; +---- +CREATE FUNCTION public.f_int(INOUT param INT8) + RETURNS INT8 + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param := param; + END; +$$ + +query I colnames +SELECT * FROM f_int(2); +---- +param +2 + +subtest end + +subtest default_parameter_names + +# Parameter names are optional. Whenever a UDF returns RECORD type, each unnamed +# OUT parameter with ordinal 'i' (among all OUT parameters) gets the default +# name that is "column" || i. + +statement ok +CREATE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN param2 = 2; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_default_names]; +---- +CREATE FUNCTION public.f_default_names(OUT INT8, OUT param2 INT8, IN INT8, OUT INT8) + RETURNS RECORD + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param2 := 2; + END; +$$ + +query T colnames +SELECT f_default_names(0); +---- +f_default_names +(,2,) + +query III colnames +SELECT * FROM f_default_names(0); +---- +column1 param2 column3 +NULL 2 NULL + +query I colnames +SELECT column1 FROM f_default_names(0); +---- +column1 +NULL + +query I colnames +SELECT param2 FROM f_default_names(0); +---- +param2 +2 + +query I colnames +SELECT column3 FROM f_default_names(0); +---- +column3 +NULL + +# However, attempting to access the parameter by the default names is invalid. +statement error pgcode 42601 pq: \"column1\" is not a known variable +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN SELECT 1 INTO column1; END; $$ LANGUAGE PLpgSQL; + +# Introducing the OUT parameter name is disallowed because it'd change the +# return type. +statement error cannot change return type of existing function +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT param3 INT) AS $$ BEGIN param2 = 2; END; $$ LANGUAGE PLpgSQL; + +# Introducing the name that matches the default OUT parameter name is allowed. +statement ok +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT column3 INT) AS $$ BEGIN SELECT 3 INTO column3; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_default_names]; +---- +CREATE FUNCTION public.f_default_names(OUT INT8, OUT param2 INT8, IN INT8, OUT column3 INT8) + RETURNS RECORD + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + SELECT 3 INTO column3; + END; +$$ + +query I colnames +SELECT column3 FROM f_default_names(0); +---- +column3 +3 + +# Then we can omit the default OUT parameter name again (but still cannot use it +# in the body). +statement error pgcode 42601 pq: \"column3\" is not a known variable +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN SELECT 3 INTO column3; END; $$ LANGUAGE PLpgSQL; + +statement ok +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN param2 = 2; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_default_names]; +---- +CREATE FUNCTION public.f_default_names(OUT INT8, OUT param2 INT8, IN INT8, OUT INT8) + RETURNS RECORD + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param2 := 2; + END; +$$ + +# Introducing the IN parameter name is ok. +statement ok +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN in_param INT, OUT INT) AS $$ BEGIN SELECT in_param INTO param2; END; $$ LANGUAGE PLpgSQL; + +query T +SELECT create_statement FROM [SHOW CREATE FUNCTION f_default_names]; +---- +CREATE FUNCTION public.f_default_names(OUT INT8, OUT param2 INT8, IN in_param INT8, OUT INT8) + RETURNS RECORD + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + SELECT in_param INTO param2; + END; +$$ + +# But then the IN parameter name cannot be changed anymore. +statement error cannot change name of input parameter "in_param" +CREATE OR REPLACE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN in_param_new INT, OUT INT) AS $$ BEGIN SELECT in_param_new INTO param2; END; $$ LANGUAGE PLpgSQL; + +query T colnames +SELECT f_default_names(0); +---- +f_default_names +(,0,) + +query III colnames +SELECT * FROM f_default_names(0); +---- +column1 param2 column3 +NULL 0 NULL + +subtest end + +statement ok +CREATE TYPE typ AS (a INT, b INT); +CREATE FUNCTION f_udt() RETURNS typ AS $$ BEGIN RETURN (1, 2); END; $$ LANGUAGE PLpgSQL; + +query T colnames +SELECT f_udt() +---- +f_udt +(1,2) + +query II colnames +SELECT * FROM f_udt() +---- +a b +1 2 + +query I colnames +SELECT a FROM f_udt() +---- +a +1 + +query I colnames +SELECT b FROM f_udt() +---- +b +2 diff --git a/pkg/ccl/logictestccl/testdata/logic_test/udf_plpgsql b/pkg/ccl/logictestccl/testdata/logic_test/udf_plpgsql index 1b9cf077fff7..f5ac75744fce 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/udf_plpgsql +++ b/pkg/ccl/logictestccl/testdata/logic_test/udf_plpgsql @@ -2900,3 +2900,11 @@ CREATE OR REPLACE FUNCTION f(x INT) RETURNS INT AS $$ $$ LANGUAGE PLpgSQL; subtest end + +statement ok +CREATE FUNCTION f_empty() RETURNS VOID AS $$ BEGIN END; $$ LANGUAGE PLpgSQL; + +query T +SELECT f_empty() +---- +NULL diff --git a/pkg/ccl/logictestccl/testdata/logic_test/udf_rewrite b/pkg/ccl/logictestccl/testdata/logic_test/udf_rewrite index 2b8b2286176a..9696e10d90eb 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/udf_rewrite +++ b/pkg/ccl/logictestccl/testdata/logic_test/udf_rewrite @@ -388,6 +388,73 @@ ALTER TYPE weekday RENAME VALUE 'humpday' TO 'wednesday'; statement ok DROP FUNCTION f_rewrite(); +statement ok +CREATE FUNCTION f_rewrite(INOUT param1 weekday, OUT param2 weekday) AS +$$ + BEGIN + param2 = param1; + param1 = 'friday'::weekday; + END +$$ LANGUAGE PLPGSQL; + +query T +SELECT get_body_str('f_rewrite'); +---- +"BEGIN\nparam2 := param1;\nparam1 := b'\\xc0':::@100107;\nEND;\n" + +query TT +SHOW CREATE FUNCTION f_rewrite; +---- +f_rewrite CREATE FUNCTION public.f_rewrite(INOUT param1 test.public.weekday, OUT param2 test.public.weekday) + RETURNS RECORD + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param2 := param1; + param1 := 'friday':::test.public.weekday; + END; + $$ + +statement ok +ALTER TYPE weekday RENAME VALUE 'friday' TO 'humpday'; + +statement ok +ALTER TYPE weekday RENAME TO workday; + +query T +SELECT get_body_str('f_rewrite'); +---- +"BEGIN\nparam2 := param1;\nparam1 := b'\\xc0':::@100107;\nEND;\n" + +query TT +SHOW CREATE FUNCTION f_rewrite; +---- +f_rewrite CREATE FUNCTION public.f_rewrite(INOUT param1 test.public.workday, OUT param2 test.public.workday) + RETURNS RECORD + VOLATILE + NOT LEAKPROOF + CALLED ON NULL INPUT + LANGUAGE plpgsql + AS $$ + BEGIN + param2 := param1; + param1 := 'humpday':::test.public.workday; + END; + $$ + +# Reset types for subtest. +statement ok +ALTER TYPE workday RENAME TO weekday; + +statement ok +ALTER TYPE weekday RENAME VALUE 'humpday' TO 'friday'; + +statement ok +DROP FUNCTION f_rewrite; + subtest end subtest rewrite_proc diff --git a/pkg/cmd/roachtest/tests/pgjdbc_blocklist.go b/pkg/cmd/roachtest/tests/pgjdbc_blocklist.go index b1b2e4135e95..f5788279270e 100644 --- a/pkg/cmd/roachtest/tests/pgjdbc_blocklist.go +++ b/pkg/cmd/roachtest/tests/pgjdbc_blocklist.go @@ -487,10 +487,8 @@ var pgjdbcBlockList = blocklist{ `org.postgresql.test.jdbc3.CompositeTest.testSimpleSelect`: "27793", `org.postgresql.test.jdbc3.CompositeTest.testTableMetadata`: "27793", `org.postgresql.test.jdbc3.DatabaseMetaDataTest.testGetColumnsForDomain`: "27796", - `org.postgresql.test.jdbc3.EscapeSyntaxCallModeCallIfNoReturnTest.testInvokeFunction`: "100405", `org.postgresql.test.jdbc3.EscapeSyntaxCallModeCallIfNoReturnTest.testInvokeFunctionHavingReturnParameter`: "17511", `org.postgresql.test.jdbc3.EscapeSyntaxCallModeCallIfNoReturnTest.testInvokeProcedure`: "17511", - `org.postgresql.test.jdbc3.EscapeSyntaxCallModeCallTest.testInvokeFunction`: "100405", `org.postgresql.test.jdbc3.EscapeSyntaxCallModeCallTest.testInvokeFunctionHavingReturnParameter`: "17511", `org.postgresql.test.jdbc3.EscapeSyntaxCallModeCallTest.testInvokeProcedure`: "17511", `org.postgresql.test.jdbc3.EscapeSyntaxCallModeSelectTest.testInvokeFunction`: "17511", diff --git a/pkg/sql/alter_function.go b/pkg/sql/alter_function.go index 3713088bc854..f63e275b7fd4 100644 --- a/pkg/sql/alter_function.go +++ b/pkg/sql/alter_function.go @@ -462,7 +462,7 @@ func toSchemaOverloadSignature(fnDesc *funcdesc.Mutable) descpb.SchemaDescriptor IsProcedure: fnDesc.IsProcedure(), } for _, param := range fnDesc.Params { - if tree.IsInParamClass(funcdesc.ToTreeRoutineParamClass(param.Class)) { + if tree.IsParamIncludedIntoSignature(funcdesc.ToTreeRoutineParamClass(param.Class), ret.IsProcedure) { ret.ArgTypes = append(ret.ArgTypes, param.Type) } } diff --git a/pkg/sql/catalog/descpb/structured.proto b/pkg/sql/catalog/descpb/structured.proto index 389284c33ad2..0362504bc24f 100644 --- a/pkg/sql/catalog/descpb/structured.proto +++ b/pkg/sql/catalog/descpb/structured.proto @@ -1551,7 +1551,8 @@ message SchemaDescriptor { optional uint32 id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ID", (gogoproto.casttype) = "ID"]; - // ArgTypes contains only IN / INOUT parameters. + // ArgTypes contains only IN / INOUT parameters when IsProcedure is false, + // and all parameters when IsProcedure is true. repeated sql.sem.types.T arg_types = 2; optional sql.sem.types.T return_type = 3; @@ -1621,7 +1622,8 @@ message FunctionDescriptor { optional uint32 parent_schema_id = 4 [(gogoproto.nullable) = false, (gogoproto.customname) = "ParentSchemaID", (gogoproto.casttype) = "ID"]; - // params represents the list of parameters of the UDF signature. + // params represents the list of parameters, regardless of the parameter + // class, of the UDF signature. repeated Parameter params = 5 [(gogoproto.nullable) = false]; // return_type represents the return type of the UDF signature. diff --git a/pkg/sql/catalog/funcdesc/func_desc.go b/pkg/sql/catalog/funcdesc/func_desc.go index e8dcbdb8ff01..73df0eabd48c 100644 --- a/pkg/sql/catalog/funcdesc/func_desc.go +++ b/pkg/sql/catalog/funcdesc/func_desc.go @@ -720,9 +720,7 @@ func (desc *immutable) ToOverload() (ret *tree.Overload, err error) { var outParamNames []string for _, param := range desc.Params { class := ToTreeRoutineParamClass(param.Class) - if tree.IsInParamClass(class) { - // Only IN parameters should be included into the signature of this - // function overload. + if tree.IsParamIncludedIntoSignature(class, desc.IsProcedure()) { signatureTypes = append(signatureTypes, tree.ParamType{Name: param.Name, Typ: param.Type}) } if tree.IsOutParamClass(class) { diff --git a/pkg/sql/catalog/schemadesc/schema_desc.go b/pkg/sql/catalog/schemadesc/schema_desc.go index ae4bcf7a6740..fc529698c521 100644 --- a/pkg/sql/catalog/schemadesc/schema_desc.go +++ b/pkg/sql/catalog/schemadesc/schema_desc.go @@ -526,6 +526,9 @@ func (desc *immutable) GetResolvedFuncDefinition( if funcDescPb.Signatures[i].ReturnSet { overload.Class = tree.GeneratorClass } + // There is no need to look at the parameter classes since ArgTypes + // already contains only parameters that are included into the + // signature of the overload. paramTypes := make(tree.ParamTypes, 0, len(sig.ArgTypes)) for _, paramType := range sig.ArgTypes { paramTypes = append( diff --git a/pkg/sql/create_function.go b/pkg/sql/create_function.go index 8583591373bc..f68713310f85 100644 --- a/pkg/sql/create_function.go +++ b/pkg/sql/create_function.go @@ -141,7 +141,7 @@ func (n *createFunctionNode) createNewFunction( } signatureTypes := make([]*types.T, 0, len(udfDesc.Params)) for _, param := range udfDesc.Params { - if tree.IsInParamClass(funcdesc.ToTreeRoutineParamClass(param.Class)) { + if tree.IsParamIncludedIntoSignature(funcdesc.ToTreeRoutineParamClass(param.Class), udfDesc.IsProcedure()) { signatureTypes = append(signatureTypes, param.Type) } } diff --git a/pkg/sql/logictest/testdata/logic_test/udf_params b/pkg/sql/logictest/testdata/logic_test/udf_params index 59ffa768f996..5dd6ed8279c4 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_params +++ b/pkg/sql/logictest/testdata/logic_test/udf_params @@ -172,10 +172,6 @@ CREATE FUNCTION f_same_name(OUT a INT, INOUT a INT) IMMUTABLE LANGUAGE SQL AS $$ statement ok CREATE FUNCTION f_same_name(IN a INT, OUT a INT) IMMUTABLE LANGUAGE SQL AS $$ SELECT 1 $$; -# TODO(100405): this should work. -# statement ok -# CREATE FUNCTION f_same_name(IN a INT, OUT a INT) IMMUTABLE LANGUAGE SQL AS $$ SELECT a $$; - query I colnames SELECT f_same_name(2); ---- @@ -188,6 +184,39 @@ SELECT * FROM f_same_name(2); a 1 +statement ok +CREATE OR REPLACE FUNCTION f_same_name(IN a INT, OUT a INT) IMMUTABLE LANGUAGE SQL AS $$ SELECT a $$; + +query I colnames +SELECT f_same_name(2); +---- +f_same_name +2 + +query I colnames +SELECT * FROM f_same_name(2); +---- +a +2 + +statement error pgcode 42703 pq: column "param_out" does not exist +CREATE FUNCTION f_names(IN param_in INT, OUT param_out INT) IMMUTABLE LANGUAGE SQL AS $$ SELECT param_out $$; + +statement ok +CREATE FUNCTION f_names(IN param_in INT, OUT param_out INT) IMMUTABLE LANGUAGE SQL AS $$ SELECT param_in $$; + +query I colnames +SELECT f_names(2); +---- +f_names +2 + +query I colnames +SELECT * FROM f_names(2); +---- +param_out +2 + statement ok CREATE FUNCTION f_out_int(OUT param INT) RETURNS INT AS $$ SELECT 1; $$ LANGUAGE SQL; @@ -381,24 +410,16 @@ param # We can change the order of parameters across IN and OUT "namespaces" as long # as we preserve the right ordering within each "namespace". statement ok -CREATE FUNCTION f_3_in_2_out(IN param1 INT, IN param2 INT, IN param3 INT, OUT param1 INT, OUT param2 INT) AS $$ SELECT (1, 1); $$ LANGUAGE SQL; - -# TODO(100405): this should work. -# statement ok -# CREATE FUNCTION f_3_in_2_out(IN param1 INT, IN param2 INT, IN param3 INT, OUT param1 INT, OUT param2 INT) AS $$ SELECT (param1, param2 + param3); $$ LANGUAGE SQL; +CREATE FUNCTION f_3_in_2_out(IN param1 INT, IN param2 INT, IN param3 INT, OUT param1 INT, OUT param2 INT) AS $$ SELECT (param1, param2 + param3); $$ LANGUAGE SQL; query II colnames SELECT * FROM f_3_in_2_out(2, 2, 2); ---- param1 param2 -1 1 +2 4 statement ok -CREATE OR REPLACE FUNCTION f_3_in_2_out(IN param1 INT, OUT param1 INT, IN param2 INT, IN param3 INT, OUT param2 INT) AS $$ SELECT (1, 1); $$ LANGUAGE SQL; - -# TODO(100405): this should work. -# statement ok -# CREATE OR REPLACE FUNCTION f_3_in_2_out(IN param1 INT, OUT param1 INT, IN param2 INT, IN param3 INT, OUT param2 INT) AS $$ SELECT (param1, param2 + param3); $$ LANGUAGE SQL; +CREATE OR REPLACE FUNCTION f_3_in_2_out(IN param1 INT, OUT param1 INT, IN param2 INT, IN param3 INT, OUT param2 INT) AS $$ SELECT (param1, param2 + param3); $$ LANGUAGE SQL; query T SELECT create_statement FROM [SHOW CREATE FUNCTION f_3_in_2_out]; @@ -410,25 +431,21 @@ CREATE FUNCTION public.f_3_in_2_out(IN param1 INT8, OUT param1 INT8, IN param2 I CALLED ON NULL INPUT LANGUAGE SQL AS $$ - SELECT (1:::INT8, 1:::INT8); + SELECT (param1, param2 + param3); $$ query II colnames SELECT * FROM f_3_in_2_out(2, 2, 2); ---- param1 param2 -1 1 +2 4 # We can also merge some parameters as long as they have the same names. statement error pgcode 42P13 pq: cannot change return type of existing function CREATE OR REPLACE FUNCTION f_3_in_2_out(INOUT param1 INT, IN param2 INT, INOUT param3 INT) AS $$ SELECT (1, 1); $$ LANGUAGE SQL; statement ok -CREATE OR REPLACE FUNCTION f_3_in_2_out(INOUT param1 INT, INOUT param2 INT, IN param3 INT) AS $$ SELECT (1, 1); $$ LANGUAGE SQL; - -# TODO(100405): this should work. -# statement ok -# CREATE OR REPLACE FUNCTION f_3_in_2_out(INOUT param1 INT, INOUT param2 INT, IN param3 INT) AS $$ SELECT (param1, param2 + param3); $$ LANGUAGE SQL; +CREATE OR REPLACE FUNCTION f_3_in_2_out(INOUT param1 INT, INOUT param2 INT, IN param3 INT) AS $$ SELECT (param1, param2 + param3); $$ LANGUAGE SQL; query T SELECT create_statement FROM [SHOW CREATE FUNCTION f_3_in_2_out]; @@ -440,14 +457,14 @@ CREATE FUNCTION public.f_3_in_2_out(INOUT param1 INT8, INOUT param2 INT8, IN par CALLED ON NULL INPUT LANGUAGE SQL AS $$ - SELECT (1:::INT8, 1:::INT8); + SELECT (param1, param2 + param3); $$ query II colnames SELECT * FROM f_3_in_2_out(2, 2, 2); ---- param1 param2 -1 1 +2 4 subtest end diff --git a/pkg/sql/logictest/testdata/logic_test/udf_rewrite b/pkg/sql/logictest/testdata/logic_test/udf_rewrite index b87a80ad224a..e78cca5437ae 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_rewrite +++ b/pkg/sql/logictest/testdata/logic_test/udf_rewrite @@ -93,6 +93,34 @@ SELECT get_body_str('f_rewrite'); statement ok DROP FUNCTION f_rewrite(); +statement ok +CREATE FUNCTION f_rewrite(OUT weekday) AS +$$ + SELECT 'thursday'::weekday; +$$ LANGUAGE SQL + +query T +SELECT get_body_str('f_rewrite'); +---- +"SELECT b'\\xa0':::@100107;" + +statement ok +DROP FUNCTION f_rewrite(); + +statement ok +CREATE FUNCTION f_rewrite(INOUT weekday) AS +$$ + SELECT 'thursday'::weekday; +$$ LANGUAGE SQL + +query T +SELECT get_body_str('f_rewrite'); +---- +"SELECT b'\\xa0':::@100107;" + +statement ok +DROP FUNCTION f_rewrite; + subtest end subtest rewrite_proc diff --git a/pkg/sql/opt/optbuilder/create_function.go b/pkg/sql/opt/optbuilder/create_function.go index 23521417908d..45a47f7b4a59 100644 --- a/pkg/sql/opt/optbuilder/create_function.go +++ b/pkg/sql/opt/optbuilder/create_function.go @@ -151,14 +151,26 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o b.semaCtx.Annotations = oldSemaCtxAnn } - paramNameSeenIn, paramNameSeenOut := make(map[tree.Name]struct{}), make(map[tree.Name]struct{}) - for _, param := range cf.Params { - if param.Name != "" { - if param.IsInParam() { - checkDuplicateParamName(param, paramNameSeenIn) + // TODO(100405): check this logic for procedures. + if language == tree.RoutineLangPLpgSQL { + paramNameSeen := make(map[tree.Name]struct{}) + for _, param := range cf.Params { + if param.Name != "" { + checkDuplicateParamName(param, paramNameSeen) } - if param.IsOutParam() { - checkDuplicateParamName(param, paramNameSeenOut) + } + } else { + // For SQL routines, input and output parameters form separate + // "namespaces". + paramNameSeenIn, paramNameSeenOut := make(map[tree.Name]struct{}), make(map[tree.Name]struct{}) + for _, param := range cf.Params { + if param.Name != "" { + if param.IsInParam() { + checkDuplicateParamName(param, paramNameSeenIn) + } + if param.IsOutParam() { + checkDuplicateParamName(param, paramNameSeenOut) + } } } } @@ -167,11 +179,11 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o // named parameters to the scope so that references to them in the body can // be resolved. bodyScope := b.allocScope() - var paramTypes tree.ParamTypes + // routineParams are all parameters of PLpgSQL routines. + var routineParams []routineParam var outParamTypes []*types.T // When multiple OUT parameters are present, parameter names become the // labels in the output RECORD type. - // TODO(#100405): this needs to be checked for PLpgSQL routines. var outParamNames []string for i := range cf.Params { param := &cf.Params[i] @@ -201,10 +213,12 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o } } - // Add the parameter to the base scope of the body. - paramColName := funcParamColName(param.Name, i) - col := b.synthesizeColumn(bodyScope, paramColName, typ, nil /* expr */, nil /* scalar */) - col.setParamOrd(i) + // Add this parameter to the base scope of the body if needed. + if tree.IsParamIncludedIntoSignature(param.Class, cf.IsProcedure) { + paramColName := funcParamColName(param.Name, i) + col := b.synthesizeColumn(bodyScope, paramColName, typ, nil /* expr */, nil /* scalar */) + col.setParamOrd(i) + } // Collect the user defined type dependencies. typedesc.GetTypeDescriptorClosure(typ).ForEach(func(id descpb.ID) { @@ -213,9 +227,10 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o // Collect the parameters for PLpgSQL routines. if language == tree.RoutineLangPLpgSQL { - paramTypes = append(paramTypes, tree.ParamType{ - Name: param.Name.String(), - Typ: typ, + routineParams = append(routineParams, routineParam{ + name: param.Name, + typ: typ, + class: param.Class, }) } } @@ -325,9 +340,9 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o // the volatility. b.factory.FoldingControl().TemporarilyDisallowStableFolds(func() { plBuilder := newPLpgSQLBuilder( - b, cf.Name.Object(), nil /* colRefs */, paramTypes, funcReturnType, + b, cf.Name.Object(), nil /* colRefs */, routineParams, funcReturnType, ) - stmtScope = plBuilder.buildRootBlock(stmt.AST, bodyScope) + stmtScope = plBuilder.buildRootBlock(stmt.AST, bodyScope, routineParams) }) checkStmtVolatility(targetVolatility, stmtScope, stmt) diff --git a/pkg/sql/opt/optbuilder/plpgsql.go b/pkg/sql/opt/optbuilder/plpgsql.go index 06fdbd6adfa1..e4570877c8bd 100644 --- a/pkg/sql/opt/optbuilder/plpgsql.go +++ b/pkg/sql/opt/optbuilder/plpgsql.go @@ -167,13 +167,25 @@ type plpgsqlBuilder struct { blocks []plBlock identCounter int + + // hasOutParam indicates whether the routine has at least one OUT / INOUT + // parameter. + hasOutParam bool +} + +// routineParam is similar to tree.RoutineParam but stores the resolved type. +type routineParam struct { + name ast.Variable + typ *types.T + class tree.RoutineParamClass + // TODO(100962): populate DefaultVal. } func newPLpgSQLBuilder( ob *Builder, routineName string, colRefs *opt.ColSet, - params []tree.ParamType, + routineParams []routineParam, returnType *types.T, ) *plpgsqlBuilder { const initialBlocksCap = 2 @@ -187,11 +199,18 @@ func newPLpgSQLBuilder( // PL/pgSQL variables. b.pushBlock(plBlock{ label: routineName, - vars: make([]ast.Variable, 0, len(params)), + vars: make([]ast.Variable, 0, len(routineParams)), varTypes: make(map[ast.Variable]*types.T), }) - for _, param := range params { - b.addVariable(ast.Variable(param.Name), param.Typ) + for _, param := range routineParams { + if param.name != "" { + // TODO(119502): unnamed parameters can only be accessed via $i + // notation. + b.addVariable(param.name, param.typ) + } + if tree.IsOutParamClass(param.class) { + b.hasOutParam = true + } } return b } @@ -229,14 +248,25 @@ type plBlock struct { } // buildRootBlock builds a PL/pgSQL routine starting with the root block. -func (b *plpgsqlBuilder) buildRootBlock(astBlock *ast.Block, s *scope) *scope { +func (b *plpgsqlBuilder) buildRootBlock( + astBlock *ast.Block, s *scope, routineParams []routineParam, +) *scope { // Push the scope so that the routine parameters live on a parent scope // instead of the current one. This indicates that the columns are "outer" // columns, which can be referenced but do not originate from an input // expression. If we don't do this, the result would be internal errors due // to Project expressions that try to "pass through" input columns that aren't // actually produced by the input expression. - return b.buildBlock(astBlock, s.push()) + s = s.push() + b.ensureScopeHasExpr(s) + // Initialize OUT parameters to NULL. + for _, param := range routineParams { + if param.class != tree.RoutineParamOut || param.name == "" { + continue + } + s = b.addPLpgSQLAssign(s, param.name, &tree.CastExpr{Expr: tree.DNull, Type: param.typ}) + } + return b.buildBlock(astBlock, s) } // buildBlock constructs an expression that returns the result of executing a @@ -357,6 +387,11 @@ func (b *plpgsqlBuilder) buildPLpgSQLStatements(stmts []ast.Statement, s *scope) return b.buildBlock(t, s) case *ast.Return: + if b.hasOutParam && !t.Implicit { + // TODO(yuzefovich): we should not error out here if we have an + // empty RETURN (which is currently not supported by parser). + panic(returnWithOUTParameterErr) + } // RETURN is handled by projecting a single column with the expression // that is being returned. returnScalar := b.buildPLpgSQLExpr(t.Expr, b.returnType, s) @@ -1758,4 +1793,7 @@ var ( nestedBlockExceptionErr = unimplemented.New("exception handler for nested blocks", "PL/pgSQL blocks cannot yet be nested within a block that has an exception handler", ) + returnWithOUTParameterErr = pgerror.New(pgcode.DatatypeMismatch, + "RETURN cannot have a parameter in function with OUT parameters", + ) ) diff --git a/pkg/sql/opt/optbuilder/routine.go b/pkg/sql/opt/optbuilder/routine.go index e626ecfa35fd..0eec089dfeb3 100644 --- a/pkg/sql/opt/optbuilder/routine.go +++ b/pkg/sql/opt/optbuilder/routine.go @@ -21,7 +21,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" plpgsql "github.com/cockroachdb/cockroach/pkg/sql/plpgsql/parser" "github.com/cockroachdb/cockroach/pkg/sql/sem/cast" - "github.com/cockroachdb/cockroach/pkg/sql/sem/plpgsqltree" + ast "github.com/cockroachdb/cockroach/pkg/sql/sem/plpgsqltree" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sqlerrors" "github.com/cockroachdb/cockroach/pkg/sql/types" @@ -310,22 +310,70 @@ func (b *Builder) buildRoutine( if err != nil { panic(err) } - // Add a RETURN NULL statement if the return type of the function is - // VOID and the last statement is not already a RETURN statement. This - // ensures that all possible code paths lead to a RETURN statement. - // TODO(#108298): There is a parsing bug that affects some PLpgSQL - // functions with VOID return types. - if rtyp.Family() == types.VoidFamily { + var hasReturn bool + if len(stmt.AST.Body) > 0 { lastStmt := stmt.AST.Body[len(stmt.AST.Body)-1] - if _, ok := lastStmt.(*plpgsqltree.Return); !ok { - stmt.AST.Body = append(stmt.AST.Body, &plpgsqltree.Return{Expr: tree.DNull}) + _, hasReturn = lastStmt.(*ast.Return) + } + if !hasReturn { + if rtyp.Family() == types.VoidFamily { + // Add a RETURN NULL statement if the return type of the + // function is VOID and the last statement is not already a + // RETURN statement. This ensures that all possible code paths + // lead to a RETURN statement. + // TODO(#108298): There is a parsing bug that affects some + // PLpgSQL functions with VOID return types. + stmt.AST.Body = append(stmt.AST.Body, &ast.Return{ + Expr: tree.DNull, + Implicit: true, + }) + } else { + // If the last statement is not a RETURN, and we have OUT + // parameters, then we need to add an implicit RETURN statement + // ourselves. + var exprs tree.Exprs + for _, param := range o.RoutineParams { + if param.IsOutParam() { + if param.Name != "" { + exprs = append(exprs, tree.NewUnresolvedName(string(param.Name))) + } else { + // TODO(100962): this logic will likely need to be + // changed. + exprs = append(exprs, tree.DNull) + } + } + } + if len(exprs) > 1 { + stmt.AST.Body = append(stmt.AST.Body, &ast.Return{ + Expr: &tree.Tuple{Exprs: exprs}, + Implicit: true, + }) + } else if len(exprs) == 1 { + stmt.AST.Body = append(stmt.AST.Body, &ast.Return{ + Expr: exprs[0], + Implicit: true, + }) + } } } + routineParams := make([]routineParam, 0, len(o.RoutineParams)) + for _, param := range o.RoutineParams { + // TODO(yuzefovich): can we avoid type resolution here? + typ, err := tree.ResolveType(b.ctx, param.Type, b.semaCtx.TypeResolver) + if err != nil { + panic(err) + } + routineParams = append(routineParams, routineParam{ + name: param.Name, + typ: typ, + class: param.Class, + }) + } + plBuilder := newPLpgSQLBuilder(b, def.Name, colRefs, routineParams, rtyp) + stmtScope := plBuilder.buildRootBlock(stmt.AST, bodyScope, routineParams) + finishResolveType(stmtScope) var expr memo.RelExpr var physProps *physical.Required - plBuilder := newPLpgSQLBuilder(b, def.Name, colRefs, o.Types.(tree.ParamTypes), rtyp) - stmtScope := plBuilder.buildRootBlock(stmt.AST, bodyScope) - finishResolveType(stmtScope) expr, physProps, isMultiColDataSource = b.finishBuildLastStmt(stmtScope, bodyScope, isSetReturning, f) body = []memo.RelExpr{expr} diff --git a/pkg/sql/opt/optbuilder/scope_column.go b/pkg/sql/opt/optbuilder/scope_column.go index 1074acd3c1e3..422ccf7a57d8 100644 --- a/pkg/sql/opt/optbuilder/scope_column.go +++ b/pkg/sql/opt/optbuilder/scope_column.go @@ -289,6 +289,9 @@ func scopeColName(name tree.Name) scopeColumnName { // is not empty. If the given name is empty, the returned scopeColumnName // represents an anonymous function argument that cannot be referenced, and it // will be added to the metadata with the descriptive name "arg". +// TODO(119502): unnamed parameters can be referenced via $i notation (for SQL +// routines only IN / INOUT parameters can be referenced this way, for PLpgSQL +// routines all parameters can). func funcParamColName(name tree.Name, ord int) scopeColumnName { alias := string(name) if alias == "" { diff --git a/pkg/sql/opt/testutils/testcat/function.go b/pkg/sql/opt/testutils/testcat/function.go index 857ff41c091f..fea3772cfcd1 100644 --- a/pkg/sql/opt/testutils/testcat/function.go +++ b/pkg/sql/opt/testutils/testcat/function.go @@ -82,7 +82,7 @@ func (tc *Catalog) CreateRoutine(c *tree.CreateRoutine) { } // Resolve the parameter names and types. - paramTypes := make(tree.ParamTypes, len(c.Params)) + signatureTypes := make(tree.ParamTypes, 0, len(c.Params)) var outParamTypes []*types.T var outParamNames []string for i := range c.Params { @@ -91,7 +91,12 @@ func (tc *Catalog) CreateRoutine(c *tree.CreateRoutine) { if err != nil { panic(err) } - paramTypes.SetAt(i, string(param.Name), typ) + if tree.IsParamIncludedIntoSignature(param.Class, c.IsProcedure) { + signatureTypes = append(signatureTypes, tree.ParamType{ + Name: string(param.Name), + Typ: typ, + }) + } if param.IsOutParam() { outParamTypes = append(outParamTypes, typ) paramName := string(param.Name) @@ -154,7 +159,7 @@ func (tc *Catalog) CreateRoutine(c *tree.CreateRoutine) { tc.currUDFOid++ overload := &tree.Overload{ Oid: tc.currUDFOid, - Types: paramTypes, + Types: signatureTypes, ReturnType: tree.FixedReturnType(retType), Body: body, Volatility: v, diff --git a/pkg/sql/opt/testutils/testcat/testdata/udf b/pkg/sql/opt/testutils/testcat/testdata/udf index e39c49c71c4a..f5a80722591e 100644 --- a/pkg/sql/opt/testutils/testcat/testdata/udf +++ b/pkg/sql/opt/testutils/testcat/testdata/udf @@ -73,7 +73,7 @@ CREATE FUNCTION f_3_in_2_out(IN param1 INT, IN param2 INT, IN param3 INT, OUT pa exec-ddl SHOW CREATE FUNCTION f_3_in_2_out ---- -FUNCTION f_3_in_2_out(param1: int, param2: int, param3: int, param1: int, param2: int) -> tuple{int AS param1, int AS param2} [volatile] +FUNCTION f_3_in_2_out(param1: int, param2: int, param3: int) -> tuple{int AS param1, int AS param2} [volatile] └── SELECT (1, 1) exec-ddl @@ -83,7 +83,7 @@ CREATE FUNCTION f_out_int(OUT param INT) RETURNS INT LANGUAGE SQL AS 'SELECT 1' exec-ddl SHOW CREATE FUNCTION f_out_int ---- -FUNCTION f_out_int(param: int) -> int [volatile] +FUNCTION f_out_int() -> int [volatile] └── SELECT 1 exec-ddl @@ -93,5 +93,5 @@ CREATE FUNCTION f_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) RETURN exec-ddl SHOW CREATE FUNCTION f_default_names ---- -FUNCTION f_default_names(: int, param2: int, : int, : int) -> tuple{int AS column1, int AS param2, int AS column3} [volatile] +FUNCTION f_default_names(: int) -> tuple{int AS column1, int AS param2, int AS column3} [volatile] └── SELECT (1, 2, 3) diff --git a/pkg/sql/schemachanger/scexec/scmutationexec/references.go b/pkg/sql/schemachanger/scexec/scmutationexec/references.go index 04228d8b6c81..19a541411d05 100644 --- a/pkg/sql/schemachanger/scexec/scmutationexec/references.go +++ b/pkg/sql/schemachanger/scexec/scmutationexec/references.go @@ -603,11 +603,9 @@ func (i *immediateVisitor) SetObjectParentID(ctx context.Context, op scop.SetObj IsProcedure: t.IsProcedure(), } for _, p := range t.Params { - if !tree.IsInParamClass(funcdesc.ToTreeRoutineParamClass(p.Class)) { - // Only IN parameters are included into the signature. - continue + if tree.IsParamIncludedIntoSignature(funcdesc.ToTreeRoutineParamClass(p.Class), ol.IsProcedure) { + ol.ArgTypes = append(ol.ArgTypes, p.Type) } - ol.ArgTypes = append(ol.ArgTypes, p.Type) } sc.AddFunction(obj.GetName(), ol) } diff --git a/pkg/sql/sem/plpgsqltree/statements.go b/pkg/sql/sem/plpgsqltree/statements.go index 88f57ddae1c3..b6f7f9d442dc 100644 --- a/pkg/sql/sem/plpgsqltree/statements.go +++ b/pkg/sql/sem/plpgsqltree/statements.go @@ -791,6 +791,9 @@ type Return struct { StatementImpl Expr Expr RetVar Variable + // Implicit is set if this Return statement was not originally in the body + // and was added by us. + Implicit bool } func (s *Return) CopyNode() *Return { diff --git a/pkg/sql/sem/tree/create_routine.go b/pkg/sql/sem/tree/create_routine.go index 9d3ad4ae60dc..2b4f7cf4ba33 100644 --- a/pkg/sql/sem/tree/create_routine.go +++ b/pkg/sql/sem/tree/create_routine.go @@ -407,6 +407,15 @@ func IsInParamClass(class RoutineParamClass) bool { } } +// IsParamIncludedIntoSignature returns whether the parameter of the given class +// is included into the signature of the routine (either a function, when +// isProcedure is false, or a procedure, when isProcedure is true). +func IsParamIncludedIntoSignature(class RoutineParamClass, isProcedure bool) bool { + // For procedures all parameters are included into the signature, for UDFs - + // only IN / INOUT parameters. + return isProcedure || IsInParamClass(class) +} + // IsOutParamClass returns true if the given parameter class specifies an output // parameter (i.e. either OUT or INOUT). func IsOutParamClass(class RoutineParamClass) bool { @@ -502,6 +511,8 @@ func (node RoutineObj) SignatureTypes( typs = make([]*types.T, 0, len(node.Params)) for _, arg := range node.Params { if arg.IsInParam() { + // TODO(100405): we might need to include all parameters for + // procedures here. typ, err := ResolveType(ctx, arg.Type, res) if err != nil { return nil, err diff --git a/pkg/sql/sem/tree/overload.go b/pkg/sql/sem/tree/overload.go index 4476e6bf8650..f788d5c9b572 100644 --- a/pkg/sql/sem/tree/overload.go +++ b/pkg/sql/sem/tree/overload.go @@ -460,12 +460,6 @@ func (p ParamTypes) GetAt(i int) *types.T { return p[i].Typ } -// SetAt is part of the TypeList interface. -func (p ParamTypes) SetAt(i int, name string, t *types.T) { - p[i].Name = name - p[i].Typ = t -} - // Length is part of the TypeList interface. func (p ParamTypes) Length() int { return len(p) From dbb16fb8e7f38ad1dc6950f6f72d0eaf32760d9a Mon Sep 17 00:00:00 2001 From: Yahor Yuzefovich Date: Mon, 4 Mar 2024 18:13:44 +0000 Subject: [PATCH 6/6] roachtest: update pg_regress diff Release note: None --- pkg/cmd/roachtest/testdata/regression.diffs | 762 +++++++++----------- 1 file changed, 354 insertions(+), 408 deletions(-) diff --git a/pkg/cmd/roachtest/testdata/regression.diffs b/pkg/cmd/roachtest/testdata/regression.diffs index b96e2545582a..169b3710c39f 100644 --- a/pkg/cmd/roachtest/testdata/regression.diffs +++ b/pkg/cmd/roachtest/testdata/regression.diffs @@ -60011,10 +60011,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. -+ + +If you would rather not post publicly, please contact us directly +using the support form. - ++ +We appreciate your feedback. + +\df ptest8 @@ -60042,7 +60042,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. -- OUT parameters CREATE PROCEDURE ptest9(OUT a int) LANGUAGE SQL -@@ -219,151 +309,192 @@ +@@ -219,151 +309,188 @@ $$; -- standard way to do a call: CALL ptest9(NULL); @@ -60051,8 +60051,6 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. - 1 -(1 row) - -+ERROR: unknown signature: public.ptest9(unknown) -+HINT: No function matches the given name and argument types. You might need to add explicit type casts. -- you can write an expression, but it's not evaluated CALL ptest9(1/0); -- no error - a @@ -60060,16 +60058,14 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. - 1 -(1 row) - -+ERROR: unknown signature: public.ptest9(decimal) -+HINT: No function matches the given name and argument types. You might need to add explicit type casts. ++ERROR: ptest9(): unsupported binary operator: / (desired ) -- ... and it had better match the type of the parameter CALL ptest9(1./0.); -- error -ERROR: procedure ptest9(numeric) does not exist -LINE 1: CALL ptest9(1./0.); - ^ -HINT: No procedure matches the given name and argument types. You might need to add explicit type casts. -+ERROR: unknown signature: public.ptest9(decimal) -+HINT: No function matches the given name and argument types. You might need to add explicit type casts. ++ERROR: ptest9(): unsupported binary operator: / (desired ) -- check named-parameter matching CREATE PROCEDURE ptest10(OUT a int, IN b int, IN c int) LANGUAGE SQL AS $$ SELECT b - c $$; @@ -60079,8 +60075,6 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. - 3 -(1 row) - -+ERROR: unknown signature: public.ptest10(unknown, int, int) -+HINT: No function matches the given name and argument types. You might need to add explicit type casts. CALL ptest10(a => null, b => 8, c => 2); - a ---- @@ -60140,6 +60134,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. -- check resolution of ambiguous DROP commands CREATE PROCEDURE ptest10(IN a int, IN b int, IN c int) LANGUAGE SQL AS $$ SELECT a + b - c $$; ++ERROR: function "ptest10" already exists with same argument types \df ptest10 - List of functions - Schema | Name | Result data type | Argument data types | Type @@ -60165,12 +60160,14 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. +WHERE p.proname OPERATOR(pg_catalog.~) '^(ptest10)$' COLLATE pg_catalog.default + ^ drop procedure ptest10; -- fail - ERROR: procedure name "ptest10" is not unique +-ERROR: procedure name "ptest10" is not unique -HINT: Specify the argument list to select the procedure unambiguously. drop procedure ptest10(int, int, int); -- fail -ERROR: procedure name "ptest10" is not unique ++ERROR: unknown procedure: ptest10() begin; drop procedure ptest10(out int, int, int); ++ERROR: unknown procedure: ptest10() \df ptest10 - List of functions - Schema | Name | Result data type | Argument data types | Type @@ -60199,7 +60196,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. rollback; begin; drop procedure ptest10(in int, int, int); -+ERROR: procedure ptest10(int,int,int) does not exist ++ERROR: unknown procedure: ptest10() \df ptest10 - List of functions - Schema | Name | Result data type | Argument data types | Type @@ -60323,7 +60320,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_procedure. RESET ROLE; GRANT EXECUTE ON PROCEDURE ptest1(text) TO regress_cp_user1; SET ROLE regress_cp_user1; -@@ -371,13 +502,39 @@ +@@ -371,13 +498,39 @@ RESET ROLE; -- ROUTINE syntax ALTER ROUTINE cp_testfunc1(int) RENAME TO cp_testfunc1a; @@ -64930,12 +64927,12 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_view.out - -ERROR: cannot drop constraint view_base_table_pkey on table view_base_table because other objects depend on it -DETAIL: view key_dependent_view depends on constraint view_base_table_pkey on table view_base_table -HINT: Use DROP ... CASCADE to drop the dependent objects too. -+ERROR: relation "view_base_table" (315): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "view_base_table" (314): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 CREATE VIEW key_dependent_view_no_cols AS SELECT FROM view_base_table GROUP BY key HAVING length(data) > 0; -+ERROR: relation "key_dependent_view_no_cols" (317): table must contain at least 1 column ++ERROR: relation "key_dependent_view_no_cols" (316): table must contain at least 1 column -- -- CREATE OR REPLACE VIEW -- @@ -76835,7 +76832,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/drop_if_exists.ou --- --- role/user/group --- -@@ -68,275 +91,1123 @@ +@@ -68,249 +91,1081 @@ CREATE ROLE regress_test_r1; CREATE GROUP regress_test_g1; DROP USER regress_test_u2; @@ -78014,17 +78011,13 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/drop_if_exists.ou -- cleanup DROP FUNCTION test_ambiguous_funcname(int); DROP FUNCTION test_ambiguous_funcname(text); - -- Likewise for procedures. - CREATE PROCEDURE test_ambiguous_procname(int) as $$ begin end; $$ language plpgsql; -+ERROR: column "\"\"" does not exist +@@ -319,24 +1174,37 @@ CREATE PROCEDURE test_ambiguous_procname(text) as $$ begin end; $$ language plpgsql; -+ERROR: column "\"\"" does not exist DROP PROCEDURE test_ambiguous_procname; --ERROR: procedure name "test_ambiguous_procname" is not unique + ERROR: procedure name "test_ambiguous_procname" is not unique -HINT: Specify the argument list to select the procedure unambiguously. -+ERROR: unknown procedure: test_ambiguous_procname() DROP PROCEDURE IF EXISTS test_ambiguous_procname; --ERROR: procedure name "test_ambiguous_procname" is not unique + ERROR: procedure name "test_ambiguous_procname" is not unique -HINT: Specify the argument list to select the procedure unambiguously. -- Check we get a similar error if we use ROUTINE instead of PROCEDURE. DROP ROUTINE IF EXISTS test_ambiguous_procname; @@ -78037,9 +78030,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/drop_if_exists.ou +HINT: try \h DROP -- cleanup DROP PROCEDURE test_ambiguous_procname(int); -+ERROR: unknown procedure: test_ambiguous_procname() DROP PROCEDURE test_ambiguous_procname(text); -+ERROR: unknown procedure: test_ambiguous_procname() -- This test checks both the functionality of 'if exists' and the syntax -- of the drop database command. drop database test_database_exists (force); @@ -79559,7 +79550,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s -- check display of function arguments in sub-SELECT CREATE TABLE functest1 (i int); CREATE FUNCTION functest_S_16(a int, b int) RETURNS void -@@ -286,220 +420,208 @@ +@@ -286,220 +420,206 @@ BEGIN ATOMIC INSERT INTO functest1 SELECT a + $2; END; @@ -79825,9 +79816,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s RETURNS int LANGUAGE SQL AS 'SELECT $1'; -+ERROR: unimplemented: default value -+HINT: You have attempted to use a feature that is not yet implemented. -+See: https://go.crdb.dev/issue-v/100962/v24.1 ++ERROR: no value provided for placeholder: $1 CREATE FUNCTION functest_IS_3(a int default 1, out b int) RETURNS int LANGUAGE SQL @@ -79905,7 +79894,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s SELECT r0.routine_name, r1.routine_name FROM information_schema.routine_routine_usage rru JOIN information_schema.routines r0 ON r0.specific_name = rru.specific_name -@@ -507,61 +629,63 @@ +@@ -507,61 +627,63 @@ WHERE r0.routine_schema = 'temp_func_test' AND r1.routine_schema = 'temp_func_test' ORDER BY 1, 2; @@ -80001,7 +79990,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s DROP FUNCTION functest1(a int); -- inlining of set-returning functions CREATE TABLE functest3 (a int); -@@ -581,35 +705,38 @@ +@@ -581,35 +703,38 @@ (3 rows) EXPLAIN (verbose, costs off) SELECT * FROM functest_sri1(); @@ -80060,7 +80049,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s -- Check behavior of VOID-returning SQL functions CREATE FUNCTION voidtest1(a int) RETURNS VOID LANGUAGE SQL AS $$ SELECT a + 1 $$; -@@ -621,20 +748,17 @@ +@@ -621,20 +746,17 @@ CREATE FUNCTION voidtest2(a int, b int) RETURNS VOID LANGUAGE SQL AS $$ SELECT voidtest1(a + b) $$; @@ -80089,7 +80078,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s CREATE TEMP TABLE sometable(f1 int); CREATE FUNCTION voidtest3(a int) RETURNS VOID LANGUAGE SQL AS $$ INSERT INTO sometable VALUES(a + 1) $$; -@@ -664,7 +788,8 @@ +@@ -664,7 +786,8 @@ SELECT * FROM voidtest5(3); voidtest5 ----------- @@ -80099,7 +80088,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_function_s -- Regression tests for bugs: -- Check that arguments that are R/W expanded datums aren't corrupted by -@@ -674,70 +799,60 @@ +@@ -674,70 +797,60 @@ CREATE FUNCTION double_append(anyarray, anyelement) RETURNS SETOF anyarray LANGUAGE SQL IMMUTABLE AS $$ SELECT array_append($1, $2) || array_append($1, $2) $$; @@ -90459,7 +90448,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/triggers.out --la -- including that the WHEN clause works create function bark(text) returns bool language plpgsql immutable as $$ begin raise notice '% <- woof!', $1; return true; end; $$; -+ERROR: column "\"\"" does not exist ++ERROR: no value provided for placeholder: $1 create or replace function trigger_notice_ab() returns trigger as $$ begin raise notice 'trigger % on % % % for %: (a,b)=(%,%)', @@ -111971,15 +111960,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- -- test that the aggregate transition logic correctly handles -- transition / combine functions returning NULL -- First test the case of a normal transition function returning NULL -@@ -2701,6 +2437,7 @@ - END IF; - RETURN NULL; - END$$; -+ERROR: duplicate declaration at or near """" - CREATE AGGREGATE balk(int4) - ( - SFUNC = balkifnull(int8, int4), -@@ -2708,12 +2445,14 @@ +@@ -2708,12 +2444,14 @@ PARALLEL = SAFE, INITCOND = '0' ); @@ -111999,7 +111980,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- ROLLBACK; -- Secondly test the case of a parallel aggregate combiner function -- returning NULL. For that use normal transition function, but a -@@ -2730,6 +2469,23 @@ +@@ -2730,6 +2468,23 @@ END IF; RETURN NULL; END$$; @@ -112023,7 +112004,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- CREATE AGGREGATE balk(int4) ( SFUNC = int4_sum(int8, int4), -@@ -2738,26 +2494,27 @@ +@@ -2738,26 +2493,27 @@ PARALLEL = SAFE, INITCOND = '0' ); @@ -112065,7 +112046,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- ROLLBACK; -- test multiple usage of an aggregate whose finalfn returns a R/W datum BEGIN; -@@ -2767,6 +2524,8 @@ +@@ -2767,6 +2523,8 @@ RETURN array_fill(y[1], ARRAY[4]); END; $$; @@ -112074,7 +112055,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- CREATE FUNCTION rwagg_finalfunc(x anyarray) RETURNS anyarray LANGUAGE plpgsql STRICT IMMUTABLE AS $$ DECLARE -@@ -2777,11 +2536,18 @@ +@@ -2777,11 +2535,18 @@ RETURN res; END; $$; @@ -112093,7 +112074,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- CREATE FUNCTION eatarray(x real[]) RETURNS real[] LANGUAGE plpgsql STRICT IMMUTABLE AS $$ BEGIN -@@ -2789,21 +2555,35 @@ +@@ -2789,21 +2554,35 @@ RETURN x; END; $$; @@ -112134,7 +112115,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- -- variance(int4) covers numeric_poly_combine -- sum(int8) covers int8_avg_combine -- regr_count(float8, float8) covers int8inc_float8_float8 and aggregates with > 1 arg -@@ -2813,36 +2593,17 @@ +@@ -2813,36 +2592,17 @@ UNION ALL SELECT * FROM tenk1 UNION ALL SELECT * FROM tenk1 UNION ALL SELECT * FROM tenk1) u; @@ -112177,7 +112158,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- -- variance(int8) covers numeric_combine -- avg(numeric) covers numeric_avg_combine EXPLAIN (COSTS OFF, VERBOSE) -@@ -2851,46 +2612,22 @@ +@@ -2851,46 +2611,22 @@ UNION ALL SELECT * FROM tenk1 UNION ALL SELECT * FROM tenk1 UNION ALL SELECT * FROM tenk1) u; @@ -112232,7 +112213,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- -- Ensure that the STRICT checks for aggregates does not take NULLness -- of ORDER BY columns into account. See bug report around -- 2a505161-2727-2473-7c46-591ed108ac52@email.cz -@@ -2929,27 +2666,46 @@ +@@ -2929,27 +2665,46 @@ -- does not lead to array overflow due to unexpected duplicate hash keys -- see CAFeeJoKKu0u+A_A9R9316djW-YW3-+Gtgvy3ju655qRHR3jtdA@mail.gmail.com set enable_memoize to off; @@ -112291,7 +112272,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- select unique1, count(*), sum(twothousand) from tenk1 group by unique1 having sum(fivethous) > 4975 -@@ -3007,12 +2763,48 @@ +@@ -3007,12 +2762,48 @@ (48 rows) set work_mem to default; @@ -112340,7 +112321,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- create table agg_data_2k as select g from generate_series(0, 1999) g; analyze agg_data_2k; -@@ -3021,19 +2813,28 @@ +@@ -3021,19 +2812,28 @@ analyze agg_data_20k; -- Produce results with sorting. set enable_hashagg = false; @@ -112378,7 +112359,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- create table agg_group_1 as select g%10000 as c1, sum(g::numeric) as c2, count(*) as c3 from agg_data_20k group by g%10000; -@@ -3048,6 +2849,7 @@ +@@ -3048,6 +2848,7 @@ where g < r.a group by g/2) as s; set jit_above_cost to default; @@ -112386,7 +112367,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- create table agg_group_3 as select (g/2)::numeric as c1, sum(7::int4) as c2, count(*) as c3 from agg_data_2k group by g/2; -@@ -3056,18 +2858,41 @@ +@@ -3056,18 +2857,41 @@ from agg_data_2k group by g/2; -- Produce results with hash aggregation set enable_hashagg = true; @@ -112435,7 +112416,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- create table agg_hash_1 as select g%10000 as c1, sum(g::numeric) as c2, count(*) as c3 from agg_data_20k group by g%10000; -@@ -3082,6 +2907,7 @@ +@@ -3082,6 +2906,7 @@ where g < r.a group by g/2) as s; set jit_above_cost to default; @@ -112443,7 +112424,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/aggregates.out -- create table agg_hash_3 as select (g/2)::numeric as c1, sum(7::int4) as c2, count(*) as c3 from agg_data_2k group by g/2; -@@ -3089,7 +2915,31 @@ +@@ -3089,7 +2914,31 @@ select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3 from agg_data_2k group by g/2; set enable_sort = true; @@ -131010,10 +130991,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/generated.out --l -(0 rows) + attrelid | attname | attgenerated +------------+--------------------------+-------------- -+ 3931264561 | crdb_internal_idx_expr | v ++ 2586187552 | crdb_internal_idx_expr | v + 4046462210 | crdb_internal_idx_expr | v + 4046462212 | crdb_internal_idx_expr_1 | v -+ 1135731663 | crdb_internal_idx_expr | v ++ 875995384 | crdb_internal_idx_expr | v +(4 rows) CREATE TABLE gtest0 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (55) STORED); @@ -143251,7 +143232,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/privileges.out -- CREATE FUNCTION leak2(integer,integer) RETURNS boolean AS $$begin raise notice 'leak % %', $1, $2; return $1 > $2; end$$ LANGUAGE plpgsql immutable; -+ERROR: duplicate declaration at or near """" ++ERROR: no value provided for placeholder: $1 CREATE OPERATOR >>> (procedure = leak2, leftarg = integer, rightarg = integer, restrict = scalargtsel); +ERROR: at or near ">": syntax error: unimplemented: this syntax @@ -158400,7 +158381,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/merge.out --label -- remove constraints alter table target drop CONSTRAINT target_pkey; -+ERROR: relation "target" (1236): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "target" (1237): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 alter table target alter column tid drop not null; @@ -160561,7 +160542,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_table_like CREATE TABLE inhf (LIKE inhx, LIKE inhx); /* Throw error */ -ERROR: column "xx" specified more than once -+ERROR: relation "inhf" (1266): duplicate column name: "xx" ++ERROR: relation "inhf" (1267): duplicate column name: "xx" CREATE TABLE inhf (LIKE inhx INCLUDING DEFAULTS INCLUDING CONSTRAINTS); INSERT INTO inhf DEFAULT VALUES; SELECT * FROM inhf; /* Single entry with value 'text' */ @@ -161360,7 +161341,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/create_table_like diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/collate.linux.utf8_1.out --label=/mnt/data1/postgres/src/test/regress/results/collate.linux.utf8.out /mnt/data1/postgres/src/test/regress/expected/collate.linux.utf8_1.out /mnt/data1/postgres/src/test/regress/results/collate.linux.utf8.out --- /mnt/data1/postgres/src/test/regress/expected/collate.linux.utf8_1.out +++ /mnt/data1/postgres/src/test/regress/results/collate.linux.utf8.out -@@ -7,5 +7,923 @@ +@@ -7,5 +7,922 @@ (SELECT count(*) FROM pg_collation WHERE collname IN ('de_DE', 'en_US', 'sv_SE', 'tr_TR') AND collencoding = pg_char_to_encoding('UTF8')) <> 4 OR version() !~ 'linux-gnu' AS skip_test \gset @@ -161860,7 +161841,6 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/collate.linux.utf + AS $$ select $1 < $2 limit 1 $$; +CREATE FUNCTION mylt_plpgsql (text, text) RETURNS boolean LANGUAGE plpgsql + AS $$ begin return $1 < $2; end $$; -+ERROR: duplicate declaration at or near """" +SELECT a.b AS a, b.b AS b, a.b < b.b AS lt, + mylt(a.b, b.b), mylt_noninline(a.b, b.b), mylt_plpgsql(a.b, b.b) +FROM collate_test1 a, collate_test1 b @@ -162287,7 +162267,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/collate.linux.utf diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/collate.windows.win1252_1.out --label=/mnt/data1/postgres/src/test/regress/results/collate.windows.win1252.out /mnt/data1/postgres/src/test/regress/expected/collate.windows.win1252_1.out /mnt/data1/postgres/src/test/regress/results/collate.windows.win1252.out --- /mnt/data1/postgres/src/test/regress/expected/collate.windows.win1252_1.out +++ /mnt/data1/postgres/src/test/regress/results/collate.windows.win1252.out -@@ -9,5 +9,813 @@ +@@ -9,5 +9,812 @@ (SELECT count(*) FROM pg_collation WHERE collname IN ('de_DE', 'en_US', 'sv_SE') AND collencoding = pg_char_to_encoding('WIN1252')) <> 3 OR (version() !~ 'Visual C\+\+' AND version() !~ 'mingw32' AND version() !~ 'windows') AS skip_test \gset @@ -162680,7 +162660,6 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/collate.windows.w + AS $$ select $1 < $2 limit 1 $$; +CREATE FUNCTION mylt_plpgsql (text, text) RETURNS boolean LANGUAGE plpgsql + AS $$ begin return $1 < $2; end $$; -+ERROR: duplicate declaration at or near """" +SELECT a.b AS a, b.b AS b, a.b < b.b AS lt, + mylt(a.b, b.b), mylt_noninline(a.b, b.b), mylt_plpgsql(a.b, b.b) +FROM collate_test1 a, collate_test1 b @@ -173132,7 +173111,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/stats_ext.out --l CREATE FUNCTION op_leak(int, int) RETURNS bool AS 'BEGIN RAISE NOTICE ''op_leak => %, %'', $1, $2; RETURN $1 < $2; END' LANGUAGE plpgsql; -+ERROR: duplicate declaration at or near """" ++ERROR: no value provided for placeholder: $1 CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int, restrict = scalarltsel); +ERROR: at or near "<": syntax error: unimplemented: this syntax @@ -183830,7 +183809,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/functional_deps.o -ERROR: cannot drop constraint articles_pkey on table articles because other objects depend on it -DETAIL: view fdv1 depends on constraint articles_pkey on table articles -HINT: Use DROP ... CASCADE to drop the dependent objects too. -+ERROR: relation "articles" (1516): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "articles" (1519): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 DROP VIEW fdv1; @@ -183843,14 +183822,14 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/functional_deps.o -ERROR: cannot drop constraint articles_pkey on table articles because other objects depend on it -DETAIL: view fdv2 depends on constraint articles_pkey on table articles -HINT: Use DROP ... CASCADE to drop the dependent objects too. -+ERROR: relation "articles" (1516): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "articles" (1519): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 ALTER TABLE articles_in_category DROP CONSTRAINT articles_in_category_pkey RESTRICT; --fail -ERROR: cannot drop constraint articles_in_category_pkey on table articles_in_category because other objects depend on it -DETAIL: view fdv2 depends on constraint articles_in_category_pkey on table articles_in_category -HINT: Use DROP ... CASCADE to drop the dependent objects too. -+ERROR: relation "articles_in_category" (1517): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "articles_in_category" (1520): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 DROP VIEW fdv2; @@ -183863,7 +183842,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/functional_deps.o -ERROR: cannot drop constraint articles_pkey on table articles because other objects depend on it -DETAIL: view fdv3 depends on constraint articles_pkey on table articles -HINT: Use DROP ... CASCADE to drop the dependent objects too. -+ERROR: relation "articles" (1516): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "articles" (1519): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 DROP VIEW fdv3; @@ -183873,7 +183852,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/functional_deps.o -ERROR: cannot drop constraint articles_pkey on table articles because other objects depend on it -DETAIL: view fdv4 depends on constraint articles_pkey on table articles -HINT: Use DROP ... CASCADE to drop the dependent objects too. -+ERROR: relation "articles" (1516): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "articles" (1519): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 DROP VIEW fdv4; @@ -183883,7 +183862,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/functional_deps.o (0 rows) ALTER TABLE articles DROP CONSTRAINT articles_pkey RESTRICT; -+ERROR: relation "articles" (1516): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "articles" (1519): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 EXECUTE foo; -- fail @@ -224292,7 +224271,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- sql, proretset = t, prorettype = record CREATE FUNCTION getrngfunc7(int) RETURNS setof record AS 'SELECT * FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL; SELECT * FROM getrngfunc7(1) AS t1(rngfuncid int, rngfuncsubid int, rngfuncname text); -@@ -544,143 +445,119 @@ +@@ -544,143 +445,126 @@ (2 rows) SELECT * FROM ROWS FROM( getrngfunc7(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text) ) WITH ORDINALITY; @@ -224346,21 +224325,20 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- +ERROR: relation "vw_getrngfunc" does not exist -- plpgsql, proretset = f, prorettype = b CREATE FUNCTION getrngfunc8(int) RETURNS int AS 'DECLARE rngfuncint int; BEGIN SELECT rngfuncid into rngfuncint FROM rngfunc WHERE rngfuncid = $1; RETURN rngfuncint; END;' LANGUAGE plpgsql; -+ERROR: column "\"\"" does not exist SELECT * FROM getrngfunc8(1) AS t1; -- t1 ------ + t1 + ---- - 1 --(1 row) -- -+ERROR: unknown function: getrngfunc8() ++ + (1 row) + SELECT * FROM getrngfunc8(1) WITH ORDINALITY AS t1(v,o); -- v | o -----+--- + v | o + ---+--- - 1 | 1 --(1 row) -- -+ERROR: unknown function: getrngfunc8() ++ | 1 + (1 row) + CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc8(1); +ERROR: unknown function: getrngfunc8() +HINT: There is probably a typo in function name. Or the intention was to use a user-defined function in the view query, which is currently not supported. @@ -224502,17 +224480,15 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- DROP FUNCTION getrngfunc1(int); DROP FUNCTION getrngfunc2(int); DROP FUNCTION getrngfunc3(int); -@@ -689,7 +566,9 @@ - DROP FUNCTION getrngfunc6(int); +@@ -690,6 +574,7 @@ DROP FUNCTION getrngfunc7(int); DROP FUNCTION getrngfunc8(int); -+ERROR: unknown function: getrngfunc8() DROP FUNCTION getrngfunc9(int); +ERROR: unknown function: getrngfunc9() DROP FUNCTION rngfunct(int); DROP TABLE rngfunc2; DROP TABLE rngfunc; -@@ -700,6 +579,9 @@ +@@ -700,6 +585,9 @@ CREATE FUNCTION rngfunc_sql(int,int) RETURNS setof rngfunc_rescan_t AS 'SELECT i, nextval(''rngfunc_rescan_seq1'') FROM generate_series($1,$2) i;' LANGUAGE SQL; -- plpgsql functions use materialize mode CREATE FUNCTION rngfunc_mat(int,int) RETURNS setof rngfunc_rescan_t AS 'begin for i in $1..$2 loop return next (i, nextval(''rngfunc_rescan_seq2'')); end loop; end;' LANGUAGE plpgsql; @@ -224522,7 +224498,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- --invokes ExecReScanFunctionScan - all these cases should materialize the function only once -- LEFT JOIN on a condition that the planner can't prove to be true is used to ensure the function -- is on the inner path of a nestloop join -@@ -750,19 +632,7 @@ +@@ -750,19 +638,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN rngfunc_mat(11,13) ON (r+i)<100; @@ -224543,7 +224519,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -770,19 +640,7 @@ +@@ -770,19 +646,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN rngfunc_mat(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100; @@ -224564,7 +224540,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -790,30 +648,18 @@ +@@ -790,30 +654,18 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN ROWS FROM( rngfunc_sql(11,13), rngfunc_mat(11,13) ) WITH ORDINALITY AS f(i1,s1,i2,s2,o) ON (r+i1+i2)<100; @@ -224600,7 +224576,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- 3 | 13 (9 rows) -@@ -821,13 +667,13 @@ +@@ -821,13 +673,13 @@ r | i | o ---+----+--- 1 | 11 | 1 @@ -224618,7 +224594,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- 3 | 13 | 3 (9 rows) -@@ -977,16 +823,7 @@ +@@ -977,16 +829,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(10+r,13); @@ -224636,7 +224612,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -994,16 +831,7 @@ +@@ -994,16 +837,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(10+r,13) WITH ORDINALITY AS f(i,s,o); @@ -224654,7 +224630,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1011,16 +839,7 @@ +@@ -1011,16 +845,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(11,10+r); @@ -224672,7 +224648,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1028,16 +847,7 @@ +@@ -1028,16 +853,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(11,10+r) WITH ORDINALITY AS f(i,s,o); @@ -224690,7 +224666,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1045,20 +855,7 @@ +@@ -1045,20 +861,7 @@ (1 row) SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), rngfunc_mat(r1,r2); @@ -224712,7 +224688,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1066,20 +863,7 @@ +@@ -1066,20 +869,7 @@ (1 row) SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), rngfunc_mat(r1,r2) WITH ORDINALITY AS f(i,s,o); @@ -224734,7 +224710,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- selective rescan of multiple functions: SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval -@@ -1088,16 +872,7 @@ +@@ -1088,16 +878,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( rngfunc_sql(11,11), rngfunc_mat(10+r,13) ); @@ -224752,7 +224728,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1105,16 +880,7 @@ +@@ -1105,16 +886,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( rngfunc_sql(10+r,13), rngfunc_mat(11,11) ); @@ -224770,7 +224746,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1122,16 +888,7 @@ +@@ -1122,16 +894,7 @@ (1 row) SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( rngfunc_sql(10+r,13), rngfunc_mat(10+r,13) ); @@ -224788,7 +224764,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false); setval | setval --------+-------- -@@ -1139,23 +896,7 @@ +@@ -1139,23 +902,7 @@ (1 row) SELECT * FROM generate_series(1,2) r1, generate_series(r1,3) r2, ROWS FROM( rngfunc_sql(10+r1,13), rngfunc_mat(10+r2,13) ); @@ -224813,7 +224789,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT * FROM (VALUES (1),(2),(3)) v(r), generate_series(10+r,20-r) f(i); r | i ---+---- -@@ -1243,31 +984,31 @@ +@@ -1243,31 +990,31 @@ r1 | r1 | r2 | i ----+----+----+---- 1 | 1 | 10 | 21 @@ -224863,7 +224839,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- 3 | 3 | 30 | 23 (27 rows) -@@ -1302,95 +1043,47 @@ +@@ -1302,95 +1049,47 @@ r1 | r1 | r2 | i ----+----+----+---- 1 | 1 | 10 | 10 @@ -224982,7 +224958,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- check handling of FULL JOIN with multiple lateral references (bug #15741) SELECT * FROM (VALUES (1),(2)) v1(r1) -@@ -1404,20 +1097,10 @@ +@@ -1404,20 +1103,10 @@ ) AS ss1 ON TRUE FULL JOIN generate_series(1, v1.r1) AS gs4 ON FALSE ) AS ss0 ON TRUE; @@ -225005,7 +224981,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- DROP SEQUENCE rngfunc_rescan_seq1; DROP SEQUENCE rngfunc_rescan_seq2; -- -@@ -1449,7 +1132,7 @@ +@@ -1449,7 +1138,7 @@ -- error, wrong result type CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int) RETURNS float AS 'select $1+1' LANGUAGE sql; @@ -225014,7 +224990,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- with multiple OUT params you must get a RECORD result CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int, out f3 text) RETURNS int AS 'select $1+1' LANGUAGE sql; -@@ -1457,8 +1140,8 @@ +@@ -1457,8 +1146,8 @@ CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int, out f3 text) RETURNS record AS 'select $1+1' LANGUAGE sql; @@ -225025,7 +225001,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- CREATE OR REPLACE FUNCTION rngfuncr(in f1 int, out f2 int, out text) AS $$select $1-1, $1::text || 'z'$$ LANGUAGE sql; SELECT f1, rngfuncr(f1) FROM int4_tbl; -@@ -1478,23 +1161,11 @@ +@@ -1478,23 +1167,11 @@ (1 row) SELECT * FROM rngfuncr(42) AS p(a,b); @@ -225051,7 +225027,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- SELECT * FROM rngfuncb(42, 99); f2 | column2 ----+--------- -@@ -1502,11 +1173,7 @@ +@@ -1502,11 +1179,7 @@ (1 row) SELECT * FROM rngfuncb(42, 99) AS p(a,b); @@ -225064,7 +225040,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- Can reference function with or without OUT params for DROP, etc DROP FUNCTION rngfunc(int); DROP FUNCTION rngfuncr(in f2 int, out f1 int, out text); -@@ -1523,24 +1190,23 @@ +@@ -1523,24 +1196,23 @@ (1 row) SELECT dup('xyz'); -- fails @@ -225095,7 +225071,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- DROP FUNCTION dup(anyelement); -- equivalent behavior, though different name exposed for input arg CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray) -@@ -1555,133 +1221,108 @@ +@@ -1555,133 +1227,108 @@ -- fails, no way to deduce outputs CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray) AS 'select $1, array[$1,$1]' LANGUAGE sql; @@ -225275,7 +225251,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (2 rows) -- insert will execute to completion even if function needs just 1 row -@@ -1691,16 +1332,16 @@ +@@ -1691,16 +1338,16 @@ select insert_tt('fool'); insert_tt ----------- @@ -225297,7 +225273,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (4 rows) -- setof does what's expected -@@ -1710,50 +1351,50 @@ +@@ -1710,50 +1357,50 @@ select insert_tt2('foolish','barrish'); insert_tt2 ------------ @@ -225371,7 +225347,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (10 rows) -- triggers will fire, too -@@ -1762,72 +1403,88 @@ +@@ -1762,72 +1409,88 @@ raise notice 'noticetrigger % %', new.f1, new.data; return null; end $$ language plpgsql; @@ -225497,7 +225473,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- test case for a whole-row-variable bug create function rngfunc1(n integer, out a text, out b text) -@@ -1835,6 +1492,18 @@ +@@ -1835,6 +1498,18 @@ language sql as $$ select 'foo ' || i, 'bar ' || i from generate_series(1,$1) i $$; set work_mem='64kB'; @@ -225516,7 +225492,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- select t.a, t, t.a from rngfunc1(10000) t limit 1; a | t | a -------+-------------------+------- -@@ -1842,6 +1511,18 @@ +@@ -1842,6 +1517,18 @@ (1 row) reset work_mem; @@ -225535,7 +225511,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- select t.a, t, t.a from rngfunc1(10000) t limit 1; a | t | a -------+-------------------+------- -@@ -1871,31 +1552,24 @@ +@@ -1871,31 +1558,24 @@ select * from array_to_set(array['one', 'two']); -- fail ERROR: a column definition list is required for functions returning "record" @@ -225579,7 +225555,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- but without, it can be: create or replace function array_to_set(anyarray) returns setof record as $$ select i AS "index", $1[i] AS "value" from generate_subscripts($1, 1) i -@@ -1914,26 +1588,21 @@ +@@ -1914,26 +1594,21 @@ 2 | two (2 rows) @@ -225618,7 +225594,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- create temp table rngfunc(f1 int8, f2 int8); create function testrngfunc() returns record as $$ insert into rngfunc values (1,2) returning *; -@@ -1952,8 +1621,6 @@ +@@ -1952,8 +1627,6 @@ select * from testrngfunc(); -- fail ERROR: a column definition list is required for functions returning "record" @@ -225627,7 +225603,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- drop function testrngfunc(); create function testrngfunc() returns setof record as $$ insert into rngfunc values (1,2), (3,4) returning *; -@@ -1974,8 +1641,6 @@ +@@ -1974,8 +1647,6 @@ select * from testrngfunc(); -- fail ERROR: a column definition list is required for functions returning "record" @@ -225636,7 +225612,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- drop function testrngfunc(); -- Check that typmod imposed by a composite type is honored create type rngfunc_type as (f1 numeric(35,6), f2 numeric(35,2)); -@@ -1984,31 +1649,28 @@ +@@ -1984,31 +1655,28 @@ $$ language sql immutable; explain (verbose, costs off) select testrngfunc(); @@ -225684,7 +225660,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (1 row) create or replace function testrngfunc() returns rngfunc_type as $$ -@@ -2016,31 +1678,28 @@ +@@ -2016,31 +1684,28 @@ $$ language sql volatile; explain (verbose, costs off) select testrngfunc(); @@ -225732,7 +225708,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (1 row) drop function testrngfunc(); -@@ -2049,31 +1708,28 @@ +@@ -2049,31 +1714,28 @@ $$ language sql immutable; explain (verbose, costs off) select testrngfunc(); @@ -225780,7 +225756,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (1 row) create or replace function testrngfunc() returns setof rngfunc_type as $$ -@@ -2081,93 +1737,72 @@ +@@ -2081,93 +1743,72 @@ $$ language sql volatile; explain (verbose, costs off) select testrngfunc(); @@ -225916,7 +225892,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- -- Check some cases involving added/dropped columns in a rowtype result -- -@@ -2178,79 +1813,37 @@ +@@ -2178,79 +1819,37 @@ create or replace function get_first_user() returns users as $$ SELECT * FROM users ORDER BY userid LIMIT 1; $$ language sql stable; @@ -226009,7 +225985,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- We used to have a bug that would allow the above to succeed, posing -- hazards for later execution of the view. Check that the internal -- defenses for those hazards haven't bit-rotted, in case some other -@@ -2264,18 +1857,17 @@ +@@ -2264,18 +1863,17 @@ returning pg_describe_object(classid, objid, objsubid) as obj, pg_describe_object(refclassid, refobjid, refobjsubid) as ref, deptype; @@ -226035,7 +226011,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- -- likewise, check we don't crash if the dependency goes wrong begin; -- destroy the dependency entry that prevents the ALTER: -@@ -2286,19 +1878,18 @@ +@@ -2286,19 +1884,18 @@ returning pg_describe_object(classid, objid, objsubid) as obj, pg_describe_object(refclassid, refobjid, refobjsubid) as ref, deptype; @@ -226061,7 +226037,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- drop table users; -- check behavior with type coercion required for a set-op create or replace function rngfuncbar() returns setof text as -@@ -2320,17 +1911,11 @@ +@@ -2320,17 +1917,11 @@ -- this function is now inlinable, too: explain (verbose, costs off) select * from rngfuncbar(); @@ -226084,7 +226060,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- drop function rngfuncbar(); -- check handling of a SQL function with multiple OUT params (bug #5777) create or replace function rngfuncbar(out integer, out numeric) as -@@ -2344,115 +1929,182 @@ +@@ -2344,115 +1935,182 @@ create or replace function rngfuncbar(out integer, out numeric) as $$ select (1, 2) $$ language sql; select * from rngfuncbar(); -- fail @@ -226340,7 +226316,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/rangefuncs.out -- (0 rows) drop type rngfunc2; -@@ -2463,25 +2115,16 @@ +@@ -2463,25 +2121,16 @@ from unnest(array['{"lectures": [{"id": "1"}]}'::jsonb]) as unnested_modules(module)) as ss, jsonb_to_recordset(ss.lecture) as j (id text); @@ -228839,7 +228815,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/alter_table.out - ALTER TABLE attmp3 VALIDATE CONSTRAINT b_le_20; -- succeeds -- An already validated constraint must not be revalidated CREATE FUNCTION boo(int) RETURNS int IMMUTABLE STRICT LANGUAGE plpgsql AS $$ BEGIN RAISE NOTICE 'boo: %', $1; RETURN $1; END; $$; -+ERROR: column "\"\"" does not exist ++ERROR: no value provided for placeholder: $1 INSERT INTO attmp7 VALUES (8, 18); +ERROR: relation "attmp7" does not exist ALTER TABLE attmp7 ADD CONSTRAINT identity CHECK (b = boo(b)); @@ -229668,7 +229644,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/alter_table.out - -ERROR: column "test" is in a primary key +ERROR: column "test" is in a primary index alter table atacc1 drop constraint "atacc1_pkey"; -+ERROR: relation "atacc1" (1876): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "atacc1" (1880): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 alter table atacc1 alter column test drop not null; @@ -233231,13 +233207,13 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/alter_table.out - +ERROR: index with name "tt9_c_key" already exists ALTER TABLE tt9 ADD CONSTRAINT foo UNIQUE(c); -- fail, dup name -ERROR: constraint "foo" for relation "tt9" already exists -+ERROR: error executing StatementPhase stage 1 of 1 with 7 MutationType ops: relation "tt9" (1970): duplicate constraint name: "foo" ++ERROR: error executing StatementPhase stage 1 of 1 with 7 MutationType ops: relation "tt9" (1974): duplicate constraint name: "foo" ALTER TABLE tt9 ADD CONSTRAINT tt9_c_key CHECK(c > 5); -- fail, dup name -ERROR: constraint "tt9_c_key" for relation "tt9" already exists -+ERROR: error executing StatementPhase stage 1 of 1 with 2 MutationType ops: relation "tt9" (1970): duplicate constraint name: "tt9_c_key" ++ERROR: error executing StatementPhase stage 1 of 1 with 2 MutationType ops: relation "tt9" (1974): duplicate constraint name: "tt9_c_key" ALTER TABLE tt9 ADD CONSTRAINT tt9_c_key2 CHECK(c > 6); ALTER TABLE tt9 ADD UNIQUE(c); -- picks nonconflicting name -+ERROR: error executing StatementPhase stage 1 of 1 with 7 MutationType ops: relation "tt9" (1970): duplicate constraint name: "tt9_c_key2" ++ERROR: error executing StatementPhase stage 1 of 1 with 7 MutationType ops: relation "tt9" (1974): duplicate constraint name: "tt9_c_key2" \d tt9 - Table "public.tt9" - Column | Type | Collation | Nullable | Default @@ -233415,7 +233391,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/alter_table.out - DELETE FROM old_system_table WHERE othercol = 'somedata'; TRUNCATE old_system_table; ALTER TABLE old_system_table DROP CONSTRAINT new_system_table_pkey; -+ERROR: relation "old_system_table" (1973): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction ++ERROR: relation "old_system_table" (1977): unimplemented: primary key dropped without subsequent addition of new primary key in same transaction +HINT: You have attempted to use a feature that is not yet implemented. +See: https://go.crdb.dev/issue-v/48026/v24.1 ALTER TABLE old_system_table DROP COLUMN othercol; @@ -237068,7 +237044,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out raise notice 'bleat %', $1; return $1; end$$ language plpgsql; -+ERROR: column "\"\"" does not exist ++ERROR: no value provided for placeholder: $1 create function sql_if(bool, anyelement, anyelement) returns anyelement as $$ select case when $1 then $2 else $3 end $$ language sql; -- Note this would fail with integer overflow, never mind wrong bleat() output, @@ -237648,7 +237624,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out (1 row) select pg_typeof(array[1.2,55.5]); -- numeric[] -@@ -1122,252 +1455,226 @@ +@@ -1122,252 +1455,224 @@ (1 row) select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input @@ -237713,9 +237689,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out create function dfunc(a int = 1, out sum int, b int = 2) as $$ select $1 + $2; $$ language sql; -+ERROR: unimplemented: default value -+HINT: You have attempted to use a feature that is not yet implemented. -+See: https://go.crdb.dev/issue-v/100962/v24.1 ++ERROR: no value provided for placeholder: $2 select dfunc(); - dfunc -------- @@ -238026,7 +238000,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out -- but this works since the ambiguous functions aren't preferred anyway select dfunc('Hi'); dfunc -@@ -1376,7 +1683,9 @@ +@@ -1376,7 +1681,9 @@ (1 row) drop function dfunc(int, int, int); @@ -238036,7 +238010,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out drop function dfunc(text); -- -- Tests for named- and mixed-notation function calling -@@ -1385,185 +1694,159 @@ +@@ -1385,185 +1692,156 @@ returns table (a int, b int, c int, d int) as $$ select $1, $2, $3, $4; $$ language sql; @@ -238233,8 +238207,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out returns record as $$ select $1, $2; $$ language sql; -+ERROR: return type mismatch in function declared to return record -+DETAIL: Final statement returns varchar instead of decimal at column 2 ++ERROR: no value provided for placeholder: $2 select (dfunc()).*; - _a | _c --------+---- @@ -238310,22 +238283,20 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out $$ language sql; -ERROR: cannot change name of input parameter "c" -HINT: Use DROP FUNCTION dfunc(character varying,numeric) first. -+ERROR: return type mismatch in function declared to return record -+DETAIL: Final statement returns varchar instead of decimal at column 2 ++ERROR: no value provided for placeholder: $2 create or replace function dfunc(a varchar = 'def a', out _a varchar, numeric = NULL, out _c numeric) returns record as $$ select $1, $2; $$ language sql; -ERROR: cannot change name of input parameter "c" -HINT: Use DROP FUNCTION dfunc(character varying,numeric) first. -+ERROR: return type mismatch in function declared to return record -+DETAIL: Final statement returns varchar instead of decimal at column 2 ++ERROR: no value provided for placeholder: $2 drop function dfunc(varchar, numeric); +ERROR: unknown function: dfunc() --fail, named parameters are not unique create function testpolym(a int, a int) returns int as $$ select 1;$$ language sql; ERROR: parameter name "a" used more than once -@@ -1583,189 +1866,149 @@ +@@ -1583,189 +1861,149 @@ drop function testpolym(int); create function testpolym(a int) returns table(a int) as $$ select $1;$$ language sql; @@ -238620,7 +238591,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out -- need DO to protect the -- from psql do $$ declare r integer; -@@ -1775,40 +2018,38 @@ +@@ -1775,40 +2013,38 @@ raise info 'r = %', r; end; $$; @@ -238683,7 +238654,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/polymorphism.out -- -- Tests for ANYCOMPATIBLE polymorphism family -- -@@ -1816,283 +2057,213 @@ +@@ -1816,283 +2052,213 @@ returns anycompatible as $$ select greatest($1, $2) $$ language sql; @@ -245181,11 +245152,12 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- The following tests are unrelated to the scenario outlined above; -- they merely exercise specific parts of PL/pgSQL -@@ -1564,12 +1866,9 @@ +@@ -1564,12 +1866,10 @@ END IF; RETURN rslt; END;' LANGUAGE plpgsql; -+ERROR: duplicate declaration at or near """" ++ERROR: unknown function: recursion_test() ++HINT: There is probably a typo in function name. Or the intention was to use a user-defined function in the function body, which is currently not supported. SELECT recursion_test(4,3); - recursion_test ----------------- @@ -245196,7 +245168,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test the FOUND magic variable -- -@@ -1609,22 +1908,44 @@ +@@ -1609,22 +1909,44 @@ end if; return true; end;' language plpgsql; @@ -245227,14 +245199,14 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + for i in 1 .. 10 loop + ^ +HINT: You have attempted to use a feature that is not yet implemented. - ++ +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. + +If you would rather not post publicly, please contact us directly +using the support form. -+ + +We appreciate your feedback. + +select test_found(); @@ -245255,7 +245227,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test set-returning functions for PL/pgSQL -@@ -1638,17 +1959,11 @@ +@@ -1638,17 +1960,11 @@ END LOOP; RETURN; END;' language plpgsql; @@ -245277,7 +245249,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function test_table_func_row() returns setof found_test_tbl as ' DECLARE row found_test_tbl%ROWTYPE; -@@ -1658,17 +1973,11 @@ +@@ -1658,17 +1974,11 @@ END LOOP; RETURN; END;' language plpgsql; @@ -245299,7 +245271,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function test_ret_set_scalar(int,int) returns setof int as ' DECLARE i int; -@@ -1678,21 +1987,11 @@ +@@ -1678,21 +1988,11 @@ END LOOP; RETURN; END;' language plpgsql; @@ -245325,7 +245297,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function test_ret_set_rec_dyn(int) returns setof record as ' DECLARE retval RECORD; -@@ -1708,20 +2007,21 @@ +@@ -1708,20 +2008,21 @@ END IF; RETURN; END;' language plpgsql; @@ -245359,7 +245331,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function test_ret_rec_dyn(int) returns record as ' DECLARE retval RECORD; -@@ -1734,18 +2034,21 @@ +@@ -1734,18 +2035,21 @@ RETURN retval; END IF; END;' language plpgsql; @@ -245391,7 +245363,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test some simple polymorphism cases. -- -@@ -1753,43 +2056,45 @@ +@@ -1753,43 +2057,45 @@ begin return x + 1; end$$ language plpgsql; @@ -245459,7 +245431,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop function f1(x anyarray); create function f1(x anyarray) returns anyarray as $$ begin -@@ -1802,72 +2107,61 @@ +@@ -1802,72 +2108,61 @@ (1 row) select f1(stavalues1) from pg_statistic; -- fail, can't infer element type @@ -245551,7 +245523,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function f1(a anyelement, b anyarray, c anycompatible, d anycompatible, OUT x anyarray, OUT y anycompatiblearray) -@@ -1876,35 +2170,30 @@ +@@ -1876,35 +2171,30 @@ x := a || b; y := array[c, d]; end$$ language plpgsql; @@ -245601,11 +245573,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test handling of OUT parameters, including polymorphic cases. -- Note that RETURN is optional with OUT params; we try both ways. -@@ -1914,14 +2203,17 @@ - begin +@@ -1915,25 +2205,21 @@ return i+1; end$$ language plpgsql; --ERROR: RETURN cannot have a parameter in function with OUT parameters + ERROR: RETURN cannot have a parameter in function with OUT parameters -LINE 3: return i+1; - ^ create function f1(in i int, out j int) as $$ @@ -245619,30 +245590,24 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + j := i+1; + return; + ^ - select f1(42); - f1 - ---- -@@ -1939,17 +2231,9 @@ - i := i+1; - end$$ language plpgsql; select f1(42); - f1 ----- - 43 -(1 row) - -+ERROR: control reached end of function without RETURN ++ERROR: unknown function: f1() select * from f1(42); -- i +- j ----- - 43 -(1 row) - -+ERROR: control reached end of function without RETURN - drop function f1(int); - create function f1(in i int, out j int) returns setof int as $$ ++ERROR: unknown function: f1() + create or replace function f1(inout i int) as $$ begin -@@ -1959,14 +2243,27 @@ + i := i+1; +@@ -1959,14 +2245,27 @@ return next; return; end$$ language plpgsql; @@ -245663,12 +245628,12 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. - ++ +If you would rather not post publicly, please contact us directly +using the support form. + +We appreciate your feedback. -+ + +select * from f1(42); +ERROR: unknown function: f1() drop function f1(int); @@ -245676,27 +245641,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function f1(in i int, out j int, out k text) as $$ begin j := i; -@@ -1974,17 +2271,9 @@ - k := 'foo'; - end$$ language plpgsql; - select f1(42); -- f1 ------------ -- (43,foo) --(1 row) -- -+ERROR: "j" is not a known variable - select * from f1(42); -- j | k ------+----- -- 43 | foo --(1 row) -- -+ERROR: "j" is not a known variable - drop function f1(int); - create function f1(in i int, out j int, out k text) returns setof record as $$ - begin -@@ -1995,52 +2284,60 @@ +@@ -1995,52 +2294,60 @@ k := 'foot'; return next; end$$ language plpgsql; @@ -245783,15 +245728,15 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- test PERFORM -- -@@ -2057,6 +2354,7 @@ +@@ -2057,6 +2364,7 @@ RETURN FALSE; END IF; END;' language plpgsql; -+ERROR: column "\"\"" does not exist ++ERROR: no value provided for placeholder: $1 create function perform_test_func() returns void as ' BEGIN IF FOUND then -@@ -2077,19 +2375,32 @@ +@@ -2077,19 +2385,32 @@ RETURN; END;' language plpgsql; @@ -245810,11 +245755,11 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + PERFORM perform_simple_func(5); + ^ +HINT: You have attempted to use a feature that is not yet implemented. -+ + +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. - ++ +If you would rather not post publicly, please contact us directly +using the support form. + @@ -245835,7 +245780,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop table perform_test; -- -@@ -2103,19 +2414,12 @@ +@@ -2103,19 +2424,12 @@ if found then return x; end if; return 0; end$$ language plpgsql stable; @@ -245858,7 +245803,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function sp_add_user(a_login text) returns int as $$ declare my_id_user int; begin -@@ -2130,38 +2434,22 @@ +@@ -2130,38 +2444,22 @@ END IF; RETURN my_id_user; end$$ language plpgsql; @@ -245906,7 +245851,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- tests for refcursors -- -@@ -2185,12 +2473,13 @@ +@@ -2185,12 +2483,13 @@ return x.a; end $$ language plpgsql; @@ -245925,7 +245870,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function return_refcursor(rc refcursor) returns refcursor as $$ begin open rc for select a from rc_test; -@@ -2203,33 +2492,31 @@ +@@ -2203,33 +2502,31 @@ return $1; end $$ language plpgsql; @@ -245979,7 +245924,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab commit; -- should fail fetch next from test1; -@@ -2249,13 +2536,25 @@ +@@ -2249,13 +2546,25 @@ end if; end $$ language plpgsql; @@ -246010,7 +245955,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- should fail create function constant_refcursor() returns refcursor as $$ declare -@@ -2266,8 +2565,11 @@ +@@ -2266,8 +2575,11 @@ end $$ language plpgsql; select constant_refcursor(); @@ -246024,7 +245969,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- but it's okay like this create or replace function constant_refcursor() returns refcursor as $$ declare -@@ -2301,13 +2603,25 @@ +@@ -2301,13 +2613,25 @@ end if; end $$ language plpgsql; @@ -246055,7 +246000,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- mixing named and positional argument notations create function namedparmcursor_test2(int, int) returns boolean as $$ declare -@@ -2324,12 +2638,24 @@ +@@ -2324,12 +2648,24 @@ end if; end $$ language plpgsql; @@ -246077,15 +246022,15 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. - -+We appreciate your feedback. + ++We appreciate your feedback. + +select namedparmcursor_test2(20, 20); +ERROR: unknown function: namedparmcursor_test2() -- mixing named and positional: param2 is given twice, once in named notation -- and second time in positional notation. Should throw an error at parse time create function namedparmcursor_test3() returns void as $$ -@@ -2339,9 +2665,22 @@ +@@ -2339,9 +2675,22 @@ open c1(param2 := 20, 21); end $$ language plpgsql; @@ -246111,7 +246056,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- mixing named and positional: same as previous test, but param1 is duplicated create function namedparmcursor_test4() returns void as $$ declare -@@ -2350,9 +2689,22 @@ +@@ -2350,9 +2699,22 @@ open c1(20, param1 := 21); end $$ language plpgsql; @@ -246137,7 +246082,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- duplicate named parameter, should throw an error at parse time create function namedparmcursor_test5() returns void as $$ declare -@@ -2362,9 +2714,22 @@ +@@ -2362,9 +2724,22 @@ open c1 (p2 := 77, p2 := 42); end $$ language plpgsql; @@ -246163,7 +246108,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- not enough parameters, should throw an error at parse time create function namedparmcursor_test6() returns void as $$ declare -@@ -2374,9 +2739,22 @@ +@@ -2374,9 +2749,22 @@ open c1 (p2 := 77); end $$ language plpgsql; @@ -246189,7 +246134,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- division by zero runtime error, the context given in the error message -- should be sensible create function namedparmcursor_test7() returns void as $$ -@@ -2386,10 +2764,24 @@ +@@ -2386,10 +2774,24 @@ begin open c1 (p2 := 77, p1 := 42/0); end $$ language plpgsql; @@ -246217,7 +246162,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- check that line comments work correctly within the argument list (there -- is some special handling of this case in the code: the newline after the -- comment must be preserved when the argument-evaluating query is -@@ -2406,12 +2798,24 @@ +@@ -2406,12 +2808,24 @@ fetch c1 into n; return n; end $$ language plpgsql; @@ -246239,15 +246184,15 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select namedparmcursor_test8(); +ERROR: unknown function: namedparmcursor_test8() -- cursor parameter name can match plpgsql variable or unreserved keyword create function namedparmcursor_test9(p1 int) returns int4 as $$ declare -@@ -2425,12 +2829,24 @@ +@@ -2425,12 +2839,24 @@ fetch c1 into n; return n; end $$ language plpgsql; @@ -246269,15 +246214,15 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select namedparmcursor_test9(6); +ERROR: unknown function: namedparmcursor_test9() -- -- tests for "raise" processing -- -@@ -2441,7 +2857,6 @@ +@@ -2441,28 +2867,22 @@ end; $$ language plpgsql; ERROR: too many parameters specified for RAISE @@ -246285,18 +246230,19 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function raise_test2(int) returns int as $$ begin raise notice 'This message has too few parameters: %, %, %', $1, $1; -@@ -2449,20 +2864,15 @@ + return $1; end; $$ language plpgsql; - ERROR: too few parameters specified for RAISE +-ERROR: too few parameters specified for RAISE -CONTEXT: compilation of PL/pgSQL function "raise_test2" near line 3 ++ERROR: no value provided for placeholder: $1 create function raise_test3(int) returns int as $$ begin raise notice 'This message has no parameters (despite having %% signs in it)!'; return $1; end; $$ language plpgsql; -+ERROR: column "\"\"" does not exist ++ERROR: no value provided for placeholder: $1 select raise_test3(1); -NOTICE: This message has no parameters (despite having % signs in it)! - raise_test3 @@ -246308,7 +246254,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Test re-RAISE inside a nested exception block. This case is allowed -- by Oracle's PL/SQL but was handled differently by PG before 9.1. CREATE FUNCTION reraise_test() RETURNS void AS $$ -@@ -2484,14 +2894,30 @@ +@@ -2484,14 +2904,30 @@ raise notice 'WRONG - exception % caught in outer block', sqlerrm; END; $$ LANGUAGE plpgsql; @@ -246331,14 +246277,14 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + RAISE; + ^ +HINT: You have attempted to use a feature that is not yet implemented. -+ + +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. + +If you would rather not post publicly, please contact us directly +using the support form. - ++ +We appreciate your feedback. + +SELECT reraise_test(); @@ -246346,7 +246292,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- reject function definitions that contain malformed SQL queries at -- compile-time, where possible -@@ -2504,9 +2930,17 @@ +@@ -2504,9 +2940,17 @@ a := 10; return a; end$$ language plpgsql; @@ -246367,7 +246313,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function bad_sql2() returns int as $$ declare r record; begin -@@ -2515,81 +2949,117 @@ +@@ -2515,81 +2959,117 @@ end loop; return 5; end;$$ language plpgsql; @@ -246432,10 +246378,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. - ++ +If you would rather not post publicly, please contact us directly +using the support form. -+ + +We appreciate your feedback. + +-- select void_return_expr(); @@ -246528,7 +246474,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- SQLSTATE and SQLERRM test -- -@@ -2597,14 +3067,11 @@ +@@ -2597,14 +3077,11 @@ begin raise notice '% %', sqlstate, sqlerrm; end; $$ language plpgsql; @@ -246545,7 +246491,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function excpt_test2() returns void as $$ begin begin -@@ -2613,13 +3080,10 @@ +@@ -2613,13 +3090,10 @@ end; end; end; $$ language plpgsql; @@ -246561,7 +246507,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function excpt_test3() returns void as $$ begin begin -@@ -2639,31 +3103,61 @@ +@@ -2639,31 +3113,61 @@ raise notice '% %', sqlstate, sqlerrm; end; end; $$ language plpgsql; @@ -246593,9 +246539,9 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select excpt_test3(); +ERROR: unknown function: excpt_test3() create function excpt_test4() returns text as $$ @@ -246621,9 +246567,9 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select excpt_test4(); +ERROR: unknown function: excpt_test4() drop function excpt_test1(); @@ -246637,7 +246583,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- parameters of raise stmt can be expressions create function raise_exprs() returns void as $$ declare -@@ -2714,13 +3208,11 @@ +@@ -2714,13 +3218,11 @@ insert into foo values(5,6) returning * into x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246655,7 +246601,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2728,10 +3220,11 @@ +@@ -2728,10 +3230,11 @@ insert into foo values(7,8),(9,10) returning * into x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246670,7 +246616,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2739,13 +3232,11 @@ +@@ -2739,13 +3242,11 @@ execute 'insert into foo values(5,6) returning *' into x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246688,7 +246634,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2753,23 +3244,17 @@ +@@ -2753,23 +3254,17 @@ execute 'insert into foo values(7,8),(9,10) returning *' into x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246717,7 +246663,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; -@@ -2778,13 +3263,11 @@ +@@ -2778,13 +3273,11 @@ select * from foo where f1 = 3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246735,7 +246681,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2792,9 +3275,11 @@ +@@ -2792,9 +3285,11 @@ select * from foo where f1 = 0 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246749,7 +246695,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2802,10 +3287,11 @@ +@@ -2802,10 +3297,11 @@ select * from foo where f1 > 3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246764,7 +246710,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2813,13 +3299,11 @@ +@@ -2813,13 +3309,11 @@ execute 'select * from foo where f1 = 3' into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246782,7 +246728,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2827,9 +3311,11 @@ +@@ -2827,9 +3321,11 @@ execute 'select * from foo where f1 = 0' into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246796,7 +246742,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2837,12 +3323,17 @@ +@@ -2837,12 +3333,17 @@ execute 'select * from foo where f1 > 3' into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246816,7 +246762,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; -@@ -2853,10 +3344,11 @@ +@@ -2853,10 +3354,11 @@ select * from foo where f1 = p1 and f1::text = p3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246831,7 +246777,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; -@@ -2867,10 +3359,11 @@ +@@ -2867,10 +3369,11 @@ select * from foo where f1 = p1 and f1::text = p3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246846,7 +246792,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; -@@ -2881,11 +3374,11 @@ +@@ -2881,11 +3384,11 @@ select * from foo where f1 > p1 or f1::text = p3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246862,7 +246808,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2893,10 +3386,11 @@ +@@ -2893,10 +3396,11 @@ select * from foo where f1 > 3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246877,7 +246823,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2904,10 +3398,11 @@ +@@ -2904,10 +3408,11 @@ execute 'select * from foo where f1 = $1 or f1::text = $2' using 0, 'foo' into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246892,7 +246838,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2915,10 +3410,11 @@ +@@ -2915,10 +3420,11 @@ execute 'select * from foo where f1 > $1' using 1 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246907,7 +246853,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ declare x record; begin -@@ -2926,9 +3422,11 @@ +@@ -2926,9 +3432,11 @@ execute 'select * from foo where f1 > 3' into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246921,7 +246867,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stricttest() returns void as $$ -- override the global #print_strict_params off -@@ -2941,10 +3439,12 @@ +@@ -2941,10 +3449,12 @@ select * from foo where f1 > p1 or f1::text = p3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246937,7 +246883,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab reset plpgsql.print_strict_params; create or replace function stricttest() returns void as $$ -- override the global -@@ -2958,11 +3458,12 @@ +@@ -2958,11 +3468,12 @@ select * from foo where f1 > p1 or f1::text = p3 into strict x; raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; end$$ language plpgsql; @@ -246954,7 +246900,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test warnings and errors set plpgsql.extra_warnings to 'all'; set plpgsql.extra_warnings to 'none'; -@@ -2979,23 +3480,18 @@ +@@ -2979,23 +3490,18 @@ begin end $$ language plpgsql; @@ -246987,7 +246933,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function shadowtest(in1 int) returns table (out1 int) as $$ declare -@@ -3004,18 +3500,17 @@ +@@ -3004,18 +3510,17 @@ begin end $$ language plpgsql; @@ -247015,7 +246961,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- shadowing in a second DECLARE block create or replace function shadowtest() returns void as $$ -@@ -3027,10 +3522,13 @@ +@@ -3027,10 +3532,13 @@ begin end; end$$ language plpgsql; @@ -247032,7 +246978,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- several levels of shadowing create or replace function shadowtest(in1 int) returns void as $$ -@@ -3042,13 +3540,13 @@ +@@ -3042,13 +3550,13 @@ begin end; end$$ language plpgsql; @@ -247052,7 +246998,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- shadowing in cursor definitions create or replace function shadowtest() returns void as $$ -@@ -3057,34 +3555,49 @@ +@@ -3057,34 +3565,49 @@ c1 cursor (f1 int) for select 1; begin end$$ language plpgsql; @@ -247117,7 +247063,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- runtime extra checks set plpgsql.extra_warnings to 'too_many_rows'; do $$ -@@ -3093,8 +3606,10 @@ +@@ -3093,8 +3616,10 @@ select v from generate_series(1,2) g(v) into x; end; $$; @@ -247130,7 +247076,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab set plpgsql.extra_errors to 'too_many_rows'; do $$ declare x int; -@@ -3102,9 +3617,10 @@ +@@ -3102,9 +3627,10 @@ select v from generate_series(1,2) g(v) into x; end; $$; @@ -247144,7 +247090,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab reset plpgsql.extra_errors; reset plpgsql.extra_warnings; set plpgsql.extra_warnings to 'strict_multi_assignment'; -@@ -3118,12 +3634,10 @@ +@@ -3118,12 +3644,10 @@ select 1,2,3 into x, y; end $$; @@ -247161,7 +247107,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab set plpgsql.extra_errors to 'strict_multi_assignment'; do $$ declare -@@ -3135,10 +3649,10 @@ +@@ -3135,10 +3659,10 @@ select 1,2,3 into x, y; end $$; @@ -247176,7 +247122,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create table test_01(a int, b int, c int); alter table test_01 drop column a; -- the check is active only when source table is not empty -@@ -3153,11 +3667,10 @@ +@@ -3153,11 +3677,10 @@ select * from test_01 into x; -- should to fail end; $$; @@ -247192,7 +247138,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab do $$ declare t test_01; -@@ -3167,11 +3680,10 @@ +@@ -3167,11 +3690,10 @@ select 1, 2, 3 into t; -- should fail; end; $$; @@ -247208,7 +247154,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab do $$ declare t test_01; -@@ -3179,10 +3691,10 @@ +@@ -3179,10 +3701,10 @@ select 1 into t; -- should fail; end; $$; @@ -247223,7 +247169,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop table test_01; reset plpgsql.extra_errors; reset plpgsql.extra_warnings; -@@ -3201,16 +3713,11 @@ +@@ -3201,16 +3723,11 @@ close c; end; $$ language plpgsql; @@ -247244,7 +247190,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function sc_test() returns setof integer as $$ declare c no scroll cursor for select f1 from int4_tbl; -@@ -3225,10 +3732,11 @@ +@@ -3225,10 +3742,11 @@ close c; end; $$ language plpgsql; @@ -247259,7 +247205,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function sc_test() returns setof integer as $$ declare c refcursor; -@@ -3243,16 +3751,11 @@ +@@ -3243,16 +3761,11 @@ close c; end; $$ language plpgsql; @@ -247280,7 +247226,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function sc_test() returns setof integer as $$ declare c refcursor; -@@ -3267,14 +3770,11 @@ +@@ -3267,14 +3780,11 @@ close c; end; $$ language plpgsql; @@ -247299,7 +247245,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function sc_test() returns setof integer as $$ declare c refcursor; -@@ -3290,13 +3790,11 @@ +@@ -3290,13 +3800,11 @@ close c; end; $$ language plpgsql; @@ -247317,7 +247263,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function sc_test() returns setof integer as $$ declare c cursor for select * from generate_series(1, 10); -@@ -3316,14 +3814,11 @@ +@@ -3316,14 +3824,11 @@ close c; end; $$ language plpgsql; @@ -247336,7 +247282,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function sc_test() returns setof integer as $$ declare c cursor for select * from generate_series(1, 10); -@@ -3338,13 +3833,13 @@ +@@ -3338,13 +3843,13 @@ close c; end; $$ language plpgsql; @@ -247355,7 +247301,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test qualified variable names create function pl_qual_names (param1 int) returns void as $$ <> -@@ -3362,17 +3857,22 @@ +@@ -3362,17 +3867,22 @@ end; end; $$ language plpgsql; @@ -247377,9 +247323,9 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select pl_qual_names(42); +ERROR: unknown function: pl_qual_names() drop function pl_qual_names(int); @@ -247387,7 +247333,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- tests for RETURN QUERY create function ret_query1(out int, out int) returns setof record as $$ begin -@@ -3383,24 +3883,13 @@ +@@ -3383,24 +3893,13 @@ return next; end; $$ language plpgsql; @@ -247418,7 +247364,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create type record_type as (x text, y int, z boolean); create or replace function ret_query2(lim int) returns setof record_type as $$ begin -@@ -3408,20 +3897,11 @@ +@@ -3408,20 +3907,11 @@ from generate_series(-8, lim) s (x) where s.x % 2 = 0; end; $$ language plpgsql; @@ -247443,7 +247389,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test EXECUTE USING create function exc_using(int, text) returns int as $$ declare i int; -@@ -3433,19 +3913,27 @@ +@@ -3433,19 +3923,27 @@ return i; end $$ language plpgsql; @@ -247482,7 +247428,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function exc_using(int) returns void as $$ declare c refcursor; -@@ -3461,19 +3949,29 @@ +@@ -3461,19 +3959,29 @@ return; end; $$ language plpgsql; @@ -247513,9 +247459,9 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select exc_using(5); +ERROR: unknown function: exc_using() drop function exc_using(int); @@ -247523,7 +247469,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test FOR-over-cursor create or replace function forc01() returns void as $$ declare -@@ -3513,29 +4011,24 @@ +@@ -3513,29 +4021,24 @@ return; end; $$ language plpgsql; @@ -247559,10 +247505,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. -+ + +If you would rather not post publicly, please contact us directly +using the support form. - ++ +We appreciate your feedback. + +select forc01(); @@ -247570,7 +247516,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- try updating the cursor's current row create temp table forc_test as select n as i, n as j from generate_series(1,10) n; -@@ -3549,35 +4042,39 @@ +@@ -3549,35 +4052,39 @@ end loop; end; $$ language plpgsql; @@ -247597,14 +247543,14 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + for r in c loop + ^ +HINT: You have attempted to use a feature that is not yet implemented. - ++ +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. + +If you would rather not post publicly, please contact us directly +using the support form. -+ + +We appreciate your feedback. + +select forc01(); @@ -247637,7 +247583,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab (10 rows) -- same, with a cursor whose portal name doesn't match variable name -@@ -3595,38 +4092,42 @@ +@@ -3595,38 +4102,42 @@ end loop; end; $$ language plpgsql; @@ -247707,7 +247653,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- it's okay to re-use a cursor variable name, even when bound do $$ declare cnt int := 0; -@@ -3642,7 +4143,10 @@ +@@ -3642,7 +4153,10 @@ end loop; raise notice 'cnt = %', cnt; end $$; @@ -247719,7 +247665,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- fail because cursor has no query bound to it create or replace function forc_bad() returns void as $$ declare -@@ -3653,9 +4157,24 @@ +@@ -3653,9 +4167,24 @@ end loop; end; $$ language plpgsql; @@ -247747,7 +247693,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test RETURN QUERY EXECUTE create or replace function return_dquery() returns setof int as $$ -@@ -3664,16 +4183,13 @@ +@@ -3664,16 +4193,13 @@ return query execute 'select * from (values($1),($2)) f' using 40,50; end; $$ language plpgsql; @@ -247769,7 +247715,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test RETURN QUERY with dropped columns create table tabwithcols(a int, b int, c int, d int); insert into tabwithcols values(10,20,30,40),(50,60,70,80); -@@ -3684,46 +4200,22 @@ +@@ -3684,46 +4210,22 @@ return query execute 'select * from tabwithcols'; end; $$ language plpgsql; @@ -247824,7 +247770,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop table tabwithcols; -- -- Tests for composite-type results -@@ -3753,6 +4245,9 @@ +@@ -3753,6 +4255,9 @@ return v; end; $$ language plpgsql; @@ -247834,7 +247780,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab select compos(); compos ----------- -@@ -3778,9 +4273,11 @@ +@@ -3778,9 +4283,11 @@ end; $$ language plpgsql; select compos(); @@ -247849,7 +247795,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- ... but this does create or replace function compos() returns compostype as $$ begin -@@ -3803,12 +4300,11 @@ +@@ -3803,12 +4310,11 @@ return v; end; $$ language plpgsql; @@ -247866,7 +247812,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test: return row expr in return statement. create or replace function composrec() returns record as $$ begin -@@ -3833,26 +4329,22 @@ +@@ -3833,26 +4339,22 @@ return next (2, 'goodbye')::compostype; end; $$ language plpgsql; @@ -247900,7 +247846,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- RETURN variable is a different code path ... create or replace function compos() returns compostype as $$ declare x int := 42; -@@ -3861,8 +4353,7 @@ +@@ -3861,8 +4363,7 @@ end; $$ language plpgsql; select * from compos(); @@ -247910,7 +247856,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop function compos(); -- test: invalid use of composite variable in scalar-returning function create or replace function compos() returns int as $$ -@@ -3874,8 +4365,7 @@ +@@ -3874,8 +4375,7 @@ end; $$ language plpgsql; select compos(); @@ -247920,7 +247866,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test: invalid use of composite expression in scalar-returning function create or replace function compos() returns int as $$ begin -@@ -3883,8 +4373,7 @@ +@@ -3883,8 +4383,7 @@ end; $$ language plpgsql; select compos(); @@ -247930,7 +247876,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop function compos(); drop type compostype; -- -@@ -3904,7 +4393,6 @@ +@@ -3904,7 +4403,6 @@ HINT: some hint ERROR: 1 2 3 DETAIL: some detail info @@ -247938,7 +247884,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Since we can't actually see the thrown SQLSTATE in default psql output, -- test it like this; this also tests re-RAISE create or replace function raise_test() returns void as $$ -@@ -3917,11 +4405,33 @@ +@@ -3917,11 +4415,33 @@ raise; end; $$ language plpgsql; @@ -247975,7 +247921,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise 'check me' -@@ -3932,11 +4442,33 @@ +@@ -3932,11 +4452,33 @@ raise; end; $$ language plpgsql; @@ -248012,7 +247958,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- SQLSTATE specification in WHEN create or replace function raise_test() returns void as $$ begin -@@ -3948,11 +4480,33 @@ +@@ -3948,11 +4490,33 @@ raise; end; $$ language plpgsql; @@ -248049,7 +247995,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise division_by_zero using detail = 'some detail info'; -@@ -3962,11 +4516,32 @@ +@@ -3962,11 +4526,32 @@ raise; end; $$ language plpgsql; @@ -248085,7 +248031,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise division_by_zero; -@@ -3974,7 +4549,6 @@ +@@ -3974,7 +4559,6 @@ $$ language plpgsql; select raise_test(); ERROR: division_by_zero @@ -248093,7 +248039,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise sqlstate '1234F'; -@@ -3982,7 +4556,6 @@ +@@ -3982,7 +4566,6 @@ $$ language plpgsql; select raise_test(); ERROR: 1234F @@ -248101,7 +248047,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise division_by_zero using message = 'custom' || ' message'; -@@ -3990,7 +4563,6 @@ +@@ -3990,7 +4573,6 @@ $$ language plpgsql; select raise_test(); ERROR: custom message @@ -248109,7 +248055,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise using message = 'custom' || ' message', errcode = '22012'; -@@ -3998,34 +4570,48 @@ +@@ -3998,34 +4580,48 @@ $$ language plpgsql; select raise_test(); ERROR: custom message @@ -248165,7 +248111,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test access to exception data create function zero_divide() returns int as $$ declare v int := 0; -@@ -4033,6 +4619,7 @@ +@@ -4033,6 +4629,7 @@ return 10 / v; end; $$ language plpgsql; @@ -248173,7 +248119,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function raise_test() returns void as $$ begin raise exception 'custom exception' -@@ -4055,13 +4642,27 @@ +@@ -4055,13 +4652,27 @@ _sqlstate, _message, replace(_context, E'\n', ' <- '); end; $$ language plpgsql; @@ -248196,10 +248142,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. -+ + +If you would rather not post publicly, please contact us directly +using the support form. - ++ +We appreciate your feedback. + +select stacked_diagnostics_test(); @@ -248207,7 +248153,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function stacked_diagnostics_test() returns void as $$ declare _detail text; _hint text; -@@ -4076,13 +4677,27 @@ +@@ -4076,13 +4687,27 @@ raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint; end; $$ language plpgsql; @@ -248230,18 +248176,18 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. -+ + +If you would rather not post publicly, please contact us directly +using the support form. + +We appreciate your feedback. - ++ +select stacked_diagnostics_test(); +ERROR: unknown function: stacked_diagnostics_test() -- fail, cannot use stacked diagnostics statement outside handler create or replace function stacked_diagnostics_test() returns void as $$ declare _detail text; -@@ -4096,11 +4711,24 @@ +@@ -4096,11 +4721,24 @@ raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint; end; $$ language plpgsql; @@ -248268,7 +248214,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- check cases where implicit SQLSTATE variable could be confused with -- SQLSTATE as a keyword, cf bug #5524 create or replace function raise_test() returns void as $$ -@@ -4112,10 +4740,26 @@ +@@ -4112,10 +4750,26 @@ raise sqlstate '22012' using message = 'substitute message'; end; $$ language plpgsql; @@ -248298,7 +248244,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop function raise_test(); -- test passing column_name, constraint_name, datatype_name, table_name -- and schema_name error fields -@@ -4143,14 +4787,22 @@ +@@ -4143,14 +4797,22 @@ _column_name, _constraint_name, _datatype_name, _table_name, _schema_name; end; $$ language plpgsql; @@ -248327,7 +248273,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- test variadic functions create or replace function vari(variadic int[]) returns void as $$ -@@ -4159,36 +4811,34 @@ +@@ -4159,36 +4821,34 @@ raise notice '%', $1[i]; end loop; end; $$ language plpgsql; @@ -248387,7 +248333,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- coercion test create or replace function pleast(variadic numeric[]) returns numeric as $$ -@@ -4200,30 +4850,20 @@ +@@ -4200,30 +4860,20 @@ return aux; end; $$ language plpgsql immutable strict; @@ -248428,11 +248374,11 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- in case of conflict, non-variadic version is preferred create or replace function pleast(numeric) returns numeric as $$ -@@ -4232,31 +4872,27 @@ +@@ -4232,31 +4882,27 @@ return $1; end; $$ language plpgsql immutable strict; -+ERROR: column "\"\"" does not exist ++ERROR: no value provided for placeholder: $1 select pleast(10); -NOTICE: non-variadic function called - pleast @@ -248471,7 +248417,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function tftest(a1 int) returns table(a int, b int) as $$ begin a := a1; b := a1 + 1; -@@ -4265,14 +4901,16 @@ +@@ -4265,14 +4911,16 @@ return next; end; $$ language plpgsql immutable strict; @@ -248494,7 +248440,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function rttest() returns setof int as $$ declare rc int; -@@ -4291,19 +4929,11 @@ +@@ -4291,19 +4939,11 @@ raise notice '% %', found, rc; end; $$ language plpgsql; @@ -248518,7 +248464,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- check some error cases, too create or replace function rttest() returns setof int as $$ -@@ -4311,25 +4941,26 @@ +@@ -4311,25 +4951,26 @@ return query select 10 into no_such_table; end; $$ language plpgsql; @@ -248553,7 +248499,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Test for proper cleanup at subtransaction exit. This example -- exposed a bug in PG 8.2. CREATE FUNCTION leaker_1(fail BOOL) RETURNS INTEGER AS $$ -@@ -4344,6 +4975,8 @@ +@@ -4344,6 +4985,8 @@ RETURN 1; END; $$ LANGUAGE plpgsql; @@ -248562,7 +248508,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE FUNCTION leaker_2(fail BOOL, OUT error_code INTEGER, OUT new_id INTEGER) RETURNS RECORD AS $$ BEGIN -@@ -4355,20 +4988,24 @@ +@@ -4355,20 +4998,24 @@ RETURN; END; $$ LANGUAGE plpgsql; @@ -248597,7 +248543,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Test for appropriate cleanup of non-simple expression evaluations -- (bug in all versions prior to August 2010) CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS $$ -@@ -4385,13 +5022,27 @@ +@@ -4385,13 +5032,27 @@ RETURN arr; END; $$ LANGUAGE plpgsql; @@ -248630,7 +248576,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE FUNCTION nonsimple_expr_test() RETURNS integer AS $$ declare i integer NOT NULL := 0; -@@ -4405,13 +5056,13 @@ +@@ -4405,13 +5066,13 @@ return i; end; $$ LANGUAGE plpgsql; @@ -248649,7 +248595,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test cases involving recursion and error recovery in simple expressions -- (bugs in all versions before October 2010). The problems are most -@@ -4427,43 +5078,56 @@ +@@ -4427,43 +5088,56 @@ end if; end; $$ language plpgsql; @@ -248719,7 +248665,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function cast_invoker(integer) returns date as $$ begin return $1; -@@ -4471,62 +5135,81 @@ +@@ -4471,62 +5145,81 @@ select cast_invoker(20150717); cast_invoker -------------- @@ -248812,7 +248758,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab end; -- Test for consistent reporting of error context create function fail() returns int language plpgsql as $$ -@@ -4534,45 +5217,29 @@ +@@ -4534,45 +5227,29 @@ return 1/0; end $$; @@ -248869,7 +248815,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab (1 row) create or replace function strtest() returns text as $$ -@@ -4625,21 +5292,16 @@ +@@ -4625,21 +5302,16 @@ RAISE NOTICE '%, %', r.roomno, r.comment; END LOOP; END$$; @@ -248899,7 +248845,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab DO $$ DECLARE r record; BEGIN -@@ -4648,11 +5310,10 @@ +@@ -4648,11 +5320,10 @@ RAISE NOTICE '%, %', r.roomno, r.comment; END LOOP; END$$; @@ -248915,7 +248861,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Check handling of errors thrown from/into anonymous code blocks. do $outer$ begin -@@ -4672,16 +5333,10 @@ +@@ -4672,16 +5343,10 @@ end loop; end; $outer$; @@ -248936,7 +248882,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Check variable scoping -- a var is not available in its own or prior -- default expressions, but it is available in later ones. do $$ -@@ -4690,11 +5345,10 @@ +@@ -4690,11 +5355,10 @@ raise notice 'x = %', x; end; $$; @@ -248952,7 +248898,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab do $$ declare y int := x + 1; -- error x int := 42; -@@ -4702,11 +5356,10 @@ +@@ -4702,11 +5366,10 @@ raise notice 'x = %, y = %', x, y; end; $$; @@ -248968,7 +248914,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab do $$ declare x int := 42; y int := x + 1; -@@ -4714,7 +5367,10 @@ +@@ -4714,7 +5377,10 @@ raise notice 'x = %, y = %', x, y; end; $$; @@ -248980,7 +248926,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab do $$ declare x int := 42; begin -@@ -4726,7 +5382,10 @@ +@@ -4726,7 +5392,10 @@ end; end; $$; @@ -248992,7 +248938,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Check handling of conflicts between plpgsql vars and table columns. set plpgsql.variable_conflict = error; create function conflict_test() returns setof int8_tbl as $$ -@@ -4738,13 +5397,11 @@ +@@ -4738,13 +5407,11 @@ end loop; end; $$ language plpgsql; @@ -249010,7 +248956,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function conflict_test() returns setof int8_tbl as $$ #variable_conflict use_variable declare r record; -@@ -4755,16 +5412,11 @@ +@@ -4755,16 +5422,11 @@ end loop; end; $$ language plpgsql; @@ -249031,7 +248977,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function conflict_test() returns setof int8_tbl as $$ #variable_conflict use_column declare r record; -@@ -4775,17 +5427,13 @@ +@@ -4775,17 +5437,13 @@ end loop; end; $$ language plpgsql; @@ -249054,7 +249000,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Check that an unreserved keyword can be used as a variable name create function unreserved_test() returns int as $$ declare -@@ -4795,12 +5443,15 @@ +@@ -4795,12 +5453,15 @@ return forward; end $$ language plpgsql; @@ -249075,7 +249021,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function unreserved_test() returns int as $$ declare return int := 42; -@@ -4809,12 +5460,20 @@ +@@ -4809,12 +5470,20 @@ return return; end $$ language plpgsql; @@ -249101,7 +249047,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function unreserved_test() returns int as $$ declare comment int := 21; -@@ -4824,19 +5483,26 @@ +@@ -4824,19 +5493,26 @@ return comment; end $$ language plpgsql; @@ -249138,7 +249084,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test FOREACH over arrays -- -@@ -4850,26 +5516,27 @@ +@@ -4850,26 +5526,27 @@ end loop; end; $$ language plpgsql; @@ -249174,9 +249120,9 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab + +If you would rather not post publicly, please contact us directly +using the support form. -+ -+We appreciate your feedback. ++We appreciate your feedback. ++ +select foreach_test(ARRAY[1,2,3,4]); +ERROR: unknown function: foreach_test() +select foreach_test(ARRAY[[1,2],[3,4]]); @@ -249184,7 +249130,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function foreach_test(anyarray) returns void as $$ declare x int; -@@ -4880,13 +5547,28 @@ +@@ -4880,13 +5557,28 @@ end loop; end; $$ language plpgsql; @@ -249217,7 +249163,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function foreach_test(anyarray) returns void as $$ declare x int[]; -@@ -4897,21 +5579,27 @@ +@@ -4897,21 +5589,27 @@ end loop; end; $$ language plpgsql; @@ -249245,10 +249191,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. - ++ +If you would rather not post publicly, please contact us directly +using the support form. -+ + +We appreciate your feedback. + +select foreach_test(ARRAY[1,2,3,4]); @@ -249258,7 +249204,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- higher level of slicing create or replace function foreach_test(anyarray) returns void as $$ -@@ -4923,26 +5611,31 @@ +@@ -4923,26 +5621,31 @@ end loop; end; $$ language plpgsql; @@ -249305,7 +249251,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create type xy_tuple AS (x int, y int); -- iteration over array of records create or replace function foreach_test(anyarray) -@@ -4955,25 +5648,27 @@ +@@ -4955,25 +5658,27 @@ end loop; end; $$ language plpgsql; @@ -249337,10 +249283,10 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab +Please check the public issue tracker to check whether this problem is +already tracked. If you cannot find it there, please report the error +with details by creating a new issue. - ++ +If you would rather not post publicly, please contact us directly +using the support form. -+ + +We appreciate your feedback. + +select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]); @@ -249350,7 +249296,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function foreach_test(anyarray) returns void as $$ declare x int; y int; -@@ -4984,25 +5679,27 @@ +@@ -4984,25 +5689,27 @@ end loop; end; $$ language plpgsql; @@ -249395,7 +249341,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- slicing over array of composite types create or replace function foreach_test(anyarray) returns void as $$ -@@ -5014,22 +5711,29 @@ +@@ -5014,22 +5721,29 @@ end loop; end; $$ language plpgsql; @@ -249438,7 +249384,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab drop type xy_tuple; -- -- Assorted tests for array subscript assignment -@@ -5043,28 +5747,34 @@ +@@ -5043,28 +5757,34 @@ r.ar[2] := 'replace'; return r.ar; end$$; @@ -249489,7 +249435,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create function testoa(x1 int, x2 int, x3 int) returns orderedarray language plpgsql as $$ declare res orderedarray; -@@ -5073,26 +5783,19 @@ +@@ -5073,26 +5793,19 @@ res[2] := x3; return res; end$$; @@ -249523,7 +249469,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test handling of expanded arrays -- -@@ -5116,17 +5819,11 @@ +@@ -5116,17 +5829,11 @@ select i, a from (select returns_rw_array(1) as a offset 0) ss, lateral consumes_rw_array(a) i; @@ -249546,7 +249492,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab select i, a from (select returns_rw_array(1) as a offset 0) ss, lateral consumes_rw_array(a) i; -@@ -5137,13 +5834,11 @@ +@@ -5137,13 +5844,11 @@ explain (verbose, costs off) select consumes_rw_array(a), a from returns_rw_array(1) a; @@ -249565,7 +249511,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab select consumes_rw_array(a), a from returns_rw_array(1) a; consumes_rw_array | a -------------------+------- -@@ -5153,12 +5848,11 @@ +@@ -5153,12 +5858,11 @@ explain (verbose, costs off) select consumes_rw_array(a), a from (values (returns_rw_array(1)), (returns_rw_array(2))) v(a); @@ -249583,7 +249529,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab select consumes_rw_array(a), a from (values (returns_rw_array(1)), (returns_rw_array(2))) v(a); consumes_rw_array | a -@@ -5173,7 +5867,10 @@ +@@ -5173,7 +5877,10 @@ a := a || 3; raise notice 'a = %', a; end$$; @@ -249595,7 +249541,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test access to call stack -- -@@ -5190,6 +5887,18 @@ +@@ -5190,6 +5897,18 @@ return 2 * $1; end; $$ language plpgsql; @@ -249614,7 +249560,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function outer_func(int) returns int as $$ declare -@@ -5201,6 +5910,8 @@ +@@ -5201,6 +5920,8 @@ return myresult; end; $$ language plpgsql; @@ -249623,7 +249569,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function outer_outer_func(int) returns int as $$ declare -@@ -5212,44 +5923,19 @@ +@@ -5212,44 +5933,19 @@ return myresult; end; $$ language plpgsql; @@ -249675,7 +249621,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- access to call stack from exception create function inner_func(int) returns int as $$ -@@ -5272,6 +5958,26 @@ +@@ -5272,6 +5968,26 @@ return 2 * $1; end; $$ language plpgsql; @@ -249702,7 +249648,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function outer_func(int) returns int as $$ declare -@@ -5283,6 +5989,8 @@ +@@ -5283,6 +5999,8 @@ return myresult; end; $$ language plpgsql; @@ -249711,7 +249657,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab create or replace function outer_outer_func(int) returns int as $$ declare -@@ -5294,44 +6002,19 @@ +@@ -5294,44 +6012,19 @@ return myresult; end; $$ language plpgsql; @@ -249763,7 +249709,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- Test pg_routine_oid create function current_function(text) returns regprocedure as $$ -@@ -5342,13 +6025,17 @@ +@@ -5342,13 +6035,17 @@ return fn_oid; end; $$ language plpgsql; @@ -249786,7 +249732,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- shouldn't fail in DO, even though there's no useful data do $$ declare -@@ -5358,7 +6045,10 @@ +@@ -5358,7 +6055,10 @@ raise notice 'pg_routine_oid = %', fn_oid; end; $$; @@ -249798,7 +249744,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test ASSERT -- -@@ -5367,20 +6057,28 @@ +@@ -5367,20 +6067,28 @@ assert 1=1; -- should succeed end; $$; @@ -249831,7 +249777,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- check controlling GUC set plpgsql.check_asserts = off; do $$ -@@ -5388,6 +6086,10 @@ +@@ -5388,6 +6096,10 @@ assert 1=0; -- won't be tested end; $$; @@ -249842,7 +249788,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab reset plpgsql.check_asserts; -- test custom message do $$ -@@ -5396,8 +6098,10 @@ +@@ -5396,8 +6108,10 @@ assert 1=0, format('assertion failed, var = "%s"', var); end; $$; @@ -249855,7 +249801,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- ensure assertions are not trapped by 'others' do $$ begin -@@ -5406,32 +6110,52 @@ +@@ -5406,32 +6120,52 @@ null; -- do nothing end; $$; @@ -249912,7 +249858,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab do $$ declare v_test plpgsql_arr_domain; begin -@@ -5439,14 +6163,20 @@ +@@ -5439,14 +6173,20 @@ v_test := v_test || 2; end; $$; @@ -249935,7 +249881,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- test usage of transition tables in AFTER triggers -- -@@ -5472,25 +6202,31 @@ +@@ -5472,25 +6212,31 @@ RETURN new; END; $$; @@ -249974,7 +249920,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE OR REPLACE FUNCTION transition_table_base_upd_func() RETURNS trigger LANGUAGE plpgsql -@@ -5512,30 +6248,28 @@ +@@ -5512,30 +6258,28 @@ RETURN new; END; $$; @@ -250013,7 +249959,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE TABLE transition_table_level2 ( level2_no serial NOT NULL , -@@ -5543,6 +6277,7 @@ +@@ -5543,6 +6287,7 @@ level1_node_name varchar(255), PRIMARY KEY (level2_no) ) WITHOUT OIDS; @@ -250021,7 +249967,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE TABLE transition_table_status ( level int NOT NULL, -@@ -5563,11 +6298,18 @@ +@@ -5563,11 +6308,18 @@ RETURN NULL; END; $$; @@ -250040,7 +249986,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE FUNCTION transition_table_level1_ri_parent_upd_func() RETURNS TRIGGER LANGUAGE plpgsql -@@ -5590,11 +6332,18 @@ +@@ -5590,11 +6342,18 @@ RETURN NULL; END; $$; @@ -250059,7 +250005,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE FUNCTION transition_table_level2_ri_child_insupd_func() RETURNS TRIGGER LANGUAGE plpgsql -@@ -5610,16 +6359,29 @@ +@@ -5610,16 +6369,29 @@ RETURN NULL; END; $$; @@ -250089,7 +250035,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- create initial test data INSERT INTO transition_table_level1 (level1_no) SELECT generate_series(1,200); -@@ -5627,6 +6389,7 @@ +@@ -5627,6 +6399,7 @@ INSERT INTO transition_table_level2 (level2_no, parent_no) SELECT level2_no, level2_no / 50 + 1 AS parent_no FROM generate_series(1,9999) level2_no; @@ -250097,7 +250043,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab ANALYZE transition_table_level2; INSERT INTO transition_table_status (level, node_no, status) SELECT 1, level1_no, 0 FROM transition_table_level1; -@@ -5646,35 +6409,37 @@ +@@ -5646,35 +6419,37 @@ RETURN NULL; END; $$; @@ -250146,7 +250092,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- attempt modifications which would not break RI (should all succeed) DELETE FROM transition_table_level1 WHERE level1_no BETWEEN 201 AND 1000; -@@ -5683,7 +6448,7 @@ +@@ -5683,7 +6458,7 @@ SELECT count(*) FROM transition_table_level1; count ------- @@ -250155,7 +250101,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab (1 row) DELETE FROM transition_table_level2 -@@ -5691,7 +6456,7 @@ +@@ -5691,7 +6466,7 @@ SELECT count(*) FROM transition_table_level2; count ------- @@ -250164,7 +250110,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab (1 row) CREATE TABLE alter_table_under_transition_tables -@@ -5711,42 +6476,49 @@ +@@ -5711,42 +6486,49 @@ RETURN NULL; END; $$; @@ -250224,7 +250170,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Test multiple reference to a transition table -- -@@ -5761,22 +6533,45 @@ +@@ -5761,22 +6543,45 @@ FROM (SELECT * FROM new_test UNION ALL SELECT * FROM new_test) ss); RETURN NULL; END$$; @@ -250272,7 +250218,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE OR REPLACE FUNCTION get_from_partitioned_table(partitioned_table.a%type) RETURNS partitioned_table AS $$ DECLARE -@@ -5787,13 +6582,13 @@ +@@ -5787,13 +6592,13 @@ SELECT * INTO result FROM partitioned_table WHERE a = a_val; RETURN result; END; $$ LANGUAGE plpgsql; @@ -250292,7 +250238,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab CREATE OR REPLACE FUNCTION list_partitioned_table() RETURNS SETOF partitioned_table.a%TYPE AS $$ DECLARE -@@ -5806,14 +6601,13 @@ +@@ -5806,14 +6611,13 @@ END LOOP; RETURN; END; $$ LANGUAGE plpgsql; @@ -250313,7 +250259,7 @@ diff -U3 --label=/mnt/data1/postgres/src/test/regress/expected/plpgsql.out --lab -- -- Check argument name is used instead of $n in error message -- -@@ -5822,6 +6616,9 @@ +@@ -5822,6 +6626,9 @@ GET DIAGNOSTICS x = ROW_COUNT; RETURN; END; $$ LANGUAGE plpgsql;