constraints.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package storage
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. )
  7. // PrimaryKeyViolationError preserves duplicate-key identity through wrapped
  8. // executor errors so wire adapters can report integrity SQLSTATE 23505.
  9. type PrimaryKeyViolationError struct {
  10. Table string
  11. Key string
  12. }
  13. func (e *PrimaryKeyViolationError) Error() string {
  14. return fmt.Sprintf("duplicate primary key: %s", e.Key)
  15. }
  16. // NotNullViolationError identifies the final row that violates a required column.
  17. type NotNullViolationError struct {
  18. Table string
  19. Column string
  20. }
  21. func (e *NotNullViolationError) Error() string {
  22. return fmt.Sprintf("NOT NULL constraint failed: %s.%s", e.Table, e.Column)
  23. }
  24. func validateNotNull(schema *Schema, row Row) error {
  25. for _, column := range schema.Columns {
  26. if !column.Nullable && row[column.Name] == nil {
  27. return &NotNullViolationError{Table: schema.Name, Column: column.Name}
  28. }
  29. }
  30. return nil
  31. }
  32. // CheckViolationError identifies the CHECK predicate a write violated. It is a
  33. // distinct type so the protocol layers can report SQLSTATE 23514.
  34. type CheckViolationError struct {
  35. Table string
  36. Constraint string
  37. }
  38. func (e *CheckViolationError) Error() string {
  39. return "CHECK constraint failed: " + e.Constraint
  40. }
  41. // validateChecks evaluates every persisted CHECK predicate against a complete
  42. // row image. The evaluator reports NULL and other unknown results as passing, so
  43. // SQL three-valued logic is preserved: a constraint only rejects a definite
  44. // false.
  45. func (m *SchemaManager) validateChecks(schema *Schema, row Row) error {
  46. if len(schema.Checks) == 0 {
  47. return nil
  48. }
  49. eval := m.checkEvaluator()
  50. if eval == nil {
  51. return fmt.Errorf("cannot validate CHECK constraints on %s: no CHECK evaluator installed", schema.Name)
  52. }
  53. for _, check := range schema.Checks {
  54. holds, err := eval(check.Expression, row)
  55. if err != nil {
  56. return fmt.Errorf("evaluate CHECK constraint %s on %s: %w", check.Label(), schema.Name, err)
  57. }
  58. if !holds {
  59. return &CheckViolationError{Table: schema.Name, Constraint: check.Label()}
  60. }
  61. }
  62. return nil
  63. }
  64. // validateRowConstraints enforces the NOT NULL and CHECK constraints a schema
  65. // declares against a complete row image. Every write path calls it after
  66. // defaults are applied and before the row becomes visible.
  67. func (m *SchemaManager) validateRowConstraints(schema *Schema, row Row) error {
  68. if err := validateNotNull(schema, row); err != nil {
  69. return err
  70. }
  71. return m.validateChecks(schema, row)
  72. }
  73. // applySchemaDefaults completes a row image that was built against an older
  74. // schema: columns the row predates receive their catalog default, and the row is
  75. // then validated against the required columns of the current schema.
  76. //
  77. // Write paths re-run it under the table gate because building a row image and
  78. // publishing it are separate steps. A transaction can normalize an INSERT before
  79. // a concurrent ADD COLUMN publishes a column and commit after it; the commit's
  80. // compare check cannot reject that row, because a new key is only checked for
  81. // absence. Re-applying the current schema keeps such a row from becoming a
  82. // durable NOT NULL violation, and gives it the default every other row received
  83. // from the backfill. An absent key is the only thing filled, so an explicit NULL
  84. // still does not select a default. Callers validate CHECK predicates separately
  85. // through validateRowConstraints/validateChecks so each write site can run them
  86. // against the final row image.
  87. //
  88. // A constant default is copied from the catalog. An expression default is
  89. // evaluated here instead, so a row that reaches storage without one (for
  90. // example a staged transaction row whose column was published later) receives a
  91. // value rather than freezing the DDL-time one. Ordinary INSERT/UPDATE resolve
  92. // expression defaults in the executor before the write; this is the fallback
  93. // for every other path.
  94. func (m *SchemaManager) applySchemaDefaults(schema *Schema, row Row) error {
  95. for _, column := range schema.Columns {
  96. if _, ok := rowColumnValue(row, column.Name); ok {
  97. continue
  98. }
  99. value, ok, err := m.columnDefaultValue(column, m.defaultNow())
  100. if err != nil {
  101. return err
  102. }
  103. if ok {
  104. row[column.Name] = value
  105. }
  106. }
  107. return validateNotNull(schema, row)
  108. }
  109. // columnDefaultValue returns the value a row receives for a column it omits.
  110. // A column with no default reports ok=false. DefaultExpr takes precedence over
  111. // Default; the two are never both set by DDL, which keeps constant defaults in
  112. // the catalog as values and clock-reading defaults as SQL text. now is the
  113. // instant the caller sampled for its statement; a constant default ignores it.
  114. func (m *SchemaManager) columnDefaultValue(column Column, now time.Time) (interface{}, bool, error) {
  115. if column.DefaultExpr != "" {
  116. eval := m.defaultEvaluator()
  117. if eval == nil {
  118. return nil, false, fmt.Errorf("column %q has a DEFAULT expression but no evaluator is installed", column.Name)
  119. }
  120. value, err := eval(column.DefaultExpr, now)
  121. if err != nil {
  122. return nil, false, fmt.Errorf("evaluate DEFAULT for column %q: %w", column.Name, err)
  123. }
  124. return value, true, nil
  125. }
  126. if column.Default != nil {
  127. return column.Default, true, nil
  128. }
  129. return nil, false, nil
  130. }
  131. // rowColumnValue returns the value a row holds for a column, matching the column
  132. // name case-insensitively.
  133. func rowColumnValue(row Row, name string) (interface{}, bool) {
  134. if value, ok := row[name]; ok {
  135. return value, true
  136. }
  137. for key, value := range row {
  138. if strings.EqualFold(key, name) {
  139. return value, true
  140. }
  141. }
  142. return nil, false
  143. }