github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/create.go (about) 1 // Copyright 2012, Google Inc. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in licenses/BSD-vitess.txt. 4 5 // Portions of this file are additionally subject to the following 6 // license and copyright. 7 // 8 // Copyright 2015 The Cockroach Authors. 9 // 10 // Use of this software is governed by the Business Source License 11 // included in the file licenses/BSL.txt. 12 // 13 // As of the Change Date specified in that file, in accordance with 14 // the Business Source License, use of this software will be governed 15 // by the Apache License, Version 2.0, included in the file 16 // licenses/APL.txt. 17 18 // This code was derived from https://github.com/youtube/vitess. 19 20 package tree 21 22 import ( 23 "fmt" 24 "math/rand" 25 "strconv" 26 "strings" 27 28 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/lexbase" 29 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode" 30 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror" 31 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/types" 32 "github.com/cockroachdb/cockroachdb-parser/pkg/util/collatedstring" 33 "github.com/cockroachdb/cockroachdb-parser/pkg/util/pretty" 34 "github.com/cockroachdb/errors" 35 "github.com/cockroachdb/redact" 36 "golang.org/x/text/language" 37 ) 38 39 // CreateDatabase represents a CREATE DATABASE statement. 40 type CreateDatabase struct { 41 IfNotExists bool 42 Name Name 43 Template string 44 Encoding string 45 Collate string 46 CType string 47 ConnectionLimit int32 48 PrimaryRegion Name 49 Regions NameList 50 SurvivalGoal SurvivalGoal 51 Placement DataPlacement 52 Owner RoleSpec 53 SuperRegion SuperRegion 54 SecondaryRegion Name 55 } 56 57 // Format implements the NodeFormatter interface. 58 func (node *CreateDatabase) Format(ctx *FmtCtx) { 59 ctx.WriteString("CREATE DATABASE ") 60 if node.IfNotExists { 61 ctx.WriteString("IF NOT EXISTS ") 62 } 63 ctx.FormatNode(&node.Name) 64 if node.Template != "" { 65 // NB: the template is not currently edited out under FmtAnonymize, 66 // because we don't support custom templates. If/when custom 67 // templates are supported, this should call ctx.FormatNode 68 // on the template expr. 69 ctx.WriteString(" TEMPLATE = ") 70 lexbase.EncodeSQLStringWithFlags(&ctx.Buffer, node.Template, ctx.flags.EncodeFlags()) 71 } 72 if node.Encoding != "" { 73 // NB: the encoding is not currently edited out under FmtAnonymize, 74 // because we don't support custom encodings. If/when custom 75 // encodings are supported, this should call ctx.FormatNode 76 // on the encoding expr. 77 ctx.WriteString(" ENCODING = ") 78 lexbase.EncodeSQLStringWithFlags(&ctx.Buffer, node.Encoding, ctx.flags.EncodeFlags()) 79 } 80 if node.Collate != "" { 81 // NB: the collation is not currently edited out under FmtAnonymize, 82 // because we don't support custom collations. If/when custom 83 // collations are supported, this should call ctx.FormatNode 84 // on the collation expr. 85 ctx.WriteString(" LC_COLLATE = ") 86 lexbase.EncodeSQLStringWithFlags(&ctx.Buffer, node.Collate, ctx.flags.EncodeFlags()) 87 } 88 if node.CType != "" { 89 // NB: the ctype (formatting customization) is not currently 90 // edited out under FmtAnonymize, because we don't support custom 91 // cutomizations. If/when custom customizations are supported, 92 // this should call ctx.FormatNode on the ctype expr. 93 ctx.WriteString(" LC_CTYPE = ") 94 lexbase.EncodeSQLStringWithFlags(&ctx.Buffer, node.CType, ctx.flags.EncodeFlags()) 95 } 96 if node.ConnectionLimit != -1 { 97 ctx.WriteString(" CONNECTION LIMIT = ") 98 if ctx.flags.HasFlags(FmtHideConstants) { 99 ctx.WriteByte('0') 100 } else { 101 // NB: use ctx.FormatNode when the connection limit becomes an expression. 102 ctx.WriteString(strconv.Itoa(int(node.ConnectionLimit))) 103 } 104 } 105 if node.PrimaryRegion != "" { 106 ctx.WriteString(" PRIMARY REGION ") 107 ctx.FormatNode(&node.PrimaryRegion) 108 } 109 if node.Regions != nil { 110 ctx.WriteString(" REGIONS = ") 111 ctx.FormatNode(&node.Regions) 112 } 113 if node.SurvivalGoal != SurvivalGoalDefault { 114 ctx.WriteString(" ") 115 ctx.FormatNode(&node.SurvivalGoal) 116 } 117 if node.Placement != DataPlacementUnspecified { 118 ctx.WriteString(" ") 119 ctx.FormatNode(&node.Placement) 120 } 121 122 if node.Owner.Name != "" { 123 ctx.WriteString(" OWNER = ") 124 ctx.FormatNode(&node.Owner) 125 } 126 127 if node.SuperRegion.Name != "" { 128 ctx.FormatNode(&node.SuperRegion) 129 } 130 131 if node.SecondaryRegion != "" { 132 ctx.WriteString(" SECONDARY REGION ") 133 ctx.FormatNode(&node.SecondaryRegion) 134 } 135 } 136 137 // IndexElem represents a column with a direction in a CREATE INDEX statement. 138 type IndexElem struct { 139 // Column is set if this is a simple column reference (the common case). 140 Column Name 141 // Expr is set if the index element is an expression (part of an expression 142 // index). If set, Column is empty. 143 Expr Expr 144 Direction Direction 145 NullsOrder NullsOrder 146 147 // OpClass is set if an index element was created using a named opclass. 148 OpClass Name 149 } 150 151 // Format implements the NodeFormatter interface. 152 func (node *IndexElem) Format(ctx *FmtCtx) { 153 if node.Expr == nil { 154 ctx.FormatNode(&node.Column) 155 } else { 156 // Expressions in indexes need an extra set of parens, unless they are a 157 // simple function call. 158 _, isFunc := node.Expr.(*FuncExpr) 159 if !isFunc { 160 ctx.WriteByte('(') 161 } 162 ctx.FormatNode(node.Expr) 163 if !isFunc { 164 ctx.WriteByte(')') 165 } 166 } 167 if node.OpClass != "" { 168 ctx.WriteByte(' ') 169 ctx.WriteString(node.OpClass.String()) 170 } 171 if node.Direction != DefaultDirection { 172 ctx.WriteByte(' ') 173 ctx.WriteString(node.Direction.String()) 174 } 175 if node.NullsOrder != DefaultNullsOrder { 176 ctx.WriteByte(' ') 177 ctx.WriteString(node.NullsOrder.String()) 178 } 179 } 180 181 func (node *IndexElem) doc(p *PrettyCfg) pretty.Doc { 182 var d pretty.Doc 183 if node.Expr == nil { 184 d = p.Doc(&node.Column) 185 } else { 186 // Expressions in indexes need an extra set of parens, unless they are a 187 // simple function call. 188 d = p.Doc(node.Expr) 189 if _, isFunc := node.Expr.(*FuncExpr); !isFunc { 190 d = p.bracket("(", d, ")") 191 } 192 } 193 if node.OpClass != "" { 194 d = pretty.ConcatSpace(d, pretty.Text(node.OpClass.String())) 195 } 196 if node.Direction != DefaultDirection { 197 d = pretty.ConcatSpace(d, pretty.Keyword(node.Direction.String())) 198 } 199 if node.NullsOrder != DefaultNullsOrder { 200 d = pretty.ConcatSpace(d, pretty.Keyword(node.NullsOrder.String())) 201 } 202 return d 203 } 204 205 // IndexElemList is list of IndexElem. 206 type IndexElemList []IndexElem 207 208 // Format pretty-prints the contained names separated by commas. 209 // Format implements the NodeFormatter interface. 210 func (l *IndexElemList) Format(ctx *FmtCtx) { 211 for i := range *l { 212 if i > 0 { 213 ctx.WriteString(", ") 214 } 215 ctx.FormatNode(&(*l)[i]) 216 } 217 } 218 219 // doc is part of the docer interface. 220 func (l *IndexElemList) doc(p *PrettyCfg) pretty.Doc { 221 if l == nil || len(*l) == 0 { 222 return pretty.Nil 223 } 224 d := make([]pretty.Doc, len(*l)) 225 for i := range *l { 226 d[i] = p.Doc(&(*l)[i]) 227 } 228 return p.commaSeparated(d...) 229 } 230 231 type IndexInvisibility struct { 232 Value float64 233 FloatProvided bool 234 } 235 236 // CreateIndex represents a CREATE INDEX statement. 237 type CreateIndex struct { 238 Name Name 239 Table TableName 240 Unique bool 241 Inverted bool 242 IfNotExists bool 243 Columns IndexElemList 244 Sharded *ShardedIndexDef 245 // Extra columns to be stored together with the indexed ones as an optimization 246 // for improved reading performance. 247 Storing NameList 248 PartitionByIndex *PartitionByIndex 249 StorageParams StorageParams 250 Predicate Expr 251 Concurrently bool 252 Invisibility IndexInvisibility 253 } 254 255 // Format implements the NodeFormatter interface. 256 func (node *CreateIndex) Format(ctx *FmtCtx) { 257 // Please also update indexForDisplay function in 258 // pkg/sql/catalog/catformat/index.go if there's any update to index 259 // definition components. 260 ctx.WriteString("CREATE ") 261 if node.Unique { 262 ctx.WriteString("UNIQUE ") 263 } 264 if node.Inverted { 265 ctx.WriteString("INVERTED ") 266 } 267 ctx.WriteString("INDEX ") 268 if node.Concurrently { 269 ctx.WriteString("CONCURRENTLY ") 270 } 271 if node.IfNotExists { 272 ctx.WriteString("IF NOT EXISTS ") 273 } 274 if node.Name != "" { 275 ctx.FormatNode(&node.Name) 276 ctx.WriteByte(' ') 277 } 278 ctx.WriteString("ON ") 279 ctx.FormatNode(&node.Table) 280 281 ctx.WriteString(" (") 282 ctx.FormatNode(&node.Columns) 283 ctx.WriteByte(')') 284 if node.Sharded != nil { 285 ctx.FormatNode(node.Sharded) 286 } 287 if len(node.Storing) > 0 { 288 ctx.WriteString(" STORING (") 289 ctx.FormatNode(&node.Storing) 290 ctx.WriteByte(')') 291 } 292 if node.PartitionByIndex != nil { 293 ctx.FormatNode(node.PartitionByIndex) 294 } 295 if node.StorageParams != nil { 296 ctx.WriteString(" WITH (") 297 ctx.FormatNode(&node.StorageParams) 298 ctx.WriteString(")") 299 } 300 if node.Predicate != nil { 301 ctx.WriteString(" WHERE ") 302 ctx.FormatNode(node.Predicate) 303 } 304 switch { 305 case node.Invisibility.FloatProvided: 306 ctx.WriteString(" VISIBILITY " + fmt.Sprintf("%.2f", 1-node.Invisibility.Value)) 307 case node.Invisibility.Value == 1.0: 308 ctx.WriteString(" NOT VISIBLE") 309 } 310 } 311 312 // CreateTypeVariety represents a particular variety of user defined types. 313 type CreateTypeVariety int 314 315 //go:generate stringer -type=CreateTypeVariety 316 const ( 317 _ CreateTypeVariety = iota 318 // Enum represents an ENUM user defined type. 319 Enum 320 // Composite represents a composite user defined type. 321 Composite 322 // Range represents a RANGE user defined type. 323 Range 324 // Base represents a base user defined type. 325 Base 326 // Shell represents a shell user defined type. 327 Shell 328 // Domain represents a DOMAIN user defined type. 329 Domain 330 ) 331 332 // EnumValue represents a single enum value. 333 type EnumValue string 334 335 // Format implements the NodeFormatter interface. 336 func (n *EnumValue) Format(ctx *FmtCtx) { 337 f := ctx.flags 338 if f.HasFlags(FmtAnonymize) { 339 ctx.WriteByte('_') 340 } else if f.HasFlags(FmtMarkRedactionNode) { 341 ctx.WriteString(string(redact.StartMarker())) 342 lexbase.EncodeSQLString(&ctx.Buffer, string(*n)) 343 ctx.WriteString(string(redact.EndMarker())) 344 } else { 345 lexbase.EncodeSQLString(&ctx.Buffer, string(*n)) 346 } 347 } 348 349 // EnumValueList represents a list of enum values. 350 type EnumValueList []EnumValue 351 352 // Format implements the NodeFormatter interface. 353 func (l *EnumValueList) Format(ctx *FmtCtx) { 354 for i := range *l { 355 if i > 0 { 356 ctx.WriteString(", ") 357 } 358 ctx.FormatNode(&(*l)[i]) 359 } 360 } 361 362 // CompositeTypeElem is a single element in a composite type definition. 363 type CompositeTypeElem struct { 364 Label Name 365 Type ResolvableTypeReference 366 } 367 368 // CreateType represents a CREATE TYPE statement. 369 type CreateType struct { 370 TypeName *UnresolvedObjectName 371 Variety CreateTypeVariety 372 // EnumLabels is set when this represents a CREATE TYPE ... AS ENUM statement. 373 EnumLabels EnumValueList 374 // CompositeTypeList is set when this repesnets a CREATE TYPE ... AS ( ) 375 // statement. 376 CompositeTypeList []CompositeTypeElem 377 // IfNotExists is true if IF NOT EXISTS was requested. 378 IfNotExists bool 379 } 380 381 var _ Statement = &CreateType{} 382 383 // Format implements the NodeFormatter interface. 384 func (node *CreateType) Format(ctx *FmtCtx) { 385 ctx.WriteString("CREATE TYPE ") 386 if node.IfNotExists { 387 ctx.WriteString("IF NOT EXISTS ") 388 } 389 ctx.FormatNode(node.TypeName) 390 ctx.WriteString(" ") 391 switch node.Variety { 392 case Enum: 393 ctx.WriteString("AS ENUM (") 394 ctx.FormatNode(&node.EnumLabels) 395 ctx.WriteString(")") 396 case Composite: 397 ctx.WriteString("AS (") 398 for i := range node.CompositeTypeList { 399 elem := &node.CompositeTypeList[i] 400 if i != 0 { 401 ctx.WriteString(", ") 402 } 403 ctx.FormatNode(&elem.Label) 404 ctx.WriteString(" ") 405 ctx.FormatTypeReference(elem.Type) 406 } 407 ctx.WriteString(")") 408 } 409 } 410 411 func (node *CreateType) String() string { 412 return AsString(node) 413 } 414 415 // TableDef represents a column, index or constraint definition within a CREATE 416 // TABLE statement. 417 type TableDef interface { 418 NodeFormatter 419 // Placeholder function to ensure that only desired types (*TableDef) conform 420 // to the TableDef interface. 421 tableDef() 422 } 423 424 func (*ColumnTableDef) tableDef() {} 425 func (*IndexTableDef) tableDef() {} 426 func (*FamilyTableDef) tableDef() {} 427 func (*ForeignKeyConstraintTableDef) tableDef() {} 428 func (*CheckConstraintTableDef) tableDef() {} 429 func (*LikeTableDef) tableDef() {} 430 431 // TableDefs represents a list of table definitions. 432 type TableDefs []TableDef 433 434 // Format implements the NodeFormatter interface. 435 func (node *TableDefs) Format(ctx *FmtCtx) { 436 for i, n := range *node { 437 if i > 0 { 438 ctx.WriteString(", ") 439 } 440 ctx.FormatNode(n) 441 } 442 } 443 444 // Nullability represents either NULL, NOT NULL or an unspecified value (silent 445 // NULL). 446 type Nullability int 447 448 // The values for NullType. 449 const ( 450 NotNull Nullability = iota 451 Null 452 SilentNull 453 ) 454 455 // RandomNullability returns a random valid Nullability, given a random number 456 // generator, `rand`. If nullableOnly is true, the random Nullability will not 457 // be `NotNull`. 458 func RandomNullability(rand *rand.Rand, nullableOnly bool) Nullability { 459 if nullableOnly { 460 // Add 1 after getting the random number to exclude the zero-value NotNull. 461 return Nullability(rand.Intn(int(SilentNull)) + 1) 462 } 463 return Nullability(rand.Intn(int(SilentNull) + 1)) 464 } 465 466 // GeneratedIdentityType represents either GENERATED ALWAYS AS IDENTITY 467 // or GENERATED BY DEFAULT AS IDENTITY. 468 type GeneratedIdentityType int 469 470 // The values of GeneratedIdentity.GeneratedAsIdentityType. 471 const ( 472 GeneratedAlways GeneratedIdentityType = iota 473 GeneratedByDefault 474 ) 475 476 // ColumnTableDef represents a column definition within a CREATE TABLE 477 // statement. 478 type ColumnTableDef struct { 479 Name Name 480 Type ResolvableTypeReference 481 IsSerial bool 482 // IsCreateAs is set to true if the Type is resolved after parsing. 483 // CREATE AS statements must not display column types during formatting. 484 IsCreateAs bool 485 GeneratedIdentity struct { 486 IsGeneratedAsIdentity bool 487 GeneratedAsIdentityType GeneratedIdentityType 488 SeqOptions SequenceOptions 489 } 490 Hidden bool 491 Nullable struct { 492 Nullability Nullability 493 ConstraintName Name 494 } 495 PrimaryKey struct { 496 IsPrimaryKey bool 497 Sharded bool 498 ShardBuckets Expr 499 StorageParams StorageParams 500 } 501 Unique struct { 502 IsUnique bool 503 WithoutIndex bool 504 ConstraintName Name 505 } 506 DefaultExpr struct { 507 Expr Expr 508 ConstraintName Name 509 } 510 OnUpdateExpr struct { 511 Expr Expr 512 ConstraintName Name 513 } 514 CheckExprs []ColumnTableDefCheckExpr 515 References struct { 516 Table *TableName 517 Col Name 518 ConstraintName Name 519 Actions ReferenceActions 520 Match CompositeKeyMatchMethod 521 } 522 Computed struct { 523 Computed bool 524 Expr Expr 525 Virtual bool 526 } 527 Family struct { 528 Name Name 529 Create bool 530 IfNotExists bool 531 } 532 } 533 534 // ColumnTableDefCheckExpr represents a check constraint on a column definition 535 // within a CREATE TABLE statement. 536 type ColumnTableDefCheckExpr struct { 537 Expr Expr 538 ConstraintName Name 539 } 540 541 func processCollationOnType( 542 name Name, ref ResolvableTypeReference, c ColumnCollation, 543 ) (*types.T, error) { 544 // At the moment, only string types can be collated. User defined types 545 // like enums don't support collations, so check this at parse time. 546 typ, ok := GetStaticallyKnownType(ref) 547 if !ok { 548 return nil, pgerror.Newf(pgcode.DatatypeMismatch, 549 "COLLATE declaration for non-string-typed column %q", name) 550 } 551 switch typ.Family() { 552 case types.StringFamily: 553 return types.MakeCollatedString(typ, string(c)), nil 554 case types.CollatedStringFamily: 555 return nil, pgerror.Newf(pgcode.Syntax, 556 "multiple COLLATE declarations for column %q", name) 557 case types.ArrayFamily: 558 elemTyp, err := processCollationOnType(name, typ.ArrayContents(), c) 559 if err != nil { 560 return nil, err 561 } 562 return types.MakeArray(elemTyp), nil 563 default: 564 return nil, pgerror.Newf(pgcode.DatatypeMismatch, 565 "COLLATE declaration for non-string-typed column %q", name) 566 } 567 } 568 569 // NewColumnTableDef constructs a column definition for a CreateTable statement. 570 func NewColumnTableDef( 571 name Name, 572 typRef ResolvableTypeReference, 573 isSerial bool, 574 qualifications []NamedColumnQualification, 575 ) (*ColumnTableDef, error) { 576 d := &ColumnTableDef{ 577 Name: name, 578 Type: typRef, 579 IsSerial: isSerial, 580 } 581 d.Nullable.Nullability = SilentNull 582 for _, c := range qualifications { 583 switch t := c.Qualification.(type) { 584 case ColumnCollation: 585 locale := string(t) 586 // In postgres, all strings have collations defaulting to "default". 587 // In CRDB, collated strings are treated separately to string family types. 588 // To most behave like postgres, set the CollatedString type if a non-"default" 589 // collation is used. 590 if locale != collatedstring.DefaultCollationTag { 591 _, err := language.Parse(locale) 592 if err != nil { 593 return nil, pgerror.Wrapf(err, pgcode.Syntax, "invalid locale %s", locale) 594 } 595 collatedTyp, err := processCollationOnType(name, d.Type, t) 596 if err != nil { 597 return nil, err 598 } 599 d.Type = collatedTyp 600 } 601 case *ColumnDefault: 602 if d.HasDefaultExpr() || d.GeneratedIdentity.IsGeneratedAsIdentity { 603 return nil, pgerror.Newf(pgcode.Syntax, 604 "multiple default values specified for column %q", name) 605 } 606 d.DefaultExpr.Expr = t.Expr 607 d.DefaultExpr.ConstraintName = c.Name 608 case *ColumnOnUpdate: 609 if d.HasOnUpdateExpr() { 610 return nil, pgerror.Newf(pgcode.Syntax, 611 "multiple ON UPDATE values specified for column %q", name) 612 } 613 if d.GeneratedIdentity.IsGeneratedAsIdentity { 614 return nil, pgerror.Newf(pgcode.Syntax, 615 "both generated identity and on update expression specified for column %q", 616 name) 617 } 618 d.OnUpdateExpr.Expr = t.Expr 619 d.OnUpdateExpr.ConstraintName = c.Name 620 case *GeneratedAlwaysAsIdentity, *GeneratedByDefAsIdentity: 621 if typ, ok := typRef.(*types.T); !ok || typ.InternalType.Family != types.IntFamily { 622 return nil, pgerror.Newf( 623 pgcode.InvalidParameterValue, 624 "identity column type must be an INT", 625 ) 626 } 627 if d.GeneratedIdentity.IsGeneratedAsIdentity { 628 return nil, pgerror.Newf(pgcode.Syntax, 629 "multiple identity specifications for column %q", name) 630 } 631 if d.HasDefaultExpr() { 632 return nil, pgerror.Newf(pgcode.Syntax, 633 "multiple default values specified for column %q", name) 634 } 635 if d.Computed.Computed { 636 return nil, pgerror.Newf(pgcode.Syntax, 637 "both generated identity and computed expression specified for column %q", name) 638 } 639 if d.Nullable.Nullability == Null { 640 return nil, pgerror.Newf(pgcode.Syntax, 641 "conflicting NULL/NOT NULL declarations for column %q", name) 642 } 643 if d.HasOnUpdateExpr() { 644 return nil, pgerror.Newf(pgcode.Syntax, 645 "both generated identity and on update expression specified for column %q", 646 name) 647 } 648 d.GeneratedIdentity.IsGeneratedAsIdentity = true 649 d.Nullable.Nullability = NotNull 650 switch c.Qualification.(type) { 651 case *GeneratedAlwaysAsIdentity: 652 d.GeneratedIdentity.GeneratedAsIdentityType = GeneratedAlways 653 d.GeneratedIdentity.SeqOptions = t.(*GeneratedAlwaysAsIdentity).SeqOptions 654 case *GeneratedByDefAsIdentity: 655 d.GeneratedIdentity.GeneratedAsIdentityType = GeneratedByDefault 656 d.GeneratedIdentity.SeqOptions = t.(*GeneratedByDefAsIdentity).SeqOptions 657 } 658 case HiddenConstraint: 659 d.Hidden = true 660 case NotNullConstraint: 661 if d.Nullable.Nullability == Null { 662 return nil, pgerror.Newf(pgcode.Syntax, 663 "conflicting NULL/NOT NULL declarations for column %q", name) 664 } 665 d.Nullable.Nullability = NotNull 666 d.Nullable.ConstraintName = c.Name 667 case NullConstraint: 668 if d.Nullable.Nullability == NotNull { 669 return nil, pgerror.Newf(pgcode.Syntax, 670 "conflicting NULL/NOT NULL declarations for column %q", name) 671 } 672 d.Nullable.Nullability = Null 673 d.Nullable.ConstraintName = c.Name 674 case PrimaryKeyConstraint: 675 d.PrimaryKey.IsPrimaryKey = true 676 d.PrimaryKey.StorageParams = c.Qualification.(PrimaryKeyConstraint).StorageParams 677 d.Unique.ConstraintName = c.Name 678 case ShardedPrimaryKeyConstraint: 679 d.PrimaryKey.IsPrimaryKey = true 680 constraint := c.Qualification.(ShardedPrimaryKeyConstraint) 681 d.PrimaryKey.Sharded = true 682 d.PrimaryKey.ShardBuckets = constraint.ShardBuckets 683 d.PrimaryKey.StorageParams = constraint.StorageParams 684 d.Unique.ConstraintName = c.Name 685 case UniqueConstraint: 686 d.Unique.IsUnique = true 687 d.Unique.WithoutIndex = t.WithoutIndex 688 d.Unique.ConstraintName = c.Name 689 case *ColumnCheckConstraint: 690 d.CheckExprs = append(d.CheckExprs, ColumnTableDefCheckExpr{ 691 Expr: t.Expr, 692 ConstraintName: c.Name, 693 }) 694 case *ColumnFKConstraint: 695 if d.HasFKConstraint() { 696 return nil, pgerror.Newf(pgcode.InvalidTableDefinition, 697 "multiple foreign key constraints specified for column %q", name) 698 } 699 d.References.Table = &t.Table 700 d.References.Col = t.Col 701 d.References.ConstraintName = c.Name 702 d.References.Actions = t.Actions 703 d.References.Match = t.Match 704 case *ColumnComputedDef: 705 if d.GeneratedIdentity.IsGeneratedAsIdentity { 706 return nil, pgerror.Newf(pgcode.Syntax, 707 "both generated identity and computed expression specified for column %q", name) 708 } 709 d.Computed.Computed = true 710 d.Computed.Expr = t.Expr 711 d.Computed.Virtual = t.Virtual 712 case *ColumnFamilyConstraint: 713 if d.HasColumnFamily() { 714 return nil, pgerror.Newf(pgcode.InvalidTableDefinition, 715 "multiple column families specified for column %q", name) 716 } 717 d.Family.Name = t.Family 718 d.Family.Create = t.Create 719 d.Family.IfNotExists = t.IfNotExists 720 default: 721 return nil, errors.AssertionFailedf("unexpected column qualification: %T", c) 722 } 723 } 724 725 return d, nil 726 } 727 728 // HasDefaultExpr returns if the ColumnTableDef has a default expression. 729 func (node *ColumnTableDef) HasDefaultExpr() bool { 730 return node.DefaultExpr.Expr != nil 731 } 732 733 // HasOnUpdateExpr returns if the ColumnTableDef has an ON UPDATE expression. 734 func (node *ColumnTableDef) HasOnUpdateExpr() bool { 735 return node.OnUpdateExpr.Expr != nil 736 } 737 738 // HasFKConstraint returns if the ColumnTableDef has a foreign key constraint. 739 func (node *ColumnTableDef) HasFKConstraint() bool { 740 return node.References.Table != nil 741 } 742 743 // IsComputed returns if the ColumnTableDef is a computed column. 744 func (node *ColumnTableDef) IsComputed() bool { 745 return node.Computed.Computed 746 } 747 748 // IsVirtual returns if the ColumnTableDef is a virtual column. 749 func (node *ColumnTableDef) IsVirtual() bool { 750 return node.Computed.Virtual 751 } 752 753 // HasColumnFamily returns if the ColumnTableDef has a column family. 754 func (node *ColumnTableDef) HasColumnFamily() bool { 755 return node.Family.Name != "" || node.Family.Create 756 } 757 758 // Format implements the NodeFormatter interface. 759 func (node *ColumnTableDef) Format(ctx *FmtCtx) { 760 ctx.FormatNode(&node.Name) 761 762 // ColumnTableDef node type will not be specified if it represents a CREATE 763 // TABLE ... AS query. 764 if !node.IsCreateAs && node.Type != nil { 765 ctx.WriteByte(' ') 766 node.formatColumnType(ctx) 767 } 768 769 if node.Nullable.Nullability != SilentNull && node.Nullable.ConstraintName != "" { 770 ctx.WriteString(" CONSTRAINT ") 771 ctx.FormatNode(&node.Nullable.ConstraintName) 772 } 773 switch node.Nullable.Nullability { 774 case Null: 775 ctx.WriteString(" NULL") 776 case NotNull: 777 ctx.WriteString(" NOT NULL") 778 } 779 if node.Hidden { 780 ctx.WriteString(" NOT VISIBLE") 781 } 782 if node.PrimaryKey.IsPrimaryKey || node.Unique.IsUnique { 783 if node.Unique.ConstraintName != "" { 784 ctx.WriteString(" CONSTRAINT ") 785 ctx.FormatNode(&node.Unique.ConstraintName) 786 } 787 if node.PrimaryKey.IsPrimaryKey { 788 ctx.WriteString(" PRIMARY KEY") 789 790 // Always prefer to output hash sharding bucket count as a storage param. 791 pkStorageParams := node.PrimaryKey.StorageParams 792 if node.PrimaryKey.Sharded { 793 ctx.WriteString(" USING HASH") 794 bcStorageParam := node.PrimaryKey.StorageParams.GetVal(`bucket_count`) 795 if _, ok := node.PrimaryKey.ShardBuckets.(DefaultVal); !ok && bcStorageParam == nil { 796 pkStorageParams = append( 797 pkStorageParams, 798 StorageParam{ 799 Key: `bucket_count`, 800 Value: node.PrimaryKey.ShardBuckets, 801 }, 802 ) 803 } 804 } 805 if len(pkStorageParams) > 0 { 806 ctx.WriteString(" WITH (") 807 ctx.FormatNode(&pkStorageParams) 808 ctx.WriteString(")") 809 } 810 } else if node.Unique.IsUnique { 811 ctx.WriteString(" UNIQUE") 812 if node.Unique.WithoutIndex { 813 ctx.WriteString(" WITHOUT INDEX") 814 } 815 } 816 } 817 if node.HasDefaultExpr() { 818 if node.DefaultExpr.ConstraintName != "" { 819 ctx.WriteString(" CONSTRAINT ") 820 ctx.FormatNode(&node.DefaultExpr.ConstraintName) 821 } 822 ctx.WriteString(" DEFAULT ") 823 ctx.FormatNode(node.DefaultExpr.Expr) 824 } 825 if node.HasOnUpdateExpr() { 826 if node.OnUpdateExpr.ConstraintName != "" { 827 ctx.WriteString(" CONSTRAINT ") 828 ctx.FormatNode(&node.OnUpdateExpr.ConstraintName) 829 } 830 ctx.WriteString(" ON UPDATE ") 831 ctx.FormatNode(node.OnUpdateExpr.Expr) 832 } 833 if node.GeneratedIdentity.IsGeneratedAsIdentity { 834 switch node.GeneratedIdentity.GeneratedAsIdentityType { 835 case GeneratedAlways: 836 ctx.WriteString(" GENERATED ALWAYS AS IDENTITY") 837 case GeneratedByDefault: 838 ctx.WriteString(" GENERATED BY DEFAULT AS IDENTITY") 839 } 840 if genSeqOpt := node.GeneratedIdentity.SeqOptions; genSeqOpt != nil { 841 ctx.WriteString(" (") 842 // TODO(janexing): remove the leading and ending space of the 843 // sequence option expression. 844 genSeqOpt.Format(ctx) 845 ctx.WriteString(" ) ") 846 } 847 } 848 for _, checkExpr := range node.CheckExprs { 849 if checkExpr.ConstraintName != "" { 850 ctx.WriteString(" CONSTRAINT ") 851 ctx.FormatNode(&checkExpr.ConstraintName) 852 } 853 ctx.WriteString(" CHECK (") 854 ctx.FormatNode(checkExpr.Expr) 855 ctx.WriteByte(')') 856 } 857 if node.HasFKConstraint() { 858 if node.References.ConstraintName != "" { 859 ctx.WriteString(" CONSTRAINT ") 860 ctx.FormatNode(&node.References.ConstraintName) 861 } 862 ctx.WriteString(" REFERENCES ") 863 ctx.FormatNode(node.References.Table) 864 if node.References.Col != "" { 865 ctx.WriteString(" (") 866 ctx.FormatNode(&node.References.Col) 867 ctx.WriteByte(')') 868 } 869 if node.References.Match != MatchSimple { 870 ctx.WriteByte(' ') 871 ctx.WriteString(node.References.Match.String()) 872 } 873 ctx.FormatNode(&node.References.Actions) 874 } 875 if node.IsComputed() { 876 ctx.WriteString(" AS (") 877 ctx.FormatNode(node.Computed.Expr) 878 if node.Computed.Virtual { 879 ctx.WriteString(") VIRTUAL") 880 } else { 881 ctx.WriteString(") STORED") 882 } 883 } 884 if node.HasColumnFamily() { 885 if node.Family.Create { 886 ctx.WriteString(" CREATE") 887 if node.Family.IfNotExists { 888 ctx.WriteString(" IF NOT EXISTS") 889 } 890 } 891 ctx.WriteString(" FAMILY") 892 if len(node.Family.Name) > 0 { 893 ctx.WriteByte(' ') 894 ctx.FormatNode(&node.Family.Name) 895 } 896 } 897 } 898 899 func (node *ColumnTableDef) formatColumnType(ctx *FmtCtx) { 900 if replaced, ok := node.replacedSerialTypeName(); ok { 901 ctx.WriteString(replaced) 902 } else { 903 ctx.FormatTypeReference(node.Type) 904 } 905 } 906 907 func (node *ColumnTableDef) replacedSerialTypeName() (string, bool) { 908 if node.IsSerial { 909 // Map INT types to SERIAL keyword. 910 // TODO (rohany): This should be pushed until type resolution occurs. 911 // However, the argument is that we deal with serial at parse time only, 912 // so we handle those cases here. 913 switch MustBeStaticallyKnownType(node.Type).Width() { 914 case 16: 915 return "SERIAL2", true 916 case 32: 917 return "SERIAL4", true 918 default: 919 return "SERIAL8", true 920 } 921 } 922 return "", false 923 } 924 925 // String implements the fmt.Stringer interface. 926 func (node *ColumnTableDef) String() string { return AsString(node) } 927 928 // NamedColumnQualification wraps a NamedColumnQualification with a name. 929 type NamedColumnQualification struct { 930 Name Name 931 Qualification ColumnQualification 932 } 933 934 // ColumnQualification represents a constraint on a column. 935 type ColumnQualification interface { 936 columnQualification() 937 } 938 939 func (ColumnCollation) columnQualification() {} 940 func (*ColumnDefault) columnQualification() {} 941 func (*ColumnOnUpdate) columnQualification() {} 942 func (NotNullConstraint) columnQualification() {} 943 func (NullConstraint) columnQualification() {} 944 func (HiddenConstraint) columnQualification() {} 945 func (PrimaryKeyConstraint) columnQualification() {} 946 func (ShardedPrimaryKeyConstraint) columnQualification() {} 947 func (UniqueConstraint) columnQualification() {} 948 func (*ColumnCheckConstraint) columnQualification() {} 949 func (*ColumnComputedDef) columnQualification() {} 950 func (*ColumnFKConstraint) columnQualification() {} 951 func (*ColumnFamilyConstraint) columnQualification() {} 952 func (*GeneratedAlwaysAsIdentity) columnQualification() {} 953 func (*GeneratedByDefAsIdentity) columnQualification() {} 954 955 // ColumnCollation represents a COLLATE clause for a column. 956 type ColumnCollation string 957 958 // ColumnDefault represents a DEFAULT clause for a column. 959 type ColumnDefault struct { 960 Expr Expr 961 } 962 963 // ColumnOnUpdate represents a ON UPDATE clause for a column. 964 type ColumnOnUpdate struct { 965 Expr Expr 966 } 967 968 // GeneratedAlwaysAsIdentity represents a column generated always as identity. 969 type GeneratedAlwaysAsIdentity struct { 970 SeqOptions SequenceOptions 971 } 972 973 // GeneratedByDefAsIdentity represents a column generated by default as identity. 974 type GeneratedByDefAsIdentity struct { 975 SeqOptions SequenceOptions 976 } 977 978 // NotNullConstraint represents NOT NULL on a column. 979 type NotNullConstraint struct{} 980 981 // NullConstraint represents NULL on a column. 982 type NullConstraint struct{} 983 984 // HiddenConstraint represents HIDDEN on a column. 985 type HiddenConstraint struct{} 986 987 // PrimaryKeyConstraint represents PRIMARY KEY on a column. 988 type PrimaryKeyConstraint struct { 989 StorageParams StorageParams 990 } 991 992 // ShardedPrimaryKeyConstraint represents `PRIMARY KEY .. USING HASH..` 993 // on a column. 994 type ShardedPrimaryKeyConstraint struct { 995 Sharded bool 996 ShardBuckets Expr 997 StorageParams StorageParams 998 } 999 1000 // UniqueConstraint represents UNIQUE on a column. 1001 type UniqueConstraint struct { 1002 WithoutIndex bool 1003 } 1004 1005 // ColumnCheckConstraint represents either a check on a column. 1006 type ColumnCheckConstraint struct { 1007 Expr Expr 1008 } 1009 1010 // ColumnFKConstraint represents a FK-constaint on a column. 1011 type ColumnFKConstraint struct { 1012 Table TableName 1013 Col Name // empty-string means use PK 1014 Actions ReferenceActions 1015 Match CompositeKeyMatchMethod 1016 } 1017 1018 // ColumnComputedDef represents the description of a computed column. 1019 type ColumnComputedDef struct { 1020 Expr Expr 1021 Virtual bool 1022 } 1023 1024 // ColumnFamilyConstraint represents FAMILY on a column. 1025 type ColumnFamilyConstraint struct { 1026 Family Name 1027 Create bool 1028 IfNotExists bool 1029 } 1030 1031 // IndexTableDef represents an index definition within a CREATE TABLE 1032 // statement. 1033 type IndexTableDef struct { 1034 Name Name 1035 Columns IndexElemList 1036 Sharded *ShardedIndexDef 1037 Storing NameList 1038 Inverted bool 1039 PartitionByIndex *PartitionByIndex 1040 StorageParams StorageParams 1041 Predicate Expr 1042 Invisibility IndexInvisibility 1043 } 1044 1045 // Format implements the NodeFormatter interface. 1046 func (node *IndexTableDef) Format(ctx *FmtCtx) { 1047 if node.Inverted { 1048 ctx.WriteString("INVERTED ") 1049 } 1050 ctx.WriteString("INDEX ") 1051 if node.Name != "" { 1052 ctx.FormatNode(&node.Name) 1053 ctx.WriteByte(' ') 1054 } 1055 ctx.WriteByte('(') 1056 ctx.FormatNode(&node.Columns) 1057 ctx.WriteByte(')') 1058 if node.Sharded != nil { 1059 ctx.FormatNode(node.Sharded) 1060 } 1061 if node.Storing != nil { 1062 ctx.WriteString(" STORING (") 1063 ctx.FormatNode(&node.Storing) 1064 ctx.WriteByte(')') 1065 } 1066 if node.PartitionByIndex != nil { 1067 ctx.FormatNode(node.PartitionByIndex) 1068 } 1069 if node.StorageParams != nil { 1070 ctx.WriteString(" WITH (") 1071 ctx.FormatNode(&node.StorageParams) 1072 ctx.WriteString(")") 1073 } 1074 if node.Predicate != nil { 1075 ctx.WriteString(" WHERE ") 1076 ctx.FormatNode(node.Predicate) 1077 } 1078 switch { 1079 case node.Invisibility.FloatProvided: 1080 ctx.WriteString(" VISIBILITY " + fmt.Sprintf("%.2f", 1-node.Invisibility.Value)) 1081 case node.Invisibility.Value == 1.0: 1082 ctx.WriteString(" NOT VISIBLE") 1083 } 1084 } 1085 1086 // ConstraintTableDef represents a constraint definition within a CREATE TABLE 1087 // statement. 1088 type ConstraintTableDef interface { 1089 TableDef 1090 // Placeholder function to ensure that only desired types 1091 // (*ConstraintTableDef) conform to the ConstraintTableDef interface. 1092 constraintTableDef() 1093 1094 // SetName replaces the name of the definition in-place. Used in the parser. 1095 SetName(name Name) 1096 1097 // SetIfNotExists sets this definition as coming from an 1098 // ADD CONSTRAINT IF NOT EXISTS statement. Used in the parser. 1099 SetIfNotExists() 1100 } 1101 1102 func (*UniqueConstraintTableDef) constraintTableDef() {} 1103 func (*ForeignKeyConstraintTableDef) constraintTableDef() {} 1104 func (*CheckConstraintTableDef) constraintTableDef() {} 1105 1106 // UniqueConstraintTableDef represents a unique constraint within a CREATE 1107 // TABLE statement. 1108 type UniqueConstraintTableDef struct { 1109 IndexTableDef 1110 PrimaryKey bool 1111 WithoutIndex bool 1112 IfNotExists bool 1113 } 1114 1115 // SetName implements the TableDef interface. 1116 func (node *UniqueConstraintTableDef) SetName(name Name) { 1117 node.Name = name 1118 } 1119 1120 // SetIfNotExists implements the ConstraintTableDef interface. 1121 func (node *UniqueConstraintTableDef) SetIfNotExists() { 1122 node.IfNotExists = true 1123 } 1124 1125 // Format implements the NodeFormatter interface. 1126 func (node *UniqueConstraintTableDef) Format(ctx *FmtCtx) { 1127 if node.Name != "" { 1128 ctx.WriteString("CONSTRAINT ") 1129 if node.IfNotExists { 1130 ctx.WriteString("IF NOT EXISTS ") 1131 } 1132 ctx.FormatNode(&node.Name) 1133 ctx.WriteByte(' ') 1134 } 1135 if node.PrimaryKey { 1136 ctx.WriteString("PRIMARY KEY ") 1137 } else { 1138 ctx.WriteString("UNIQUE ") 1139 } 1140 if node.WithoutIndex { 1141 ctx.WriteString("WITHOUT INDEX ") 1142 } 1143 ctx.WriteByte('(') 1144 ctx.FormatNode(&node.Columns) 1145 ctx.WriteByte(')') 1146 if node.Sharded != nil { 1147 ctx.FormatNode(node.Sharded) 1148 } 1149 if node.Storing != nil { 1150 ctx.WriteString(" STORING (") 1151 ctx.FormatNode(&node.Storing) 1152 ctx.WriteByte(')') 1153 } 1154 if node.PartitionByIndex != nil { 1155 ctx.FormatNode(node.PartitionByIndex) 1156 } 1157 if node.Predicate != nil { 1158 ctx.WriteString(" WHERE ") 1159 ctx.FormatNode(node.Predicate) 1160 } 1161 switch { 1162 case node.Invisibility.FloatProvided: 1163 ctx.WriteString(" VISIBILITY " + fmt.Sprintf("%.2f", 1-node.Invisibility.Value)) 1164 case node.Invisibility.Value == 1.0: 1165 ctx.WriteString(" NOT VISIBLE") 1166 } 1167 if node.StorageParams != nil { 1168 ctx.WriteString(" WITH (") 1169 ctx.FormatNode(&node.StorageParams) 1170 ctx.WriteString(")") 1171 } 1172 } 1173 1174 // ForeignKeyConstraintTableDef represents a FOREIGN KEY constraint in the AST. 1175 type ForeignKeyConstraintTableDef struct { 1176 Name Name 1177 Table TableName 1178 FromCols NameList 1179 ToCols NameList 1180 Actions ReferenceActions 1181 Match CompositeKeyMatchMethod 1182 IfNotExists bool 1183 } 1184 1185 // Format implements the NodeFormatter interface. 1186 func (node *ForeignKeyConstraintTableDef) Format(ctx *FmtCtx) { 1187 if node.Name != "" { 1188 ctx.WriteString("CONSTRAINT ") 1189 if node.IfNotExists { 1190 ctx.WriteString("IF NOT EXISTS ") 1191 } 1192 ctx.FormatNode(&node.Name) 1193 ctx.WriteByte(' ') 1194 } 1195 ctx.WriteString("FOREIGN KEY (") 1196 ctx.FormatNode(&node.FromCols) 1197 ctx.WriteString(") REFERENCES ") 1198 ctx.FormatNode(&node.Table) 1199 1200 if len(node.ToCols) > 0 { 1201 ctx.WriteByte(' ') 1202 ctx.WriteByte('(') 1203 ctx.FormatNode(&node.ToCols) 1204 ctx.WriteByte(')') 1205 } 1206 1207 if node.Match != MatchSimple { 1208 ctx.WriteByte(' ') 1209 ctx.WriteString(node.Match.String()) 1210 } 1211 1212 ctx.FormatNode(&node.Actions) 1213 } 1214 1215 // SetName implements the ConstraintTableDef interface. 1216 func (node *ForeignKeyConstraintTableDef) SetName(name Name) { 1217 node.Name = name 1218 } 1219 1220 // SetIfNotExists implements the ConstraintTableDef interface. 1221 func (node *ForeignKeyConstraintTableDef) SetIfNotExists() { 1222 node.IfNotExists = true 1223 } 1224 1225 // CheckConstraintTableDef represents a check constraint within a CREATE 1226 // TABLE statement. 1227 type CheckConstraintTableDef struct { 1228 Name Name 1229 Expr Expr 1230 FromHashShardedColumn bool 1231 IfNotExists bool 1232 } 1233 1234 // SetName implements the ConstraintTableDef interface. 1235 func (node *CheckConstraintTableDef) SetName(name Name) { 1236 node.Name = name 1237 } 1238 1239 // SetIfNotExists implements the ConstraintTableDef interface. 1240 func (node *CheckConstraintTableDef) SetIfNotExists() { 1241 node.IfNotExists = true 1242 } 1243 1244 // Format implements the NodeFormatter interface. 1245 func (node *CheckConstraintTableDef) Format(ctx *FmtCtx) { 1246 if node.Name != "" { 1247 ctx.WriteString("CONSTRAINT ") 1248 if node.IfNotExists { 1249 ctx.WriteString("IF NOT EXISTS ") 1250 } 1251 ctx.FormatNode(&node.Name) 1252 ctx.WriteByte(' ') 1253 } 1254 ctx.WriteString("CHECK (") 1255 ctx.FormatNode(node.Expr) 1256 ctx.WriteByte(')') 1257 } 1258 1259 // FamilyTableDef represents a family definition within a CREATE TABLE 1260 // statement. 1261 type FamilyTableDef struct { 1262 Name Name 1263 Columns NameList 1264 } 1265 1266 // Format implements the NodeFormatter interface. 1267 func (node *FamilyTableDef) Format(ctx *FmtCtx) { 1268 ctx.WriteString("FAMILY ") 1269 if node.Name != "" { 1270 ctx.FormatNode(&node.Name) 1271 ctx.WriteByte(' ') 1272 } 1273 ctx.WriteByte('(') 1274 ctx.FormatNode(&node.Columns) 1275 ctx.WriteByte(')') 1276 } 1277 1278 // ShardedIndexDef represents a hash sharded secondary index definition within a CREATE 1279 // TABLE or CREATE INDEX statement. 1280 type ShardedIndexDef struct { 1281 ShardBuckets Expr 1282 } 1283 1284 // Format implements the NodeFormatter interface. 1285 func (node *ShardedIndexDef) Format(ctx *FmtCtx) { 1286 if _, ok := node.ShardBuckets.(DefaultVal); ok { 1287 ctx.WriteString(" USING HASH") 1288 return 1289 } 1290 ctx.WriteString(" USING HASH WITH BUCKET_COUNT = ") 1291 ctx.FormatNode(node.ShardBuckets) 1292 } 1293 1294 // PartitionByType is an enum of each type of partitioning (LIST/RANGE). 1295 type PartitionByType string 1296 1297 const ( 1298 // PartitionByList indicates a PARTITION BY LIST clause. 1299 PartitionByList PartitionByType = "LIST" 1300 // PartitionByRange indicates a PARTITION BY LIST clause. 1301 PartitionByRange PartitionByType = "RANGE" 1302 ) 1303 1304 // PartitionByIndex represents a PARTITION BY definition within 1305 // a CREATE/ALTER INDEX statement. 1306 type PartitionByIndex struct { 1307 *PartitionBy 1308 } 1309 1310 // ContainsPartitions determines if the partition by table contains 1311 // a partition clause which is not PARTITION BY NOTHING. 1312 func (node *PartitionByIndex) ContainsPartitions() bool { 1313 return node != nil && node.PartitionBy != nil 1314 } 1315 1316 // ContainsPartitioningClause determines if the partition by table contains 1317 // a partitioning clause, including PARTITION BY NOTHING. 1318 func (node *PartitionByIndex) ContainsPartitioningClause() bool { 1319 return node != nil 1320 } 1321 1322 // PartitionByTable represents a PARTITION [ALL] BY definition within 1323 // a CREATE/ALTER TABLE statement. 1324 type PartitionByTable struct { 1325 // All denotes PARTITION ALL BY. 1326 All bool 1327 1328 *PartitionBy 1329 } 1330 1331 // Format implements the NodeFormatter interface. 1332 func (node *PartitionByTable) Format(ctx *FmtCtx) { 1333 if node == nil { 1334 ctx.WriteString(` PARTITION BY NOTHING`) 1335 return 1336 } 1337 ctx.WriteString(` PARTITION `) 1338 if node.All { 1339 ctx.WriteString(`ALL `) 1340 } 1341 ctx.WriteString(`BY `) 1342 node.PartitionBy.formatListOrRange(ctx) 1343 } 1344 1345 // ContainsPartitions determines if the partition by table contains 1346 // a partition clause which is not PARTITION BY NOTHING. 1347 func (node *PartitionByTable) ContainsPartitions() bool { 1348 return node != nil && node.PartitionBy != nil 1349 } 1350 1351 // ContainsPartitioningClause determines if the partition by table contains 1352 // a partitioning clause, including PARTITION BY NOTHING. 1353 func (node *PartitionByTable) ContainsPartitioningClause() bool { 1354 return node != nil 1355 } 1356 1357 // PartitionBy represents an PARTITION BY definition within a CREATE/ALTER 1358 // TABLE/INDEX statement or within a subpartition statement. 1359 // This is wrapped by top level PartitionByTable/PartitionByIndex 1360 // structs for table and index definitions respectively. 1361 type PartitionBy struct { 1362 Fields NameList 1363 // Exactly one of List or Range is required to be non-empty. 1364 List []ListPartition 1365 Range []RangePartition 1366 } 1367 1368 // Format implements the NodeFormatter interface. 1369 func (node *PartitionBy) Format(ctx *FmtCtx) { 1370 ctx.WriteString(` PARTITION BY `) 1371 node.formatListOrRange(ctx) 1372 } 1373 1374 func (node *PartitionBy) formatListOrRange(ctx *FmtCtx) { 1375 if node == nil { 1376 ctx.WriteString(`NOTHING`) 1377 return 1378 } 1379 if len(node.List) > 0 { 1380 ctx.WriteString(`LIST (`) 1381 } else if len(node.Range) > 0 { 1382 ctx.WriteString(`RANGE (`) 1383 } 1384 ctx.FormatNode(&node.Fields) 1385 ctx.WriteString(`) (`) 1386 for i := range node.List { 1387 if i > 0 { 1388 ctx.WriteString(", ") 1389 } 1390 ctx.FormatNode(&node.List[i]) 1391 } 1392 for i := range node.Range { 1393 if i > 0 { 1394 ctx.WriteString(", ") 1395 } 1396 ctx.FormatNode(&node.Range[i]) 1397 } 1398 ctx.WriteString(`)`) 1399 } 1400 1401 // ListPartition represents a PARTITION definition within a PARTITION BY LIST. 1402 type ListPartition struct { 1403 Name Name 1404 Exprs Exprs 1405 Subpartition *PartitionBy 1406 } 1407 1408 // Format implements the NodeFormatter interface. 1409 func (node *ListPartition) Format(ctx *FmtCtx) { 1410 ctx.WriteString(`PARTITION `) 1411 ctx.FormatNode(&node.Name) 1412 ctx.WriteString(` VALUES IN (`) 1413 ctx.FormatNode(&node.Exprs) 1414 ctx.WriteByte(')') 1415 if node.Subpartition != nil { 1416 ctx.FormatNode(node.Subpartition) 1417 } 1418 } 1419 1420 // RangePartition represents a PARTITION definition within a PARTITION BY RANGE. 1421 type RangePartition struct { 1422 Name Name 1423 From Exprs 1424 To Exprs 1425 Subpartition *PartitionBy 1426 } 1427 1428 // Format implements the NodeFormatter interface. 1429 func (node *RangePartition) Format(ctx *FmtCtx) { 1430 ctx.WriteString(`PARTITION `) 1431 ctx.FormatNode(&node.Name) 1432 ctx.WriteString(` VALUES FROM (`) 1433 ctx.FormatNode(&node.From) 1434 ctx.WriteString(`) TO (`) 1435 ctx.FormatNode(&node.To) 1436 ctx.WriteByte(')') 1437 if node.Subpartition != nil { 1438 ctx.FormatNode(node.Subpartition) 1439 } 1440 } 1441 1442 // StorageParam is a key-value parameter for table storage. 1443 type StorageParam struct { 1444 Key Name 1445 Value Expr 1446 } 1447 1448 // StorageParams is a list of StorageParams. 1449 type StorageParams []StorageParam 1450 1451 // Format implements the NodeFormatter interface. 1452 func (o *StorageParams) Format(ctx *FmtCtx) { 1453 for i := range *o { 1454 n := &(*o)[i] 1455 if i > 0 { 1456 ctx.WriteString(", ") 1457 } 1458 // TODO(knz): the key may need to be formatted differently 1459 // if we want to de-anonymize it. 1460 ctx.FormatNode(&n.Key) 1461 if n.Value != nil { 1462 ctx.WriteString(` = `) 1463 ctx.FormatNode(n.Value) 1464 } 1465 } 1466 } 1467 1468 // GetVal returns corresponding value if a key exists, otherwise nil is 1469 // returned. 1470 func (o *StorageParams) GetVal(key string) Expr { 1471 k := Name(key) 1472 for _, param := range *o { 1473 if param.Key == k { 1474 return param.Value 1475 } 1476 } 1477 return nil 1478 } 1479 1480 // CreateTableOnCommitSetting represents the CREATE TABLE ... ON COMMIT <action> 1481 // parameters. 1482 type CreateTableOnCommitSetting uint32 1483 1484 const ( 1485 // CreateTableOnCommitUnset indicates that ON COMMIT was unset. 1486 CreateTableOnCommitUnset CreateTableOnCommitSetting = iota 1487 // CreateTableOnCommitPreserveRows indicates that ON COMMIT PRESERVE ROWS was set. 1488 CreateTableOnCommitPreserveRows 1489 ) 1490 1491 // CreateTable represents a CREATE TABLE statement. 1492 type CreateTable struct { 1493 IfNotExists bool 1494 Table TableName 1495 PartitionByTable *PartitionByTable 1496 Persistence Persistence 1497 StorageParams StorageParams 1498 OnCommit CreateTableOnCommitSetting 1499 // In CREATE...AS queries, Defs represents a list of ColumnTableDefs, one for 1500 // each column, and a ConstraintTableDef for each constraint on a subset of 1501 // these columns. 1502 Defs TableDefs 1503 AsSource *Select 1504 Locality *Locality 1505 } 1506 1507 // As returns true if this table represents a CREATE TABLE ... AS statement, 1508 // false otherwise. 1509 func (node *CreateTable) As() bool { 1510 return node.AsSource != nil 1511 } 1512 1513 // AsHasUserSpecifiedPrimaryKey returns true if a CREATE TABLE ... AS statement 1514 // has a PRIMARY KEY constraint specified. 1515 func (node *CreateTable) AsHasUserSpecifiedPrimaryKey() bool { 1516 if node.As() { 1517 for _, def := range node.Defs { 1518 if d, ok := def.(*ColumnTableDef); !ok { 1519 return false 1520 } else if d.PrimaryKey.IsPrimaryKey { 1521 return true 1522 } 1523 } 1524 } 1525 return false 1526 } 1527 1528 // Format implements the NodeFormatter interface. 1529 func (node *CreateTable) Format(ctx *FmtCtx) { 1530 ctx.WriteString("CREATE ") 1531 switch node.Persistence { 1532 case PersistenceTemporary: 1533 ctx.WriteString("TEMPORARY ") 1534 case PersistenceUnlogged: 1535 ctx.WriteString("UNLOGGED ") 1536 } 1537 ctx.WriteString("TABLE ") 1538 if node.IfNotExists { 1539 ctx.WriteString("IF NOT EXISTS ") 1540 } 1541 ctx.FormatNode(&node.Table) 1542 node.FormatBody(ctx) 1543 } 1544 1545 // FormatBody formats the "body" of the create table definition - everything 1546 // but the CREATE TABLE tableName part. 1547 func (node *CreateTable) FormatBody(ctx *FmtCtx) { 1548 if node.As() { 1549 if len(node.Defs) > 0 { 1550 ctx.WriteString(" (") 1551 ctx.FormatNode(&node.Defs) 1552 ctx.WriteByte(')') 1553 } 1554 if node.StorageParams != nil { 1555 ctx.WriteString(` WITH (`) 1556 ctx.FormatNode(&node.StorageParams) 1557 ctx.WriteByte(')') 1558 } 1559 ctx.WriteString(" AS ") 1560 ctx.FormatNode(node.AsSource) 1561 } else { 1562 ctx.WriteString(" (") 1563 ctx.FormatNode(&node.Defs) 1564 ctx.WriteByte(')') 1565 if node.PartitionByTable != nil { 1566 ctx.FormatNode(node.PartitionByTable) 1567 } 1568 if node.StorageParams != nil { 1569 ctx.WriteString(` WITH (`) 1570 ctx.FormatNode(&node.StorageParams) 1571 ctx.WriteByte(')') 1572 } 1573 if node.Locality != nil { 1574 ctx.WriteString(" ") 1575 ctx.FormatNode(node.Locality) 1576 } 1577 } 1578 } 1579 1580 // HoistConstraints finds column check and foreign key constraints defined 1581 // inline with their columns and makes them table-level constraints, stored in 1582 // n.Defs. For example, the foreign key constraint in 1583 // 1584 // CREATE TABLE foo (a INT REFERENCES bar(a)) 1585 // 1586 // gets pulled into a top-level constraint like: 1587 // 1588 // CREATE TABLE foo (a INT, FOREIGN KEY (a) REFERENCES bar(a)) 1589 // 1590 // Similarly, the CHECK constraint in 1591 // 1592 // CREATE TABLE foo (a INT CHECK (a < 1), b INT) 1593 // 1594 // gets pulled into a top-level constraint like: 1595 // 1596 // CREATE TABLE foo (a INT, b INT, CHECK (a < 1)) 1597 // 1598 // Note that some SQL databases require that a constraint attached to a column 1599 // to refer only to the column it is attached to. We follow Postgres' behavior, 1600 // however, in omitting this restriction by blindly hoisting all column 1601 // constraints. For example, the following table definition is accepted in 1602 // CockroachDB and Postgres, but not necessarily other SQL databases: 1603 // 1604 // CREATE TABLE foo (a INT CHECK (a < b), b INT) 1605 // 1606 // Unique constraints are not hoisted. 1607 func (node *CreateTable) HoistConstraints() { 1608 for _, d := range node.Defs { 1609 if col, ok := d.(*ColumnTableDef); ok { 1610 for _, checkExpr := range col.CheckExprs { 1611 node.Defs = append(node.Defs, 1612 &CheckConstraintTableDef{ 1613 Expr: checkExpr.Expr, 1614 Name: checkExpr.ConstraintName, 1615 }, 1616 ) 1617 } 1618 col.CheckExprs = nil 1619 if col.HasFKConstraint() { 1620 var targetCol NameList 1621 if col.References.Col != "" { 1622 targetCol = append(targetCol, col.References.Col) 1623 } 1624 node.Defs = append(node.Defs, &ForeignKeyConstraintTableDef{ 1625 Table: *col.References.Table, 1626 FromCols: NameList{col.Name}, 1627 ToCols: targetCol, 1628 Name: col.References.ConstraintName, 1629 Actions: col.References.Actions, 1630 Match: col.References.Match, 1631 }) 1632 col.References.Table = nil 1633 } 1634 } 1635 } 1636 } 1637 1638 // CreateSchema represents a CREATE SCHEMA statement. 1639 type CreateSchema struct { 1640 IfNotExists bool 1641 AuthRole RoleSpec 1642 Schema ObjectNamePrefix 1643 } 1644 1645 // Format implements the NodeFormatter interface. 1646 func (node *CreateSchema) Format(ctx *FmtCtx) { 1647 ctx.WriteString("CREATE SCHEMA") 1648 1649 if node.IfNotExists { 1650 ctx.WriteString(" IF NOT EXISTS") 1651 } 1652 1653 if node.Schema.ExplicitSchema { 1654 ctx.WriteString(" ") 1655 ctx.FormatNode(&node.Schema) 1656 } 1657 1658 if !node.AuthRole.Undefined() { 1659 ctx.WriteString(" AUTHORIZATION ") 1660 ctx.FormatNode(&node.AuthRole) 1661 } 1662 } 1663 1664 // CreateSequence represents a CREATE SEQUENCE statement. 1665 type CreateSequence struct { 1666 IfNotExists bool 1667 Name TableName 1668 Persistence Persistence 1669 Options SequenceOptions 1670 } 1671 1672 // Format implements the NodeFormatter interface. 1673 func (node *CreateSequence) Format(ctx *FmtCtx) { 1674 ctx.WriteString("CREATE ") 1675 1676 if node.Persistence == PersistenceTemporary { 1677 ctx.WriteString("TEMPORARY ") 1678 } 1679 1680 ctx.WriteString("SEQUENCE ") 1681 1682 if node.IfNotExists { 1683 ctx.WriteString("IF NOT EXISTS ") 1684 } 1685 ctx.FormatNode(&node.Name) 1686 ctx.FormatNode(&node.Options) 1687 } 1688 1689 // SequenceOptions represents a list of sequence options. 1690 type SequenceOptions []SequenceOption 1691 1692 // Format implements the NodeFormatter interface. 1693 func (node *SequenceOptions) Format(ctx *FmtCtx) { 1694 for i := range *node { 1695 option := &(*node)[i] 1696 ctx.WriteByte(' ') 1697 switch option.Name { 1698 case SeqOptAs: 1699 ctx.WriteString(option.Name) 1700 ctx.WriteByte(' ') 1701 ctx.WriteString(option.AsIntegerType.SQLString()) 1702 case SeqOptCycle, SeqOptNoCycle: 1703 ctx.WriteString(option.Name) 1704 case SeqOptCache: 1705 ctx.WriteString(option.Name) 1706 ctx.WriteByte(' ') 1707 // TODO(knz): replace all this with ctx.FormatNode if/when 1708 // the cache option supports expressions. 1709 if ctx.flags.HasFlags(FmtHideConstants) { 1710 ctx.WriteByte('0') 1711 } else { 1712 ctx.Printf("%d", *option.IntVal) 1713 } 1714 case SeqOptMaxValue, SeqOptMinValue: 1715 if option.IntVal == nil { 1716 ctx.WriteString("NO ") 1717 ctx.WriteString(option.Name) 1718 } else { 1719 ctx.WriteString(option.Name) 1720 ctx.WriteByte(' ') 1721 // TODO(knz): replace all this with ctx.FormatNode if/when 1722 // the min/max value options support expressions. 1723 if ctx.flags.HasFlags(FmtHideConstants) { 1724 ctx.WriteByte('0') 1725 } else { 1726 ctx.Printf("%d", *option.IntVal) 1727 } 1728 } 1729 case SeqOptStart: 1730 ctx.WriteString(option.Name) 1731 ctx.WriteByte(' ') 1732 if option.OptionalWord { 1733 ctx.WriteString("WITH ") 1734 } 1735 // TODO(knz): replace all this with ctx.FormatNode if/when 1736 // the start option supports expressions. 1737 if ctx.flags.HasFlags(FmtHideConstants) { 1738 ctx.WriteByte('0') 1739 } else { 1740 ctx.Printf("%d", *option.IntVal) 1741 } 1742 case SeqOptRestart: 1743 ctx.WriteString(option.Name) 1744 if option.IntVal != nil { 1745 ctx.WriteByte(' ') 1746 if option.OptionalWord { 1747 ctx.WriteString("WITH ") 1748 } 1749 if ctx.flags.HasFlags(FmtHideConstants) { 1750 ctx.WriteByte('0') 1751 } else { 1752 ctx.Printf("%d", *option.IntVal) 1753 } 1754 } 1755 case SeqOptIncrement: 1756 ctx.WriteString(option.Name) 1757 ctx.WriteByte(' ') 1758 if option.OptionalWord { 1759 ctx.WriteString("BY ") 1760 } 1761 // TODO(knz): replace all this with ctx.FormatNode if/when 1762 // the increment option supports expressions. 1763 if ctx.flags.HasFlags(FmtHideConstants) { 1764 ctx.WriteByte('0') 1765 } else { 1766 ctx.Printf("%d", *option.IntVal) 1767 } 1768 case SeqOptVirtual: 1769 ctx.WriteString(option.Name) 1770 case SeqOptOwnedBy: 1771 ctx.WriteString(option.Name) 1772 ctx.WriteByte(' ') 1773 switch option.ColumnItemVal { 1774 case nil: 1775 ctx.WriteString("NONE") 1776 default: 1777 ctx.FormatNode(option.ColumnItemVal) 1778 } 1779 default: 1780 panic(errors.AssertionFailedf("unexpected SequenceOption: %v", option)) 1781 } 1782 } 1783 } 1784 1785 // SequenceOption represents an option on a CREATE SEQUENCE statement. 1786 type SequenceOption struct { 1787 Name string 1788 1789 // AsIntegerType specifies default min and max values of a sequence. 1790 AsIntegerType *types.T 1791 1792 IntVal *int64 1793 1794 OptionalWord bool 1795 1796 ColumnItemVal *ColumnItem 1797 } 1798 1799 // Names of options on CREATE SEQUENCE. 1800 const ( 1801 SeqOptAs = "AS" 1802 SeqOptCycle = "CYCLE" 1803 SeqOptNoCycle = "NO CYCLE" 1804 SeqOptOwnedBy = "OWNED BY" 1805 SeqOptCache = "CACHE" 1806 SeqOptIncrement = "INCREMENT" 1807 SeqOptMinValue = "MINVALUE" 1808 SeqOptMaxValue = "MAXVALUE" 1809 SeqOptStart = "START" 1810 SeqOptRestart = "RESTART" 1811 SeqOptVirtual = "VIRTUAL" 1812 1813 // Avoid unused warning for constants. 1814 _ = SeqOptAs 1815 ) 1816 1817 // LikeTableDef represents a LIKE table declaration on a CREATE TABLE statement. 1818 type LikeTableDef struct { 1819 Name TableName 1820 Options []LikeTableOption 1821 } 1822 1823 // LikeTableOption represents an individual INCLUDING / EXCLUDING statement 1824 // on a LIKE table declaration. 1825 type LikeTableOption struct { 1826 Excluded bool 1827 Opt LikeTableOpt 1828 } 1829 1830 // Format implements the NodeFormatter interface. 1831 func (def *LikeTableDef) Format(ctx *FmtCtx) { 1832 ctx.WriteString("LIKE ") 1833 ctx.FormatNode(&def.Name) 1834 for _, o := range def.Options { 1835 ctx.WriteString(" ") 1836 ctx.FormatNode(o) 1837 } 1838 } 1839 1840 // Format implements the NodeFormatter interface. 1841 func (l LikeTableOption) Format(ctx *FmtCtx) { 1842 if l.Excluded { 1843 ctx.WriteString("EXCLUDING ") 1844 } else { 1845 ctx.WriteString("INCLUDING ") 1846 } 1847 ctx.WriteString(l.Opt.String()) 1848 } 1849 1850 // LikeTableOpt represents one of the types of things that can be included or 1851 // excluded in a LIKE table declaration. It's a bitmap, where each of the Opt 1852 // values is a single enabled bit in the map. 1853 type LikeTableOpt int 1854 1855 // The values for LikeTableOpt. 1856 const ( 1857 LikeTableOptConstraints LikeTableOpt = 1 << iota 1858 LikeTableOptDefaults 1859 LikeTableOptGenerated 1860 LikeTableOptIndexes 1861 1862 // Make sure this field stays last! 1863 likeTableOptInvalid 1864 ) 1865 1866 // LikeTableOptAll is the full LikeTableOpt bitmap. 1867 const LikeTableOptAll = ^likeTableOptInvalid 1868 1869 // Has returns true if the receiver has the other options bits set. 1870 func (o LikeTableOpt) Has(other LikeTableOpt) bool { 1871 return int(o)&int(other) != 0 1872 } 1873 1874 func (o LikeTableOpt) String() string { 1875 switch o { 1876 case LikeTableOptConstraints: 1877 return "CONSTRAINTS" 1878 case LikeTableOptDefaults: 1879 return "DEFAULTS" 1880 case LikeTableOptGenerated: 1881 return "GENERATED" 1882 case LikeTableOptIndexes: 1883 return "INDEXES" 1884 case LikeTableOptAll: 1885 return "ALL" 1886 default: 1887 panic("unknown like table opt" + strconv.Itoa(int(o))) 1888 } 1889 } 1890 1891 func (o *KVOptions) formatAsRoleOptions(ctx *FmtCtx) { 1892 for _, option := range *o { 1893 ctx.WriteByte(' ') 1894 // Role option keys are always sequences of keywords separated 1895 // by spaces. 1896 ctx.WriteString(strings.ToUpper(string(option.Key))) 1897 1898 // Password is a special case. 1899 if strings.HasSuffix(string(option.Key), "password") { 1900 ctx.WriteByte(' ') 1901 if ctx.flags.HasFlags(FmtShowPasswords) { 1902 ctx.FormatNode(option.Value) 1903 } else { 1904 ctx.WriteString(PasswordSubstitution) 1905 } 1906 } else if option.Value != nil { 1907 ctx.WriteByte(' ') 1908 if ctx.HasFlags(FmtHideConstants) { 1909 ctx.WriteString("'_'") 1910 } else { 1911 ctx.FormatNode(option.Value) 1912 } 1913 } 1914 } 1915 } 1916 1917 // CreateRole represents a CREATE ROLE statement. 1918 type CreateRole struct { 1919 Name RoleSpec 1920 IfNotExists bool 1921 IsRole bool 1922 KVOptions KVOptions 1923 } 1924 1925 // Format implements the NodeFormatter interface. 1926 func (node *CreateRole) Format(ctx *FmtCtx) { 1927 ctx.WriteString("CREATE") 1928 if node.IsRole { 1929 ctx.WriteString(" ROLE ") 1930 } else { 1931 ctx.WriteString(" USER ") 1932 } 1933 if node.IfNotExists { 1934 ctx.WriteString("IF NOT EXISTS ") 1935 } 1936 ctx.FormatNode(&node.Name) 1937 1938 if len(node.KVOptions) > 0 { 1939 ctx.WriteString(" WITH") 1940 node.KVOptions.formatAsRoleOptions(ctx) 1941 } 1942 } 1943 1944 // CreateView represents a CREATE VIEW statement. 1945 type CreateView struct { 1946 Name TableName 1947 ColumnNames NameList 1948 AsSource *Select 1949 IfNotExists bool 1950 Persistence Persistence 1951 Replace bool 1952 Materialized bool 1953 WithData bool 1954 } 1955 1956 // Format implements the NodeFormatter interface. 1957 func (node *CreateView) Format(ctx *FmtCtx) { 1958 ctx.WriteString("CREATE ") 1959 1960 if node.Replace { 1961 ctx.WriteString("OR REPLACE ") 1962 } 1963 1964 if node.Persistence == PersistenceTemporary { 1965 ctx.WriteString("TEMPORARY ") 1966 } 1967 1968 if node.Materialized { 1969 ctx.WriteString("MATERIALIZED ") 1970 } 1971 1972 ctx.WriteString("VIEW ") 1973 1974 if node.IfNotExists { 1975 ctx.WriteString("IF NOT EXISTS ") 1976 } 1977 ctx.FormatNode(&node.Name) 1978 1979 if len(node.ColumnNames) > 0 { 1980 ctx.WriteByte(' ') 1981 ctx.WriteByte('(') 1982 ctx.FormatNode(&node.ColumnNames) 1983 ctx.WriteByte(')') 1984 } 1985 1986 ctx.WriteString(" AS ") 1987 ctx.FormatNode(node.AsSource) 1988 if node.Materialized && node.WithData { 1989 ctx.WriteString(" WITH DATA") 1990 } else if node.Materialized && !node.WithData { 1991 ctx.WriteString(" WITH NO DATA") 1992 } 1993 } 1994 1995 // RefreshMaterializedView represents a REFRESH MATERIALIZED VIEW statement. 1996 type RefreshMaterializedView struct { 1997 Name *UnresolvedObjectName 1998 Concurrently bool 1999 RefreshDataOption RefreshDataOption 2000 } 2001 2002 // RefreshDataOption corresponds to arguments for the REFRESH MATERIALIZED VIEW 2003 // statement. 2004 type RefreshDataOption int 2005 2006 const ( 2007 // RefreshDataDefault refers to no option provided to the REFRESH MATERIALIZED 2008 // VIEW statement. 2009 RefreshDataDefault RefreshDataOption = iota 2010 // RefreshDataWithData refers to the WITH DATA option provided to the REFRESH 2011 // MATERIALIZED VIEW statement. 2012 RefreshDataWithData 2013 // RefreshDataClear refers to the WITH NO DATA option provided to the REFRESH 2014 // MATERIALIZED VIEW statement. 2015 RefreshDataClear 2016 ) 2017 2018 // Format implements the NodeFormatter interface. 2019 func (node *RefreshMaterializedView) Format(ctx *FmtCtx) { 2020 ctx.WriteString("REFRESH MATERIALIZED VIEW ") 2021 if node.Concurrently { 2022 ctx.WriteString("CONCURRENTLY ") 2023 } 2024 ctx.FormatNode(node.Name) 2025 switch node.RefreshDataOption { 2026 case RefreshDataWithData: 2027 ctx.WriteString(" WITH DATA") 2028 case RefreshDataClear: 2029 ctx.WriteString(" WITH NO DATA") 2030 } 2031 } 2032 2033 // CreateStats represents a CREATE STATISTICS statement. 2034 type CreateStats struct { 2035 Name Name 2036 ColumnNames NameList 2037 Table TableExpr 2038 Options CreateStatsOptions 2039 } 2040 2041 // Format implements the NodeFormatter interface. 2042 func (node *CreateStats) Format(ctx *FmtCtx) { 2043 ctx.WriteString("CREATE STATISTICS ") 2044 ctx.FormatNode(&node.Name) 2045 2046 if len(node.ColumnNames) > 0 { 2047 ctx.WriteString(" ON ") 2048 ctx.FormatNode(&node.ColumnNames) 2049 } 2050 2051 ctx.WriteString(" FROM ") 2052 ctx.FormatNode(node.Table) 2053 2054 if !node.Options.Empty() { 2055 ctx.WriteString(" WITH OPTIONS") 2056 ctx.FormatNode(&node.Options) 2057 } 2058 } 2059 2060 // CreateStatsOptions contains options for CREATE STATISTICS. 2061 type CreateStatsOptions struct { 2062 // Throttling enables throttling and indicates the fraction of time we are 2063 // idling (between 0 and 1). 2064 Throttling float64 2065 2066 // AsOf performs a historical read at the given timestamp. 2067 // Note that the timestamp will be moved up during the operation if it gets 2068 // too old (in order to avoid problems with TTL expiration). 2069 AsOf AsOfClause 2070 2071 // UsingExtremes is true when the statistics collection is at 2072 // extreme values of the table or the index specified. 2073 UsingExtremes bool 2074 2075 // Where will specify statistics collection in a set of rows of the table 2076 // or index specified. 2077 Where *Where 2078 } 2079 2080 // Empty returns true if no options were provided. 2081 func (o *CreateStatsOptions) Empty() bool { 2082 return o.Throttling == 0 && o.AsOf.Expr == nil && o.Where == nil && !o.UsingExtremes 2083 } 2084 2085 // Format implements the NodeFormatter interface. 2086 func (o *CreateStatsOptions) Format(ctx *FmtCtx) { 2087 if o.UsingExtremes { 2088 ctx.WriteString(" USING EXTREMES") 2089 } 2090 if o.Where != nil { 2091 ctx.WriteByte(' ') 2092 ctx.FormatNode(o.Where) 2093 } 2094 if o.Throttling != 0 { 2095 ctx.WriteString(" THROTTLING ") 2096 // TODO(knz): Remove all this with ctx.FormatNode() 2097 // if/when throttling supports full expressions. 2098 if ctx.flags.HasFlags(FmtHideConstants) { 2099 // Using the value '0.001' instead of '0.0', because 2100 // when using '0.0' the statement does not get 2101 // formatted with the THROTTLING option. 2102 ctx.WriteString("0.001") 2103 } else { 2104 fmt.Fprintf(ctx, "%g", o.Throttling) 2105 } 2106 } 2107 if o.AsOf.Expr != nil { 2108 ctx.WriteByte(' ') 2109 ctx.FormatNode(&o.AsOf) 2110 } 2111 } 2112 2113 // CombineWith combines two options, erroring out if the two options contain 2114 // incompatible settings. 2115 func (o *CreateStatsOptions) CombineWith(other *CreateStatsOptions) error { 2116 if other.Throttling != 0 { 2117 if o.Throttling != 0 { 2118 return errors.New("THROTTLING specified multiple times") 2119 } 2120 o.Throttling = other.Throttling 2121 } 2122 if other.AsOf.Expr != nil { 2123 if o.AsOf.Expr != nil { 2124 return errors.New("AS OF specified multiple times") 2125 } 2126 o.AsOf = other.AsOf 2127 } 2128 if other.UsingExtremes { 2129 if o.UsingExtremes { 2130 return errors.New("USING EXTREMES specified multiple times") 2131 } 2132 o.UsingExtremes = other.UsingExtremes 2133 } 2134 if other.Where != nil { 2135 if o.Where != nil { 2136 return errors.New("WHERE specified multiple times") 2137 } 2138 o.Where = other.Where 2139 } 2140 if other.Where != nil && o.UsingExtremes || o.Where != nil && other.UsingExtremes { 2141 return errors.New("USING EXTREMES and WHERE may not be specified together") 2142 } 2143 return nil 2144 } 2145 2146 // CreateExtension represents a CREATE EXTENSION statement. 2147 type CreateExtension struct { 2148 Name Name 2149 IfNotExists bool 2150 } 2151 2152 // Format implements the NodeFormatter interface. 2153 func (node *CreateExtension) Format(ctx *FmtCtx) { 2154 ctx.WriteString("CREATE EXTENSION ") 2155 if node.IfNotExists { 2156 ctx.WriteString("IF NOT EXISTS ") 2157 } 2158 // NB: we do not anonymize the extension name 2159 // because 1) we assume that extension names 2160 // do not contain sensitive information and 2161 // 2) we want to get telemetry on which extensions 2162 // users attempt to load. 2163 ctx.WithFlags(ctx.flags&^FmtAnonymize, func() { 2164 ctx.FormatNode(&node.Name) 2165 }) 2166 } 2167 2168 // CreateExternalConnection represents a CREATE EXTERNAL CONNECTION statement. 2169 type CreateExternalConnection struct { 2170 ConnectionLabelSpec LabelSpec 2171 As Expr 2172 } 2173 2174 var _ Statement = &CreateExternalConnection{} 2175 2176 // Format implements the Statement interface. 2177 func (node *CreateExternalConnection) Format(ctx *FmtCtx) { 2178 ctx.WriteString("CREATE EXTERNAL CONNECTION") 2179 ctx.FormatNode(&node.ConnectionLabelSpec) 2180 ctx.WriteString(" AS ") 2181 ctx.FormatNode(node.As) 2182 } 2183 2184 // CreateTenant represents a CREATE VIRTUAL CLUSTER statement. 2185 type CreateTenant struct { 2186 IfNotExists bool 2187 TenantSpec *TenantSpec 2188 Like *LikeTenantSpec 2189 } 2190 2191 // Format implements the NodeFormatter interface. 2192 func (node *CreateTenant) Format(ctx *FmtCtx) { 2193 ctx.WriteString("CREATE VIRTUAL CLUSTER ") 2194 if node.IfNotExists { 2195 ctx.WriteString("IF NOT EXISTS ") 2196 } 2197 ctx.FormatNode(node.TenantSpec) 2198 ctx.FormatNode(node.Like) 2199 } 2200 2201 // LikeTenantSpec represents a LIKE clause in CREATE VIRTUAL CLUSTER. 2202 type LikeTenantSpec struct { 2203 OtherTenant *TenantSpec 2204 } 2205 2206 func (node *LikeTenantSpec) Format(ctx *FmtCtx) { 2207 if node.OtherTenant == nil { 2208 return 2209 } 2210 ctx.WriteString(" LIKE ") 2211 ctx.FormatNode(node.OtherTenant) 2212 } 2213 2214 // CreateTenantFromReplication represents a CREATE VIRTUAL CLUSTER...FROM REPLICATION 2215 // statement. 2216 type CreateTenantFromReplication struct { 2217 IfNotExists bool 2218 TenantSpec *TenantSpec 2219 2220 // ReplicationSourceTenantName is the name of the tenant that 2221 // we are replicating into the newly created tenant. 2222 // Note: even though this field can only be a name 2223 // (this is guaranteed during parsing), we still want 2224 // to use the TenantSpec type. This supports the auto-promotion 2225 // of simple identifiers to strings. 2226 ReplicationSourceTenantName *TenantSpec 2227 // ReplicationSourceAddress is the address of the source cluster that we are 2228 // replicating data from. 2229 ReplicationSourceAddress Expr 2230 2231 Options TenantReplicationOptions 2232 2233 Like *LikeTenantSpec 2234 } 2235 2236 // TenantReplicationOptions options for the CREATE VIRTUAL CLUSTER FROM REPLICATION command. 2237 type TenantReplicationOptions struct { 2238 Retention Expr 2239 ResumeTimestamp Expr 2240 } 2241 2242 var _ NodeFormatter = &TenantReplicationOptions{} 2243 2244 // Format implements the NodeFormatter interface. 2245 func (node *CreateTenantFromReplication) Format(ctx *FmtCtx) { 2246 ctx.WriteString("CREATE VIRTUAL CLUSTER ") 2247 if node.IfNotExists { 2248 ctx.WriteString("IF NOT EXISTS ") 2249 } 2250 // NB: we do not anonymize the tenant name because we assume that tenant names 2251 // do not contain sensitive information. 2252 ctx.FormatNode(node.TenantSpec) 2253 ctx.FormatNode(node.Like) 2254 2255 if node.ReplicationSourceAddress != nil { 2256 ctx.WriteString(" FROM REPLICATION OF ") 2257 ctx.FormatNode(node.ReplicationSourceTenantName) 2258 ctx.WriteString(" ON ") 2259 _, canOmitParentheses := node.ReplicationSourceAddress.(alreadyDelimitedAsSyntacticDExpr) 2260 if !canOmitParentheses { 2261 ctx.WriteByte('(') 2262 } 2263 ctx.FormatNode(node.ReplicationSourceAddress) 2264 if !canOmitParentheses { 2265 ctx.WriteByte(')') 2266 } 2267 2268 } 2269 if !node.Options.IsDefault() { 2270 ctx.WriteString(" WITH ") 2271 ctx.FormatNode(&node.Options) 2272 } 2273 } 2274 2275 // Format implements the NodeFormatter interface 2276 func (o *TenantReplicationOptions) Format(ctx *FmtCtx) { 2277 var addSep bool 2278 maybeAddSep := func() { 2279 if addSep { 2280 ctx.WriteString(", ") 2281 } 2282 addSep = true 2283 } 2284 if o.Retention != nil { 2285 maybeAddSep() 2286 ctx.WriteString("RETENTION = ") 2287 _, canOmitParentheses := o.Retention.(alreadyDelimitedAsSyntacticDExpr) 2288 if !canOmitParentheses { 2289 ctx.WriteByte('(') 2290 } 2291 ctx.FormatNode(o.Retention) 2292 if !canOmitParentheses { 2293 ctx.WriteByte(')') 2294 } 2295 } 2296 if o.ResumeTimestamp != nil { 2297 maybeAddSep() 2298 ctx.WriteString("RESUME TIMESTAMP = ") 2299 _, canOmitParentheses := o.ResumeTimestamp.(alreadyDelimitedAsSyntacticDExpr) 2300 if !canOmitParentheses { 2301 ctx.WriteByte('(') 2302 } 2303 ctx.FormatNode(o.ResumeTimestamp) 2304 if !canOmitParentheses { 2305 ctx.WriteByte(')') 2306 } 2307 } 2308 } 2309 2310 // CombineWith merges other TenantReplicationOptions into this struct. 2311 // An error is returned if the same option merged multiple times. 2312 func (o *TenantReplicationOptions) CombineWith(other *TenantReplicationOptions) error { 2313 if o.Retention != nil { 2314 if other.Retention != nil { 2315 return errors.New("RETENTION option specified multiple times") 2316 } 2317 } else { 2318 o.Retention = other.Retention 2319 } 2320 2321 if o.ResumeTimestamp != nil { 2322 if other.ResumeTimestamp != nil { 2323 return errors.New("RESUME TIMESTAMP option specified multiple times") 2324 } 2325 } else { 2326 o.ResumeTimestamp = other.ResumeTimestamp 2327 } 2328 2329 return nil 2330 } 2331 2332 // IsDefault returns true if this backup options struct has default value. 2333 func (o TenantReplicationOptions) IsDefault() bool { 2334 options := TenantReplicationOptions{} 2335 return o.Retention == options.Retention && 2336 o.ResumeTimestamp == options.ResumeTimestamp 2337 } 2338 2339 type SuperRegion struct { 2340 Name Name 2341 Regions NameList 2342 } 2343 2344 func (node *SuperRegion) Format(ctx *FmtCtx) { 2345 ctx.WriteString(" SUPER REGION ") 2346 ctx.FormatNode(&node.Name) 2347 ctx.WriteString(" VALUES ") 2348 for i := range node.Regions { 2349 if i != 0 { 2350 ctx.WriteString(",") 2351 } 2352 ctx.FormatNode(&node.Regions[i]) 2353 } 2354 }