Skip to content

Commit a036214

Browse files
craig[bot]rafiss
andcommitted
Merge #147817
147817: sql/catalog,schemachanger: allow UDFs in ON UPDATE and computed expressions r=rafiss a=rafiss We already had the dependency tracking in place, but there was still a block in place since we don't yet support UDFs in backfills. There were just a few places relating to ON UPDATE expressions that needed to be updated to emit the mutation event that modifies dependency back references. This patch removes the block within the schemachanger, so that now the only thing that gets blocked is actually attempting to use a UDF in the context of a backfill. informs #87699 fixes #115346 Release note (sql change): Computed column expressions and ON UPDATE expressions can now reference user-defined functions. Co-authored-by: Rafi Shamim <[email protected]>
2 parents be2cc31 + dde848c commit a036214

File tree

76 files changed

+3227
-1619
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+3227
-1619
lines changed

pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ccl/logictestccl/tests/local-read-committed/generated_test.go

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ccl/logictestccl/tests/local-repeatable-read/generated_test.go

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/add_column.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,16 @@ func (p *planner) addColumnImpl(
156156
}
157157

158158
// We need to allocate new ID for the created column in order to correctly
159-
// assign sequence ownership.
159+
// assign sequence ownership and function dependencies.
160160
version := params.ExecCfg().Settings.Version.ActiveVersion(params.ctx)
161161
if err := n.tableDesc.AllocateIDs(params.ctx, version); err != nil {
162162
return err
163163
}
164164

165+
if err := params.p.maybeUpdateFunctionReferencesForColumn(params.ctx, n.tableDesc, col); err != nil {
166+
return err
167+
}
168+
165169
// If the new column has a DEFAULT or an ON UPDATE expression that uses a
166170
// sequence, add references between its descriptor and this column descriptor.
167171
if err := cdd.ForEachTypedExpr(func(expr tree.TypedExpr, colExprKind tabledesc.ColExprKind) error {

pkg/sql/backfill/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ go_library(
2020
"//pkg/sql/catalog",
2121
"//pkg/sql/catalog/catenumpb",
2222
"//pkg/sql/catalog/descpb",
23+
"//pkg/sql/catalog/descs",
2324
"//pkg/sql/catalog/fetchpb",
2425
"//pkg/sql/catalog/schemaexpr",
2526
"//pkg/sql/catalog/tabledesc",

pkg/sql/backfill/backfill.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import (
1818
"github.com/cockroachdb/cockroach/pkg/settings"
1919
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
2020
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
21+
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descs"
2122
"github.com/cockroachdb/cockroach/pkg/sql/catalog/fetchpb"
2223
"github.com/cockroachdb/cockroach/pkg/sql/catalog/schemaexpr"
2324
"github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc"
2425
"github.com/cockroachdb/cockroach/pkg/sql/execinfra"
25-
"github.com/cockroachdb/cockroach/pkg/sql/isql"
2626
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
2727
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
2828
"github.com/cockroachdb/cockroach/pkg/sql/row"
@@ -230,7 +230,7 @@ func (cb *ColumnBackfiller) InitForDistributedUse(
230230
var defaultExprs, computedExprs []tree.TypedExpr
231231
// Install type metadata in the target descriptors, as well as resolve any
232232
// user defined types in the column expressions.
233-
if err := flowCtx.Cfg.DB.Txn(ctx, func(ctx context.Context, txn isql.Txn) error {
233+
if err := flowCtx.Cfg.DB.DescsTxn(ctx, func(ctx context.Context, txn descs.Txn) error {
234234
resolver := flowCtx.NewTypeResolver(txn.KV())
235235
// Hydrate all the types present in the table.
236236
if err := typedesc.HydrateTypesInDescriptor(ctx, desc, &resolver); err != nil {
@@ -239,6 +239,7 @@ func (cb *ColumnBackfiller) InitForDistributedUse(
239239
// Set up a SemaContext to type check the default and computed expressions.
240240
semaCtx := tree.MakeSemaContext(&resolver)
241241
semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(evalCtx.Settings.Version)
242+
semaCtx.FunctionResolver = descs.NewDistSQLFunctionResolver(txn.Descriptors(), txn.KV())
242243
var err error
243244
defaultExprs, err = schemaexpr.MakeDefaultExprs(
244245
ctx, cb.added, &transform.ExprTransformContext{}, evalCtx, &semaCtx,
@@ -758,7 +759,7 @@ func (ib *IndexBackfiller) InitForDistributedUse(
758759

759760
// Install type metadata in the target descriptors, as well as resolve any
760761
// user defined types in partial index predicate expressions.
761-
if err := flowCtx.Cfg.DB.Txn(ctx, func(ctx context.Context, txn isql.Txn) (err error) {
762+
if err := flowCtx.Cfg.DB.DescsTxn(ctx, func(ctx context.Context, txn descs.Txn) (err error) {
762763
resolver := flowCtx.NewTypeResolver(txn.KV())
763764
// Hydrate all the types present in the table.
764765
if err = typedesc.HydrateTypesInDescriptor(ctx, desc, &resolver); err != nil {
@@ -767,6 +768,7 @@ func (ib *IndexBackfiller) InitForDistributedUse(
767768
// Set up a SemaContext to type check the default and computed expressions.
768769
semaCtx := tree.MakeSemaContext(&resolver)
769770
semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(evalCtx.Settings.Version)
771+
semaCtx.FunctionResolver = descs.NewDistSQLFunctionResolver(txn.Descriptors(), txn.KV())
770772
// Convert any partial index predicate strings into expressions.
771773
predicates, colExprs, referencedColumns, err = constructExprs(
772774
ctx, desc, ib.added, ib.cols, ib.addedCols, ib.computedCols, evalCtx, &semaCtx,

pkg/sql/catalog/descriptor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,12 @@ type TableDescriptor interface {
680680
colID descpb.ColumnID,
681681
) (DescriptorIDSet, error)
682682

683+
// GetAllReferencedFunctionIDsInIndex returns descriptor IDs of all user
684+
// defined functions referenced in expressions used by this index.
685+
GetAllReferencedFunctionIDsInIndex(
686+
indexID descpb.IndexID,
687+
) (DescriptorIDSet, error)
688+
683689
// ForeachDependedOnBy runs a function on all indexes, including those being
684690
// added in the mutations.
685691
ForeachDependedOnBy(f func(dep *descpb.TableDescriptor_Reference) error) error

pkg/sql/catalog/funcdesc/func_desc.go

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,18 @@ func (desc *immutable) validateInboundTableRef(
385385
return errors.AssertionFailedf("depended-on-by relation %q (%d) does not have an index with ID %d",
386386
backRefTbl.GetName(), by.ID, idxID)
387387
}
388-
// TODO(chengxiong): add logic to validate reference in index expressions
389-
// when UDF usage is allowed in indexes.
388+
fnIDs, err := backRefTbl.GetAllReferencedFunctionIDsInIndex(idxID)
389+
if err != nil {
390+
return err
391+
}
392+
if fnIDs.Contains(desc.GetID()) {
393+
foundInTable = true
394+
continue
395+
}
396+
return errors.AssertionFailedf(
397+
"index %d in depended-on-by relation %q (%d) does not have reference to function %q (%d)",
398+
idxID, backRefTbl.GetName(), backRefTbl.GetID(), desc.GetName(), desc.GetID(),
399+
)
390400
}
391401

392402
for _, cstID := range by.ConstraintIDs {
@@ -852,6 +862,55 @@ func (desc *Mutable) RemovePolicyReference(id descpb.ID, policyID descpb.PolicyI
852862
}
853863
}
854864

865+
// AddIndexReference adds back reference to an index to the function.
866+
func (desc *Mutable) AddIndexReference(id descpb.ID, indexID descpb.IndexID) error {
867+
for _, dep := range desc.DependsOn {
868+
if dep == id {
869+
return pgerror.Newf(pgcode.InvalidFunctionDefinition,
870+
"cannot add dependency from descriptor %d to function %s (%d) because there will be a dependency cycle", id, desc.GetName(), desc.GetID(),
871+
)
872+
}
873+
}
874+
for i := range desc.DependedOnBy {
875+
if desc.DependedOnBy[i].ID == id {
876+
for _, prevID := range desc.DependedOnBy[i].IndexIDs {
877+
if prevID == indexID {
878+
return nil
879+
}
880+
}
881+
desc.DependedOnBy[i].IndexIDs = append(desc.DependedOnBy[i].IndexIDs, indexID)
882+
return nil
883+
}
884+
}
885+
desc.DependedOnBy = append(
886+
desc.DependedOnBy,
887+
descpb.FunctionDescriptor_Reference{
888+
ID: id,
889+
IndexIDs: []descpb.IndexID{indexID},
890+
},
891+
)
892+
sort.Slice(desc.DependedOnBy, func(i, j int) bool {
893+
return desc.DependedOnBy[i].ID < desc.DependedOnBy[j].ID
894+
})
895+
return nil
896+
}
897+
898+
// RemoveIndexReference removes back reference to an index from the function.
899+
func (desc *Mutable) RemoveIndexReference(id descpb.ID, indexID descpb.IndexID) {
900+
for i := range desc.DependedOnBy {
901+
if desc.DependedOnBy[i].ID == id {
902+
dep := &desc.DependedOnBy[i]
903+
for j := range dep.IndexIDs {
904+
if dep.IndexIDs[j] == indexID {
905+
dep.IndexIDs = append(dep.IndexIDs[:j], dep.IndexIDs[j+1:]...)
906+
desc.maybeRemoveTableReference(id)
907+
return
908+
}
909+
}
910+
}
911+
}
912+
}
913+
855914
// maybeRemoveTableReference removes a table's references from the function if
856915
// the column, index and constraint references are all empty. This function is
857916
// only used internally when removing an individual column, index or constraint

pkg/sql/catalog/funcdesc/helpers.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,22 @@ var schemaExprContextAllowingUDF = map[tree.SchemaExprContext]clusterversion.Key
1515
tree.CheckConstraintExpr: clusterversion.MinSupported,
1616
tree.ColumnDefaultExprInNewTable: clusterversion.MinSupported,
1717
tree.ColumnDefaultExprInSetDefault: clusterversion.MinSupported,
18+
19+
tree.PolicyUsingExpr: clusterversion.V25_2,
20+
tree.PolicyWithCheckExpr: clusterversion.V25_2,
21+
22+
tree.ColumnDefaultExprInAddColumn: clusterversion.V25_3,
23+
tree.ColumnDefaultExprInNewView: clusterversion.V25_3,
24+
tree.ColumnOnUpdateExpr: clusterversion.V25_3,
25+
tree.ExpressionIndexElementExpr: clusterversion.V25_3,
26+
tree.IndexPredicateExpr: clusterversion.V25_3,
27+
tree.StoredComputedColumnExpr: clusterversion.V25_3,
28+
tree.VirtualComputedColumnExpr: clusterversion.V25_3,
1829
}
1930

2031
// MaybeFailOnUDFUsage returns an error if the given expression or any
2132
// sub-expression used a UDF unless it's explicitly listed as an allowed use
2233
// case.
23-
// TODO(chengxiong): remove this function when we start allowing UDF references.
2434
func MaybeFailOnUDFUsage(
2535
expr tree.TypedExpr, exprContext tree.SchemaExprContext, version clusterversion.ClusterVersion,
2636
) error {

pkg/sql/catalog/schemaexpr/expr.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
2727
"github.com/cockroachdb/cockroach/pkg/sql/sqlerrors"
2828
"github.com/cockroachdb/cockroach/pkg/sql/types"
29-
"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
3029
"github.com/cockroachdb/errors"
3130
)
3231

@@ -80,13 +79,8 @@ func DequalifyAndValidateExprImpl(
8079
return "", nil, colIDs, err
8180
}
8281

83-
// TODO(87699): We can remove this once we have forward/backward references to
84-
// functions. We skip this for policies because we have those references in
85-
// place already.
86-
if context != tree.PolicyUsingExpr && context != tree.PolicyWithCheckExpr {
87-
if err := funcdesc.MaybeFailOnUDFUsage(typedExpr, context, version); err != nil {
88-
return "", nil, colIDs, unimplemented.NewWithIssue(87699, "usage of user-defined function from relations not supported")
89-
}
82+
if err := funcdesc.MaybeFailOnUDFUsage(typedExpr, context, version); err != nil {
83+
return "", nil, colIDs, err
9084
}
9185

9286
// We need to do the rewrite here before the expression is serialized because

0 commit comments

Comments
 (0)