constraints.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package storage
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // PrimaryKeyViolationError preserves duplicate-key identity through wrapped
  7. // executor errors so wire adapters can report integrity SQLSTATE 23505.
  8. type PrimaryKeyViolationError struct {
  9. Table string
  10. Key string
  11. }
  12. func (e *PrimaryKeyViolationError) Error() string {
  13. return fmt.Sprintf("duplicate primary key: %s", e.Key)
  14. }
  15. // NotNullViolationError identifies the final row that violates a required column.
  16. type NotNullViolationError struct {
  17. Table string
  18. Column string
  19. }
  20. func (e *NotNullViolationError) Error() string {
  21. return fmt.Sprintf("NOT NULL constraint failed: %s.%s", e.Table, e.Column)
  22. }
  23. func validateNotNull(schema *Schema, row Row) error {
  24. for _, column := range schema.Columns {
  25. if !column.Nullable && row[column.Name] == nil {
  26. return &NotNullViolationError{Table: schema.Name, Column: column.Name}
  27. }
  28. }
  29. return nil
  30. }
  31. // applySchemaDefaults completes a row image that was built against an older
  32. // schema: columns the row predates receive their catalog default, and the row is
  33. // then validated against the required columns of the current schema.
  34. //
  35. // Write paths re-run it under the table gate because building a row image and
  36. // publishing it are separate steps. A transaction can normalize an INSERT before
  37. // a concurrent ADD COLUMN publishes a column and commit after it; the commit's
  38. // compare check cannot reject that row, because a new key is only checked for
  39. // absence. Re-applying the current schema keeps such a row from becoming a
  40. // durable NOT NULL violation, and gives it the default every other row received
  41. // from the backfill. An absent key is the only thing filled, so an explicit NULL
  42. // still does not select a default.
  43. //
  44. // A constant default is copied from the catalog. An expression default is
  45. // evaluated here instead, so a row that reaches storage without one (for
  46. // example a staged transaction row whose column was published later) receives a
  47. // value rather than freezing the DDL-time one. Ordinary INSERT/UPDATE resolve
  48. // expression defaults in the executor before the write; this is the fallback
  49. // for every other path.
  50. func (m *SchemaManager) applySchemaDefaults(schema *Schema, row Row) error {
  51. for _, column := range schema.Columns {
  52. if _, ok := rowColumnValue(row, column.Name); ok {
  53. continue
  54. }
  55. value, ok, err := m.columnDefaultValue(column)
  56. if err != nil {
  57. return err
  58. }
  59. if ok {
  60. row[column.Name] = value
  61. }
  62. }
  63. return validateNotNull(schema, row)
  64. }
  65. // columnDefaultValue returns the value a row receives for a column it omits.
  66. // A column with no default reports ok=false. DefaultExpr takes precedence over
  67. // Default; the two are never both set by DDL, which keeps constant defaults in
  68. // the catalog as values and clock-reading defaults as SQL text.
  69. func (m *SchemaManager) columnDefaultValue(column Column) (interface{}, bool, error) {
  70. if column.DefaultExpr != "" {
  71. eval := m.defaultEvaluator()
  72. if eval == nil {
  73. return nil, false, fmt.Errorf("column %q has a DEFAULT expression but no evaluator is installed", column.Name)
  74. }
  75. value, err := eval(column.DefaultExpr)
  76. if err != nil {
  77. return nil, false, fmt.Errorf("evaluate DEFAULT for column %q: %w", column.Name, err)
  78. }
  79. return value, true, nil
  80. }
  81. if column.Default != nil {
  82. return column.Default, true, nil
  83. }
  84. return nil, false, nil
  85. }
  86. // rowColumnValue returns the value a row holds for a column, matching the column
  87. // name case-insensitively.
  88. func rowColumnValue(row Row, name string) (interface{}, bool) {
  89. if value, ok := row[name]; ok {
  90. return value, true
  91. }
  92. for key, value := range row {
  93. if strings.EqualFold(key, name) {
  94. return value, true
  95. }
  96. }
  97. return nil, false
  98. }