github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/optbuilder/mutation_builder.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package optbuilder 12 13 import ( 14 "fmt" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/server/telemetry" 18 "github.com/cockroachdb/cockroach/pkg/sql/opt" 19 "github.com/cockroachdb/cockroach/pkg/sql/opt/cat" 20 "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" 21 "github.com/cockroachdb/cockroach/pkg/sql/parser" 22 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 23 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 24 "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins" 25 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 26 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 27 "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" 28 "github.com/cockroachdb/cockroach/pkg/sql/types" 29 "github.com/cockroachdb/cockroach/pkg/util" 30 "github.com/cockroachdb/errors" 31 ) 32 33 // mutationBuilder is a helper struct that supports building Insert, Update, 34 // Upsert, and Delete operators in stages. 35 // TODO(andyk): Add support for Delete. 36 type mutationBuilder struct { 37 b *Builder 38 md *opt.Metadata 39 40 // opName is the statement's name, used in error messages. 41 opName string 42 43 // tab is the target table. 44 tab cat.Table 45 46 // tabID is the metadata ID of the table. 47 tabID opt.TableID 48 49 // alias is the table alias specified in the mutation statement, or just the 50 // resolved table name if no alias was specified. 51 alias tree.TableName 52 53 // outScope contains the current set of columns that are in scope, as well as 54 // the output expression as it is incrementally built. Once the final mutation 55 // expression is completed, it will be contained in outScope.expr. Columns, 56 // when present, are arranged in this order: 57 // 58 // +--------+-------+--------+--------+-------+------------------+ 59 // | Insert | Fetch | Update | Upsert | Check | Index Predicates | 60 // +--------+-------+--------+--------+-------+------------------+ 61 // 62 // Each column is identified by its ordinal position in outScope, and those 63 // ordinals are stored in the corresponding ScopeOrds fields (see below). 64 outScope *scope 65 66 // targetColList is an ordered list of IDs of the table columns into which 67 // values will be inserted, or which will be updated with new values. It is 68 // incrementally built as the mutation operator is built. 69 targetColList opt.ColList 70 71 // targetColSet contains the same column IDs as targetColList, but as a set. 72 targetColSet opt.ColSet 73 74 // insertOrds lists the outScope columns providing values to insert. Its 75 // length is always equal to the number of columns in the target table, 76 // including mutation columns. Table columns which will not have values 77 // inserted are set to -1 (e.g. delete-only mutation columns). insertOrds 78 // is empty if this is not an Insert/Upsert operator. 79 insertOrds []scopeOrdinal 80 81 // fetchOrds lists the outScope columns storing values which are fetched 82 // from the target table in order to provide existing values that will form 83 // lookup and update values. Its length is always equal to the number of 84 // columns in the target table, including mutation columns. Table columns 85 // which do not need to be fetched are set to -1. fetchOrds is empty if 86 // this is an Insert operator. 87 fetchOrds []scopeOrdinal 88 89 // updateOrds lists the outScope columns providing update values. Its length 90 // is always equal to the number of columns in the target table, including 91 // mutation columns. Table columns which do not need to be updated are set 92 // to -1. 93 updateOrds []scopeOrdinal 94 95 // upsertOrds lists the outScope columns that choose between an insert or 96 // update column using a CASE expression: 97 // 98 // CASE WHEN canary_col IS NULL THEN ins_col ELSE upd_col END 99 // 100 // These columns are used to compute constraints and to return result rows. 101 // The length of upsertOrds is always equal to the number of columns in 102 // the target table, including mutation columns. Table columns which do not 103 // need to be updated are set to -1. upsertOrds is empty if this is not 104 // an Upsert operator. 105 upsertOrds []scopeOrdinal 106 107 // checkOrds lists the outScope columns storing the boolean results of 108 // evaluating check constraint expressions defined on the target table. Its 109 // length is always equal to the number of check constraints on the table 110 // (see opt.Table.CheckCount). 111 checkOrds []scopeOrdinal 112 113 // indexPredicateOrds lists the outScope columns storing the boolean results 114 // of evaluating partial index predicate expressions defined on the indexes 115 // of the target table. Its length is always equal to the number of partial 116 // indexes on the table. 117 // TODO(mgartner): We will likely need two sets of columns to support 118 // updates for partial indexes; one set to indicate current rows that need 119 // to be removed from the index, and the other to indicate updated rows that 120 // need to be added to the index. 121 indexPredicateOrds []scopeOrdinal 122 123 // canaryColID is the ID of the column that is used to decide whether to 124 // insert or update each row. If the canary column's value is null, then it's 125 // an insert; otherwise it's an update. 126 canaryColID opt.ColumnID 127 128 // subqueries temporarily stores subqueries that were built during initial 129 // analysis of SET expressions. They will be used later when the subqueries 130 // are joined into larger LEFT OUTER JOIN expressions. 131 subqueries []*scope 132 133 // parsedExprs is a cached set of parsed default and computed expressions 134 // from the table schema. These are parsed once and cached for reuse. 135 parsedExprs []tree.Expr 136 137 // checks contains foreign key check queries; see buildFK* methods. 138 checks memo.FKChecksExpr 139 140 // cascades contains foreign key check cascades; see buildFK* methods. 141 cascades memo.FKCascades 142 143 // fkFallback is true if we need to fall back on the legacy path for 144 // FK checks / cascades. See buildFK* methods. 145 fkFallback bool 146 147 // withID is nonzero if we need to buffer the input for FK checks. 148 withID opt.WithID 149 150 // extraAccessibleCols stores all the columns that are available to the 151 // mutation that are not part of the target table. This is useful for 152 // UPDATE ... FROM queries, as the columns from the FROM tables must be 153 // made accessible to the RETURNING clause. 154 extraAccessibleCols []scopeColumn 155 156 // fkCheckHelper is used to prevent allocating the helper separately. 157 fkCheckHelper fkCheckHelper 158 } 159 160 func (mb *mutationBuilder) init(b *Builder, opName string, tab cat.Table, alias tree.TableName) { 161 mb.b = b 162 mb.md = b.factory.Metadata() 163 mb.opName = opName 164 mb.tab = tab 165 mb.alias = alias 166 mb.targetColList = make(opt.ColList, 0, tab.DeletableColumnCount()) 167 168 // Allocate segmented array of scope column ordinals. 169 n := tab.DeletableColumnCount() 170 scopeOrds := make([]scopeOrdinal, n*4+tab.CheckCount()+partialIndexCount(tab)) 171 for i := range scopeOrds { 172 scopeOrds[i] = -1 173 } 174 mb.insertOrds = scopeOrds[:n] 175 mb.fetchOrds = scopeOrds[n : n*2] 176 mb.updateOrds = scopeOrds[n*2 : n*3] 177 mb.upsertOrds = scopeOrds[n*3 : n*4] 178 mb.checkOrds = scopeOrds[n*4 : n*4+tab.CheckCount()] 179 mb.indexPredicateOrds = scopeOrds[n*4+tab.CheckCount():] 180 181 // Add the table and its columns (including mutation columns) to metadata. 182 mb.tabID = mb.md.AddTable(tab, &mb.alias) 183 } 184 185 // scopeOrdToColID returns the ID of the given scope column. If no scope column 186 // is defined, scopeOrdToColID returns 0. 187 func (mb *mutationBuilder) scopeOrdToColID(ord scopeOrdinal) opt.ColumnID { 188 if ord == -1 { 189 return 0 190 } 191 return mb.outScope.cols[ord].id 192 } 193 194 // insertColID is a convenience method that returns the ID of the input column 195 // that provides the insertion value for the given table column (specified by 196 // ordinal position in the table). 197 func (mb *mutationBuilder) insertColID(tabOrd int) opt.ColumnID { 198 return mb.scopeOrdToColID(mb.insertOrds[tabOrd]) 199 } 200 201 // buildInputForUpdate constructs a Select expression from the fields in 202 // the Update operator, similar to this: 203 // 204 // SELECT <cols> 205 // FROM <table> 206 // WHERE <where> 207 // ORDER BY <order-by> 208 // LIMIT <limit> 209 // 210 // All columns from the table to update are added to fetchColList. 211 // If a FROM clause is defined, we build out each of the table 212 // expressions required and JOIN them together (LATERAL joins between 213 // the tables are allowed). We then JOIN the result with the target 214 // table (the FROM tables can't reference this table) and apply the 215 // appropriate WHERE conditions. 216 // 217 // It is the responsibility of the user to guarantee that the JOIN 218 // produces a maximum of one row per row of the target table. If multiple 219 // are found, an arbitrary one is chosen (this row is not readily 220 // predictable, consistent with the POSTGRES implementation). 221 // buildInputForUpdate stores the columns of the FROM tables in the 222 // mutation builder so they can be made accessible to other parts of 223 // the query (RETURNING clause). 224 // TODO(andyk): Do needed column analysis to project fewer columns if possible. 225 func (mb *mutationBuilder) buildInputForUpdate( 226 inScope *scope, 227 texpr tree.TableExpr, 228 from tree.TableExprs, 229 where *tree.Where, 230 limit *tree.Limit, 231 orderBy tree.OrderBy, 232 ) { 233 var indexFlags *tree.IndexFlags 234 if source, ok := texpr.(*tree.AliasedTableExpr); ok && source.IndexFlags != nil { 235 indexFlags = source.IndexFlags 236 telemetry.Inc(sqltelemetry.IndexHintUseCounter) 237 telemetry.Inc(sqltelemetry.IndexHintUpdateUseCounter) 238 } 239 240 // Fetch columns from different instance of the table metadata, so that it's 241 // possible to remap columns, as in this example: 242 // 243 // UPDATE abc SET a=b 244 // 245 // NOTE: Include mutation columns, but be careful to never use them for any 246 // reason other than as "fetch columns". See buildScan comment. 247 mb.outScope = mb.b.buildScan( 248 mb.b.addTable(mb.tab, &mb.alias), 249 nil, /* ordinals */ 250 indexFlags, 251 noRowLocking, 252 includeMutations, 253 inScope, 254 ) 255 256 fromClausePresent := len(from) > 0 257 numCols := len(mb.outScope.cols) 258 259 // If there is a FROM clause present, we must join all the tables 260 // together with the table being updated. 261 if fromClausePresent { 262 fromScope := mb.b.buildFromTables(from, noRowLocking, inScope) 263 264 // Check that the same table name is not used multiple times. 265 mb.b.validateJoinTableNames(mb.outScope, fromScope) 266 267 // The FROM table columns can be accessed by the RETURNING clause of the 268 // query and so we have to make them accessible. 269 mb.extraAccessibleCols = fromScope.cols 270 271 // Add the columns in the FROM scope. 272 mb.outScope.appendColumnsFromScope(fromScope) 273 274 left := mb.outScope.expr.(memo.RelExpr) 275 right := fromScope.expr.(memo.RelExpr) 276 mb.outScope.expr = mb.b.factory.ConstructInnerJoin(left, right, memo.TrueFilter, memo.EmptyJoinPrivate) 277 } 278 279 // WHERE 280 mb.b.buildWhere(where, mb.outScope) 281 282 // SELECT + ORDER BY (which may add projected expressions) 283 projectionsScope := mb.outScope.replace() 284 projectionsScope.appendColumnsFromScope(mb.outScope) 285 orderByScope := mb.b.analyzeOrderBy(orderBy, mb.outScope, projectionsScope) 286 mb.b.buildOrderBy(mb.outScope, projectionsScope, orderByScope) 287 mb.b.constructProjectForScope(mb.outScope, projectionsScope) 288 289 // LIMIT 290 if limit != nil { 291 mb.b.buildLimit(limit, inScope, projectionsScope) 292 } 293 294 mb.outScope = projectionsScope 295 296 // Build a distinct on to ensure there is at most one row in the joined output 297 // for every row in the table. 298 if fromClausePresent { 299 var pkCols opt.ColSet 300 301 // We need to ensure that the join has a maximum of one row for every row 302 // in the table and we ensure this by constructing a distinct on the primary 303 // key columns. 304 primaryIndex := mb.tab.Index(cat.PrimaryIndex) 305 for i := 0; i < primaryIndex.KeyColumnCount(); i++ { 306 pkCol := mb.outScope.cols[primaryIndex.Column(i).Ordinal] 307 308 // If the primary key column is hidden, then we don't need to use it 309 // for the distinct on. 310 if !pkCol.hidden { 311 pkCols.Add(pkCol.id) 312 } 313 } 314 315 if !pkCols.Empty() { 316 mb.outScope = mb.b.buildDistinctOn( 317 pkCols, mb.outScope, false /* nullsAreDistinct */, "" /* errorOnDup */) 318 } 319 } 320 321 // Set list of columns that will be fetched by the input expression. 322 for i := 0; i < numCols; i++ { 323 mb.fetchOrds[i] = scopeOrdinal(i) 324 } 325 } 326 327 // buildInputForDelete constructs a Select expression from the fields in 328 // the Delete operator, similar to this: 329 // 330 // SELECT <cols> 331 // FROM <table> 332 // WHERE <where> 333 // ORDER BY <order-by> 334 // LIMIT <limit> 335 // 336 // All columns from the table to update are added to fetchColList. 337 // TODO(andyk): Do needed column analysis to project fewer columns if possible. 338 func (mb *mutationBuilder) buildInputForDelete( 339 inScope *scope, texpr tree.TableExpr, where *tree.Where, limit *tree.Limit, orderBy tree.OrderBy, 340 ) { 341 var indexFlags *tree.IndexFlags 342 if source, ok := texpr.(*tree.AliasedTableExpr); ok && source.IndexFlags != nil { 343 indexFlags = source.IndexFlags 344 telemetry.Inc(sqltelemetry.IndexHintUseCounter) 345 telemetry.Inc(sqltelemetry.IndexHintDeleteUseCounter) 346 } 347 348 // Fetch columns from different instance of the table metadata, so that it's 349 // possible to remap columns, as in this example: 350 // 351 // DELETE FROM abc WHERE a=b 352 // 353 // NOTE: Include mutation columns, but be careful to never use them for any 354 // reason other than as "fetch columns". See buildScan comment. 355 // TODO(andyk): Why does execution engine need mutation columns for Delete? 356 mb.outScope = mb.b.buildScan( 357 mb.b.addTable(mb.tab, &mb.alias), 358 nil, /* ordinals */ 359 indexFlags, 360 noRowLocking, 361 includeMutations, 362 inScope, 363 ) 364 365 // WHERE 366 mb.b.buildWhere(where, mb.outScope) 367 368 // SELECT + ORDER BY (which may add projected expressions) 369 projectionsScope := mb.outScope.replace() 370 projectionsScope.appendColumnsFromScope(mb.outScope) 371 orderByScope := mb.b.analyzeOrderBy(orderBy, mb.outScope, projectionsScope) 372 mb.b.buildOrderBy(mb.outScope, projectionsScope, orderByScope) 373 mb.b.constructProjectForScope(mb.outScope, projectionsScope) 374 375 // LIMIT 376 if limit != nil { 377 mb.b.buildLimit(limit, inScope, projectionsScope) 378 } 379 380 mb.outScope = projectionsScope 381 382 // Set list of columns that will be fetched by the input expression. 383 for i := range mb.outScope.cols { 384 mb.fetchOrds[i] = scopeOrdinal(i) 385 } 386 } 387 388 // addTargetColsByName adds one target column for each of the names in the given 389 // list. 390 func (mb *mutationBuilder) addTargetColsByName(names tree.NameList) { 391 for _, name := range names { 392 // Determine the ordinal position of the named column in the table and 393 // add it as a target column. 394 if ord := cat.FindTableColumnByName(mb.tab, name); ord != -1 { 395 mb.addTargetCol(ord) 396 continue 397 } 398 panic(sqlbase.NewUndefinedColumnError(string(name))) 399 } 400 } 401 402 // addTargetCol adds a target column by its ordinal position in the target 403 // table. It raises an error if a mutation or computed column is targeted, or if 404 // the same column is targeted multiple times. 405 func (mb *mutationBuilder) addTargetCol(ord int) { 406 tabCol := mb.tab.Column(ord) 407 408 // Don't allow targeting of mutation columns. 409 if cat.IsMutationColumn(mb.tab, ord) { 410 panic(makeBackfillError(tabCol.ColName())) 411 } 412 413 // Computed columns cannot be targeted with input values. 414 if tabCol.IsComputed() { 415 panic(sqlbase.CannotWriteToComputedColError(string(tabCol.ColName()))) 416 } 417 418 // Ensure that the name list does not contain duplicates. 419 colID := mb.tabID.ColumnID(ord) 420 if mb.targetColSet.Contains(colID) { 421 panic(pgerror.Newf(pgcode.Syntax, 422 "multiple assignments to the same column %q", tabCol.ColName())) 423 } 424 mb.targetColSet.Add(colID) 425 426 mb.targetColList = append(mb.targetColList, colID) 427 } 428 429 // extractValuesInput tests whether the given input is a VALUES clause with no 430 // WITH, ORDER BY, or LIMIT modifier. If so, it's returned, otherwise nil is 431 // returned. 432 func (mb *mutationBuilder) extractValuesInput(inputRows *tree.Select) *tree.ValuesClause { 433 if inputRows == nil { 434 return nil 435 } 436 437 // Only extract a simple VALUES clause with no modifiers. 438 if inputRows.With != nil || inputRows.OrderBy != nil || inputRows.Limit != nil { 439 return nil 440 } 441 442 // Discard parentheses. 443 if parens, ok := inputRows.Select.(*tree.ParenSelect); ok { 444 return mb.extractValuesInput(parens.Select) 445 } 446 447 if values, ok := inputRows.Select.(*tree.ValuesClause); ok { 448 return values 449 } 450 451 return nil 452 } 453 454 // replaceDefaultExprs looks for DEFAULT specifiers in input value expressions 455 // and replaces them with the corresponding default value expression for the 456 // corresponding column. This is only possible when the input is a VALUES 457 // clause. For example: 458 // 459 // INSERT INTO t (a, b) (VALUES (1, DEFAULT), (DEFAULT, 2)) 460 // 461 // Here, the two DEFAULT specifiers are replaced by the default value expression 462 // for the a and b columns, respectively. 463 // 464 // replaceDefaultExprs returns a VALUES expression with replaced DEFAULT values, 465 // or just the unchanged input expression if there are no DEFAULT values. 466 func (mb *mutationBuilder) replaceDefaultExprs(inRows *tree.Select) (outRows *tree.Select) { 467 values := mb.extractValuesInput(inRows) 468 if values == nil { 469 return inRows 470 } 471 472 // Ensure that the number of input columns exactly matches the number of 473 // target columns. 474 numCols := len(values.Rows[0]) 475 mb.checkNumCols(len(mb.targetColList), numCols) 476 477 var newRows []tree.Exprs 478 for irow, tuple := range values.Rows { 479 if len(tuple) != numCols { 480 reportValuesLenError(numCols, len(tuple)) 481 } 482 483 // Scan list of tuples in the VALUES row, looking for DEFAULT specifiers. 484 var newTuple tree.Exprs 485 for itup, val := range tuple { 486 if _, ok := val.(tree.DefaultVal); ok { 487 // Found DEFAULT, so lazily create new rows and tuple lists. 488 if newRows == nil { 489 newRows = make([]tree.Exprs, irow, len(values.Rows)) 490 copy(newRows, values.Rows[:irow]) 491 } 492 493 if newTuple == nil { 494 newTuple = make(tree.Exprs, itup, numCols) 495 copy(newTuple, tuple[:itup]) 496 } 497 498 val = mb.parseDefaultOrComputedExpr(mb.targetColList[itup]) 499 } 500 if newTuple != nil { 501 newTuple = append(newTuple, val) 502 } 503 } 504 505 if newRows != nil { 506 if newTuple != nil { 507 newRows = append(newRows, newTuple) 508 } else { 509 newRows = append(newRows, tuple) 510 } 511 } 512 } 513 514 if newRows != nil { 515 return &tree.Select{Select: &tree.ValuesClause{Rows: newRows}} 516 } 517 return inRows 518 } 519 520 // addSynthesizedCols is a helper method for addSynthesizedColsForInsert 521 // and addSynthesizedColsForUpdate that scans the list of table columns, looking 522 // for any that do not yet have values provided by the input expression. New 523 // columns are synthesized for any missing columns, as long as the addCol 524 // callback function returns true for that column. 525 // 526 // Values are synthesized for columns based on checking these rules, in order: 527 // 1. If column is computed, evaluate that expression as its value. 528 // 2. If column has a default value specified for it, use that as its value. 529 // 3. If column is nullable, use NULL as its value. 530 // 4. If column is currently being added or dropped (i.e. a mutation column), 531 // use a default value (0 for INT column, "" for STRING column, etc). Note 532 // that the existing "fetched" value returned by the scan cannot be used, 533 // since it may not have been initialized yet by the backfiller. 534 // 535 func (mb *mutationBuilder) addSynthesizedCols( 536 scopeOrds []scopeOrdinal, addCol func(colOrd int) bool, 537 ) { 538 var projectionsScope *scope 539 540 // Skip delete-only mutation columns, since they are ignored by all mutation 541 // operators that synthesize columns. 542 for i, n := 0, mb.tab.WritableColumnCount(); i < n; i++ { 543 // Skip columns that are already specified. 544 if scopeOrds[i] != -1 { 545 continue 546 } 547 548 // Invoke addCol to determine whether column should be added. 549 if !addCol(i) { 550 continue 551 } 552 553 // Construct a new Project operator that will contain the newly synthesized 554 // column(s). 555 if projectionsScope == nil { 556 projectionsScope = mb.outScope.replace() 557 projectionsScope.appendColumnsFromScope(mb.outScope) 558 } 559 tabColID := mb.tabID.ColumnID(i) 560 tabCol := mb.tab.Column(i) 561 expr := mb.parseDefaultOrComputedExpr(tabColID) 562 texpr := mb.outScope.resolveAndRequireType(expr, tabCol.DatumType()) 563 scopeCol := mb.b.addColumn(projectionsScope, "" /* alias */, texpr) 564 mb.b.buildScalar(texpr, mb.outScope, projectionsScope, scopeCol, nil) 565 566 // Assign name to synthesized column. Computed columns may refer to default 567 // columns in the table by name. 568 scopeCol.name = tabCol.ColName() 569 570 // Remember ordinal position of the new scope column. 571 scopeOrds[i] = scopeOrdinal(len(projectionsScope.cols) - 1) 572 573 // Add corresponding target column. 574 mb.targetColList = append(mb.targetColList, tabColID) 575 mb.targetColSet.Add(tabColID) 576 } 577 578 if projectionsScope != nil { 579 mb.b.constructProjectForScope(mb.outScope, projectionsScope) 580 mb.outScope = projectionsScope 581 } 582 } 583 584 // roundDecimalValues wraps each DECIMAL-related column (including arrays of 585 // decimals) with a call to the crdb_internal.round_decimal_values function, if 586 // column values may need to be rounded. This is necessary when mutating table 587 // columns that have a limited scale (e.g. DECIMAL(10, 1)). Here is the PG docs 588 // description: 589 // 590 // http://www.postgresql.org/docs/9.5/static/datatype-numeric.html 591 // "If the scale of a value to be stored is greater than 592 // the declared scale of the column, the system will round the 593 // value to the specified number of fractional digits. Then, 594 // if the number of digits to the left of the decimal point 595 // exceeds the declared precision minus the declared scale, an 596 // error is raised." 597 // 598 // Note that this function only handles the rounding portion of that. The 599 // precision check is done by the execution engine. The rounding cannot be done 600 // there, since it needs to happen before check constraints are computed, and 601 // before UPSERT joins. 602 // 603 // if roundComputedCols is false, then don't wrap computed columns. If true, 604 // then only wrap computed columns. This is necessary because computed columns 605 // can depend on other columns mutated by the operation; it is necessary to 606 // first round those values, then evaluated the computed expression, and then 607 // round the result of the computation. 608 func (mb *mutationBuilder) roundDecimalValues(scopeOrds []scopeOrdinal, roundComputedCols bool) { 609 var projectionsScope *scope 610 611 for i, ord := range scopeOrds { 612 if ord == -1 { 613 // Column not mutated, so nothing to do. 614 continue 615 } 616 617 // Include or exclude computed columns, depending on the value of 618 // roundComputedCols. 619 col := mb.tab.Column(i) 620 if col.IsComputed() != roundComputedCols { 621 continue 622 } 623 624 // Check whether the target column's type may require rounding of the 625 // input value. 626 props, overload := findRoundingFunction(col.DatumType(), col.ColTypePrecision()) 627 if props == nil { 628 continue 629 } 630 private := &memo.FunctionPrivate{ 631 Name: "crdb_internal.round_decimal_values", 632 Typ: mb.outScope.cols[ord].typ, 633 Properties: props, 634 Overload: overload, 635 } 636 variable := mb.b.factory.ConstructVariable(mb.scopeOrdToColID(ord)) 637 scale := mb.b.factory.ConstructConstVal(tree.NewDInt(tree.DInt(col.ColTypeWidth())), types.Int) 638 fn := mb.b.factory.ConstructFunction(memo.ScalarListExpr{variable, scale}, private) 639 640 // Lazily create new scope and update the scope column to be rounded. 641 if projectionsScope == nil { 642 projectionsScope = mb.outScope.replace() 643 projectionsScope.appendColumnsFromScope(mb.outScope) 644 } 645 mb.b.populateSynthesizedColumn(&projectionsScope.cols[ord], fn) 646 } 647 648 if projectionsScope != nil { 649 mb.b.constructProjectForScope(mb.outScope, projectionsScope) 650 mb.outScope = projectionsScope 651 } 652 } 653 654 // findRoundingFunction returns the builtin function overload needed to round 655 // input values. This is only necessary for DECIMAL or DECIMAL[] types that have 656 // limited precision, such as: 657 // 658 // DECIMAL(15, 1) 659 // DECIMAL(10, 3)[] 660 // 661 // If an input decimal value has more than the required number of fractional 662 // digits, it must be rounded before being inserted into these types. 663 // 664 // NOTE: CRDB does not allow nested array storage types, so only one level of 665 // array nesting needs to be checked. 666 func findRoundingFunction(typ *types.T, precision int) (*tree.FunctionProperties, *tree.Overload) { 667 if precision == 0 { 668 // Unlimited precision decimal target type never needs rounding. 669 return nil, nil 670 } 671 672 props, overloads := builtins.GetBuiltinProperties("crdb_internal.round_decimal_values") 673 674 if typ.Equivalent(types.Decimal) { 675 return props, &overloads[0] 676 } 677 if typ.Equivalent(types.DecimalArray) { 678 return props, &overloads[1] 679 } 680 681 // Not DECIMAL or DECIMAL[]. 682 return nil, nil 683 } 684 685 // addCheckConstraintCols synthesizes a boolean output column for each check 686 // constraint defined on the target table. The mutation operator will report 687 // a constraint violation error if the value of the column is false. 688 func (mb *mutationBuilder) addCheckConstraintCols() { 689 if mb.tab.CheckCount() != 0 { 690 projectionsScope := mb.outScope.replace() 691 projectionsScope.appendColumnsFromScope(mb.outScope) 692 693 for i, n := 0, mb.tab.CheckCount(); i < n; i++ { 694 expr, err := parser.ParseExpr(mb.tab.Check(i).Constraint) 695 if err != nil { 696 panic(err) 697 } 698 699 alias := fmt.Sprintf("check%d", i+1) 700 texpr := mb.outScope.resolveAndRequireType(expr, types.Bool) 701 scopeCol := mb.b.addColumn(projectionsScope, alias, texpr) 702 703 // TODO(ridwanmsharif): Maybe we can avoid building constraints here 704 // and instead use the constraints stored in the table metadata. 705 mb.b.buildScalar(texpr, mb.outScope, projectionsScope, scopeCol, nil) 706 mb.checkOrds[i] = scopeOrdinal(len(projectionsScope.cols) - 1) 707 } 708 709 mb.b.constructProjectForScope(mb.outScope, projectionsScope) 710 mb.outScope = projectionsScope 711 } 712 } 713 714 // addPartialIndexPredicateCols synthesizes a boolean output column for each 715 // partial index defined on the target table. The execution code uses these 716 // booleans to determine whether or not to insert or delete a row in the partial 717 // index. 718 func (mb *mutationBuilder) addPartialIndexPredicateCols() { 719 projectionsScope := mb.outScope.replace() 720 projectionsScope.appendColumnsFromScope(mb.outScope) 721 722 ord := 0 723 for i, n := 0, mb.tab.IndexCount(); i < n; i++ { 724 index := mb.tab.Index(i) 725 predicate, ok := index.Predicate() 726 if !ok { 727 continue 728 } 729 730 expr, err := parser.ParseExpr(predicate) 731 if err != nil { 732 panic(err) 733 } 734 735 alias := fmt.Sprintf("indexpred%d", ord+1) 736 texpr := mb.outScope.resolveAndRequireType(expr, types.Bool) 737 scopeCol := mb.b.addColumn(projectionsScope, alias, texpr) 738 739 mb.b.buildScalar(texpr, mb.outScope, projectionsScope, scopeCol, nil) 740 mb.indexPredicateOrds[ord] = scopeOrdinal(len(projectionsScope.cols) - 1) 741 742 ord++ 743 } 744 745 mb.b.constructProjectForScope(mb.outScope, projectionsScope) 746 mb.outScope = projectionsScope 747 } 748 749 // disambiguateColumns ranges over the scope and ensures that at most one column 750 // has each table column name, and that name refers to the column with the final 751 // value that the mutation applies. 752 func (mb *mutationBuilder) disambiguateColumns() { 753 // Determine the set of scope columns that will have their names preserved. 754 var preserve util.FastIntSet 755 for i, n := 0, mb.tab.DeletableColumnCount(); i < n; i++ { 756 scopeOrd := mb.mapToReturnScopeOrd(i) 757 if scopeOrd != -1 { 758 preserve.Add(int(scopeOrd)) 759 } 760 } 761 762 // Clear names of all non-preserved columns. 763 for i := range mb.outScope.cols { 764 if !preserve.Contains(i) { 765 mb.outScope.cols[i].clearName() 766 } 767 } 768 } 769 770 // makeMutationPrivate builds a MutationPrivate struct containing the table and 771 // column metadata needed for the mutation operator. 772 func (mb *mutationBuilder) makeMutationPrivate(needResults bool) *memo.MutationPrivate { 773 // Helper function to create a column list in the MutationPrivate. 774 makeColList := func(scopeOrds []scopeOrdinal) opt.ColList { 775 var colList opt.ColList 776 for i := range scopeOrds { 777 if scopeOrds[i] != -1 { 778 if colList == nil { 779 colList = make(opt.ColList, len(scopeOrds)) 780 } 781 colList[i] = mb.scopeOrdToColID(scopeOrds[i]) 782 } 783 } 784 return colList 785 } 786 787 private := &memo.MutationPrivate{ 788 Table: mb.tabID, 789 InsertCols: makeColList(mb.insertOrds), 790 FetchCols: makeColList(mb.fetchOrds), 791 UpdateCols: makeColList(mb.updateOrds), 792 CanaryCol: mb.canaryColID, 793 CheckCols: makeColList(mb.checkOrds), 794 IndexPredicateCols: makeColList(mb.indexPredicateOrds), 795 FKCascades: mb.cascades, 796 FKFallback: mb.fkFallback, 797 } 798 799 // If we didn't actually plan any checks or cascades, don't buffer the input. 800 if len(mb.checks) > 0 || len(mb.cascades) > 0 { 801 private.WithID = mb.withID 802 } 803 804 if needResults { 805 // Only non-mutation columns are output columns. ReturnCols needs to have 806 // DeletableColumnCount entries, but only the first ColumnCount entries 807 // can be defined (i.e. >= 0). 808 private.ReturnCols = make(opt.ColList, mb.tab.DeletableColumnCount()) 809 for i, n := 0, mb.tab.ColumnCount(); i < n; i++ { 810 scopeOrd := mb.mapToReturnScopeOrd(i) 811 if scopeOrd == -1 { 812 panic(errors.AssertionFailedf("column %d is not available in the mutation input", i)) 813 } 814 private.ReturnCols[i] = mb.outScope.cols[scopeOrd].id 815 } 816 } 817 818 return private 819 } 820 821 // mapToReturnScopeOrd returns the ordinal of the scope column that provides the 822 // final value for the column at the given ordinal position in the table. This 823 // value might mutate the column, or it might be returned by the mutation 824 // statement, or it might not be used at all. Columns take priority in this 825 // order: 826 // 827 // upsert, update, fetch, insert 828 // 829 // If an upsert column is available, then it already combines an update/fetch 830 // value with an insert value, so it takes priority. If an update column is 831 // available, then it overrides any fetch value. Finally, the relative priority 832 // of fetch and insert columns doesn't matter, since they're only used together 833 // in the upsert case where an upsert column would be available. 834 // 835 // If the column is never referenced by the statement, then mapToReturnScopeOrd 836 // returns 0. This would be the case for delete-only columns in an Insert 837 // statement, because they're neither fetched nor mutated. 838 func (mb *mutationBuilder) mapToReturnScopeOrd(tabOrd int) scopeOrdinal { 839 switch { 840 case mb.upsertOrds[tabOrd] != -1: 841 return mb.upsertOrds[tabOrd] 842 843 case mb.updateOrds[tabOrd] != -1: 844 return mb.updateOrds[tabOrd] 845 846 case mb.fetchOrds[tabOrd] != -1: 847 return mb.fetchOrds[tabOrd] 848 849 case mb.insertOrds[tabOrd] != -1: 850 return mb.insertOrds[tabOrd] 851 852 default: 853 // Column is never referenced by the statement. 854 return -1 855 } 856 } 857 858 // buildReturning wraps the input expression with a Project operator that 859 // projects the given RETURNING expressions. 860 func (mb *mutationBuilder) buildReturning(returning tree.ReturningExprs) { 861 // Handle case of no RETURNING clause. 862 if returning == nil { 863 expr := mb.outScope.expr 864 mb.outScope = mb.b.allocScope() 865 mb.outScope.expr = expr 866 return 867 } 868 869 // Start out by constructing a scope containing one column for each non- 870 // mutation column in the target table, in the same order, and with the 871 // same names. These columns can be referenced by the RETURNING clause. 872 // 873 // 1. Project only non-mutation columns. 874 // 2. Alias columns to use table column names. 875 // 3. Mark hidden columns. 876 // 4. Project columns in same order as defined in table schema. 877 // 878 inScope := mb.outScope.replace() 879 inScope.expr = mb.outScope.expr 880 inScope.appendColumnsFromTable(mb.md.TableMeta(mb.tabID), &mb.alias) 881 882 // extraAccessibleCols contains all the columns that the RETURNING 883 // clause can refer to in addition to the table columns. This is useful for 884 // UPDATE ... FROM statements, where all columns from tables in the FROM clause 885 // are in scope for the RETURNING clause. 886 inScope.appendColumns(mb.extraAccessibleCols) 887 888 // Construct the Project operator that projects the RETURNING expressions. 889 outScope := inScope.replace() 890 mb.b.analyzeReturningList(returning, nil /* desiredTypes */, inScope, outScope) 891 mb.b.buildProjectionList(inScope, outScope) 892 mb.b.constructProjectForScope(inScope, outScope) 893 mb.outScope = outScope 894 } 895 896 // checkNumCols raises an error if the expected number of columns does not match 897 // the actual number of columns. 898 func (mb *mutationBuilder) checkNumCols(expected, actual int) { 899 if actual != expected { 900 more, less := "expressions", "target columns" 901 if actual < expected { 902 more, less = less, more 903 } 904 905 panic(pgerror.Newf(pgcode.Syntax, 906 "%s has more %s than %s, %d expressions for %d targets", 907 strings.ToUpper(mb.opName), more, less, actual, expected)) 908 } 909 } 910 911 // parseDefaultOrComputedExpr parses the default (including nullable) or 912 // computed value expression for the given table column, and caches it for 913 // reuse. 914 func (mb *mutationBuilder) parseDefaultOrComputedExpr(colID opt.ColumnID) tree.Expr { 915 if mb.parsedExprs == nil { 916 mb.parsedExprs = make([]tree.Expr, mb.tab.DeletableColumnCount()) 917 } 918 919 // Return expression from cache, if it was already parsed previously. 920 ord := mb.tabID.ColumnOrdinal(colID) 921 if mb.parsedExprs[ord] != nil { 922 return mb.parsedExprs[ord] 923 } 924 925 var exprStr string 926 tabCol := mb.tab.Column(ord) 927 switch { 928 case tabCol.IsComputed(): 929 exprStr = tabCol.ComputedExprStr() 930 case tabCol.HasDefault(): 931 exprStr = tabCol.DefaultExprStr() 932 case tabCol.IsNullable(): 933 return tree.DNull 934 default: 935 // Synthesize default value for NOT NULL mutation column so that it can be 936 // set when in the write-only state. This is only used when no other value 937 // is possible (no default value available, NULL not allowed). 938 if cat.IsMutationColumn(mb.tab, ord) { 939 datum, err := tree.NewDefaultDatum(mb.b.evalCtx, tabCol.DatumType()) 940 if err != nil { 941 panic(err) 942 } 943 return datum 944 } 945 return tree.DNull 946 } 947 948 expr, err := parser.ParseExpr(exprStr) 949 if err != nil { 950 panic(err) 951 } 952 953 mb.parsedExprs[ord] = expr 954 return expr 955 } 956 957 // getIndexLaxKeyOrdinals returns the ordinals of all lax key columns in the 958 // given index. A column's ordinal is the ordered position of that column in the 959 // owning table. 960 func getIndexLaxKeyOrdinals(index cat.Index) util.FastIntSet { 961 var keyOrds util.FastIntSet 962 for i, n := 0, index.LaxKeyColumnCount(); i < n; i++ { 963 keyOrds.Add(index.Column(i).Ordinal) 964 } 965 return keyOrds 966 } 967 968 // findNotNullIndexCol finds the first not-null column in the given index and 969 // returns its ordinal position in the owner table. There must always be such a 970 // column, even if it turns out to be an implicit primary key column. 971 func findNotNullIndexCol(index cat.Index) int { 972 for i, n := 0, index.KeyColumnCount(); i < n; i++ { 973 indexCol := index.Column(i) 974 if !indexCol.IsNullable() { 975 return indexCol.Ordinal 976 } 977 } 978 panic(errors.AssertionFailedf("should have found not null column in index")) 979 } 980 981 // resultsNeeded determines whether a statement that might have a RETURNING 982 // clause needs to provide values for result rows for a downstream plan. 983 func resultsNeeded(r tree.ReturningClause) bool { 984 switch t := r.(type) { 985 case *tree.ReturningExprs: 986 return true 987 case *tree.ReturningNothing, *tree.NoReturningClause: 988 return false 989 default: 990 panic(errors.AssertionFailedf("unexpected ReturningClause type: %T", t)) 991 } 992 } 993 994 // checkDatumTypeFitsColumnType verifies that a given scalar value type is valid 995 // to be stored in a column of the given column type. 996 // 997 // For the purpose of this analysis, column type aliases are not considered to 998 // be different (eg. TEXT and VARCHAR will fit the same scalar type String). 999 // 1000 // This is used by the UPDATE, INSERT and UPSERT code. 1001 func checkDatumTypeFitsColumnType(col cat.Column, typ *types.T) { 1002 if typ.Equivalent(col.DatumType()) { 1003 return 1004 } 1005 1006 colName := string(col.ColName()) 1007 panic(pgerror.Newf(pgcode.DatatypeMismatch, 1008 "value type %s doesn't match type %s of column %q", 1009 typ, col.DatumType(), tree.ErrNameString(colName))) 1010 } 1011 1012 // partialIndexCount returns the number of public, write-only, and delete-only 1013 // partial indexes defined on the table. 1014 func partialIndexCount(tab cat.Table) int { 1015 count := 0 1016 for i, n := 0, tab.DeletableIndexCount(); i < n; i++ { 1017 if _, ok := tab.Index(i).Predicate(); ok { 1018 count++ 1019 } 1020 } 1021 return count 1022 }