diff --git a/go.mod b/go.mod index 0bad8cc603..ca9092bab5 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/dolthub/doltgresql go 1.21 require ( + github.com/PuerkitoBio/goquery v1.8.1 github.com/cockroachdb/apd/v2 v2.0.3-0.20200518165714-d020e156310a github.com/cockroachdb/errors v1.7.5 github.com/dolthub/dolt/go v0.40.5-0.20231114163244-0cc42b844045 @@ -19,6 +20,7 @@ require ( github.com/lib/pq v1.10.2 github.com/madflojo/testcerts v1.1.1 github.com/pierrre/geohash v1.0.0 + github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.8.2 github.com/tidwall/gjson v1.14.4 github.com/twpayne/go-geom v1.3.6 @@ -36,6 +38,7 @@ require ( github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible // indirect github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 // indirect + github.com/andybalholm/cascadia v1.3.1 // indirect github.com/apache/thrift v0.13.1-0.20201008052519-daf620915714 // indirect github.com/aws/aws-sdk-go v1.34.0 // indirect github.com/bcicen/jstream v1.0.0 // indirect @@ -109,7 +112,6 @@ require ( github.com/sergi/go-diff v1.1.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/silvasur/buzhash v0.0.0-20160816060738-9bdec3dec7c6 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/tealeg/xlsx v1.0.5 // indirect github.com/tetratelabs/wazero v1.1.0 // indirect diff --git a/go.sum b/go.sum index e8e0d647e5..e1e968109a 100644 --- a/go.sum +++ b/go.sum @@ -77,6 +77,8 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= +github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= @@ -103,6 +105,8 @@ github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible h1:QoRMR0TCctLDqBCMyOu1e github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.0.0-20181112125854-24918abba929/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -1044,11 +1048,13 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= diff --git a/server/ast/column_table_def.go b/server/ast/column_table_def.go index b2dd3654be..be984d8dd9 100644 --- a/server/ast/column_table_def.go +++ b/server/ast/column_table_def.go @@ -39,7 +39,7 @@ func nodeColumnTableDef(node *tree.ColumnTableDef) (_ *vitess.ColumnDefinition, return nil, fmt.Errorf("FAMILY is not yet supported") } - typeParams, err := nodeResolvableTypeReference(node.Type) + convertType, err := nodeResolvableTypeReference(node.Type) if err != nil { return nil, err } @@ -104,13 +104,13 @@ func nodeColumnTableDef(node *tree.ColumnTableDef) (_ *vitess.ColumnDefinition, return &vitess.ColumnDefinition{ Name: vitess.NewColIdent(string(node.Name)), Type: vitess.ColumnType{ - Type: typeParams.name, + Type: convertType.Type, Null: isNull, NotNull: isNotNull, Autoincrement: vitess.BoolVal(node.IsSerial), Default: defaultExpr, - Length: typeParams.length, - Scale: typeParams.scale, + Length: convertType.Length, + Scale: convertType.Scale, KeyOpt: keyOpt, ForeignKeyDef: fkDef, GeneratedExpr: generated, diff --git a/server/ast/expr.go b/server/ast/expr.go index 220ea2b468..0296a417b5 100644 --- a/server/ast/expr.go +++ b/server/ast/expr.go @@ -199,7 +199,7 @@ func nodeExpr(node tree.Expr) (vitess.Expr, error) { return nil, fmt.Errorf("unknown cast syntax") } - params, err := nodeResolvableTypeReference(node.Type) + convertType, err := nodeResolvableTypeReference(node.Type) if err != nil { return nil, err } @@ -207,12 +207,7 @@ func nodeExpr(node tree.Expr) (vitess.Expr, error) { return &vitess.ConvertExpr{ Name: "CAST", Expr: expr, - Type: &vitess.ConvertType{ - Type: params.name, - Length: params.length, - Scale: params.scale, - Charset: "", // TODO - }, + Type: convertType, }, nil case *tree.CoalesceExpr: return nil, fmt.Errorf("COALESCE is not yet supported") diff --git a/server/ast/resolvable_type_reference.go b/server/ast/resolvable_type_reference.go index 20d5e15c49..677e25497b 100755 --- a/server/ast/resolvable_type_reference.go +++ b/server/ast/resolvable_type_reference.go @@ -24,13 +24,8 @@ import ( "github.com/dolthub/doltgresql/postgres/parser/types" ) -type typeParams struct { - name string - length *vitess.SQLVal - scale *vitess.SQLVal -} - -func nodeResolvableTypeReference(typ tree.ResolvableTypeReference) (*typeParams, error) { +// nodeResolvableTypeReference handles tree.ResolvableTypeReference nodes. +func nodeResolvableTypeReference(typ tree.ResolvableTypeReference) (*vitess.ConvertType, error) { if typ == nil { return nil, nil } @@ -62,9 +57,10 @@ func nodeResolvableTypeReference(typ tree.ResolvableTypeReference) (*typeParams, } } - return &typeParams{ - name: columnTypeName, - length: columnTypeLength, - scale: columnTypeScale, + return &vitess.ConvertType{ + Type: columnTypeName, + Length: columnTypeLength, + Scale: columnTypeScale, + Charset: "", // TODO }, nil } diff --git a/testing/generation/command_docs/create_tests.go b/testing/generation/command_docs/create_tests.go new file mode 100644 index 0000000000..2bf75eeaa7 --- /dev/null +++ b/testing/generation/command_docs/create_tests.go @@ -0,0 +1,277 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "errors" + "fmt" + "os" + "strings" + "time" + + "github.com/sergi/go-diff/diffmatchpatch" + + "github.com/dolthub/doltgresql/postgres/parser/parser" + "github.com/dolthub/doltgresql/server/ast" +) + +const TestHeader = `// Copyright %d Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package output + +import "testing" + +func Test%s(t *testing.T) { + tests := []QueryParses{ +` + +const TestFooter = ` } + RunTests(t, tests) +} +` + +// GenerateTestsFromSynopses generates a test file in the output directory for each file in the synopses directory. +func GenerateTestsFromSynopses() (err error) { + parentFolder, err := GetCommandDocsFolder() + if err != nil { + return err + } + fileInfos, err := os.ReadDir(fmt.Sprintf("%s/synopses", parentFolder)) + if err != nil { + return err + } + +FileLoop: + for i, fileInfo := range fileInfos { + if i != 0 { + //TODO: this runs a single file to prevent writing all of the files, since some are unbelievably large + continue FileLoop + } + prefix := strings.ToUpper( + strings.ReplaceAll( + strings.ReplaceAll( + fileInfo.Name(), + ".txt", + "", + ), + "_", + " ", + ), + ) + fmt.Println(SectionMarker(prefix, '+', 80)) + data, nErr := os.ReadFile(fmt.Sprintf("%s/synopses/%s", parentFolder, fileInfo.Name())) + if nErr != nil { + err = errors.Join(err, nErr) + continue FileLoop + } + dataStr := strings.TrimSpace(string(data)) + scanner := NewScanner(dataStr) + tokens, nErr := scanner.Process() + if nErr != nil { + err = errors.Join(err, nErr) + continue FileLoop + } + scannerString := scanner.String() + if dataStr != scannerString { + sb := strings.Builder{} + dmp := diffmatchpatch.New() + diffs := dmp.DiffMain(dataStr, scannerString, true) + whitespaceOnly := true + for _, diff := range diffs { + if diff.Type != diffmatchpatch.DiffEqual && diff.Text != " " && diff.Text != "\n" { + whitespaceOnly = false + } + } + if whitespaceOnly { + sb.WriteString(SectionMarker("Whitespace Differences", '-', 80)) + } else { + sb.WriteString(dmp.DiffPrettyText(diffs)) + } + err = errors.Join(err, errors.New(sb.String())) + continue FileLoop + } + stmtGen, nErr := ParseTokens(tokens) + if nErr != nil { + err = errors.Join(err, nErr) + continue FileLoop + } + sb := strings.Builder{} + sb.WriteString(fmt.Sprintf(TestHeader, time.Now().Year(), strings.ReplaceAll(strings.Title(strings.ToLower(prefix)), " ", ""))) + + result, nErr := GetQueryResult(stmtGen.String()) + if nErr != nil { + err = errors.Join(err, nErr) + continue FileLoop + } + sb.WriteString(result) + for stmtGen.Consume() { + result, nErr = GetQueryResult(stmtGen.String()) + if nErr != nil { + err = errors.Join(err, nErr) + continue FileLoop + } + sb.WriteString(result) + } + + sb.WriteString(TestFooter) + outputFileName := strings.ToLower(strings.ReplaceAll(prefix, " ", "_")) + if nErr = os.WriteFile(fmt.Sprintf("%s/output/%s_test.go", parentFolder, outputFileName), []byte(sb.String()), 0644); nErr != nil { + err = errors.Join(err, nErr) + continue FileLoop + } + } + return err +} + +// ParseTokens parses the given tokens into a StatementGenerator. +func ParseTokens(tokens []Token) (StatementGenerator, error) { + stack := NewStatementGeneratorStack() + var statements []StatementGenerator + tokenReader := NewTokenReader(tokens) +ForLoop: + for { + token, ok := tokenReader.Next() + if !ok { + break ForLoop + } + switch token.Type { + case TokenType_Text: + stack.AddText(token.Literal) + case TokenType_Variable: + stack.AddVariable(token.Literal) + case TokenType_VariableDefinition: + //TODO: implement variable definitions + break ForLoop + case TokenType_Or: + if err := stack.Or(); err != nil { + return nil, err + } + case TokenType_Repeat: + if err := stack.Repeat(false); err != nil { + return nil, err + } + case TokenType_CommaRepeat: + if err := stack.Repeat(true); err != nil { + return nil, err + } + case TokenType_OptionalRepeat: + if err := stack.OptionalRepeat(false); err != nil { + return nil, err + } + case TokenType_OptionalCommaRepeat: + if err := stack.OptionalRepeat(true); err != nil { + return nil, err + } + case TokenType_ShortSpace, TokenType_MediumSpace: + return nil, fmt.Errorf("token reader should have removed all short and medium spaces") + case TokenType_LongSpace, TokenType_EOF: + newStatement, err := stack.Finish() + if err != nil { + return nil, err + } + if newStatement == nil { + return nil, fmt.Errorf("long space encountered before writing to the stack") + } + statements = append(statements, newStatement) + if token.Type == TokenType_EOF { + break ForLoop + } else { + stack = NewStatementGeneratorStack() + } + case TokenType_ParenOpen: + stack.NewParenScope() + case TokenType_ParenClose: + if err := stack.ExitParenScope(); err != nil { + return nil, err + } + case TokenType_OptionalOpen: + stack.NewOptionalScope() + case TokenType_OptionalClose: + if err := stack.ExitOptionalScope(); err != nil { + return nil, err + } + case TokenType_OneOfOpen: + stack.NewScope() + case TokenType_OneOfClose: + if err := stack.ExitScope(); err != nil { + return nil, err + } + default: + panic("unhandled token type") + } + } + finalStackContents, err := stack.Finish() + if err != nil { + return nil, err + } + if finalStackContents != nil { + return nil, fmt.Errorf("encountered an early EOF, as the stack was still processing") + } + if len(statements) == 0 { + return nil, fmt.Errorf("no statements were generated from the token stream") + } else if len(statements) == 1 { + return statements[0], nil + } else { + return Or(statements...), nil + } +} + +// GetQueryResult runs the query against a Postgres server to validate that the query is syntactically valid. It then +// tests the query against the Postgres parser and Postgres-Vitess AST converter to check the current level of support. +// It returns a string that may be inserted directly into a test source file (two tabs are prefixed). +func GetQueryResult(query string) (string, error) { + //TODO: verify the query against a Postgres server + formattedQuery := strings.ReplaceAll(query, `"`, `\"`) + statements, err := parser.Parse(query) + if err != nil || len(statements) == 0 { + return fmt.Sprintf("\t\tUnimplemented(\"%s\"),\n", formattedQuery), nil + } + for _, statement := range statements { + vitessAST, err := ast.Convert(statement) + if err != nil || vitessAST == nil { + return fmt.Sprintf("\t\tParses(\"%s\"),\n", formattedQuery), nil + } + } + return fmt.Sprintf("\t\tConverts(\"%s\"),\n", formattedQuery), nil +} + +// SectionMarker returns a marker that may be used to denote sections. +// +// For example, SectionMarker("abc", '-', 21) would return: +// +// -------- abc -------- +func SectionMarker(centeredText string, fillerCharacter rune, totalLength int) string { + fillerStr := string(fillerCharacter) + remainingLength := totalLength - (len(centeredText) + 2) + if remainingLength <= 0 { + return fmt.Sprintf(" %s ", centeredText) + } + left := remainingLength / 2 + right := remainingLength - left // Integer division doesn't do fractions, so this will handle odd counts + return fmt.Sprintf("%s %s %s", + strings.Repeat(fillerStr, left), centeredText, strings.Repeat(fillerStr, right)) +} diff --git a/testing/generation/command_docs/download.go b/testing/generation/command_docs/download.go new file mode 100644 index 0000000000..0ccc6938f7 --- /dev/null +++ b/testing/generation/command_docs/download.go @@ -0,0 +1,108 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/PuerkitoBio/goquery" + "golang.org/x/net/html" +) + +const ( + postgresBaseLink = `https://www.postgresql.org/docs/15/` + commandPageLink = `sql-commands.html` +) + +type Link struct { + CommandName string + Link string +} + +// DownloadAllSynopses downloads and writes all synopses from the internet. It is assumed that this will be run from +// within an IDE, and will download to the `commands_docs/synopses` folder. Uses `postgresBaseLink` to determine which +// version of the command page will be downloaded, and `commandPageLink` specifies the exact page that the commands are +// contained on. This function is only necessary if we're upgrading the Postgres version. +func DownloadAllSynopses() { + commandDocument, err := FetchDocument(postgresBaseLink + commandPageLink) + if err != nil { + panic(err) + } + var allLinks []Link + _ = commandDocument.Find(".toc a").Each(func(i int, e *goquery.Selection) { + href, exists := e.Attr("href") + if exists { + allLinks = append(allLinks, Link{ + CommandName: e.Text(), + Link: postgresBaseLink + strings.Trim(href, `\/`), + }) + } + }) + for _, link := range allLinks { + linkDocument, err := FetchDocument(link.Link) + if err != nil { + panic(err) + } + synopsis := linkDocument.Find(".synopsis").First() + if strings.Contains(synopsis.Text(), "$") { + panic(fmt.Errorf("Synopsis has a $, which is unexpected:\n\n%s\n\n%s", link, synopsis.Text())) + } + synopsis.Find(".replaceable").Each(func(i int, e *goquery.Selection) { + e.SetText(fmt.Sprintf("$%s$", e.Text())) + }) + func() { + fileLocation, err := GetCommandDocsFolder() + if err != nil { + fmt.Println(err.Error()) + return + } + fileName := strings.ToLower(strings.ReplaceAll(link.CommandName, " ", "_")) + data := []byte(synopsis.Text()) + if err = os.WriteFile(fmt.Sprintf("%s/synopses/%s.txt", fileLocation, fileName), data, 0644); err != nil { + fmt.Println(err.Error()) + } + fmt.Printf("Downloaded: %s\n", link.Link) + }() + } +} + +// FetchDocument fetches the document from the given link. The link should be a full HTTP/HTTPS URL. +func FetchDocument(link string) (*goquery.Document, error) { + res, err := http.Get(link) + if err != nil { + return nil, err + } + defer res.Body.Close() + node, err := html.Parse(res.Body) + if err != nil { + return nil, err + } + return goquery.NewDocumentFromNode(node), nil +} + +// GetCommandDocsFolder returns the location of this particular Go file: download.go. This is useful to locate relative +// directories, such as the synopses folder. It is assumed that this will always be called from within an IDE. +func GetCommandDocsFolder() (string, error) { + _, currentFileLocation, _, ok := runtime.Caller(0) + if !ok { + return "", fmt.Errorf("failed to fetch the location of the current file") + } + return filepath.ToSlash(filepath.Dir(currentFileLocation)), nil +} diff --git a/testing/generation/command_docs/generator_stack.go b/testing/generation/command_docs/generator_stack.go new file mode 100644 index 0000000000..38903955ac --- /dev/null +++ b/testing/generation/command_docs/generator_stack.go @@ -0,0 +1,307 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + + "github.com/dolthub/doltgresql/utils" +) + +// StatementGeneratorStackElement represents an element within the StatementGeneratorStack. +type StatementGeneratorStackElement struct { + depth int + generators []StatementGenerator +} + +// StatementGeneratorStack handles the creation of a StatementGenerator by contextually applying operations based on the +// current state of the internal stack whenever calls are made. +type StatementGeneratorStack struct { + stack *utils.Stack[*StatementGeneratorStackElement] + depth int +} + +// NewStatementGeneratorStack returns a new *StatementGeneratorStack. +func NewStatementGeneratorStack() *StatementGeneratorStack { + sgs := &StatementGeneratorStack{ + stack: utils.NewStack[*StatementGeneratorStackElement](), + depth: 0, + } + sgs.stack.Push(NewStatementGeneratorStackElement(0)) + return sgs +} + +// NewStatementGeneratorStackElement returns a new *StatementGeneratorStackElement. +func NewStatementGeneratorStackElement(depth int, gens ...StatementGenerator) *StatementGeneratorStackElement { + return &StatementGeneratorStackElement{ + depth: depth, + generators: gens, + } +} + +// AddText creates a new TextGen at the current depth. +func (sgs *StatementGeneratorStack) AddText(text string) { + sgs.stack.Peek().Append(Text(text)) +} + +// AddVariable creates a new VariableGen at the current depth. +func (sgs *StatementGeneratorStack) AddVariable(name string) { + sgs.stack.Peek().Append(Variable(name)) +} + +// Or will take all items from the current depth and add them to a parent OrGen. Either the previous depth is an OrGen, +// or the stack will increment the sub depth to insert an OrGen. +func (sgs *StatementGeneratorStack) Or() error { + if sgs.stack.Empty() { + return fmt.Errorf("cannot apply Or to an empty stack") + } + parentElement := sgs.stack.PeekDepth(1) + current := sgs.aggregate(sgs.stack.Pop().generators) + if parentElement == nil { + // We're the root, so we put an OrGen as the root, and make the current a child of the new OrGen + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth, Or(current))) + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth)) + } else if len(parentElement.generators) == 0 { + if parentElement.depth == sgs.depth { + // We're still at the same depth, so it's safe to append an OrGen + parentElement.Append(Or(current)) + } else { + // We should retain the depth, so we need to create a new element since there's a depth boundary + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth, Or(current))) + } + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth)) + } else { + if parentElement.depth == sgs.depth { + // We're still at the same depth, so we need to check if the parent is an OrGen or not + if orGen, ok := parentElement.LastGenerator().(*OrGen); ok { + // The parent is an OrGen, so we can simply add this as another option + if err := orGen.AddChildren(current); err != nil { + return err + } + } else { + // The parent is not an OrGen, so we need to add to the depth + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth, Or(current))) + } + } else { + // We should retain the depth, so we need to create a new element since there's a depth boundary + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth, Or(current))) + } + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth)) + } + return nil +} + +// NewScope increases the depth. +func (sgs *StatementGeneratorStack) NewScope() { + sgs.depth++ + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth)) +} + +// NewOptionalScope increases the depth, creating an OptionalGen at the depth root, and adding elements to the sub depth. +func (sgs *StatementGeneratorStack) NewOptionalScope() { + sgs.depth++ + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth, Optional())) + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth)) +} + +// NewParenScope increases the depth, creating a CollectionGen at the depth root, adding Text("(") to the CollectionGen, +// and adding any new elements to the sub depth. +func (sgs *StatementGeneratorStack) NewParenScope() { + sgs.depth++ + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth, Collection(Text("(")))) + sgs.stack.Push(NewStatementGeneratorStackElement(sgs.depth)) +} + +// ExitScope decrements the depth, writing all elements from the current depth (and all sub depths) to the preceding +// depth. +func (sgs *StatementGeneratorStack) ExitScope() error { + defer func() { + sgs.depth-- + }() + current := sgs.aggregate(sgs.stack.Pop().generators) + for parentElement := sgs.stack.Peek(); parentElement.depth == sgs.depth; parentElement = sgs.stack.Peek() { + if orGen, ok := parentElement.LastGenerator().(*OrGen); ok { + if err := orGen.AddChildren(current); err != nil { + return err + } + } else { + parentElement.Append(current) + } + current = sgs.aggregate(sgs.stack.Pop().generators) + } + sgs.stack.Peek().Append(current) + return nil +} + +// ExitOptionalScope decrements the depth, writing all elements from the current depth (and all sub depths) to the +// preceding depth. This will fail if the root of the current depth is not an OptionalGen. +func (sgs *StatementGeneratorStack) ExitOptionalScope() error { + defer func() { + sgs.depth-- + }() + current := sgs.aggregate(sgs.stack.Pop().generators) + for parentElement := sgs.stack.Peek(); sgs.stack.PeekDepth(1).depth == sgs.depth; parentElement = sgs.stack.Peek() { + if orGen, ok := parentElement.LastGenerator().(*OrGen); ok { + if err := orGen.AddChildren(current); err != nil { + return err + } + } else { + parentElement.Append(current) + } + current = sgs.aggregate(sgs.stack.Pop().generators) + } + optionalElement := sgs.stack.Pop() + if optionalElement.depth != sgs.depth { + return fmt.Errorf("internal bookkeeping error, attempted to exit from optional scope but the depth is incorrect") + } + if optionalGen, ok := optionalElement.LastGenerator().(*OptionalGen); ok { + if err := optionalGen.AddChildren(current); err != nil { + return err + } + } else { + return fmt.Errorf("internal bookkeeping error, attempted to exit from optional scope but missing OptionalGen") + } + sgs.stack.Peek().Append(sgs.aggregate(optionalElement.generators)) + return nil +} + +// ExitParenScope decrements the depth, writing all elements from the current depth (and all sub depths) to the +// preceding depth, while appending an ending Text(")"). +func (sgs *StatementGeneratorStack) ExitParenScope() error { + defer func() { + sgs.depth-- + }() + current := sgs.aggregate(sgs.stack.Pop().generators) + for parentElement := sgs.stack.Peek(); sgs.stack.PeekDepth(1).depth == sgs.depth; parentElement = sgs.stack.Peek() { + if orGen, ok := parentElement.LastGenerator().(*OrGen); ok { + if err := orGen.AddChildren(current); err != nil { + return err + } + } else { + parentElement.Append(current) + } + current = sgs.aggregate(sgs.stack.Pop().generators) + } + collectionElement := sgs.stack.Pop() + if collectionElement.depth != sgs.depth { + return fmt.Errorf("internal bookkeeping error, attempted to exit from paren scope but the depth is incorrect") + } + if collectionGen, ok := collectionElement.LastGenerator().(*CollectionGen); ok { + if err := collectionGen.AddChildren(current, Text(")")); err != nil { + return err + } + } else { + return fmt.Errorf("internal bookkeeping error, attempted to exit from paren scope but missing CollectionGen") + } + sgs.stack.Peek().Append(sgs.aggregate(collectionElement.generators)) + return nil +} + +// Repeat will add the last StatementGenerator at the current depth to a RepeatGen. By default, the limit is 2, however +// an optional parameter may be passed to specify a custom limit (only the first limit given is used). +func (sgs *StatementGeneratorStack) Repeat(includesComma bool, limit ...int) error { + current := sgs.stack.Peek() + lastGen := current.LastGenerator() + if lastGen == nil { + return fmt.Errorf("unable to repeat as no generators exist at the current depth") + } + actualLimit := 2 + if len(limit) >= 1 { + actualLimit = limit[0] + } + if includesComma { + current.Append(Repeat(0, actualLimit, Collection(Text(","), lastGen.Copy()))) + } else { + current.Append(Repeat(0, actualLimit, lastGen.Copy())) + } + return nil +} + +// OptionalRepeat will add the last StatementGenerator at the current depth to a RepeatGen inside an OptionalGen. By +// default, the limit is 2, however an optional parameter may be passed to specify a custom limit (only the first limit +// given is used). +func (sgs *StatementGeneratorStack) OptionalRepeat(includesComma bool, limit ...int) error { + current := sgs.stack.Peek() + lastGen := current.LastGenerator() + if lastGen == nil { + return fmt.Errorf("unable to optionally repeat as no generators exist at the current depth") + } + actualLimit := 2 + if len(limit) >= 1 { + actualLimit = limit[0] + } + if includesComma { + current.Append(Optional(Repeat(1, actualLimit, Collection(Text(","), lastGen.Copy())))) + } else { + current.Append(Optional(Repeat(1, actualLimit, lastGen.Copy()))) + } + return nil +} + +// Finish returns a StatementGenerator containing all of the generators that have been added. This returns an error if +// the stack is not at the root depth, as that indicates a missing scope exit, or too many scope entries. +func (sgs *StatementGeneratorStack) Finish() (StatementGenerator, error) { + if sgs.depth != 0 { + if sgs.depth < 0 { + return nil, fmt.Errorf("depth is invalid, too many scope exits") + } else { + return nil, fmt.Errorf("depth is invalid, too many scope entries") + } + } else if !sgs.stack.Empty() && sgs.stack.Peek().depth != 0 { + return nil, fmt.Errorf("internal bookkeeping error, stack depth does not match handle depth") + } + if sgs.stack.Len() == 1 && len(sgs.stack.Peek().generators) == 0 { + return nil, nil + } + var lastDepth []StatementGenerator + for !sgs.stack.Empty() { + currentDepth := sgs.stack.Pop() + if len(currentDepth.generators) == 0 { + return nil, fmt.Errorf("internal bookkeeping error, stack has a depth with no generators") + } + if len(lastDepth) == 1 { + currentDepth.generators = append(currentDepth.generators, lastDepth[0]) + } else if len(lastDepth) > 1 { + currentDepth.generators = append(currentDepth.generators, Collection(lastDepth...)) + } + lastDepth = currentDepth.generators + } + return sgs.aggregate(lastDepth), nil +} + +// aggregate returns an aggregate of the given generators. Returns nil if the slice is empty. +func (sgs *StatementGeneratorStack) aggregate(gens []StatementGenerator) StatementGenerator { + gens = removeNilGenerators(gens) + if len(gens) == 0 { + return nil + } else if len(gens) == 1 { + return gens[0] + } else { + return Collection(gens...) + } +} + +// LastGenerator returns the last StatementGenerator contained within its slice. +func (sgse *StatementGeneratorStackElement) LastGenerator() StatementGenerator { + if sgse == nil || len(sgse.generators) == 0 { + return nil + } + return sgse.generators[len(sgse.generators)-1] +} + +// Append adds the given child to this element's collection. +func (sgse *StatementGeneratorStackElement) Append(child StatementGenerator) { + sgse.generators = append(sgse.generators, child) +} diff --git a/testing/generation/command_docs/main.go b/testing/generation/command_docs/main.go new file mode 100644 index 0000000000..3048929fbe --- /dev/null +++ b/testing/generation/command_docs/main.go @@ -0,0 +1,27 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" +) + +func main() { + //DownloadAllSynopses() + err := GenerateTestsFromSynopses() + if err != nil { + fmt.Println(err.Error()) + } +} diff --git a/testing/generation/command_docs/output/abort_test.go b/testing/generation/command_docs/output/abort_test.go new file mode 100644 index 0000000000..485443aef6 --- /dev/null +++ b/testing/generation/command_docs/output/abort_test.go @@ -0,0 +1,32 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package output + +import "testing" + +func TestAbort(t *testing.T) { + tests := []QueryParses{ + Converts("ABORT"), + Converts("ABORT WORK"), + Converts("ABORT TRANSACTION"), + Unimplemented("ABORT AND CHAIN"), + Unimplemented("ABORT WORK AND CHAIN"), + Unimplemented("ABORT TRANSACTION AND CHAIN"), + Unimplemented("ABORT AND NO CHAIN"), + Unimplemented("ABORT WORK AND NO CHAIN"), + Unimplemented("ABORT TRANSACTION AND NO CHAIN"), + } + RunTests(t, tests) +} diff --git a/testing/generation/command_docs/output/framework_test.go b/testing/generation/command_docs/output/framework_test.go new file mode 100644 index 0000000000..64fd7b21c2 --- /dev/null +++ b/testing/generation/command_docs/output/framework_test.go @@ -0,0 +1,119 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package output + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/dolthub/doltgresql/postgres/parser/parser" + "github.com/dolthub/doltgresql/server/ast" +) + +// QueryParses determines whether a query parses, and then whether it has an AST conversion. +type QueryParses interface { + // ShouldParse returns whether the query successfully creates a Postgres AST. + ShouldParse() bool + // ShouldConvert returns whether the query successfully converts from a Postgres AST to a Vitess AST. + ShouldConvert() bool + // String returns the query to test. + String() string +} + +// Unimplemented is used when a query has not yet been implemented in the parser. +type Unimplemented string + +var _ QueryParses = Unimplemented("") + +// ShouldParse implements the interface QueryParses. +func (Unimplemented) ShouldParse() bool { + return false +} + +// ShouldConvert implements the interface QueryParses. +func (Unimplemented) ShouldConvert() bool { + return false +} + +// String implements the interface QueryParses. +func (u Unimplemented) String() string { + return string(u) +} + +// Parses is used when a query parses into a Postgres AST, but cannot yet convert to a Vitess AST. +type Parses string + +var _ QueryParses = Parses("") + +// ShouldParse implements the interface QueryParses. +func (Parses) ShouldParse() bool { + return true +} + +// ShouldConvert implements the interface QueryParses. +func (Parses) ShouldConvert() bool { + return false +} + +// String implements the interface QueryParses. +func (p Parses) String() string { + return string(p) +} + +// Converts is used when a query parses into a Postgres AST and converts to a Vitess AST. +type Converts string + +var _ QueryParses = Converts("") + +// ShouldParse implements the interface QueryParses. +func (Converts) ShouldParse() bool { + return true +} + +// ShouldConvert implements the interface QueryParses. +func (Converts) ShouldConvert() bool { + return true +} + +// String implements the interface QueryParses. +func (c Converts) String() string { + return string(c) +} + +// RunTests runs the given collection of QueryParses tests. +func RunTests(t *testing.T, tests []QueryParses) { + for _, test := range tests { + t.Run(test.String(), func(t *testing.T) { + statements, err := parser.Parse(test.String()) + if !test.ShouldParse() { + assert.Error(t, err, "Query now parses, please upgrade the type to `Parses`") + return + } + require.NoError(t, err, "Regression, query previously parsed") + require.Truef(t, len(statements) > 0, "Regression, query previously produced a Postgres AST") + for _, statement := range statements { + vitessAST, err := ast.Convert(statement) + if !test.ShouldConvert() { + assert.Error(t, err, "Query now converts, please upgrade the type to `Converts`") + return + } + assert.NoError(t, err, "Regression, query previously converted from a Postgres AST to a Vitess AST") + assert.NotNil(t, vitessAST, "Regression, query now returns a nil Vitess AST") + } + }) + } +} diff --git a/testing/generation/command_docs/scanner.go b/testing/generation/command_docs/scanner.go new file mode 100644 index 0000000000..661fb986c0 --- /dev/null +++ b/testing/generation/command_docs/scanner.go @@ -0,0 +1,347 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "strings" +) + +// Scanner allows for scanning through the synopsis to generate tokens. +type Scanner struct { + source []rune + tokens []Token + sourceIdx int + isFinished bool + savedErr error +} + +// NewScanner returns a new *Scanner by reading through the synopsis. +func NewScanner(synopsis string) *Scanner { + scanner := &Scanner{ + source: []rune(strings.ReplaceAll(synopsis, "\r", "")), + tokens: nil, + sourceIdx: -1, + isFinished: false, + savedErr: nil, + } + _, _ = scanner.Process() + return scanner +} + +// Next returns the next rune while advancing the scanner. Returns false if there are no more runes. +func (scanner *Scanner) Next() (rune, bool) { + if scanner.sourceIdx+1 >= len(scanner.source) { + return 0, false + } + scanner.sourceIdx++ + return scanner.source[scanner.sourceIdx], true +} + +// Peek returns the next rune. Does not advance the scanner. Returns false if there are no more runes. +func (scanner *Scanner) Peek() (rune, bool) { + if scanner.sourceIdx+1 >= len(scanner.source) { + return 0, false + } + return scanner.source[scanner.sourceIdx+1], true +} + +// PeekBy returns the next rune that is n positions from the current rune. Does not advance the scanner. Returns false +// if we are peeking beyond the source. +func (scanner *Scanner) PeekBy(n int) (rune, bool) { + if scanner.sourceIdx+n >= len(scanner.source) || scanner.sourceIdx+n < 0 { + return 0, false + } + return scanner.source[scanner.sourceIdx+n], true +} + +// PeekMatch returns whether the given string exactly matches runes starting after the current position. This is +// equivalent to calling PeekMatchOffset with an offset of 1. +func (scanner *Scanner) PeekMatch(str string) bool { + return scanner.PeekMatchOffset(str, 1) +} + +// PeekMatchOffset returns whether the given string exactly matches runes starting from the offset applied to the +// current position. An offset of 0 means that we are including the rune at the current position. +func (scanner *Scanner) PeekMatchOffset(str string, offset int) bool { + for i, r := range []rune(str) { + sr, ok := scanner.PeekBy(i + offset) + if !ok || sr != r { + return false + } + } + return true +} + +// Advance is equivalent to calling AdvanceBy(1). +func (scanner *Scanner) Advance() { + scanner.AdvanceBy(1) +} + +// AdvanceBy advances the scanner by the given amount. If the amount is greater than the number of remaining runes, then +// it advances to the end. Cannot advance backwards. +func (scanner *Scanner) AdvanceBy(n int) { + if n < 0 { + n = 0 + } + if scanner.sourceIdx+n >= len(scanner.source) { + n = len(scanner.source) - scanner.sourceIdx - 1 + } + scanner.sourceIdx += n +} + +// Process processes the synopsis and returns the generated tokens. +func (scanner *Scanner) Process() ([]Token, error) { + if scanner.isFinished || scanner.savedErr != nil { + return scanner.tokens, scanner.savedErr + } +ScannerLoop: + for { + r, ok := scanner.Next() + if !ok { + break ScannerLoop + } + switch r { + case '$': + var name []rune + for r, ok = scanner.Peek(); ok && r != '$'; r, ok = scanner.Peek() { + scanner.Advance() + name = append(name, r) + } + if !ok { + scanner.savedErr = fmt.Errorf("unexpected EOF when reading variable name") + break ScannerLoop + } + scanner.Advance() + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_Variable, + Literal: string(name), + }) + case '\t': + scanner.savedErr = fmt.Errorf("tab found, remove all tabs from the synopsis") + break ScannerLoop + case ' ', '\n': + spaceCount := 0 + lineCount := 0 + if r == ' ' { + spaceCount += 1 + } + if r == '\n' { + lineCount++ + } + WhitespaceLoop: + for r, ok = scanner.Peek(); ok; r, ok = scanner.Peek() { + switch r { + case ' ': + scanner.Advance() + spaceCount += 1 + case '\n': + scanner.Advance() + lineCount++ + default: + break WhitespaceLoop + } + } + // EOF, no need to add the last bit of whitespace + if !ok { + break ScannerLoop + } + if spaceCount == 1 && lineCount == 0 { + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_ShortSpace}) + } else if spaceCount > 1 && lineCount <= 1 { + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_MediumSpace}) + } else { + // This will match the case where spaceCount == 0 and lineCount == 1. + // This may seem counter-intuitive, however it's consistent with how new statements are defined. + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_LongSpace}) + } + case '.': + dotCount := 1 + // All dot repetition blocks look like `...` + DotRepetitionLoop: + for n := 1; true; n++ { + peek, _ := scanner.PeekBy(n) + switch peek { + case '.': + dotCount++ + default: + scanner.AdvanceBy(n - 1) + // If the dot count is different from 3, then we'll treat it as a string + if dotCount == 3 { + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_Repeat}) + } else { + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_Text, + Literal: strings.Repeat(".", dotCount), + }) + } + break DotRepetitionLoop + } + } + case ',': + // All comma-dot repetition blocks look like `, ...` + if peek, _ := scanner.Peek(); peek != ' ' { + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_Text, + Literal: ",", + }) + continue ScannerLoop + } + dotCount := 0 + CommaDotRepetitionLoop: + for n := 2; true; n++ { + peek, _ := scanner.PeekBy(n) + switch peek { + case '.': + dotCount++ + default: + // If the dot count is different from 3, then we treat the comma as text + if dotCount == 3 { + scanner.AdvanceBy(n - 1) + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_CommaRepeat}) + } else { + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_Text, + Literal: ",", + }) + } + break CommaDotRepetitionLoop + } + } + + case '[': + commaCount := 0 + dotCount := 0 + // Optional repetition blocks generally look like either [...] or [ , ... ] + RepetitionLoop: + for n := 1; true; n++ { + peek, ok := scanner.PeekBy(n) + if !ok { + scanner.savedErr = fmt.Errorf("unexpected EOF when looking for potential repetition") + break ScannerLoop + } + switch peek { + case ' ': + // We ignore spaces here, as no optional repetition blocks have other forms of whitespace. + case '.': + dotCount++ + case ',': + commaCount++ + case ']': + // If the dot count is different from 3, then we'll ignore it + if dotCount == 3 { + // If the comma count is greater than 1, then we'll ignore it + if commaCount == 0 { + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OptionalRepeat}) + } else if commaCount == 1 { + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OptionalCommaRepeat}) + } + scanner.AdvanceBy(n) + break RepetitionLoop + } + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OptionalOpen}) + break RepetitionLoop + default: + // We've encountered something not present in normal repetition blocks + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OptionalOpen}) + break RepetitionLoop + } + } + case ']': + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OptionalClose}) + case '{': + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OneOfOpen}) + case '}': + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_OneOfClose}) + case '(': + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_ParenOpen}) + case ')': + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_ParenClose}) + case '|': + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_Or}) + default: + if scanner.PeekMatchOffset("where $", 0) { + // Skip past what we peeked at + scanner.AdvanceBy(6) + var varName []rune + VariableDescriptionLoop: + for r, ok = scanner.Peek(); ok; r, ok = scanner.Peek() { + switch r { + case '$': + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_VariableDefinition, + Literal: string(varName), + }) + if !scanner.PeekMatch("$ is:") { + scanner.savedErr = fmt.Errorf("invalid variable definition format") + break ScannerLoop + } + // Skip past what we peeked at + scanner.AdvanceBy(5) + break VariableDescriptionLoop + default: + scanner.Advance() + varName = append(varName, r) + } + } + } else { + text := []rune{r} + TextLoop: + for r, ok = scanner.Peek(); ok; r, ok = scanner.Peek() { + switch r { + case '$', ' ', '\t', '\n', '.', ',', '[', ']', '{', '}', '(', ')', '|': + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_Text, + Literal: string(text), + }) + break TextLoop + default: + scanner.Advance() + text = append(text, r) + } + } + // If we hit EOF, then we haven't added the word yet, so we'll do it here + if !ok { + scanner.tokens = append(scanner.tokens, Token{ + Type: TokenType_Text, + Literal: string(text), + }) + } + } + } + } + // Remove any ending spaces + if len(scanner.tokens) > 0 && scanner.tokens[len(scanner.tokens)-1].IsSpace() { + scanner.tokens = scanner.tokens[:len(scanner.tokens)-1] + } + // Add an EOF + scanner.tokens = append(scanner.tokens, Token{Type: TokenType_EOF}) + // Set that we're finished now (we'll also finish on errors) + scanner.isFinished = true + return scanner.tokens, scanner.savedErr +} + +// String returns the processed contents of the scanner as a string. This means that it will not be the original string, +// as the processed string may differ in format. +func (scanner *Scanner) String() string { + sb := strings.Builder{} + for _, token := range scanner.tokens { + str := token.String() + if len(str) > 0 { + sb.WriteString(str) + } + } + return sb.String() +} diff --git a/testing/generation/command_docs/statement_generator.go b/testing/generation/command_docs/statement_generator.go new file mode 100644 index 0000000000..28abc06c49 --- /dev/null +++ b/testing/generation/command_docs/statement_generator.go @@ -0,0 +1,477 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "errors" + "fmt" + "strings" +) + +// StatementGenerator represents a statement, and is able to produce all valid variations of the statement. +type StatementGenerator interface { + // AddChildren adds the given children to the generator. Not all generators accept all children, so this may error. + AddChildren(child ...StatementGenerator) error + // Consume returns true when the generator is able to produce a unique mutation, and false if it is not. Only one + // generator should mutate per call, meaning a parent generator should only mutate when its children return false. + // If the top-level generator returns false, then all permutations have been created. + Consume() bool + // String returns a string based on the current permutation. + String() string + // Copy returns a copy of the given generator (along with all of its children) in its original setting. This means + // that the copy is in the same state that the target would be in if it had never called Consume. + Copy() StatementGenerator + // Reset sets the StatementGenerator back to its original state, which would be as though Consume was never called. + Reset() + // SourceString returns a string that may be used to recreate the StatementGenerator in a Go source file. + SourceString() string +} + +// TextGen is a generator that returns a simple string. +type TextGen string + +var _ StatementGenerator = (*TextGen)(nil) + +// Text creates a new StatementGenerator representing a simple string. +func Text(str string) *TextGen { + gen := TextGen(str) + return &gen +} + +// AddChildren implements the interface StatementGenerator. +func (t *TextGen) AddChildren(children ...StatementGenerator) error { + return fmt.Errorf("text cannot have children") +} + +// Consume implements the interface StatementGenerator. +func (t *TextGen) Consume() bool { + return false +} + +// Copy implements the interface StatementGenerator. +func (t *TextGen) Copy() StatementGenerator { + if t == nil { + return nil + } + return Text(string(*t)) +} + +// String implements the interface StatementGenerator. +func (t *TextGen) String() string { + return string(*t) +} + +// Reset implements the interface StatementGenerator. +func (t *TextGen) Reset() {} + +// SourceString implements the interface StatementGenerator. +func (t *TextGen) SourceString() string { + return fmt.Sprintf(`Text("%s")`, string(*t)) +} + +// OrGen is a generator that contains multiple child generators, and will print only one at a time. Consuming will +// cycle to the next child. +type OrGen struct { + children []StatementGenerator + index int +} + +var _ StatementGenerator = (*OrGen)(nil) + +// Or creates a new StatementGenerator representing an OrGen. +func Or(children ...StatementGenerator) *OrGen { + return &OrGen{ + children: copyGenerators(children), + index: 0, + } +} + +// AddChildren implements the interface StatementGenerator. +func (o *OrGen) AddChildren(children ...StatementGenerator) error { + o.children = append(o.children, removeNilGenerators(children)...) + return nil +} + +// Consume implements the interface StatementGenerator. +func (o *OrGen) Consume() bool { + if len(o.children) == 0 { + return false + } + if o.children[o.index].Consume() { + return true + } + o.index++ + if o.index >= len(o.children) { + o.index = 0 + return false + } + return true +} + +// Copy implements the interface StatementGenerator. +func (o *OrGen) Copy() StatementGenerator { + if o == nil { + return nil + } + return Or(o.children...) +} + +// String implements the interface StatementGenerator. +func (o *OrGen) String() string { + return o.children[o.index].String() +} + +// Reset implements the interface StatementGenerator. +func (o *OrGen) Reset() { + o.index = 0 + for _, child := range o.children { + child.Reset() + } +} + +// SourceString implements the interface StatementGenerator. +func (o *OrGen) SourceString() string { + return fmt.Sprintf(`Or(%s)`, sourceGenerators(o.children)) +} + +// VariableGen represents a variable in the synopsis. Its values are user-configurable if they cannot be deduced from +// the synopsis. +type VariableGen struct { + name string + options *OrGen +} + +var _ StatementGenerator = (*VariableGen)(nil) + +// Variable creates a new StatementGenerator representing a VariableGen. +func Variable(name string, children ...StatementGenerator) *VariableGen { + return &VariableGen{ + name: name, + options: Or(children...), + } +} + +// AddChildren implements the interface StatementGenerator. +func (v *VariableGen) AddChildren(children ...StatementGenerator) error { + children = removeNilGenerators(children) + if len(children) == 0 { + return nil + } + if len(children) > 1 { + return fmt.Errorf("attempting to give variable `%s` too many children", v.name) + } + if v.options != nil { + return fmt.Errorf("variable `%s` has already been assigned", v.name) + } + orChild, ok := children[0].(*OrGen) + if !ok { + return fmt.Errorf("variable `%s` was given an invalid child type `%T`", v.name, children[0]) + } + v.options = orChild + return nil +} + +// Consume implements the interface StatementGenerator. +func (v *VariableGen) Consume() bool { + if v.options != nil { + return v.options.Consume() + } + return false +} + +// Copy implements the interface StatementGenerator. +func (v *VariableGen) Copy() StatementGenerator { + if v == nil { + return nil + } + return Variable(v.name, v.options.children...) +} + +// String implements the interface StatementGenerator. +func (v *VariableGen) String() string { + if len(v.options.children) > 0 { + return v.options.String() + } else { + return v.name + } +} + +// Reset implements the interface StatementGenerator. +func (v *VariableGen) Reset() { + v.options.Reset() +} + +// SourceString implements the interface StatementGenerator. +func (v *VariableGen) SourceString() string { + if len(v.options.children) > 0 { + return fmt.Sprintf(`Variable("%s", %s)`, v.name, sourceGenerators(v.options.children)) + } else { + return fmt.Sprintf(`Variable("%s")`, v.name) + } +} + +// CollectionGen is a generator that contains multiple child generators, and will print all of its children. +type CollectionGen struct { + children []StatementGenerator +} + +var _ StatementGenerator = (*CollectionGen)(nil) + +// Collection creates a new StatementGenerator representing a CollectionGen. +func Collection(children ...StatementGenerator) *CollectionGen { + return &CollectionGen{ + children: copyGenerators(children), + } +} + +// AddChildren implements the interface StatementGenerator. +func (c *CollectionGen) AddChildren(children ...StatementGenerator) error { + c.children = append(c.children, removeNilGenerators(children)...) + return nil +} + +// Consume implements the interface StatementGenerator. +func (c *CollectionGen) Consume() bool { + for i := range c.children { + if c.children[i].Consume() { + return true + } + } + return false +} + +// Copy implements the interface StatementGenerator. +func (c *CollectionGen) Copy() StatementGenerator { + if c == nil { + return nil + } + return Collection(c.children...) +} + +// String implements the interface StatementGenerator. +func (c *CollectionGen) String() string { + var childrenStrings []string + for i := range c.children { + childString := c.children[i].String() + if len(childString) > 0 { + childrenStrings = append(childrenStrings, childString) + } + } + return strings.Join(childrenStrings, " ") +} + +// Reset implements the interface StatementGenerator. +func (c *CollectionGen) Reset() { + for _, child := range c.children { + child.Reset() + } +} + +// SourceString implements the interface StatementGenerator. +func (c *CollectionGen) SourceString() string { + return fmt.Sprintf(`Collection(%s)`, sourceGenerators(c.children)) +} + +// RepeatGen is a generator that will repeat its children up to the limit, starting with no repetition. +type RepeatGen struct { + template *CollectionGen + children *CollectionGen + start int + current int + limit int +} + +var _ StatementGenerator = (*RepeatGen)(nil) + +// Repeat creates a new StatementGenerator representing a RepeatGen. The start count must be either zero or one, and is +// bounded to whichever is closest. The limit cannot be less than the start count, and is set to the start count in such +// cases. +func Repeat(startCount int, limit int, children ...StatementGenerator) *RepeatGen { + if startCount < 0 { + startCount = 0 + } else if startCount > 1 { + startCount = 1 + } + if limit < startCount { + limit = startCount + } + repeatGen := &RepeatGen{ + template: Collection(children...), + children: Collection(), + start: startCount, + current: startCount, + limit: limit, + } + if startCount == 1 { + _ = repeatGen.children.AddChildren(children...) + } + return repeatGen +} + +// AddChildren implements the interface StatementGenerator. +func (r *RepeatGen) AddChildren(children ...StatementGenerator) error { + err1 := r.template.AddChildren(children...) + var err2 error + if r.start == 1 { + err2 = r.children.AddChildren(children...) + } + return errors.Join(err1, err2) +} + +// Consume implements the interface StatementGenerator. +func (r *RepeatGen) Consume() bool { + if r.children.Consume() { + return true + } + if r.current < r.limit { + _ = r.children.AddChildren(r.template.Copy()) + r.current++ + return true + } + return false +} + +// Copy implements the interface StatementGenerator. +func (r *RepeatGen) Copy() StatementGenerator { + if r == nil { + return nil + } + return Repeat(r.start, r.limit, r.template.children...) +} + +// String implements the interface StatementGenerator. +func (r *RepeatGen) String() string { + return r.children.String() +} + +// Reset implements the interface StatementGenerator. +func (r *RepeatGen) Reset() { + r.current = r.start + r.children = Collection() + if r.start == 1 { + _ = r.children.AddChildren(r.template.children...) + } +} + +// SourceString implements the interface StatementGenerator. +func (r *RepeatGen) SourceString() string { + if len(r.template.children) > 0 { + return fmt.Sprintf(`Repeat(%d, %s)`, r.limit, sourceGenerators(r.template.children)) + } else { + return fmt.Sprintf(`Repeat(%d)`, r.limit) + } +} + +// OptionalGen is a generator that will toggle between displaying its children and not displaying its children. +type OptionalGen struct { + children *CollectionGen + display bool +} + +var _ StatementGenerator = (*OptionalGen)(nil) + +// Optional creates a new StatementGenerator representing an OptionalGen. +func Optional(children ...StatementGenerator) *OptionalGen { + return &OptionalGen{ + children: Collection(children...), + display: false, + } +} + +// AddChildren implements the interface StatementGenerator. +func (o *OptionalGen) AddChildren(children ...StatementGenerator) error { + return o.children.AddChildren(children...) +} + +// Consume implements the interface StatementGenerator. +func (o *OptionalGen) Consume() bool { + if !o.display { + o.display = true + return true + } else if o.children.Consume() { + return true + } else { + o.display = false + return false + } +} + +// Copy implements the interface StatementGenerator. +func (o *OptionalGen) Copy() StatementGenerator { + if o == nil { + return nil + } + return Optional(o.children.children...) +} + +// String implements the interface StatementGenerator. +func (o *OptionalGen) String() string { + if o.display { + return o.children.String() + } else { + return "" + } +} + +// Reset implements the interface StatementGenerator. +func (o *OptionalGen) Reset() { + o.display = false + o.children.Reset() +} + +// SourceString implements the interface StatementGenerator. +func (o *OptionalGen) SourceString() string { + return fmt.Sprintf(`Optional(%s)`, sourceGenerators(o.children.children)) +} + +// copyGenerators returns a full copy of the given slice of generators. Each generator will be in its original state. +func copyGenerators(gens []StatementGenerator) []StatementGenerator { + gens = removeNilGenerators(gens) + if len(gens) == 0 { + return nil + } + newGens := make([]StatementGenerator, len(gens)) + for i, gen := range gens { + newGens[i] = gen.Copy() + } + return newGens +} + +// sourceGenerators returns a comma-separated SourceString from the given generator slice. +func sourceGenerators(gens []StatementGenerator) string { + gens = removeNilGenerators(gens) + if len(gens) == 0 { + return "" + } + sourceStrs := make([]string, len(gens)) + for i, gen := range gens { + sourceStrs[i] = gen.SourceString() + } + return strings.Join(sourceStrs, ", ") +} + +// removeNilGenerators returns a new slice of generators with all nils removed. +func removeNilGenerators(gens []StatementGenerator) []StatementGenerator { + newGens := make([]StatementGenerator, 0, len(gens)) + for i := range gens { + if gens[i] != nil { + newGens = append(newGens, gens[i]) + } + } + if len(newGens) == 0 { + return nil + } + return newGens +} diff --git a/testing/generation/command_docs/synopses/abort.txt b/testing/generation/command_docs/synopses/abort.txt new file mode 100644 index 0000000000..9221b85538 --- /dev/null +++ b/testing/generation/command_docs/synopses/abort.txt @@ -0,0 +1 @@ +ABORT [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] diff --git a/testing/generation/command_docs/synopses/alter_aggregate.txt b/testing/generation/command_docs/synopses/alter_aggregate.txt new file mode 100644 index 0000000000..307a73d6d3 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_aggregate.txt @@ -0,0 +1,12 @@ +ALTER AGGREGATE $name$ ( $aggregate_signature$ ) RENAME TO $new_name$ + +ALTER AGGREGATE $name$ ( $aggregate_signature$ ) + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER AGGREGATE $name$ ( $aggregate_signature$ ) SET SCHEMA $new_schema$ + +where $aggregate_signature$ is: + +* | + [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] | + [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ORDER BY [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/alter_collation.txt b/testing/generation/command_docs/synopses/alter_collation.txt new file mode 100644 index 0000000000..12de7de8d2 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_collation.txt @@ -0,0 +1,7 @@ +ALTER COLLATION $name$ REFRESH VERSION + +ALTER COLLATION $name$ RENAME TO $new_name$ + +ALTER COLLATION $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER COLLATION $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_conversion.txt b/testing/generation/command_docs/synopses/alter_conversion.txt new file mode 100644 index 0000000000..2604cc9bf6 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_conversion.txt @@ -0,0 +1,5 @@ +ALTER CONVERSION $name$ RENAME TO $new_name$ + +ALTER CONVERSION $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER CONVERSION $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_database.txt b/testing/generation/command_docs/synopses/alter_database.txt new file mode 100644 index 0000000000..1b930d787b --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_database.txt @@ -0,0 +1,23 @@ +ALTER DATABASE $name$ [ [ WITH ] $option$ [ ... ] ] + +ALTER DATABASE $name$ RENAME TO $new_name$ + +ALTER DATABASE $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER DATABASE $name$ SET TABLESPACE $new_tablespace$ + +ALTER DATABASE $name$ REFRESH COLLATION VERSION + +ALTER DATABASE $name$ SET $configuration_parameter$ { TO | = } { $value$ | DEFAULT } + +ALTER DATABASE $name$ SET $configuration_parameter$ FROM CURRENT + +ALTER DATABASE $name$ RESET $configuration_parameter$ + +ALTER DATABASE $name$ RESET ALL + +where $option$ is: + +ALLOW_CONNECTIONS $allowconn$ | + CONNECTION LIMIT $connlimit$ | + IS_TEMPLATE $istemplate$ diff --git a/testing/generation/command_docs/synopses/alter_default_privileges.txt b/testing/generation/command_docs/synopses/alter_default_privileges.txt new file mode 100644 index 0000000000..083212c15b --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_default_privileges.txt @@ -0,0 +1,51 @@ +ALTER DEFAULT PRIVILEGES + [ FOR { ROLE | USER } $target_role$ [ , ... ] ] + [ IN SCHEMA $schema_name$ [ , ... ] ] + $abbreviated_grant_or_revoke$ + +where $abbreviated_grant_or_revoke$ is: + +GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } + [ , ... ] | ALL [ PRIVILEGES ] } + ON TABLES + TO { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] [ WITH GRANT OPTION ] | + GRANT { { USAGE | SELECT | UPDATE } + [ , ... ] | ALL [ PRIVILEGES ] } + ON SEQUENCES + TO { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] [ WITH GRANT OPTION ] | + GRANT { EXECUTE | ALL [ PRIVILEGES ] } + ON { FUNCTIONS | ROUTINES } + TO { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] [ WITH GRANT OPTION ] | + GRANT { USAGE | ALL [ PRIVILEGES ] } + ON TYPES + TO { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] [ WITH GRANT OPTION ] | + GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] } + ON SCHEMAS + TO { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] [ WITH GRANT OPTION ] | + REVOKE [ GRANT OPTION FOR ] + { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } + [ , ... ] | ALL [ PRIVILEGES ] } + ON TABLES + FROM { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] + [ CASCADE | RESTRICT ] | + REVOKE [ GRANT OPTION FOR ] + { { USAGE | SELECT | UPDATE } + [ , ... ] | ALL [ PRIVILEGES ] } + ON SEQUENCES + FROM { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] + [ CASCADE | RESTRICT ] | + REVOKE [ GRANT OPTION FOR ] + { EXECUTE | ALL [ PRIVILEGES ] } + ON { FUNCTIONS | ROUTINES } + FROM { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] + [ CASCADE | RESTRICT ] | + REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON TYPES + FROM { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] + [ CASCADE | RESTRICT ] | + REVOKE [ GRANT OPTION FOR ] + { USAGE | CREATE | ALL [ PRIVILEGES ] } + ON SCHEMAS + FROM { [ GROUP ] $role_name$ | PUBLIC } [ , ... ] + [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/alter_domain.txt b/testing/generation/command_docs/synopses/alter_domain.txt new file mode 100644 index 0000000000..c2efa1c45f --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_domain.txt @@ -0,0 +1,26 @@ +ALTER DOMAIN $name$ + { SET DEFAULT $expression$ | DROP DEFAULT } + +ALTER DOMAIN $name$ + { SET | DROP } NOT NULL + +ALTER DOMAIN $name$ + ADD $domain_constraint$ [ NOT VALID ] + +ALTER DOMAIN $name$ + DROP CONSTRAINT [ IF EXISTS ] $constraint_name$ [ RESTRICT | CASCADE ] + +ALTER DOMAIN $name$ + RENAME CONSTRAINT $constraint_name$ TO $new_constraint_name$ + +ALTER DOMAIN $name$ + VALIDATE CONSTRAINT $constraint_name$ + +ALTER DOMAIN $name$ + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER DOMAIN $name$ + RENAME TO $new_name$ + +ALTER DOMAIN $name$ + SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_event_trigger.txt b/testing/generation/command_docs/synopses/alter_event_trigger.txt new file mode 100644 index 0000000000..a83cdada8d --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_event_trigger.txt @@ -0,0 +1,7 @@ +ALTER EVENT TRIGGER $name$ DISABLE + +ALTER EVENT TRIGGER $name$ ENABLE [ REPLICA | ALWAYS ] + +ALTER EVENT TRIGGER $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER EVENT TRIGGER $name$ RENAME TO $new_name$ diff --git a/testing/generation/command_docs/synopses/alter_extension.txt b/testing/generation/command_docs/synopses/alter_extension.txt new file mode 100644 index 0000000000..45cd01d5b8 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_extension.txt @@ -0,0 +1,44 @@ +ALTER EXTENSION $name$ UPDATE [ TO $new_version$ ] + +ALTER EXTENSION $name$ SET SCHEMA $new_schema$ + +ALTER EXTENSION $name$ ADD $member_object$ + +ALTER EXTENSION $name$ DROP $member_object$ + +where $member_object$ is: + +ACCESS METHOD $object_name$ | + AGGREGATE $aggregate_name$ ( $aggregate_signature$ ) | + CAST ($source_type$ AS $target_type$) | + COLLATION $object_name$ | + CONVERSION $object_name$ | + DOMAIN $object_name$ | + EVENT TRIGGER $object_name$ | + FOREIGN DATA WRAPPER $object_name$ | + FOREIGN TABLE $object_name$ | + FUNCTION $function_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + MATERIALIZED VIEW $object_name$ | + OPERATOR $operator_name$ ($left_type$, $right_type$) | + OPERATOR CLASS $object_name$ USING $index_method$ | + OPERATOR FAMILY $object_name$ USING $index_method$ | + [ PROCEDURAL ] LANGUAGE $object_name$ | + PROCEDURE $procedure_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + ROUTINE $routine_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + SCHEMA $object_name$ | + SEQUENCE $object_name$ | + SERVER $object_name$ | + TABLE $object_name$ | + TEXT SEARCH CONFIGURATION $object_name$ | + TEXT SEARCH DICTIONARY $object_name$ | + TEXT SEARCH PARSER $object_name$ | + TEXT SEARCH TEMPLATE $object_name$ | + TRANSFORM FOR $type_name$ LANGUAGE $lang_name$ | + TYPE $object_name$ | + VIEW $object_name$ + +where $aggregate_signature$ is: + +* | + [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] | + [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ORDER BY [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/alter_foreign_data_wrapper.txt b/testing/generation/command_docs/synopses/alter_foreign_data_wrapper.txt new file mode 100644 index 0000000000..78a14dc886 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_foreign_data_wrapper.txt @@ -0,0 +1,8 @@ +ALTER FOREIGN DATA WRAPPER $name$ + [ HANDLER $handler_function$ | NO HANDLER ] + [ VALIDATOR $validator_function$ | NO VALIDATOR ] + [ OPTIONS ( [ ADD | SET | DROP ] $option$ ['$value$'] [ , ... ]) ] + +ALTER FOREIGN DATA WRAPPER $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER FOREIGN DATA WRAPPER $name$ RENAME TO $new_name$ diff --git a/testing/generation/command_docs/synopses/alter_foreign_table.txt b/testing/generation/command_docs/synopses/alter_foreign_table.txt new file mode 100644 index 0000000000..6a44224346 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_foreign_table.txt @@ -0,0 +1,37 @@ +ALTER FOREIGN TABLE [ IF EXISTS ] [ ONLY ] $name$ [ * ] + $action$ [ , ... ] + +ALTER FOREIGN TABLE [ IF EXISTS ] [ ONLY ] $name$ [ * ] + RENAME [ COLUMN ] $column_name$ TO $new_column_name$ + +ALTER FOREIGN TABLE [ IF EXISTS ] $name$ + RENAME TO $new_name$ + +ALTER FOREIGN TABLE [ IF EXISTS ] $name$ + SET SCHEMA $new_schema$ + +where $action$ is: + +ADD [ COLUMN ] $column_name$ $data_type$ [ COLLATE $collation$ ] [ $column_constraint$ [ ... ] ] | + DROP [ COLUMN ] [ IF EXISTS ] $column_name$ [ RESTRICT | CASCADE ] | + ALTER [ COLUMN ] $column_name$ [ SET DATA ] TYPE $data_type$ [ COLLATE $collation$ ] | + ALTER [ COLUMN ] $column_name$ SET DEFAULT $expression$ | + ALTER [ COLUMN ] $column_name$ DROP DEFAULT | + ALTER [ COLUMN ] $column_name$ { SET | DROP } NOT NULL | + ALTER [ COLUMN ] $column_name$ SET STATISTICS $integer$ | + ALTER [ COLUMN ] $column_name$ SET ( $attribute_option$ = $value$ [ , ... ] ) | + ALTER [ COLUMN ] $column_name$ RESET ( $attribute_option$ [ , ... ] ) | + ALTER [ COLUMN ] $column_name$ SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } | + ALTER [ COLUMN ] $column_name$ OPTIONS ( [ ADD | SET | DROP ] $option$ ['$value$'] [ , ... ]) | + ADD $table_constraint$ [ NOT VALID ] | + VALIDATE CONSTRAINT $constraint_name$ | + DROP CONSTRAINT [ IF EXISTS ] $constraint_name$ [ RESTRICT | CASCADE ] | + DISABLE TRIGGER [ $trigger_name$ | ALL | USER ] | + ENABLE TRIGGER [ $trigger_name$ | ALL | USER ] | + ENABLE REPLICA TRIGGER $trigger_name$ | + ENABLE ALWAYS TRIGGER $trigger_name$ | + SET WITHOUT OIDS | + INHERIT $parent_table$ | + NO INHERIT $parent_table$ | + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } | + OPTIONS ( [ ADD | SET | DROP ] $option$ ['$value$'] [ , ... ]) diff --git a/testing/generation/command_docs/synopses/alter_function.txt b/testing/generation/command_docs/synopses/alter_function.txt new file mode 100644 index 0000000000..ebe043ab63 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_function.txt @@ -0,0 +1,29 @@ +ALTER FUNCTION $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + $action$ [ ... ] [ RESTRICT ] + +ALTER FUNCTION $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + RENAME TO $new_name$ + +ALTER FUNCTION $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER FUNCTION $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + SET SCHEMA $new_schema$ + +ALTER FUNCTION $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + [ NO ] DEPENDS ON EXTENSION $extension_name$ + +where $action$ is: + +CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT | + IMMUTABLE | STABLE | VOLATILE | + [ NOT ] LEAKPROOF | + [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | + PARALLEL { UNSAFE | RESTRICTED | SAFE } | + COST $execution_cost$ | + ROWS $result_rows$ | + SUPPORT $support_function$ | + SET $configuration_parameter$ { TO | = } { $value$ | DEFAULT } | + SET $configuration_parameter$ FROM CURRENT | + RESET $configuration_parameter$ | + RESET ALL diff --git a/testing/generation/command_docs/synopses/alter_group.txt b/testing/generation/command_docs/synopses/alter_group.txt new file mode 100644 index 0000000000..cbaf3c3350 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_group.txt @@ -0,0 +1,12 @@ +ALTER GROUP $role_specification$ ADD USER $user_name$ [ , ... ] + +ALTER GROUP $role_specification$ DROP USER $user_name$ [ , ... ] + +ALTER GROUP $group_name$ RENAME TO $new_name$ + +where $role_specification$ is: + +$role_name$ | + CURRENT_ROLE | + CURRENT_USER | + SESSION_USER diff --git a/testing/generation/command_docs/synopses/alter_index.txt b/testing/generation/command_docs/synopses/alter_index.txt new file mode 100644 index 0000000000..312cb7fae1 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_index.txt @@ -0,0 +1,17 @@ +ALTER INDEX [ IF EXISTS ] $name$ RENAME TO $new_name$ + +ALTER INDEX [ IF EXISTS ] $name$ SET TABLESPACE $tablespace_name$ + +ALTER INDEX $name$ ATTACH PARTITION $index_name$ + +ALTER INDEX $name$ [ NO ] DEPENDS ON EXTENSION $extension_name$ + +ALTER INDEX [ IF EXISTS ] $name$ SET ( $storage_parameter$ [= $value$] [ , ... ] ) + +ALTER INDEX [ IF EXISTS ] $name$ RESET ( $storage_parameter$ [ , ... ] ) + +ALTER INDEX [ IF EXISTS ] $name$ ALTER [ COLUMN ] $column_number$ + SET STATISTICS $integer$ + +ALTER INDEX ALL IN TABLESPACE $name$ [ OWNED BY $role_name$ [ , ... ] ] + SET TABLESPACE $new_tablespace$ [ NOWAIT ] diff --git a/testing/generation/command_docs/synopses/alter_language.txt b/testing/generation/command_docs/synopses/alter_language.txt new file mode 100644 index 0000000000..0b88877459 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_language.txt @@ -0,0 +1,3 @@ +ALTER [ PROCEDURAL ] LANGUAGE $name$ RENAME TO $new_name$ + +ALTER [ PROCEDURAL ] LANGUAGE $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } diff --git a/testing/generation/command_docs/synopses/alter_large_object.txt b/testing/generation/command_docs/synopses/alter_large_object.txt new file mode 100644 index 0000000000..c463f399cf --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_large_object.txt @@ -0,0 +1 @@ +ALTER LARGE OBJECT $large_object_oid$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } diff --git a/testing/generation/command_docs/synopses/alter_materialized_view.txt b/testing/generation/command_docs/synopses/alter_materialized_view.txt new file mode 100644 index 0000000000..bdd0844b9f --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_materialized_view.txt @@ -0,0 +1,32 @@ +ALTER MATERIALIZED VIEW [ IF EXISTS ] $name$ + $action$ [ , ... ] + +ALTER MATERIALIZED VIEW $name$ + [ NO ] DEPENDS ON EXTENSION $extension_name$ + +ALTER MATERIALIZED VIEW [ IF EXISTS ] $name$ + RENAME [ COLUMN ] $column_name$ TO $new_column_name$ + +ALTER MATERIALIZED VIEW [ IF EXISTS ] $name$ + RENAME TO $new_name$ + +ALTER MATERIALIZED VIEW [ IF EXISTS ] $name$ + SET SCHEMA $new_schema$ + +ALTER MATERIALIZED VIEW ALL IN TABLESPACE $name$ [ OWNED BY $role_name$ [ , ... ] ] + SET TABLESPACE $new_tablespace$ [ NOWAIT ] + +where $action$ is: + +ALTER [ COLUMN ] $column_name$ SET STATISTICS $integer$ + ALTER [ COLUMN ] $column_name$ SET ( $attribute_option$ = $value$ [ , ... ] ) | + ALTER [ COLUMN ] $column_name$ RESET ( $attribute_option$ [ , ... ] ) | + ALTER [ COLUMN ] $column_name$ SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } | + ALTER [ COLUMN ] $column_name$ SET COMPRESSION $compression_method$ | + CLUSTER ON $index_name$ | + SET WITHOUT CLUSTER | + SET ACCESS METHOD $new_access_method$ | + SET TABLESPACE $new_tablespace$ | + SET ( $storage_parameter$ [= $value$] [ , ... ] ) | + RESET ( $storage_parameter$ [ , ... ] ) | + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } diff --git a/testing/generation/command_docs/synopses/alter_operator.txt b/testing/generation/command_docs/synopses/alter_operator.txt new file mode 100644 index 0000000000..494cf2361b --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_operator.txt @@ -0,0 +1,10 @@ +ALTER OPERATOR $name$ ( { $left_type$ | NONE } , $right_type$ ) + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER OPERATOR $name$ ( { $left_type$ | NONE } , $right_type$ ) + SET SCHEMA $new_schema$ + +ALTER OPERATOR $name$ ( { $left_type$ | NONE } , $right_type$ ) + SET ( { RESTRICT = { $res_proc$ | NONE } + | JOIN = { $join_proc$ | NONE } + } [ , ... ] ) diff --git a/testing/generation/command_docs/synopses/alter_operator_class.txt b/testing/generation/command_docs/synopses/alter_operator_class.txt new file mode 100644 index 0000000000..de7e210dcc --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_operator_class.txt @@ -0,0 +1,8 @@ +ALTER OPERATOR CLASS $name$ USING $index_method$ + RENAME TO $new_name$ + +ALTER OPERATOR CLASS $name$ USING $index_method$ + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER OPERATOR CLASS $name$ USING $index_method$ + SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_operator_family.txt b/testing/generation/command_docs/synopses/alter_operator_family.txt new file mode 100644 index 0000000000..e0b165e45d --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_operator_family.txt @@ -0,0 +1,20 @@ +ALTER OPERATOR FAMILY $name$ USING $index_method$ ADD + { OPERATOR $strategy_number$ $operator_name$ ( $op_type$, $op_type$ ) + [ FOR SEARCH | FOR ORDER BY $sort_family_name$ ] + | FUNCTION $support_number$ [ ( $op_type$ [ , $op_type$ ] ) ] + $function_name$ [ ( $argument_type$ [ , ... ] ) ] + } [ , ... ] + +ALTER OPERATOR FAMILY $name$ USING $index_method$ DROP + { OPERATOR $strategy_number$ ( $op_type$ [ , $op_type$ ] ) + | FUNCTION $support_number$ ( $op_type$ [ , $op_type$ ] ) + } [ , ... ] + +ALTER OPERATOR FAMILY $name$ USING $index_method$ + RENAME TO $new_name$ + +ALTER OPERATOR FAMILY $name$ USING $index_method$ + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER OPERATOR FAMILY $name$ USING $index_method$ + SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_policy.txt b/testing/generation/command_docs/synopses/alter_policy.txt new file mode 100644 index 0000000000..1b8c9ac46f --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_policy.txt @@ -0,0 +1,6 @@ +ALTER POLICY $name$ ON $table_name$ RENAME TO $new_name$ + +ALTER POLICY $name$ ON $table_name$ + [ TO { $role_name$ | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [ , ... ] ] + [ USING ( $using_expression$ ) ] + [ WITH CHECK ( $check_expression$ ) ] diff --git a/testing/generation/command_docs/synopses/alter_procedure.txt b/testing/generation/command_docs/synopses/alter_procedure.txt new file mode 100644 index 0000000000..0f16d788e7 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_procedure.txt @@ -0,0 +1,22 @@ +ALTER PROCEDURE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + $action$ [ ... ] [ RESTRICT ] + +ALTER PROCEDURE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + RENAME TO $new_name$ + +ALTER PROCEDURE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER PROCEDURE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + SET SCHEMA $new_schema$ + +ALTER PROCEDURE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + [ NO ] DEPENDS ON EXTENSION $extension_name$ + +where $action$ is: + +[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | + SET $configuration_parameter$ { TO | = } { $value$ | DEFAULT } | + SET $configuration_parameter$ FROM CURRENT | + RESET $configuration_parameter$ | + RESET ALL diff --git a/testing/generation/command_docs/synopses/alter_publication.txt b/testing/generation/command_docs/synopses/alter_publication.txt new file mode 100644 index 0000000000..444713e595 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_publication.txt @@ -0,0 +1,16 @@ +ALTER PUBLICATION $name$ ADD $publication_object$ [ , ... ] + +ALTER PUBLICATION $name$ SET $publication_object$ [ , ... ] + +ALTER PUBLICATION $name$ DROP $publication_object$ [ , ... ] + +ALTER PUBLICATION $name$ SET ( $publication_parameter$ [= $value$] [ , ... ] ) + +ALTER PUBLICATION $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER PUBLICATION $name$ RENAME TO $new_name$ + +where $publication_object$ is: + +TABLE [ ONLY ] $table_name$ [ * ] [ ( $column_name$ [ , ... ] ) ] [ WHERE ( $expression$ ) ] [ , ... ] | + TABLES IN SCHEMA { $schema_name$ | CURRENT_SCHEMA } [ , ... ] diff --git a/testing/generation/command_docs/synopses/alter_role.txt b/testing/generation/command_docs/synopses/alter_role.txt new file mode 100644 index 0000000000..6f7a245d89 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_role.txt @@ -0,0 +1,31 @@ +ALTER ROLE $role_specification$ [ WITH ] { $option$ [ ... ] } + +ALTER ROLE $name$ RENAME TO $new_name$ + +ALTER ROLE { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] SET $configuration_parameter$ { TO | = } { $value$ | DEFAULT } + +ALTER ROLE { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] SET $configuration_parameter$ FROM CURRENT + +ALTER ROLE { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] RESET $configuration_parameter$ + +ALTER ROLE { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] RESET ALL + +where $option$ is: + +SUPERUSER | NOSUPERUSER | + CREATEDB | NOCREATEDB | + CREATEROLE | NOCREATEROLE | + INHERIT | NOINHERIT | + LOGIN | NOLOGIN | + REPLICATION | NOREPLICATION | + BYPASSRLS | NOBYPASSRLS | + CONNECTION LIMIT $connlimit$ | + [ ENCRYPTED ] PASSWORD '$password$' | PASSWORD NULL | + VALID UNTIL '$timestamp$' + +where $role_specification$ is: + +$role_name$ | + CURRENT_ROLE | + CURRENT_USER | + SESSION_USER diff --git a/testing/generation/command_docs/synopses/alter_routine.txt b/testing/generation/command_docs/synopses/alter_routine.txt new file mode 100644 index 0000000000..9db63c67e8 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_routine.txt @@ -0,0 +1,27 @@ +ALTER ROUTINE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + $action$ [ ... ] [ RESTRICT ] + +ALTER ROUTINE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + RENAME TO $new_name$ + +ALTER ROUTINE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER ROUTINE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + SET SCHEMA $new_schema$ + +ALTER ROUTINE $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] + [ NO ] DEPENDS ON EXTENSION $extension_name$ + +where $action$ is: + +IMMUTABLE | STABLE | VOLATILE | + [ NOT ] LEAKPROOF | + [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | + PARALLEL { UNSAFE | RESTRICTED | SAFE } | + COST $execution_cost$ | + ROWS $result_rows$ | + SET $configuration_parameter$ { TO | = } { $value$ | DEFAULT } | + SET $configuration_parameter$ FROM CURRENT | + RESET $configuration_parameter$ | + RESET ALL diff --git a/testing/generation/command_docs/synopses/alter_rule.txt b/testing/generation/command_docs/synopses/alter_rule.txt new file mode 100644 index 0000000000..8dbf5138e7 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_rule.txt @@ -0,0 +1 @@ +ALTER RULE $name$ ON $table_name$ RENAME TO $new_name$ diff --git a/testing/generation/command_docs/synopses/alter_schema.txt b/testing/generation/command_docs/synopses/alter_schema.txt new file mode 100644 index 0000000000..438cbbcea2 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_schema.txt @@ -0,0 +1,3 @@ +ALTER SCHEMA $name$ RENAME TO $new_name$ + +ALTER SCHEMA $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } diff --git a/testing/generation/command_docs/synopses/alter_sequence.txt b/testing/generation/command_docs/synopses/alter_sequence.txt new file mode 100644 index 0000000000..1a0b463b6c --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_sequence.txt @@ -0,0 +1,16 @@ +ALTER SEQUENCE [ IF EXISTS ] $name$ + [ AS $data_type$ ] + [ INCREMENT [ BY ] $increment$ ] + [ MINVALUE $minvalue$ | NO MINVALUE ] [ MAXVALUE $maxvalue$ | NO MAXVALUE ] + [ START [ WITH ] $start$ ] + [ RESTART [ [ WITH ] $restart$ ] ] + [ CACHE $cache$ ] [ [ NO ] CYCLE ] + [ OWNED BY { $table_name$.$column_name$ | NONE } ] + +ALTER SEQUENCE [ IF EXISTS ] $name$ SET { LOGGED | UNLOGGED } + +ALTER SEQUENCE [ IF EXISTS ] $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER SEQUENCE [ IF EXISTS ] $name$ RENAME TO $new_name$ + +ALTER SEQUENCE [ IF EXISTS ] $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_server.txt b/testing/generation/command_docs/synopses/alter_server.txt new file mode 100644 index 0000000000..bdda0202b3 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_server.txt @@ -0,0 +1,6 @@ +ALTER SERVER $name$ [ VERSION '$new_version$' ] + [ OPTIONS ( [ ADD | SET | DROP ] $option$ ['$value$'] [ , ... ] ) ] + +ALTER SERVER $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER SERVER $name$ RENAME TO $new_name$ diff --git a/testing/generation/command_docs/synopses/alter_statistics.txt b/testing/generation/command_docs/synopses/alter_statistics.txt new file mode 100644 index 0000000000..98b7170890 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_statistics.txt @@ -0,0 +1,7 @@ +ALTER STATISTICS $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER STATISTICS $name$ RENAME TO $new_name$ + +ALTER STATISTICS $name$ SET SCHEMA $new_schema$ + +ALTER STATISTICS $name$ SET STATISTICS $new_target$ diff --git a/testing/generation/command_docs/synopses/alter_subscription.txt b/testing/generation/command_docs/synopses/alter_subscription.txt new file mode 100644 index 0000000000..d81f32608f --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_subscription.txt @@ -0,0 +1,21 @@ +ALTER SUBSCRIPTION $name$ CONNECTION '$conninfo$' + +ALTER SUBSCRIPTION $name$ SET PUBLICATION $publication_name$ [ , ... ] [ WITH ( $publication_option$ [= $value$] [ , ... ] ) ] + +ALTER SUBSCRIPTION $name$ ADD PUBLICATION $publication_name$ [ , ... ] [ WITH ( $publication_option$ [= $value$] [ , ... ] ) ] + +ALTER SUBSCRIPTION $name$ DROP PUBLICATION $publication_name$ [ , ... ] [ WITH ( $publication_option$ [= $value$] [ , ... ] ) ] + +ALTER SUBSCRIPTION $name$ REFRESH PUBLICATION [ WITH ( $refresh_option$ [= $value$] [ , ... ] ) ] + +ALTER SUBSCRIPTION $name$ ENABLE + +ALTER SUBSCRIPTION $name$ DISABLE + +ALTER SUBSCRIPTION $name$ SET ( $subscription_parameter$ [= $value$] [ , ... ] ) + +ALTER SUBSCRIPTION $name$ SKIP ( $skip_option$ = $value$ ) + +ALTER SUBSCRIPTION $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER SUBSCRIPTION $name$ RENAME TO $new_name$ diff --git a/testing/generation/command_docs/synopses/alter_system.txt b/testing/generation/command_docs/synopses/alter_system.txt new file mode 100644 index 0000000000..bb45cddc84 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_system.txt @@ -0,0 +1,5 @@ +ALTER SYSTEM SET $configuration_parameter$ { TO | = } { $value$ [ , ... ] | DEFAULT } + +ALTER SYSTEM RESET $configuration_parameter$ + +ALTER SYSTEM RESET ALL diff --git a/testing/generation/command_docs/synopses/alter_table.txt b/testing/generation/command_docs/synopses/alter_table.txt new file mode 100644 index 0000000000..28ab271e22 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_table.txt @@ -0,0 +1,125 @@ +ALTER TABLE [ IF EXISTS ] [ ONLY ] $name$ [ * ] + $action$ [ , ... ] + +ALTER TABLE [ IF EXISTS ] [ ONLY ] $name$ [ * ] + RENAME [ COLUMN ] $column_name$ TO $new_column_name$ + +ALTER TABLE [ IF EXISTS ] [ ONLY ] $name$ [ * ] + RENAME CONSTRAINT $constraint_name$ TO $new_constraint_name$ + +ALTER TABLE [ IF EXISTS ] $name$ + RENAME TO $new_name$ + +ALTER TABLE [ IF EXISTS ] $name$ + SET SCHEMA $new_schema$ + +ALTER TABLE ALL IN TABLESPACE $name$ [ OWNED BY $role_name$ [ , ... ] ] + SET TABLESPACE $new_tablespace$ [ NOWAIT ] + +ALTER TABLE [ IF EXISTS ] $name$ + ATTACH PARTITION $partition_name$ { FOR VALUES $partition_bound_spec$ | DEFAULT } + +ALTER TABLE [ IF EXISTS ] $name$ + DETACH PARTITION $partition_name$ [ CONCURRENTLY | FINALIZE ] + +where $action$ is: + +ADD [ COLUMN ] [ IF NOT EXISTS ] $column_name$ $data_type$ [ COLLATE $collation$ ] [ $column_constraint$ [ ... ] ] | + DROP [ COLUMN ] [ IF EXISTS ] $column_name$ [ RESTRICT | CASCADE ] | | + ALTER [ COLUMN ] $column_name$ [ SET DATA ] TYPE $data_type$ [ COLLATE $collation$ ] [ USING $expression$ ] | | + ALTER [ COLUMN ] $column_name$ SET DEFAULT $expression$ | | + ALTER [ COLUMN ] $column_name$ DROP DEFAULT | | + ALTER [ COLUMN ] $column_name$ { SET | DROP } NOT NULL | | + ALTER [ COLUMN ] $column_name$ DROP EXPRESSION [ IF EXISTS ] | | + ALTER [ COLUMN ] $column_name$ ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( $sequence_options$ ) ] | | + ALTER [ COLUMN ] $column_name$ { SET GENERATED { ALWAYS | BY DEFAULT } | SET $sequence_option$ | RESTART [ [ WITH ] $restart$ ] } [ ... ] | + ALTER [ COLUMN ] $column_name$ DROP IDENTITY [ IF EXISTS ] | + ALTER [ COLUMN ] $column_name$ SET STATISTICS $integer$ | + ALTER [ COLUMN ] $column_name$ SET ( $attribute_option$ = $value$ [ , ... ] ) | + ALTER [ COLUMN ] $column_name$ RESET ( $attribute_option$ [ , ... ] ) | + ALTER [ COLUMN ] $column_name$ SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } | + ALTER [ COLUMN ] $column_name$ SET COMPRESSION $compression_method$ | + ADD $table_constraint$ [ NOT VALID ] | + ADD $table_constraint_using_index$ | + ALTER CONSTRAINT $constraint_name$ [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] | + VALIDATE CONSTRAINT $constraint_name$ | + DROP CONSTRAINT [ IF EXISTS ] $constraint_name$ [ RESTRICT | CASCADE ] | + DISABLE TRIGGER [ $trigger_name$ | ALL | USER ] | + ENABLE TRIGGER [ $trigger_name$ | ALL | USER ] | + ENABLE REPLICA TRIGGER $trigger_name$ | + ENABLE ALWAYS TRIGGER $trigger_name$ | + DISABLE RULE $rewrite_rule_name$ | + ENABLE RULE $rewrite_rule_name$ | + ENABLE REPLICA RULE $rewrite_rule_name$ | + ENABLE ALWAYS RULE $rewrite_rule_name$ | + DISABLE ROW LEVEL SECURITY | + ENABLE ROW LEVEL SECURITY | + FORCE ROW LEVEL SECURITY | + NO FORCE ROW LEVEL SECURITY | + CLUSTER ON $index_name$ | + SET WITHOUT CLUSTER | + SET WITHOUT OIDS | + SET ACCESS METHOD $new_access_method$ | + SET TABLESPACE $new_tablespace$ | + SET { LOGGED | UNLOGGED } | + SET ( $storage_parameter$ [= $value$] [ , ... ] ) | + RESET ( $storage_parameter$ [ , ... ] ) | + INHERIT $parent_table$ | + NO INHERIT $parent_table$ | + OF $type_name$ | + NOT OF | + OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } | + REPLICA IDENTITY { DEFAULT | USING INDEX $index_name$ | FULL | NOTHING } + +where $partition_bound_spec$ is: + +IN ( $partition_bound_expr$ [ , ... ] ) | + FROM ( { $partition_bound_expr$ | MINVALUE | MAXVALUE } [ , ... ] ) + TO ( { $partition_bound_expr$ | MINVALUE | MAXVALUE } [ , ... ] ) | + WITH ( MODULUS $numeric_literal$, REMAINDER $numeric_literal$ ) + +where $column_constraint$ is: + +[ CONSTRAINT $constraint_name$ ] + { NOT NULL | + NULL | + CHECK ( $expression$ ) [ NO INHERIT ] | + DEFAULT $default_expr$ | + GENERATED ALWAYS AS ( $generation_expr$ ) STORED | + GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( $sequence_options$ ) ] | + UNIQUE [ NULLS [ NOT ] DISTINCT ] $index_parameters$ | + PRIMARY KEY $index_parameters$ | + REFERENCES $reftable$ [ ( $refcolumn$ ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] + [ ON DELETE $referential_action$ ] [ ON UPDATE $referential_action$ ] } + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + +where $table_constraint$ is: + +[ CONSTRAINT $constraint_name$ ] + { CHECK ( $expression$ ) [ NO INHERIT ] | + UNIQUE [ NULLS [ NOT ] DISTINCT ] ( $column_name$ [ , ... ] ) $index_parameters$ | + PRIMARY KEY ( $column_name$ [ , ... ] ) $index_parameters$ | + EXCLUDE [ USING $index_method$ ] ( $exclude_element$ WITH $operator$ [ , ... ] ) $index_parameters$ [ WHERE ( $predicate$ ) ] | + FOREIGN KEY ( $column_name$ [ , ... ] ) REFERENCES $reftable$ [ ( $refcolumn$ [ , ... ] ) ] + [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE $referential_action$ ] [ ON UPDATE $referential_action$ ] } + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + +where $table_constraint_using_index$ is: + +[ CONSTRAINT $constraint_name$ ] + { UNIQUE | PRIMARY KEY } USING INDEX $index_name$ + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + +where $index_parameters$ is: + +[ INCLUDE ( $column_name$ [ , ... ] ) ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) ] + [ USING INDEX TABLESPACE $tablespace_name$ ] + +where $exclude_element$ is: + +{ $column_name$ | ( $expression$ ) } [ $opclass$ ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] + +where $referential_action$ is: + +{ NO ACTION | RESTRICT | CASCADE | SET NULL [ ( $column_name$ [ , ... ] ) ] | SET DEFAULT [ ( $column_name$ [ , ... ] ) ] } diff --git a/testing/generation/command_docs/synopses/alter_tablespace.txt b/testing/generation/command_docs/synopses/alter_tablespace.txt new file mode 100644 index 0000000000..88d0c8cb35 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_tablespace.txt @@ -0,0 +1,7 @@ +ALTER TABLESPACE $name$ RENAME TO $new_name$ + +ALTER TABLESPACE $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER TABLESPACE $name$ SET ( $tablespace_option$ = $value$ [ , ... ] ) + +ALTER TABLESPACE $name$ RESET ( $tablespace_option$ [ , ... ] ) diff --git a/testing/generation/command_docs/synopses/alter_text_search_configuration.txt b/testing/generation/command_docs/synopses/alter_text_search_configuration.txt new file mode 100644 index 0000000000..c27f7d11fd --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_text_search_configuration.txt @@ -0,0 +1,20 @@ +ALTER TEXT SEARCH CONFIGURATION $name$ + ADD MAPPING FOR $token_type$ [ , ... ] WITH $dictionary_name$ [ , ... ] + +ALTER TEXT SEARCH CONFIGURATION $name$ + ALTER MAPPING FOR $token_type$ [ , ... ] WITH $dictionary_name$ [ , ... ] + +ALTER TEXT SEARCH CONFIGURATION $name$ + ALTER MAPPING REPLACE $old_dictionary$ WITH $new_dictionary$ + +ALTER TEXT SEARCH CONFIGURATION $name$ + ALTER MAPPING FOR $token_type$ [ , ... ] REPLACE $old_dictionary$ WITH $new_dictionary$ + +ALTER TEXT SEARCH CONFIGURATION $name$ + DROP MAPPING [ IF EXISTS ] FOR $token_type$ [ , ... ] + +ALTER TEXT SEARCH CONFIGURATION $name$ RENAME TO $new_name$ + +ALTER TEXT SEARCH CONFIGURATION $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER TEXT SEARCH CONFIGURATION $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_text_search_dictionary.txt b/testing/generation/command_docs/synopses/alter_text_search_dictionary.txt new file mode 100644 index 0000000000..10f65721a0 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_text_search_dictionary.txt @@ -0,0 +1,8 @@ +ALTER TEXT SEARCH DICTIONARY $name$ ( + $option$ [ = $value$ ] [ , ... ] ) + +ALTER TEXT SEARCH DICTIONARY $name$ RENAME TO $new_name$ + +ALTER TEXT SEARCH DICTIONARY $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER TEXT SEARCH DICTIONARY $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_text_search_parser.txt b/testing/generation/command_docs/synopses/alter_text_search_parser.txt new file mode 100644 index 0000000000..5b7b97dfe2 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_text_search_parser.txt @@ -0,0 +1,3 @@ +ALTER TEXT SEARCH PARSER $name$ RENAME TO $new_name$ + +ALTER TEXT SEARCH PARSER $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_text_search_template.txt b/testing/generation/command_docs/synopses/alter_text_search_template.txt new file mode 100644 index 0000000000..48e52a0360 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_text_search_template.txt @@ -0,0 +1,3 @@ +ALTER TEXT SEARCH TEMPLATE $name$ RENAME TO $new_name$ + +ALTER TEXT SEARCH TEMPLATE $name$ SET SCHEMA $new_schema$ diff --git a/testing/generation/command_docs/synopses/alter_trigger.txt b/testing/generation/command_docs/synopses/alter_trigger.txt new file mode 100644 index 0000000000..59413ec134 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_trigger.txt @@ -0,0 +1,3 @@ +ALTER TRIGGER $name$ ON $table_name$ RENAME TO $new_name$ + +ALTER TRIGGER $name$ ON $table_name$ [ NO ] DEPENDS ON EXTENSION $extension_name$ diff --git a/testing/generation/command_docs/synopses/alter_type.txt b/testing/generation/command_docs/synopses/alter_type.txt new file mode 100644 index 0000000000..ac54d01973 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_type.txt @@ -0,0 +1,21 @@ +ALTER TYPE $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER TYPE $name$ RENAME TO $new_name$ + +ALTER TYPE $name$ SET SCHEMA $new_schema$ + +ALTER TYPE $name$ RENAME ATTRIBUTE $attribute_name$ TO $new_attribute_name$ [ CASCADE | RESTRICT ] + +ALTER TYPE { $name$ $action$ [ , ... ] } + +ALTER TYPE $name$ ADD VALUE [ IF NOT EXISTS ] $new_enum_value$ [ { BEFORE | AFTER } $neighbor_enum_value$ ] + +ALTER TYPE $name$ RENAME VALUE $existing_enum_value$ TO $new_enum_value$ + +ALTER TYPE $name$ SET ( $property$ = $value$ [ , ... ] ) + +where $action$ is: + +ADD ATTRIBUTE $attribute_name$ $data_type$ [ COLLATE $collation$ ] [ CASCADE | RESTRICT ] | + DROP ATTRIBUTE [ IF EXISTS ] $attribute_name$ [ CASCADE | RESTRICT ] | + ALTER ATTRIBUTE $attribute_name$ [ SET DATA ] TYPE $data_type$ [ COLLATE $collation$ ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/alter_user.txt b/testing/generation/command_docs/synopses/alter_user.txt new file mode 100644 index 0000000000..c2e302da7a --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_user.txt @@ -0,0 +1,31 @@ +ALTER USER $role_specification$ [ WITH ] $option$ [ ... ] + +ALTER USER $name$ RENAME TO $new_name$ + +ALTER USER { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] SET $configuration_parameter$ { TO | = } { $value$ | DEFAULT } + +ALTER USER { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] SET $configuration_parameter$ FROM CURRENT + +ALTER USER { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] RESET $configuration_parameter$ + +ALTER USER { $role_specification$ | ALL } [ IN DATABASE $database_name$ ] RESET ALL + +where $option$ is: + +SUPERUSER | NOSUPERUSER | + CREATEDB | NOCREATEDB | + CREATEROLE | NOCREATEROLE | + INHERIT | NOINHERIT | + LOGIN | NOLOGIN | + REPLICATION | NOREPLICATION | + BYPASSRLS | NOBYPASSRLS | + CONNECTION LIMIT $connlimit$ | + [ ENCRYPTED ] PASSWORD '$password$' | PASSWORD NULL | + VALID UNTIL '$timestamp$' + +where $role_specification$ is: + +$role_name$ | + CURRENT_ROLE | + CURRENT_USER | + SESSION_USER diff --git a/testing/generation/command_docs/synopses/alter_user_mapping.txt b/testing/generation/command_docs/synopses/alter_user_mapping.txt new file mode 100644 index 0000000000..a4b3fa3501 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_user_mapping.txt @@ -0,0 +1,3 @@ +ALTER USER MAPPING FOR { $user_name$ | USER | CURRENT_ROLE | CURRENT_USER | SESSION_USER | PUBLIC } + SERVER $server_name$ + OPTIONS ( [ ADD | SET | DROP ] $option$ ['$value$'] [ , ... ] ) diff --git a/testing/generation/command_docs/synopses/alter_view.txt b/testing/generation/command_docs/synopses/alter_view.txt new file mode 100644 index 0000000000..5b556426f7 --- /dev/null +++ b/testing/generation/command_docs/synopses/alter_view.txt @@ -0,0 +1,15 @@ +ALTER VIEW [ IF EXISTS ] $name$ ALTER [ COLUMN ] $column_name$ SET DEFAULT $expression$ + +ALTER VIEW [ IF EXISTS ] $name$ ALTER [ COLUMN ] $column_name$ DROP DEFAULT + +ALTER VIEW [ IF EXISTS ] $name$ OWNER TO { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } + +ALTER VIEW [ IF EXISTS ] $name$ RENAME [ COLUMN ] $column_name$ TO $new_column_name$ + +ALTER VIEW [ IF EXISTS ] $name$ RENAME TO $new_name$ + +ALTER VIEW [ IF EXISTS ] $name$ SET SCHEMA $new_schema$ + +ALTER VIEW [ IF EXISTS ] $name$ SET ( $view_option_name$ [= $view_option_value$] [ , ... ] ) + +ALTER VIEW [ IF EXISTS ] $name$ RESET ( $view_option_name$ [ , ... ] ) diff --git a/testing/generation/command_docs/synopses/analyze.txt b/testing/generation/command_docs/synopses/analyze.txt new file mode 100644 index 0000000000..8d8f02e94e --- /dev/null +++ b/testing/generation/command_docs/synopses/analyze.txt @@ -0,0 +1,12 @@ +ANALYZE [ ( $option$ [ , ... ] ) ] [ $table_and_columns$ [ , ... ] ] + +ANALYZE [ VERBOSE ] [ $table_and_columns$ [ , ... ] ] + +where $option$ is: + +VERBOSE [ $boolean$ ] | + SKIP_LOCKED [ $boolean$ ] + +where $table_and_columns$ is: + +$table_name$ [ ( $column_name$ [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/begin.txt b/testing/generation/command_docs/synopses/begin.txt new file mode 100644 index 0000000000..75f404f814 --- /dev/null +++ b/testing/generation/command_docs/synopses/begin.txt @@ -0,0 +1,7 @@ +BEGIN [ WORK | TRANSACTION ] [ $transaction_mode$ [ , ... ] ] + +where $transaction_mode$ is: + +ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED } | + READ WRITE | READ ONLY | + [ NOT ] DEFERRABLE diff --git a/testing/generation/command_docs/synopses/call.txt b/testing/generation/command_docs/synopses/call.txt new file mode 100644 index 0000000000..5cdffd6ead --- /dev/null +++ b/testing/generation/command_docs/synopses/call.txt @@ -0,0 +1 @@ +CALL $name$ ( [ $argument$ ] [ , ... ] ) diff --git a/testing/generation/command_docs/synopses/checkpoint.txt b/testing/generation/command_docs/synopses/checkpoint.txt new file mode 100644 index 0000000000..40f5231f0a --- /dev/null +++ b/testing/generation/command_docs/synopses/checkpoint.txt @@ -0,0 +1 @@ +CHECKPOINT diff --git a/testing/generation/command_docs/synopses/close.txt b/testing/generation/command_docs/synopses/close.txt new file mode 100644 index 0000000000..56168a39c7 --- /dev/null +++ b/testing/generation/command_docs/synopses/close.txt @@ -0,0 +1 @@ +CLOSE { $name$ | ALL } diff --git a/testing/generation/command_docs/synopses/cluster.txt b/testing/generation/command_docs/synopses/cluster.txt new file mode 100644 index 0000000000..9e66f0154f --- /dev/null +++ b/testing/generation/command_docs/synopses/cluster.txt @@ -0,0 +1,9 @@ +CLUSTER [ VERBOSE ] $table_name$ [ USING $index_name$ ] + +CLUSTER ( $option$ [ , ... ] ) $table_name$ [ USING $index_name$ ] + +CLUSTER [ VERBOSE ] + +where $option$ is: + +VERBOSE [ $boolean$ ] diff --git a/testing/generation/command_docs/synopses/comment.txt b/testing/generation/command_docs/synopses/comment.txt new file mode 100644 index 0000000000..5d85d3c6cc --- /dev/null +++ b/testing/generation/command_docs/synopses/comment.txt @@ -0,0 +1,50 @@ +COMMENT ON { + ACCESS METHOD $object_name$ | + AGGREGATE $aggregate_name$ ( $aggregate_signature$ ) | + CAST ($source_type$ AS $target_type$) | + COLLATION $object_name$ | + COLUMN $relation_name$.$column_name$ | + CONSTRAINT $constraint_name$ ON $table_name$ | + CONSTRAINT $constraint_name$ ON DOMAIN $domain_name$ | + CONVERSION $object_name$ | + DATABASE $object_name$ | + DOMAIN $object_name$ | + EXTENSION $object_name$ | + EVENT TRIGGER $object_name$ | + FOREIGN DATA WRAPPER $object_name$ | + FOREIGN TABLE $object_name$ | + FUNCTION $function_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + INDEX $object_name$ | + LARGE OBJECT $large_object_oid$ | + MATERIALIZED VIEW $object_name$ | + OPERATOR $operator_name$ ($left_type$, $right_type$) | + OPERATOR CLASS $object_name$ USING $index_method$ | + OPERATOR FAMILY $object_name$ USING $index_method$ | + POLICY $policy_name$ ON $table_name$ | + [ PROCEDURAL ] LANGUAGE $object_name$ | + PROCEDURE $procedure_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + PUBLICATION $object_name$ | + ROLE $object_name$ | + ROUTINE $routine_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + RULE $rule_name$ ON $table_name$ | + SCHEMA $object_name$ | + SEQUENCE $object_name$ | + SERVER $object_name$ | + STATISTICS $object_name$ | + SUBSCRIPTION $object_name$ | + TABLE $object_name$ | + TABLESPACE $object_name$ | + TEXT SEARCH CONFIGURATION $object_name$ | + TEXT SEARCH DICTIONARY $object_name$ | + TEXT SEARCH PARSER $object_name$ | + TEXT SEARCH TEMPLATE $object_name$ | + TRANSFORM FOR $type_name$ LANGUAGE $lang_name$ | + TRIGGER $trigger_name$ ON $table_name$ | + TYPE $object_name$ | + VIEW $object_name$ } IS { $string_literal$ | NULL } + +where $aggregate_signature$ is: + +* | + [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] | + [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ORDER BY [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/commit.txt b/testing/generation/command_docs/synopses/commit.txt new file mode 100644 index 0000000000..c8cc7cfa7e --- /dev/null +++ b/testing/generation/command_docs/synopses/commit.txt @@ -0,0 +1 @@ +COMMIT [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] diff --git a/testing/generation/command_docs/synopses/commit_prepared.txt b/testing/generation/command_docs/synopses/commit_prepared.txt new file mode 100644 index 0000000000..0f2a92a776 --- /dev/null +++ b/testing/generation/command_docs/synopses/commit_prepared.txt @@ -0,0 +1 @@ +COMMIT PREPARED $transaction_id$ diff --git a/testing/generation/command_docs/synopses/copy.txt b/testing/generation/command_docs/synopses/copy.txt new file mode 100644 index 0000000000..9216105dfe --- /dev/null +++ b/testing/generation/command_docs/synopses/copy.txt @@ -0,0 +1,22 @@ +COPY $table_name$ [ ( $column_name$ [ , ... ] ) ] + FROM { '$filename$' | PROGRAM '$command$' | STDIN } + [ [ WITH ] ( $option$ [ , ... ] ) ] + [ WHERE $condition$ ] + +COPY { $table_name$ [ ( $column_name$ [ , ... ] ) ] | ( $query$ ) } + TO { '$filename$' | PROGRAM '$command$' | STDOUT } + [ [ WITH ] ( $option$ [ , ... ] ) ] + +where $option$ is: + +FORMAT $format_name$ | + FREEZE [ $boolean$ ] | + DELIMITER '$delimiter_character$' | + NULL '$null_string$' | + HEADER [ $boolean$ | MATCH ] | + QUOTE '$quote_character$' | + ESCAPE '$escape_character$' | + FORCE_QUOTE { ( $column_name$ [ , ... ] ) | * } | + FORCE_NOT_NULL ( $column_name$ [ , ... ] ) | + FORCE_NULL ( $column_name$ [ , ... ] ) | + ENCODING '$encoding_name$' diff --git a/testing/generation/command_docs/synopses/create_access_method.txt b/testing/generation/command_docs/synopses/create_access_method.txt new file mode 100644 index 0000000000..83ff02128d --- /dev/null +++ b/testing/generation/command_docs/synopses/create_access_method.txt @@ -0,0 +1,3 @@ +CREATE ACCESS METHOD $name$ + TYPE $access_method_type$ + HANDLER $handler_function$ diff --git a/testing/generation/command_docs/synopses/create_aggregate.txt b/testing/generation/command_docs/synopses/create_aggregate.txt new file mode 100644 index 0000000000..6baaa0f0df --- /dev/null +++ b/testing/generation/command_docs/synopses/create_aggregate.txt @@ -0,0 +1,55 @@ +CREATE [ OR REPLACE ] AGGREGATE $name$ ( [ $argmode$ ] [ $argname$ ] $arg_data_type$ [ , ... ] ) ( + SFUNC = $sfunc$, + STYPE = $state_data_type$ + [ , SSPACE = $state_data_size$ ] + [ , FINALFUNC = $ffunc$ ] + [ , FINALFUNC_EXTRA ] + [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] + [ , COMBINEFUNC = $combinefunc$ ] + [ , SERIALFUNC = $serialfunc$ ] + [ , DESERIALFUNC = $deserialfunc$ ] + [ , INITCOND = $initial_condition$ ] + [ , MSFUNC = $msfunc$ ] + [ , MINVFUNC = $minvfunc$ ] + [ , MSTYPE = $mstate_data_type$ ] + [ , MSSPACE = $mstate_data_size$ ] + [ , MFINALFUNC = $mffunc$ ] + [ , MFINALFUNC_EXTRA ] + [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] + [ , MINITCOND = $minitial_condition$ ] + [ , SORTOP = $sort_operator$ ] + [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ] ) + +CREATE [ OR REPLACE ] AGGREGATE $name$ ( [ [ $argmode$ ] [ $argname$ ] $arg_data_type$ [ , ... ] ] + ORDER BY [ $argmode$ ] [ $argname$ ] $arg_data_type$ [ , ... ] ) ( + SFUNC = $sfunc$, + STYPE = $state_data_type$ + [ , SSPACE = $state_data_size$ ] + [ , FINALFUNC = $ffunc$ ] + [ , FINALFUNC_EXTRA ] + [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] + [ , INITCOND = $initial_condition$ ] + [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ] + [ , HYPOTHETICAL ] ) + +CREATE [ OR REPLACE ] AGGREGATE $name$ ( + BASETYPE = $base_type$, + SFUNC = $sfunc$, + STYPE = $state_data_type$ + [ , SSPACE = $state_data_size$ ] + [ , FINALFUNC = $ffunc$ ] + [ , FINALFUNC_EXTRA ] + [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] + [ , COMBINEFUNC = $combinefunc$ ] + [ , SERIALFUNC = $serialfunc$ ] + [ , DESERIALFUNC = $deserialfunc$ ] + [ , INITCOND = $initial_condition$ ] + [ , MSFUNC = $msfunc$ ] + [ , MINVFUNC = $minvfunc$ ] + [ , MSTYPE = $mstate_data_type$ ] + [ , MSSPACE = $mstate_data_size$ ] + [ , MFINALFUNC = $mffunc$ ] + [ , MFINALFUNC_EXTRA ] + [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] + [ , MINITCOND = $minitial_condition$ ] + [ , SORTOP = $sort_operator$ ] ) diff --git a/testing/generation/command_docs/synopses/create_cast.txt b/testing/generation/command_docs/synopses/create_cast.txt new file mode 100644 index 0000000000..1c8d473065 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_cast.txt @@ -0,0 +1,11 @@ +CREATE CAST ($source_type$ AS $target_type$) + WITH FUNCTION $function_name$ [ ($argument_type$ [ , ... ]) ] + [ AS ASSIGNMENT | AS IMPLICIT ] + +CREATE CAST ($source_type$ AS $target_type$) + WITHOUT FUNCTION + [ AS ASSIGNMENT | AS IMPLICIT ] + +CREATE CAST ($source_type$ AS $target_type$) + WITH INOUT + [ AS ASSIGNMENT | AS IMPLICIT ] diff --git a/testing/generation/command_docs/synopses/create_collation.txt b/testing/generation/command_docs/synopses/create_collation.txt new file mode 100644 index 0000000000..49db93d027 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_collation.txt @@ -0,0 +1,9 @@ +CREATE COLLATION [ IF NOT EXISTS ] $name$ ( + [ LOCALE = $locale$, ] + [ LC_COLLATE = $lc_collate$, ] + [ LC_CTYPE = $lc_ctype$, ] + [ PROVIDER = $provider$, ] + [ DETERMINISTIC = $boolean$, ] + [ VERSION = $version$ ] ) + +CREATE COLLATION [ IF NOT EXISTS ] $name$ FROM $existing_collation$ diff --git a/testing/generation/command_docs/synopses/create_conversion.txt b/testing/generation/command_docs/synopses/create_conversion.txt new file mode 100644 index 0000000000..211bf8dd31 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_conversion.txt @@ -0,0 +1,2 @@ +CREATE [ DEFAULT ] CONVERSION $name$ + FOR $source_encoding$ TO $dest_encoding$ FROM $function_name$ diff --git a/testing/generation/command_docs/synopses/create_database.txt b/testing/generation/command_docs/synopses/create_database.txt new file mode 100644 index 0000000000..01890ab2d4 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_database.txt @@ -0,0 +1,16 @@ +CREATE DATABASE $name$ + [ WITH ] [ OWNER [=] $user_name$ ] + [ TEMPLATE [=] $template$ ] + [ ENCODING [=] $encoding$ ] + [ STRATEGY [=] $strategy$ ] + [ LOCALE [=] $locale$ ] + [ LC_COLLATE [=] $lc_collate$ ] + [ LC_CTYPE [=] $lc_ctype$ ] + [ ICU_LOCALE [=] $icu_locale$ ] + [ LOCALE_PROVIDER [=] $locale_provider$ ] + [ COLLATION_VERSION = $collation_version$ ] + [ TABLESPACE [=] $tablespace_name$ ] + [ ALLOW_CONNECTIONS [=] $allowconn$ ] + [ CONNECTION LIMIT [=] $connlimit$ ] + [ IS_TEMPLATE [=] $istemplate$ ] + [ OID [=] $oid$ ] diff --git a/testing/generation/command_docs/synopses/create_domain.txt b/testing/generation/command_docs/synopses/create_domain.txt new file mode 100644 index 0000000000..3d546d6889 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_domain.txt @@ -0,0 +1,8 @@ +CREATE DOMAIN $name$ [ AS ] $data_type$ + [ COLLATE $collation$ ] + [ DEFAULT $expression$ ] + [ $constraint$ [ ... ] ] + +where $constraint$ is: + +[ CONSTRAINT $constraint_name$ ] { NOT NULL | NULL | CHECK ($expression$) } diff --git a/testing/generation/command_docs/synopses/create_event_trigger.txt b/testing/generation/command_docs/synopses/create_event_trigger.txt new file mode 100644 index 0000000000..171b7c76ce --- /dev/null +++ b/testing/generation/command_docs/synopses/create_event_trigger.txt @@ -0,0 +1,4 @@ +CREATE EVENT TRIGGER $name$ + ON $event$ + [ WHEN $filter_variable$ IN ($filter_value$ [ , ... ]) [ AND ... ] ] + EXECUTE { FUNCTION | PROCEDURE } $function_name$() diff --git a/testing/generation/command_docs/synopses/create_extension.txt b/testing/generation/command_docs/synopses/create_extension.txt new file mode 100644 index 0000000000..06585622e8 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_extension.txt @@ -0,0 +1,4 @@ +CREATE EXTENSION [ IF NOT EXISTS ] $extension_name$ + [ WITH ] [ SCHEMA $schema_name$ ] + [ VERSION $version$ ] + [ CASCADE ] diff --git a/testing/generation/command_docs/synopses/create_foreign_data_wrapper.txt b/testing/generation/command_docs/synopses/create_foreign_data_wrapper.txt new file mode 100644 index 0000000000..a751b94284 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_foreign_data_wrapper.txt @@ -0,0 +1,4 @@ +CREATE FOREIGN DATA WRAPPER $name$ + [ HANDLER $handler_function$ | NO HANDLER ] + [ VALIDATOR $validator_function$ | NO VALIDATOR ] + [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/create_foreign_table.txt b/testing/generation/command_docs/synopses/create_foreign_table.txt new file mode 100644 index 0000000000..763d06121e --- /dev/null +++ b/testing/generation/command_docs/synopses/create_foreign_table.txt @@ -0,0 +1,38 @@ +CREATE FOREIGN TABLE [ IF NOT EXISTS ] $table_name$ ( [ + { $column_name$ $data_type$ [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] [ COLLATE $collation$ ] [ $column_constraint$ [ ... ] ] + | $table_constraint$ } + [ , ... ] + ] ) + [ INHERITS ( $parent_table$ [ , ... ] ) ] + SERVER $server_name$ + [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] + +CREATE FOREIGN TABLE [ IF NOT EXISTS ] $table_name$ + PARTITION OF $parent_table$ [ ( + { $column_name$ [ WITH OPTIONS ] [ $column_constraint$ [ ... ] ] + | $table_constraint$ } + [ , ... ] + ) ] + { FOR VALUES $partition_bound_spec$ | DEFAULT } + SERVER $server_name$ + [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] + +where $column_constraint$ is: + +[ CONSTRAINT $constraint_name$ ] | + { NOT NULL | + NULL | + CHECK ( $expression$ ) [ NO INHERIT ] | + DEFAULT $default_expr$ | + GENERATED ALWAYS AS ( $generation_expr$ ) STORED } + +where $table_constraint$ is: + +[ CONSTRAINT $constraint_name$ ] CHECK ( $expression$ ) [ NO INHERIT ] + +where $partition_bound_spec$ is: + +IN ( $partition_bound_expr$ [ , ... ] ) | + FROM ( { $partition_bound_expr$ | MINVALUE | MAXVALUE } [ , ... ] ) + TO ( { $partition_bound_expr$ | MINVALUE | MAXVALUE } [ , ... ] ) | + WITH ( MODULUS $numeric_literal$, REMAINDER $numeric_literal$ ) diff --git a/testing/generation/command_docs/synopses/create_function.txt b/testing/generation/command_docs/synopses/create_function.txt new file mode 100644 index 0000000000..5753003d34 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_function.txt @@ -0,0 +1,20 @@ +CREATE [ OR REPLACE ] FUNCTION + $name$ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ { DEFAULT | = } $default_expr$ ] [ , ... ] ] ) + [ RETURNS $rettype$ + | RETURNS TABLE ( $column_name$ $column_type$ [ , ... ] ) ] + { LANGUAGE $lang_name$ + | TRANSFORM { FOR TYPE $type_name$ } [ , ... ] + | WINDOW + | { IMMUTABLE | STABLE | VOLATILE } + | [ NOT ] LEAKPROOF + | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT } + | { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER } + | PARALLEL { UNSAFE | RESTRICTED | SAFE } + | COST $execution_cost$ + | ROWS $result_rows$ + | SUPPORT $support_function$ + | SET $configuration_parameter$ { TO $value$ | = $value$ | FROM CURRENT } + | AS '$definition$' + | AS '$obj_file$', '$link_symbol$' + | $sql_body$ + } ... diff --git a/testing/generation/command_docs/synopses/create_group.txt b/testing/generation/command_docs/synopses/create_group.txt new file mode 100644 index 0000000000..07cd63d957 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_group.txt @@ -0,0 +1,20 @@ +CREATE GROUP $name$ [ [ WITH ] $option$ [ ... ] ] + +where $option$ is: + +SUPERUSER | NOSUPERUSER | + CREATEDB | NOCREATEDB | + CREATEROLE | NOCREATEROLE | + INHERIT | NOINHERIT | + LOGIN | NOLOGIN | + REPLICATION | NOREPLICATION | + BYPASSRLS | NOBYPASSRLS | + CONNECTION LIMIT $connlimit$ | + [ ENCRYPTED ] PASSWORD '$password$' | PASSWORD NULL | + VALID UNTIL '$timestamp$' | + IN ROLE $role_name$ [ , ... ] | + IN GROUP $role_name$ [ , ... ] | + ROLE $role_name$ [ , ... ] | + ADMIN $role_name$ [ , ... ] | + USER $role_name$ [ , ... ] | + SYSID $uid$ diff --git a/testing/generation/command_docs/synopses/create_index.txt b/testing/generation/command_docs/synopses/create_index.txt new file mode 100644 index 0000000000..779fc9c4c3 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_index.txt @@ -0,0 +1,7 @@ +CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] $name$ ] ON [ ONLY ] $table_name$ [ USING $method$ ] + ( { $column_name$ | ( $expression$ ) } [ COLLATE $collation$ ] [ $opclass$ [ ( $opclass_parameter$ = $value$ [ , ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ , ... ] ) + [ INCLUDE ( $column_name$ [ , ... ] ) ] + [ NULLS [ NOT ] DISTINCT ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) ] + [ TABLESPACE $tablespace_name$ ] + [ WHERE $predicate$ ] diff --git a/testing/generation/command_docs/synopses/create_language.txt b/testing/generation/command_docs/synopses/create_language.txt new file mode 100644 index 0000000000..1e48ecaf4b --- /dev/null +++ b/testing/generation/command_docs/synopses/create_language.txt @@ -0,0 +1,4 @@ +CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE $name$ + HANDLER $call_handler$ [ INLINE $inline_handler$ ] [ VALIDATOR $valfunction$ ] + +CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE $name$ diff --git a/testing/generation/command_docs/synopses/create_materialized_view.txt b/testing/generation/command_docs/synopses/create_materialized_view.txt new file mode 100644 index 0000000000..847194bf1a --- /dev/null +++ b/testing/generation/command_docs/synopses/create_materialized_view.txt @@ -0,0 +1,7 @@ +CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] $table_name$ + [ ($column_name$ [ , ... ] ) ] + [ USING $method$ ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) ] + [ TABLESPACE $tablespace_name$ ] + AS $query$ + [ WITH [ NO ] DATA ] diff --git a/testing/generation/command_docs/synopses/create_operator.txt b/testing/generation/command_docs/synopses/create_operator.txt new file mode 100644 index 0000000000..de2a8a46fe --- /dev/null +++ b/testing/generation/command_docs/synopses/create_operator.txt @@ -0,0 +1,6 @@ +CREATE OPERATOR $name$ ( + {FUNCTION|PROCEDURE} = $function_name$ + [, LEFTARG = $left_type$ ] [, RIGHTARG = $right_type$ ] + [, COMMUTATOR = $com_op$ ] [, NEGATOR = $neg_op$ ] + [, RESTRICT = $res_proc$ ] [, JOIN = $join_proc$ ] + [, HASHES ] [, MERGES ] ) diff --git a/testing/generation/command_docs/synopses/create_operator_class.txt b/testing/generation/command_docs/synopses/create_operator_class.txt new file mode 100644 index 0000000000..d2239b5f5e --- /dev/null +++ b/testing/generation/command_docs/synopses/create_operator_class.txt @@ -0,0 +1,6 @@ +CREATE OPERATOR CLASS $name$ [ DEFAULT ] FOR TYPE $data_type$ + USING $index_method$ [ FAMILY $family_name$ ] AS + { OPERATOR $strategy_number$ $operator_name$ [ ( $op_type$, $op_type$ ) ] [ FOR SEARCH | FOR ORDER BY $sort_family_name$ ] + | FUNCTION $support_number$ [ ( $op_type$ [ , $op_type$ ] ) ] $function_name$ ( $argument_type$ [ , ... ] ) + | STORAGE $storage_type$ + } [ , ... ] diff --git a/testing/generation/command_docs/synopses/create_operator_family.txt b/testing/generation/command_docs/synopses/create_operator_family.txt new file mode 100644 index 0000000000..a049fcdb48 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_operator_family.txt @@ -0,0 +1 @@ +CREATE OPERATOR FAMILY $name$ USING $index_method$ diff --git a/testing/generation/command_docs/synopses/create_policy.txt b/testing/generation/command_docs/synopses/create_policy.txt new file mode 100644 index 0000000000..841b4568ab --- /dev/null +++ b/testing/generation/command_docs/synopses/create_policy.txt @@ -0,0 +1,6 @@ +CREATE POLICY $name$ ON $table_name$ + [ AS { PERMISSIVE | RESTRICTIVE } ] + [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] + [ TO { $role_name$ | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [ , ... ] ] + [ USING ( $using_expression$ ) ] + [ WITH CHECK ( $check_expression$ ) ] diff --git a/testing/generation/command_docs/synopses/create_procedure.txt b/testing/generation/command_docs/synopses/create_procedure.txt new file mode 100644 index 0000000000..5dd66ce916 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_procedure.txt @@ -0,0 +1,10 @@ +CREATE [ OR REPLACE ] PROCEDURE + $name$ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ { DEFAULT | = } $default_expr$ ] [ , ... ] ] ) + { LANGUAGE $lang_name$ + | TRANSFORM { FOR TYPE $type_name$ } [ , ... ] + | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER + | SET $configuration_parameter$ { TO $value$ | = $value$ | FROM CURRENT } + | AS '$definition$' + | AS '$obj_file$', '$link_symbol$' + | $sql_body$ + } ... diff --git a/testing/generation/command_docs/synopses/create_publication.txt b/testing/generation/command_docs/synopses/create_publication.txt new file mode 100644 index 0000000000..a01f7580b3 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_publication.txt @@ -0,0 +1,9 @@ +CREATE PUBLICATION $name$ + [ FOR ALL TABLES + | FOR $publication_object$ [ , ... ] ] + [ WITH ( $publication_parameter$ [= $value$] [ , ... ] ) ] + +where $publication_object$ is: + +TABLE [ ONLY ] $table_name$ [ * ] [ ( $column_name$ [ , ... ] ) ] [ WHERE ( $expression$ ) ] [ , ... ] | + TABLES IN SCHEMA { $schema_name$ | CURRENT_SCHEMA } [ , ... ] diff --git a/testing/generation/command_docs/synopses/create_role.txt b/testing/generation/command_docs/synopses/create_role.txt new file mode 100644 index 0000000000..5451863ecc --- /dev/null +++ b/testing/generation/command_docs/synopses/create_role.txt @@ -0,0 +1,20 @@ +CREATE ROLE $name$ [ [ WITH ] $option$ [ ... ] ] + +where $option$ is: + +SUPERUSER | NOSUPERUSER | + CREATEDB | NOCREATEDB | + CREATEROLE | NOCREATEROLE | + INHERIT | NOINHERIT | + LOGIN | NOLOGIN | + REPLICATION | NOREPLICATION | + BYPASSRLS | NOBYPASSRLS | + CONNECTION LIMIT $connlimit$ | + [ ENCRYPTED ] PASSWORD '$password$' | PASSWORD NULL | + VALID UNTIL '$timestamp$' | + IN ROLE $role_name$ [ , ... ] | + IN GROUP $role_name$ [ , ... ] | + ROLE $role_name$ [ , ... ] | + ADMIN $role_name$ [ , ... ] | + USER $role_name$ [ , ... ] | + SYSID $uid$ diff --git a/testing/generation/command_docs/synopses/create_rule.txt b/testing/generation/command_docs/synopses/create_rule.txt new file mode 100644 index 0000000000..f10e8b9192 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_rule.txt @@ -0,0 +1,7 @@ +CREATE [ OR REPLACE ] RULE $name$ AS ON $event$ + TO $table_name$ [ WHERE $condition$ ] + DO [ ALSO | INSTEAD ] { NOTHING | $command$ | ( $command$ ; $command$ ... ) } + +where $event$ is: + +SELECT | INSERT | UPDATE | DELETE diff --git a/testing/generation/command_docs/synopses/create_schema.txt b/testing/generation/command_docs/synopses/create_schema.txt new file mode 100644 index 0000000000..fb3fe0b3d6 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_schema.txt @@ -0,0 +1,14 @@ +CREATE SCHEMA $schema_name$ [ AUTHORIZATION $role_specification$ ] [ $schema_element$ [ ... ] ] + +CREATE SCHEMA AUTHORIZATION $role_specification$ [ $schema_element$ [ ... ] ] + +CREATE SCHEMA IF NOT EXISTS $schema_name$ [ AUTHORIZATION $role_specification$ ] + +CREATE SCHEMA IF NOT EXISTS AUTHORIZATION $role_specification$ + +where $role_specification$ is: + +$user_name$ | + CURRENT_ROLE | + CURRENT_USER | + SESSION_USER diff --git a/testing/generation/command_docs/synopses/create_sequence.txt b/testing/generation/command_docs/synopses/create_sequence.txt new file mode 100644 index 0000000000..37ef9e004d --- /dev/null +++ b/testing/generation/command_docs/synopses/create_sequence.txt @@ -0,0 +1,6 @@ +CREATE [ { TEMPORARY | TEMP } | UNLOGGED ] SEQUENCE [ IF NOT EXISTS ] $name$ + [ AS $data_type$ ] + [ INCREMENT [ BY ] $increment$ ] + [ MINVALUE $minvalue$ | NO MINVALUE ] [ MAXVALUE $maxvalue$ | NO MAXVALUE ] + [ START [ WITH ] $start$ ] [ CACHE $cache$ ] [ [ NO ] CYCLE ] + [ OWNED BY { $table_name$.$column_name$ | NONE } ] diff --git a/testing/generation/command_docs/synopses/create_server.txt b/testing/generation/command_docs/synopses/create_server.txt new file mode 100644 index 0000000000..a3f3b9a007 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_server.txt @@ -0,0 +1,3 @@ +CREATE SERVER [ IF NOT EXISTS ] $server_name$ [ TYPE '$server_type$' ] [ VERSION '$server_version$' ] + FOREIGN DATA WRAPPER $fdw_name$ + [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/create_statistics.txt b/testing/generation/command_docs/synopses/create_statistics.txt new file mode 100644 index 0000000000..4a0524a63f --- /dev/null +++ b/testing/generation/command_docs/synopses/create_statistics.txt @@ -0,0 +1,8 @@ +CREATE STATISTICS [ IF NOT EXISTS ] $statistics_name$ + ON ( $expression$ ) + FROM $table_name$ + +CREATE STATISTICS [ IF NOT EXISTS ] $statistics_name$ + [ ( $statistics_kind$ [ , ... ] ) ] + ON { $column_name$ | ( $expression$ ) }, { $column_name$ | ( $expression$ ) } [ , ... ] + FROM $table_name$ diff --git a/testing/generation/command_docs/synopses/create_subscription.txt b/testing/generation/command_docs/synopses/create_subscription.txt new file mode 100644 index 0000000000..63b6695386 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_subscription.txt @@ -0,0 +1,4 @@ +CREATE SUBSCRIPTION $subscription_name$ + CONNECTION '$conninfo$' + PUBLICATION $publication_name$ [ , ... ] + [ WITH ( $subscription_parameter$ [= $value$] [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/create_table.txt b/testing/generation/command_docs/synopses/create_table.txt new file mode 100644 index 0000000000..6a65b39070 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_table.txt @@ -0,0 +1,87 @@ +CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] $table_name$ ( [ + { $column_name$ $data_type$ [ COMPRESSION $compression_method$ ] [ COLLATE $collation$ ] [ $column_constraint$ [ ... ] ] + | $table_constraint$ + | LIKE $source_table$ [ $like_option$ ... ] } + [ , ... ] + ] ) + [ INHERITS ( $parent_table$ [ , ... ] ) ] + [ PARTITION BY { RANGE | LIST | HASH } ( { $column_name$ | ( $expression$ ) } [ COLLATE $collation$ ] [ $opclass$ ] [ , ... ] ) ] + [ USING $method$ ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) | WITHOUT OIDS ] + [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] + [ TABLESPACE $tablespace_name$ ] + +CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] $table_name$ + OF $type_name$ [ ( + { $column_name$ [ WITH OPTIONS ] [ $column_constraint$ [ ... ] ] + | $table_constraint$ } + [ , ... ] + ) ] + [ PARTITION BY { RANGE | LIST | HASH } ( { $column_name$ | ( $expression$ ) } [ COLLATE $collation$ ] [ $opclass$ ] [ , ... ] ) ] + [ USING $method$ ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) | WITHOUT OIDS ] + [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] + [ TABLESPACE $tablespace_name$ ] + +CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] $table_name$ + PARTITION OF $parent_table$ [ ( + { $column_name$ [ WITH OPTIONS ] [ $column_constraint$ [ ... ] ] + | $table_constraint$ } + [ , ... ] + ) ] { FOR VALUES $partition_bound_spec$ | DEFAULT } + [ PARTITION BY { RANGE | LIST | HASH } ( { $column_name$ | ( $expression$ ) } [ COLLATE $collation$ ] [ $opclass$ ] [ , ... ] ) ] + [ USING $method$ ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) | WITHOUT OIDS ] + [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] + [ TABLESPACE $tablespace_name$ ] + +where $column_constraint$ is: + +[ CONSTRAINT $constraint_name$ ] + { NOT NULL | + NULL | + CHECK ( $expression$ ) [ NO INHERIT ] | + DEFAULT $default_expr$ | + GENERATED ALWAYS AS ( $generation_expr$ ) STORED | + GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( $sequence_options$ ) ] | + UNIQUE [ NULLS [ NOT ] DISTINCT ] $index_parameters$ | + PRIMARY KEY $index_parameters$ | + REFERENCES $reftable$ [ ( $refcolumn$ ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] + [ ON DELETE $referential_action$ ] [ ON UPDATE $referential_action$ ] } + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + +where $table_constraint$ is: + +[ CONSTRAINT $constraint_name$ ] + { CHECK ( $expression$ ) [ NO INHERIT ] | + UNIQUE [ NULLS [ NOT ] DISTINCT ] ( $column_name$ [ , ... ] ) $index_parameters$ | + PRIMARY KEY ( $column_name$ [ , ... ] ) $index_parameters$ | + EXCLUDE [ USING $index_method$ ] ( $exclude_element$ WITH $operator$ [ , ... ] ) $index_parameters$ [ WHERE ( $predicate$ ) ] | + FOREIGN KEY ( $column_name$ [ , ... ] ) REFERENCES $reftable$ [ ( $refcolumn$ [ , ... ] ) ] + [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE $referential_action$ ] [ ON UPDATE $referential_action$ ] } + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + +where $like_option$ is: + +{ INCLUDING | EXCLUDING } { COMMENTS | COMPRESSION | CONSTRAINTS | DEFAULTS | GENERATED | IDENTITY | INDEXES | STATISTICS | STORAGE | ALL } + +where $partition_bound_spec$ is: + +IN ( $partition_bound_expr$ [ , ... ] ) | + FROM ( { $partition_bound_expr$ | MINVALUE | MAXVALUE } [ , ... ] ) + TO ( { $partition_bound_expr$ | MINVALUE | MAXVALUE } [ , ... ] ) | + WITH ( MODULUS $numeric_literal$, REMAINDER $numeric_literal$ ) + +where $index_parameters$ is: + +[ INCLUDE ( $column_name$ [ , ... ] ) ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) ] + [ USING INDEX TABLESPACE $tablespace_name$ ] + +where $exclude_element$ is: + +{ $column_name$ | ( $expression$ ) } [ $opclass$ ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] + +where $referential_action$ is: + +{ NO ACTION | RESTRICT | CASCADE | SET NULL [ ( $column_name$ [ , ... ] ) ] | SET DEFAULT [ ( $column_name$ [ , ... ] ) ] } diff --git a/testing/generation/command_docs/synopses/create_table_as.txt b/testing/generation/command_docs/synopses/create_table_as.txt new file mode 100644 index 0000000000..486eb8dc8b --- /dev/null +++ b/testing/generation/command_docs/synopses/create_table_as.txt @@ -0,0 +1,8 @@ +CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] $table_name$ + [ ($column_name$ [ , ... ] ) ] + [ USING $method$ ] + [ WITH ( $storage_parameter$ [= $value$] [ , ... ] ) | WITHOUT OIDS ] + [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] + [ TABLESPACE $tablespace_name$ ] + AS $query$ + [ WITH [ NO ] DATA ] diff --git a/testing/generation/command_docs/synopses/create_tablespace.txt b/testing/generation/command_docs/synopses/create_tablespace.txt new file mode 100644 index 0000000000..2f8975a25e --- /dev/null +++ b/testing/generation/command_docs/synopses/create_tablespace.txt @@ -0,0 +1,4 @@ +CREATE TABLESPACE $tablespace_name$ + [ OWNER { $new_owner$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } ] + LOCATION '$directory$' + [ WITH ( $tablespace_option$ = $value$ [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/create_text_search_configuration.txt b/testing/generation/command_docs/synopses/create_text_search_configuration.txt new file mode 100644 index 0000000000..b5d9fc8df4 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_text_search_configuration.txt @@ -0,0 +1,3 @@ +CREATE TEXT SEARCH CONFIGURATION $name$ ( + PARSER = $parser_name$ | + COPY = $source_config$ ) diff --git a/testing/generation/command_docs/synopses/create_text_search_dictionary.txt b/testing/generation/command_docs/synopses/create_text_search_dictionary.txt new file mode 100644 index 0000000000..3f167e1bf6 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_text_search_dictionary.txt @@ -0,0 +1,3 @@ +CREATE TEXT SEARCH DICTIONARY $name$ ( + TEMPLATE = $template$ + [, $option$ = $value$ [ , ... ]] ) diff --git a/testing/generation/command_docs/synopses/create_text_search_parser.txt b/testing/generation/command_docs/synopses/create_text_search_parser.txt new file mode 100644 index 0000000000..f74cc4ec67 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_text_search_parser.txt @@ -0,0 +1,6 @@ +CREATE TEXT SEARCH PARSER $name$ ( + START = $start_function$ , + GETTOKEN = $gettoken_function$ , + END = $end_function$ , + LEXTYPES = $lextypes_function$ + [, HEADLINE = $headline_function$ ] ) diff --git a/testing/generation/command_docs/synopses/create_text_search_template.txt b/testing/generation/command_docs/synopses/create_text_search_template.txt new file mode 100644 index 0000000000..1e90f28169 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_text_search_template.txt @@ -0,0 +1,3 @@ +CREATE TEXT SEARCH TEMPLATE $name$ ( + [ INIT = $init_function$ , ] + LEXIZE = $lexize_function$ ) diff --git a/testing/generation/command_docs/synopses/create_transform.txt b/testing/generation/command_docs/synopses/create_transform.txt new file mode 100644 index 0000000000..f3e3e605b0 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_transform.txt @@ -0,0 +1,3 @@ +CREATE [ OR REPLACE ] TRANSFORM FOR $type_name$ LANGUAGE $lang_name$ ( + FROM SQL WITH FUNCTION $from_sql_function_name$ [ ($argument_type$ [ , ... ]) ], + TO SQL WITH FUNCTION $to_sql_function_name$ [ ($argument_type$ [ , ... ]) ] ) diff --git a/testing/generation/command_docs/synopses/create_trigger.txt b/testing/generation/command_docs/synopses/create_trigger.txt new file mode 100644 index 0000000000..99578969be --- /dev/null +++ b/testing/generation/command_docs/synopses/create_trigger.txt @@ -0,0 +1,15 @@ +CREATE [ OR REPLACE ] [ CONSTRAINT ] TRIGGER $name$ { BEFORE | AFTER | INSTEAD OF } { $event$ [ OR ... ] } + ON $table_name$ + [ FROM $referenced_table_name$ ] + [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ] + [ REFERENCING { { OLD | NEW } TABLE [ AS ] $transition_relation_name$ } [ ... ] ] + [ FOR [ EACH ] { ROW | STATEMENT } ] + [ WHEN ( $condition$ ) ] + EXECUTE { FUNCTION | PROCEDURE } $function_name$ ( $arguments$ ) + +where $event$ is: + +INSERT | + UPDATE [ OF $column_name$ [ , ... ] ] | + DELETE | + TRUNCATE diff --git a/testing/generation/command_docs/synopses/create_type.txt b/testing/generation/command_docs/synopses/create_type.txt new file mode 100644 index 0000000000..d9f2da96e1 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_type.txt @@ -0,0 +1,36 @@ +CREATE TYPE $name$ AS + ( [ $attribute_name$ $data_type$ [ COLLATE $collation$ ] [ , ... ] ] ) + +CREATE TYPE $name$ AS ENUM + ( [ '$label$' [ , ... ] ] ) + +CREATE TYPE $name$ AS RANGE ( + SUBTYPE = $subtype$ + [ , SUBTYPE_OPCLASS = $subtype_operator_class$ ] + [ , COLLATION = $collation$ ] + [ , CANONICAL = $canonical_function$ ] + [ , SUBTYPE_DIFF = $subtype_diff_function$ ] + [ , MULTIRANGE_TYPE_NAME = $multirange_type_name$ ] ) + +CREATE TYPE $name$ ( + INPUT = $input_function$, + OUTPUT = $output_function$ + [ , RECEIVE = $receive_function$ ] + [ , SEND = $send_function$ ] + [ , TYPMOD_IN = $type_modifier_input_function$ ] + [ , TYPMOD_OUT = $type_modifier_output_function$ ] + [ , ANALYZE = $analyze_function$ ] + [ , SUBSCRIPT = $subscript_function$ ] + [ , INTERNALLENGTH = { $internallength$ | VARIABLE } ] + [ , PASSEDBYVALUE ] + [ , ALIGNMENT = $alignment$ ] + [ , STORAGE = $storage$ ] + [ , LIKE = $like_type$ ] + [ , CATEGORY = $category$ ] + [ , PREFERRED = $preferred$ ] + [ , DEFAULT = $default$ ] + [ , ELEMENT = $element$ ] + [ , DELIMITER = $delimiter$ ] + [ , COLLATABLE = $collatable$ ] ) + +CREATE TYPE $name$ diff --git a/testing/generation/command_docs/synopses/create_user.txt b/testing/generation/command_docs/synopses/create_user.txt new file mode 100644 index 0000000000..c5d66dcd2b --- /dev/null +++ b/testing/generation/command_docs/synopses/create_user.txt @@ -0,0 +1,20 @@ +CREATE USER $name$ [ [ WITH ] $option$ [ ... ] ] + +where $option$ is: + +SUPERUSER | NOSUPERUSER | + CREATEDB | NOCREATEDB | + CREATEROLE | NOCREATEROLE | + INHERIT | NOINHERIT | + LOGIN | NOLOGIN | + REPLICATION | NOREPLICATION | + BYPASSRLS | NOBYPASSRLS | + CONNECTION LIMIT $connlimit$ | + [ ENCRYPTED ] PASSWORD '$password$' | PASSWORD NULL | + VALID UNTIL '$timestamp$' | + IN ROLE $role_name$ [ , ... ] | + IN GROUP $role_name$ [ , ... ] | + ROLE $role_name$ [ , ... ] | + ADMIN $role_name$ [ , ... ] | + USER $role_name$ [ , ... ] | + SYSID $uid$ diff --git a/testing/generation/command_docs/synopses/create_user_mapping.txt b/testing/generation/command_docs/synopses/create_user_mapping.txt new file mode 100644 index 0000000000..52121755a8 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_user_mapping.txt @@ -0,0 +1,3 @@ +CREATE USER MAPPING [ IF NOT EXISTS ] FOR { $user_name$ | USER | CURRENT_ROLE | CURRENT_USER | PUBLIC } + SERVER $server_name$ + [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/create_view.txt b/testing/generation/command_docs/synopses/create_view.txt new file mode 100644 index 0000000000..3a55d6b3a8 --- /dev/null +++ b/testing/generation/command_docs/synopses/create_view.txt @@ -0,0 +1,4 @@ +CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW $name$ [ ( $column_name$ [ , ... ] ) ] + [ WITH ( $view_option_name$ [= $view_option_value$] [ , ... ] ) ] + AS $query$ + [ WITH [ CASCADED | LOCAL ] CHECK OPTION ] diff --git a/testing/generation/command_docs/synopses/deallocate.txt b/testing/generation/command_docs/synopses/deallocate.txt new file mode 100644 index 0000000000..dee6739329 --- /dev/null +++ b/testing/generation/command_docs/synopses/deallocate.txt @@ -0,0 +1 @@ +DEALLOCATE [ PREPARE ] { $name$ | ALL } diff --git a/testing/generation/command_docs/synopses/declare.txt b/testing/generation/command_docs/synopses/declare.txt new file mode 100644 index 0000000000..75b26f18e3 --- /dev/null +++ b/testing/generation/command_docs/synopses/declare.txt @@ -0,0 +1,2 @@ +DECLARE $name$ [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] + CURSOR [ { WITH | WITHOUT } HOLD ] FOR $query$ diff --git a/testing/generation/command_docs/synopses/delete.txt b/testing/generation/command_docs/synopses/delete.txt new file mode 100644 index 0000000000..60ff2a29de --- /dev/null +++ b/testing/generation/command_docs/synopses/delete.txt @@ -0,0 +1,4 @@ +[ WITH [ RECURSIVE ] $with_query$ [ , ... ] ] DELETE FROM [ ONLY ] $table_name$ [ * ] [ [ AS ] $alias$ ] + [ USING $from_item$ [ , ... ] ] + [ WHERE $condition$ | WHERE CURRENT OF $cursor_name$ ] + [ RETURNING * | $output_expression$ [ [ AS ] $output_name$ ] [ , ... ] ] diff --git a/testing/generation/command_docs/synopses/discard.txt b/testing/generation/command_docs/synopses/discard.txt new file mode 100644 index 0000000000..6cfbafba9e --- /dev/null +++ b/testing/generation/command_docs/synopses/discard.txt @@ -0,0 +1 @@ +DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP } diff --git a/testing/generation/command_docs/synopses/do.txt b/testing/generation/command_docs/synopses/do.txt new file mode 100644 index 0000000000..b264685436 --- /dev/null +++ b/testing/generation/command_docs/synopses/do.txt @@ -0,0 +1 @@ +DO [ LANGUAGE $lang_name$ ] $code$ diff --git a/testing/generation/command_docs/synopses/drop_access_method.txt b/testing/generation/command_docs/synopses/drop_access_method.txt new file mode 100644 index 0000000000..70624c5c85 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_access_method.txt @@ -0,0 +1 @@ +DROP ACCESS METHOD [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_aggregate.txt b/testing/generation/command_docs/synopses/drop_aggregate.txt new file mode 100644 index 0000000000..bfe9e7f64d --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_aggregate.txt @@ -0,0 +1,7 @@ +DROP AGGREGATE [ IF EXISTS ] $name$ ( $aggregate_signature$ ) [ , ... ] [ CASCADE | RESTRICT ] + +where $aggregate_signature$ is: + +* | + [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] | + [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ORDER BY [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/drop_cast.txt b/testing/generation/command_docs/synopses/drop_cast.txt new file mode 100644 index 0000000000..d58362ac02 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_cast.txt @@ -0,0 +1 @@ +DROP CAST [ IF EXISTS ] ($source_type$ AS $target_type$) [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_collation.txt b/testing/generation/command_docs/synopses/drop_collation.txt new file mode 100644 index 0000000000..4c2998a692 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_collation.txt @@ -0,0 +1 @@ +DROP COLLATION [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_conversion.txt b/testing/generation/command_docs/synopses/drop_conversion.txt new file mode 100644 index 0000000000..d63d71e1c2 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_conversion.txt @@ -0,0 +1 @@ +DROP CONVERSION [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_database.txt b/testing/generation/command_docs/synopses/drop_database.txt new file mode 100644 index 0000000000..c31e70cf40 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_database.txt @@ -0,0 +1,5 @@ +DROP DATABASE [ IF EXISTS ] $name$ [ [ WITH ] ( $option$ [ , ... ] ) ] + +where $option$ is: + +FORCE diff --git a/testing/generation/command_docs/synopses/drop_domain.txt b/testing/generation/command_docs/synopses/drop_domain.txt new file mode 100644 index 0000000000..c145e5b124 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_domain.txt @@ -0,0 +1 @@ +DROP DOMAIN [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_event_trigger.txt b/testing/generation/command_docs/synopses/drop_event_trigger.txt new file mode 100644 index 0000000000..8ee7347e6a --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_event_trigger.txt @@ -0,0 +1 @@ +DROP EVENT TRIGGER [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_extension.txt b/testing/generation/command_docs/synopses/drop_extension.txt new file mode 100644 index 0000000000..94a47cb227 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_extension.txt @@ -0,0 +1 @@ +DROP EXTENSION [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_foreign_data_wrapper.txt b/testing/generation/command_docs/synopses/drop_foreign_data_wrapper.txt new file mode 100644 index 0000000000..7d81e8202f --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_foreign_data_wrapper.txt @@ -0,0 +1 @@ +DROP FOREIGN DATA WRAPPER [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_foreign_table.txt b/testing/generation/command_docs/synopses/drop_foreign_table.txt new file mode 100644 index 0000000000..f0c2ae34e6 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_foreign_table.txt @@ -0,0 +1 @@ +DROP FOREIGN TABLE [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_function.txt b/testing/generation/command_docs/synopses/drop_function.txt new file mode 100644 index 0000000000..d44d0888bf --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_function.txt @@ -0,0 +1,2 @@ +DROP FUNCTION [ IF EXISTS ] $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] [ , ... ] + [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_group.txt b/testing/generation/command_docs/synopses/drop_group.txt new file mode 100644 index 0000000000..3842594ed3 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_group.txt @@ -0,0 +1 @@ +DROP GROUP [ IF EXISTS ] $name$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/drop_index.txt b/testing/generation/command_docs/synopses/drop_index.txt new file mode 100644 index 0000000000..7b4ecfad0d --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_index.txt @@ -0,0 +1 @@ +DROP INDEX [ CONCURRENTLY ] [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_language.txt b/testing/generation/command_docs/synopses/drop_language.txt new file mode 100644 index 0000000000..d625c75244 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_language.txt @@ -0,0 +1 @@ +DROP [ PROCEDURAL ] LANGUAGE [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_materialized_view.txt b/testing/generation/command_docs/synopses/drop_materialized_view.txt new file mode 100644 index 0000000000..1537c55da7 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_materialized_view.txt @@ -0,0 +1 @@ +DROP MATERIALIZED VIEW [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_operator.txt b/testing/generation/command_docs/synopses/drop_operator.txt new file mode 100644 index 0000000000..7bf65dd73e --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_operator.txt @@ -0,0 +1 @@ +DROP OPERATOR [ IF EXISTS ] $name$ ( { $left_type$ | NONE } , $right_type$ ) [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_operator_class.txt b/testing/generation/command_docs/synopses/drop_operator_class.txt new file mode 100644 index 0000000000..71f64da563 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_operator_class.txt @@ -0,0 +1 @@ +DROP OPERATOR CLASS [ IF EXISTS ] $name$ USING $index_method$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_operator_family.txt b/testing/generation/command_docs/synopses/drop_operator_family.txt new file mode 100644 index 0000000000..9e3671a2be --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_operator_family.txt @@ -0,0 +1 @@ +DROP OPERATOR FAMILY [ IF EXISTS ] $name$ USING $index_method$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_owned.txt b/testing/generation/command_docs/synopses/drop_owned.txt new file mode 100644 index 0000000000..54f5801e19 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_owned.txt @@ -0,0 +1 @@ +DROP OWNED BY { $name$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_policy.txt b/testing/generation/command_docs/synopses/drop_policy.txt new file mode 100644 index 0000000000..c2025b6e39 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_policy.txt @@ -0,0 +1 @@ +DROP POLICY [ IF EXISTS ] $name$ ON $table_name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_procedure.txt b/testing/generation/command_docs/synopses/drop_procedure.txt new file mode 100644 index 0000000000..c874c18152 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_procedure.txt @@ -0,0 +1,2 @@ +DROP PROCEDURE [ IF EXISTS ] $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] [ , ... ] + [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_publication.txt b/testing/generation/command_docs/synopses/drop_publication.txt new file mode 100644 index 0000000000..618a7baf7a --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_publication.txt @@ -0,0 +1 @@ +DROP PUBLICATION [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_role.txt b/testing/generation/command_docs/synopses/drop_role.txt new file mode 100644 index 0000000000..b6ce9ae2b3 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_role.txt @@ -0,0 +1 @@ +DROP ROLE [ IF EXISTS ] $name$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/drop_routine.txt b/testing/generation/command_docs/synopses/drop_routine.txt new file mode 100644 index 0000000000..cf34fe32e8 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_routine.txt @@ -0,0 +1,2 @@ +DROP ROUTINE [ IF EXISTS ] $name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] [ , ... ] + [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_rule.txt b/testing/generation/command_docs/synopses/drop_rule.txt new file mode 100644 index 0000000000..31a285c67d --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_rule.txt @@ -0,0 +1 @@ +DROP RULE [ IF EXISTS ] $name$ ON $table_name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_schema.txt b/testing/generation/command_docs/synopses/drop_schema.txt new file mode 100644 index 0000000000..0c7d4db4cf --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_schema.txt @@ -0,0 +1 @@ +DROP SCHEMA [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_sequence.txt b/testing/generation/command_docs/synopses/drop_sequence.txt new file mode 100644 index 0000000000..222ee86582 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_sequence.txt @@ -0,0 +1 @@ +DROP SEQUENCE [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_server.txt b/testing/generation/command_docs/synopses/drop_server.txt new file mode 100644 index 0000000000..fc5f016412 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_server.txt @@ -0,0 +1 @@ +DROP SERVER [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_statistics.txt b/testing/generation/command_docs/synopses/drop_statistics.txt new file mode 100644 index 0000000000..2dc72e1856 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_statistics.txt @@ -0,0 +1 @@ +DROP STATISTICS [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_subscription.txt b/testing/generation/command_docs/synopses/drop_subscription.txt new file mode 100644 index 0000000000..9ee0c96bdd --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_subscription.txt @@ -0,0 +1 @@ +DROP SUBSCRIPTION [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_table.txt b/testing/generation/command_docs/synopses/drop_table.txt new file mode 100644 index 0000000000..5e1e05b8c9 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_table.txt @@ -0,0 +1 @@ +DROP TABLE [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_tablespace.txt b/testing/generation/command_docs/synopses/drop_tablespace.txt new file mode 100644 index 0000000000..60f04a437a --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_tablespace.txt @@ -0,0 +1 @@ +DROP TABLESPACE [ IF EXISTS ] $name$ diff --git a/testing/generation/command_docs/synopses/drop_text_search_configuration.txt b/testing/generation/command_docs/synopses/drop_text_search_configuration.txt new file mode 100644 index 0000000000..aee77ef14e --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_text_search_configuration.txt @@ -0,0 +1 @@ +DROP TEXT SEARCH CONFIGURATION [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_text_search_dictionary.txt b/testing/generation/command_docs/synopses/drop_text_search_dictionary.txt new file mode 100644 index 0000000000..11a30e2872 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_text_search_dictionary.txt @@ -0,0 +1 @@ +DROP TEXT SEARCH DICTIONARY [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_text_search_parser.txt b/testing/generation/command_docs/synopses/drop_text_search_parser.txt new file mode 100644 index 0000000000..05c01d5574 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_text_search_parser.txt @@ -0,0 +1 @@ +DROP TEXT SEARCH PARSER [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_text_search_template.txt b/testing/generation/command_docs/synopses/drop_text_search_template.txt new file mode 100644 index 0000000000..4d1bd555be --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_text_search_template.txt @@ -0,0 +1 @@ +DROP TEXT SEARCH TEMPLATE [ IF EXISTS ] $name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_transform.txt b/testing/generation/command_docs/synopses/drop_transform.txt new file mode 100644 index 0000000000..4b9c03f6f8 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_transform.txt @@ -0,0 +1 @@ +DROP TRANSFORM [ IF EXISTS ] FOR $type_name$ LANGUAGE $lang_name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_trigger.txt b/testing/generation/command_docs/synopses/drop_trigger.txt new file mode 100644 index 0000000000..9ee21fc87b --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_trigger.txt @@ -0,0 +1 @@ +DROP TRIGGER [ IF EXISTS ] $name$ ON $table_name$ [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_type.txt b/testing/generation/command_docs/synopses/drop_type.txt new file mode 100644 index 0000000000..5c500c6b9c --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_type.txt @@ -0,0 +1 @@ +DROP TYPE [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/drop_user.txt b/testing/generation/command_docs/synopses/drop_user.txt new file mode 100644 index 0000000000..50cadfc691 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_user.txt @@ -0,0 +1 @@ +DROP USER [ IF EXISTS ] $name$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/drop_user_mapping.txt b/testing/generation/command_docs/synopses/drop_user_mapping.txt new file mode 100644 index 0000000000..7470e7f2d2 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_user_mapping.txt @@ -0,0 +1 @@ +DROP USER MAPPING [ IF EXISTS ] FOR { $user_name$ | USER | CURRENT_ROLE | CURRENT_USER | PUBLIC } SERVER $server_name$ diff --git a/testing/generation/command_docs/synopses/drop_view.txt b/testing/generation/command_docs/synopses/drop_view.txt new file mode 100644 index 0000000000..f4fc089be7 --- /dev/null +++ b/testing/generation/command_docs/synopses/drop_view.txt @@ -0,0 +1 @@ +DROP VIEW [ IF EXISTS ] $name$ [ , ... ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/end.txt b/testing/generation/command_docs/synopses/end.txt new file mode 100644 index 0000000000..4911f110c7 --- /dev/null +++ b/testing/generation/command_docs/synopses/end.txt @@ -0,0 +1 @@ +END [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] diff --git a/testing/generation/command_docs/synopses/execute.txt b/testing/generation/command_docs/synopses/execute.txt new file mode 100644 index 0000000000..d932b7ff9d --- /dev/null +++ b/testing/generation/command_docs/synopses/execute.txt @@ -0,0 +1 @@ +EXECUTE $name$ [ ( $parameter$ [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/explain.txt b/testing/generation/command_docs/synopses/explain.txt new file mode 100644 index 0000000000..c3fa460071 --- /dev/null +++ b/testing/generation/command_docs/synopses/explain.txt @@ -0,0 +1,15 @@ +EXPLAIN [ ( $option$ [ , ... ] ) ] $statement$ + +EXPLAIN [ ANALYZE ] [ VERBOSE ] $statement$ + +where $option$ is: + +ANALYZE [ $boolean$ ] | + VERBOSE [ $boolean$ ] | + COSTS [ $boolean$ ] | + SETTINGS [ $boolean$ ] | + BUFFERS [ $boolean$ ] | + WAL [ $boolean$ ] | + TIMING [ $boolean$ ] | + SUMMARY [ $boolean$ ] | + FORMAT { TEXT | XML | JSON | YAML } diff --git a/testing/generation/command_docs/synopses/fetch.txt b/testing/generation/command_docs/synopses/fetch.txt new file mode 100644 index 0000000000..5a6bdf8fde --- /dev/null +++ b/testing/generation/command_docs/synopses/fetch.txt @@ -0,0 +1,18 @@ +FETCH [ $direction$ ] [ FROM | IN ] $cursor_name$ + +where $direction$ is: + +NEXT | + PRIOR | + FIRST | + LAST | + ABSOLUTE $count$ | + RELATIVE $count$ | + $count$ | + ALL | + FORWARD | + FORWARD $count$ | + FORWARD ALL | + BACKWARD | + BACKWARD $count$ | + BACKWARD ALL diff --git a/testing/generation/command_docs/synopses/grant.txt b/testing/generation/command_docs/synopses/grant.txt new file mode 100644 index 0000000000..5c5d5d1930 --- /dev/null +++ b/testing/generation/command_docs/synopses/grant.txt @@ -0,0 +1,87 @@ +GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } + [ , ... ] | ALL [ PRIVILEGES ] } + ON { [ TABLE ] $table_name$ [ , ... ] + | ALL TABLES IN SCHEMA $schema_name$ [ , ... ] } + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { { SELECT | INSERT | UPDATE | REFERENCES } ( $column_name$ [ , ... ] ) + [ , ... ] | ALL [ PRIVILEGES ] ( $column_name$ [ , ... ] ) } + ON [ TABLE ] $table_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { { USAGE | SELECT | UPDATE } + [ , ... ] | ALL [ PRIVILEGES ] } + ON { SEQUENCE $sequence_name$ [ , ... ] + | ALL SEQUENCES IN SCHEMA $schema_name$ [ , ... ] } + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [ , ... ] | ALL [ PRIVILEGES ] } + ON DATABASE $database_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { USAGE | ALL [ PRIVILEGES ] } + ON DOMAIN $domain_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { USAGE | ALL [ PRIVILEGES ] } + ON FOREIGN DATA WRAPPER $fdw_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { USAGE | ALL [ PRIVILEGES ] } + ON FOREIGN SERVER $server_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { EXECUTE | ALL [ PRIVILEGES ] } + ON { { FUNCTION | PROCEDURE | ROUTINE } $routine_name$ [ ( [ [ $argmode$ ] [ $arg_name$ ] $arg_type$ [ , ... ] ] ) ] [ , ... ] + | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA $schema_name$ [ , ... ] } + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { USAGE | ALL [ PRIVILEGES ] } + ON LANGUAGE $lang_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { { SELECT | UPDATE } [ , ... ] | ALL [ PRIVILEGES ] } + ON LARGE OBJECT $loid$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { { SET | ALTER SYSTEM } [ , ... ] | ALL [ PRIVILEGES ] } + ON PARAMETER $configuration_parameter$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { { CREATE | USAGE } [ , ... ] | ALL [ PRIVILEGES ] } + ON SCHEMA $schema_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { CREATE | ALL [ PRIVILEGES ] } + ON TABLESPACE $tablespace_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT { USAGE | ALL [ PRIVILEGES ] } + ON TYPE $type_name$ [ , ... ] + TO $role_specification$ [ , ... ] [ WITH GRANT OPTION ] + [ GRANTED BY $role_specification$ ] + +GRANT $role_name$ [ , ... ] TO $role_specification$ [ , ... ] + [ WITH ADMIN OPTION ] + [ GRANTED BY $role_specification$ ] + +where $role_specification$ is: + +[ GROUP ] $role_name$ | + PUBLIC | + CURRENT_ROLE | + CURRENT_USER | + SESSION_USER diff --git a/testing/generation/command_docs/synopses/import_foreign_schema.txt b/testing/generation/command_docs/synopses/import_foreign_schema.txt new file mode 100644 index 0000000000..62c760f5bc --- /dev/null +++ b/testing/generation/command_docs/synopses/import_foreign_schema.txt @@ -0,0 +1,5 @@ +IMPORT FOREIGN SCHEMA $remote_schema$ + [ { LIMIT TO | EXCEPT } ( $table_name$ [ , ... ] ) ] + FROM SERVER $server_name$ + INTO $local_schema$ + [ OPTIONS ( $option$ '$value$' [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/insert.txt b/testing/generation/command_docs/synopses/insert.txt new file mode 100644 index 0000000000..0368fcf049 --- /dev/null +++ b/testing/generation/command_docs/synopses/insert.txt @@ -0,0 +1,19 @@ +[ WITH [ RECURSIVE ] $with_query$ [ , ... ] ] INSERT INTO $table_name$ [ AS $alias$ ] [ ( $column_name$ [ , ... ] ) ] + [ OVERRIDING { SYSTEM | USER } VALUE ] + { DEFAULT VALUES | VALUES ( { $expression$ | DEFAULT } [ , ... ] ) [ , ... ] | $query$ } + [ ON CONFLICT [ $conflict_target$ ] $conflict_action$ ] + [ RETURNING * | $output_expression$ [ [ AS ] $output_name$ ] [ , ... ] ] + +where $conflict_target$ is: + +( { $index_column_name$ | ( $index_expression$ ) } [ COLLATE $collation$ ] [ $opclass$ ] [ , ... ] ) [ WHERE $index_predicate$ ] | + ON CONSTRAINT $constraint_name$ + +where $conflict_action$ is: + +DO NOTHING | + DO UPDATE SET { $column_name$ = { $expression$ | DEFAULT } | + ( $column_name$ [ , ... ] ) = [ ROW ] ( { $expression$ | DEFAULT } [ , ... ] ) | + ( $column_name$ [ , ... ] ) = ( $sub-SELECT$ ) + } [ , ... ] | + [ WHERE $condition$ ] diff --git a/testing/generation/command_docs/synopses/listen.txt b/testing/generation/command_docs/synopses/listen.txt new file mode 100644 index 0000000000..0c05e620f6 --- /dev/null +++ b/testing/generation/command_docs/synopses/listen.txt @@ -0,0 +1 @@ +LISTEN $channel$ diff --git a/testing/generation/command_docs/synopses/load.txt b/testing/generation/command_docs/synopses/load.txt new file mode 100644 index 0000000000..bea6d99bda --- /dev/null +++ b/testing/generation/command_docs/synopses/load.txt @@ -0,0 +1 @@ +LOAD '$filename$' diff --git a/testing/generation/command_docs/synopses/lock.txt b/testing/generation/command_docs/synopses/lock.txt new file mode 100644 index 0000000000..94c4c4479e --- /dev/null +++ b/testing/generation/command_docs/synopses/lock.txt @@ -0,0 +1,12 @@ +LOCK [ TABLE ] [ ONLY ] $name$ [ * ] [ , ... ] [ IN $lockmode$ MODE ] [ NOWAIT ] + +where $lockmode$ is: + +ACCESS SHARE | + ROW SHARE | + ROW EXCLUSIVE | + SHARE UPDATE EXCLUSIVE | + SHARE | + SHARE ROW EXCLUSIVE | + EXCLUSIVE | + ACCESS EXCLUSIVE diff --git a/testing/generation/command_docs/synopses/merge.txt b/testing/generation/command_docs/synopses/merge.txt new file mode 100644 index 0000000000..b37e6d404f --- /dev/null +++ b/testing/generation/command_docs/synopses/merge.txt @@ -0,0 +1,27 @@ +[ WITH $with_query$ [ , ... ] ] MERGE INTO [ ONLY ] $target_table_name$ [ * ] [ [ AS ] $target_alias$ ] + USING $data_source$ ON $join_condition$ + $when_clause$ [ ... ] + +where $data_source$ is: + +{ [ ONLY ] $source_table_name$ [ * ] | ( $source_query$ ) } [ [ AS ] $source_alias$ ] + +where $when_clause$ is: + +{ WHEN MATCHED [ AND $condition$ ] THEN { $merge_update$ | $merge_delete$ | DO NOTHING } | + WHEN NOT MATCHED [ AND $condition$ ] THEN { $merge_insert$ | DO NOTHING } } + +where $merge_insert$ is: + +INSERT [( $column_name$ [ , ... ] )] + [ OVERRIDING { SYSTEM | USER } VALUE ] + { VALUES ( { $expression$ | DEFAULT } [ , ... ] ) | DEFAULT VALUES } + +where $merge_update$ is: + +UPDATE SET { $column_name$ = { $expression$ | DEFAULT } | + ( $column_name$ [ , ... ] ) = ( { $expression$ | DEFAULT } [ , ... ] ) } [ , ... ] + +where $merge_delete$ is: + +DELETE diff --git a/testing/generation/command_docs/synopses/move.txt b/testing/generation/command_docs/synopses/move.txt new file mode 100644 index 0000000000..2742cfcb1d --- /dev/null +++ b/testing/generation/command_docs/synopses/move.txt @@ -0,0 +1,18 @@ +MOVE [ $direction$ ] [ FROM | IN ] $cursor_name$ + +where $direction$ is: + +NEXT + PRIOR | + FIRST | + LAST | + ABSOLUTE $count$ | + RELATIVE $count$ | + $count$ | + ALL | + FORWARD | + FORWARD $count$ | + FORWARD ALL | + BACKWARD | + BACKWARD $count$ | + BACKWARD ALL diff --git a/testing/generation/command_docs/synopses/notify.txt b/testing/generation/command_docs/synopses/notify.txt new file mode 100644 index 0000000000..719882c9fa --- /dev/null +++ b/testing/generation/command_docs/synopses/notify.txt @@ -0,0 +1 @@ +NOTIFY $channel$ [ , $payload$ ] diff --git a/testing/generation/command_docs/synopses/prepare.txt b/testing/generation/command_docs/synopses/prepare.txt new file mode 100644 index 0000000000..1306e76e77 --- /dev/null +++ b/testing/generation/command_docs/synopses/prepare.txt @@ -0,0 +1 @@ +PREPARE $name$ [ ( $data_type$ [ , ... ] ) ] AS $statement$ diff --git a/testing/generation/command_docs/synopses/prepare_transaction.txt b/testing/generation/command_docs/synopses/prepare_transaction.txt new file mode 100644 index 0000000000..68bc18ecb8 --- /dev/null +++ b/testing/generation/command_docs/synopses/prepare_transaction.txt @@ -0,0 +1 @@ +PREPARE TRANSACTION $transaction_id$ diff --git a/testing/generation/command_docs/synopses/reassign_owned.txt b/testing/generation/command_docs/synopses/reassign_owned.txt new file mode 100644 index 0000000000..234cf3984a --- /dev/null +++ b/testing/generation/command_docs/synopses/reassign_owned.txt @@ -0,0 +1,2 @@ +REASSIGN OWNED BY { $old_role$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [ , ... ] + TO { $new_role$ | CURRENT_ROLE | CURRENT_USER | SESSION_USER } diff --git a/testing/generation/command_docs/synopses/refresh_materialized_view.txt b/testing/generation/command_docs/synopses/refresh_materialized_view.txt new file mode 100644 index 0000000000..b7f18a6504 --- /dev/null +++ b/testing/generation/command_docs/synopses/refresh_materialized_view.txt @@ -0,0 +1,2 @@ +REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] $name$ + [ WITH [ NO ] DATA ] diff --git a/testing/generation/command_docs/synopses/reindex.txt b/testing/generation/command_docs/synopses/reindex.txt new file mode 100644 index 0000000000..c8162c39cc --- /dev/null +++ b/testing/generation/command_docs/synopses/reindex.txt @@ -0,0 +1,7 @@ +REINDEX [ ( $option$ [ , ... ] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] $name$ + +where $option$ is: + +CONCURRENTLY [ $boolean$ ] | + TABLESPACE $new_tablespace$ | + VERBOSE [ $boolean$ ] diff --git a/testing/generation/command_docs/synopses/release_savepoint.txt b/testing/generation/command_docs/synopses/release_savepoint.txt new file mode 100644 index 0000000000..71ba1a3c4d --- /dev/null +++ b/testing/generation/command_docs/synopses/release_savepoint.txt @@ -0,0 +1 @@ +RELEASE [ SAVEPOINT ] $savepoint_name$ diff --git a/testing/generation/command_docs/synopses/reset.txt b/testing/generation/command_docs/synopses/reset.txt new file mode 100644 index 0000000000..eddc2b9db5 --- /dev/null +++ b/testing/generation/command_docs/synopses/reset.txt @@ -0,0 +1,3 @@ +RESET $configuration_parameter$ + +RESET ALL diff --git a/testing/generation/command_docs/synopses/revoke.txt b/testing/generation/command_docs/synopses/revoke.txt new file mode 100644 index 0000000000..a04d32465c --- /dev/null +++ b/testing/generation/command_docs/synopses/revoke.txt @@ -0,0 +1,116 @@ +REVOKE [ GRANT OPTION FOR ] + { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } + [ , ... ] | ALL [ PRIVILEGES ] } + ON { [ TABLE ] $table_name$ [ , ... ] + | ALL TABLES IN SCHEMA $schema_name$ [ , ... ] } + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { SELECT | INSERT | UPDATE | REFERENCES } ( $column_name$ [ , ... ] ) + [ , ... ] | ALL [ PRIVILEGES ] ( $column_name$ [ , ... ] ) } + ON [ TABLE ] $table_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { USAGE | SELECT | UPDATE } + [ , ... ] | ALL [ PRIVILEGES ] } + ON { SEQUENCE $sequence_name$ [ , ... ] + | ALL SEQUENCES IN SCHEMA $schema_name$ [ , ... ] } + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { CREATE | CONNECT | TEMPORARY | TEMP } [ , ... ] | ALL [ PRIVILEGES ] } + ON DATABASE $database_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON DOMAIN $domain_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON FOREIGN DATA WRAPPER $fdw_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON FOREIGN SERVER $server_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { EXECUTE | ALL [ PRIVILEGES ] } + ON { { FUNCTION | PROCEDURE | ROUTINE } $function_name$ [ ( [ [ $argmode$ ] [ $arg_name$ ] $arg_type$ [ , ... ] ] ) ] [ , ... ] + | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA $schema_name$ [ , ... ] } + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON LANGUAGE $lang_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { SELECT | UPDATE } [ , ... ] | ALL [ PRIVILEGES ] } + ON LARGE OBJECT $loid$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { SET | ALTER SYSTEM } [ , ... ] | ALL [ PRIVILEGES ] } + ON PARAMETER $configuration_parameter$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { CREATE | USAGE } [ , ... ] | ALL [ PRIVILEGES ] } + ON SCHEMA $schema_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { CREATE | ALL [ PRIVILEGES ] } + ON TABLESPACE $tablespace_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON TYPE $type_name$ [ , ... ] + FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +REVOKE [ ADMIN OPTION FOR ] + $role_name$ [ , ... ] FROM $role_specification$ [ , ... ] + [ GRANTED BY $role_specification$ ] + [ CASCADE | RESTRICT ] + +where $role_specification$ is: + +[ GROUP ] $role_name$ | + PUBLIC | + CURRENT_ROLE | + CURRENT_USER | + SESSION_USER diff --git a/testing/generation/command_docs/synopses/rollback.txt b/testing/generation/command_docs/synopses/rollback.txt new file mode 100644 index 0000000000..7fde720b82 --- /dev/null +++ b/testing/generation/command_docs/synopses/rollback.txt @@ -0,0 +1 @@ +ROLLBACK [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ] diff --git a/testing/generation/command_docs/synopses/rollback_prepared.txt b/testing/generation/command_docs/synopses/rollback_prepared.txt new file mode 100644 index 0000000000..c1fd2a2cd5 --- /dev/null +++ b/testing/generation/command_docs/synopses/rollback_prepared.txt @@ -0,0 +1 @@ +ROLLBACK PREPARED $transaction_id$ diff --git a/testing/generation/command_docs/synopses/rollback_to_savepoint.txt b/testing/generation/command_docs/synopses/rollback_to_savepoint.txt new file mode 100644 index 0000000000..8aa9587208 --- /dev/null +++ b/testing/generation/command_docs/synopses/rollback_to_savepoint.txt @@ -0,0 +1 @@ +ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] $savepoint_name$ diff --git a/testing/generation/command_docs/synopses/savepoint.txt b/testing/generation/command_docs/synopses/savepoint.txt new file mode 100644 index 0000000000..a1c8ce838b --- /dev/null +++ b/testing/generation/command_docs/synopses/savepoint.txt @@ -0,0 +1 @@ +SAVEPOINT $savepoint_name$ diff --git a/testing/generation/command_docs/synopses/security_label.txt b/testing/generation/command_docs/synopses/security_label.txt new file mode 100644 index 0000000000..9e3fa1c661 --- /dev/null +++ b/testing/generation/command_docs/synopses/security_label.txt @@ -0,0 +1,28 @@ +SECURITY LABEL [ FOR $provider$ ] ON { + TABLE $object_name$ | + COLUMN $table_name$.$column_name$ | + AGGREGATE $aggregate_name$ ( $aggregate_signature$ ) | + DATABASE $object_name$ | + DOMAIN $object_name$ | + EVENT TRIGGER $object_name$ | + FOREIGN TABLE $object_name$ + FUNCTION $function_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + LARGE OBJECT $large_object_oid$ | + MATERIALIZED VIEW $object_name$ | + [ PROCEDURAL ] LANGUAGE $object_name$ | + PROCEDURE $procedure_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + PUBLICATION $object_name$ | + ROLE $object_name$ | + ROUTINE $routine_name$ [ ( [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ) ] | + SCHEMA $object_name$ | + SEQUENCE $object_name$ | + SUBSCRIPTION $object_name$ | + TABLESPACE $object_name$ | + TYPE $object_name$ | + VIEW $object_name$ } IS { $string_literal$ | NULL } + +where $aggregate_signature$ is: + +* | + [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] | + [ [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] ] ORDER BY [ $argmode$ ] [ $argname$ ] $argtype$ [ , ... ] diff --git a/testing/generation/command_docs/synopses/select.txt b/testing/generation/command_docs/synopses/select.txt new file mode 100644 index 0000000000..dc875b272f --- /dev/null +++ b/testing/generation/command_docs/synopses/select.txt @@ -0,0 +1,46 @@ +[ WITH [ RECURSIVE ] $with_query$ [ , ... ] ] SELECT [ ALL | DISTINCT [ ON ( $expression$ [ , ... ] ) ] ] + [ * | $expression$ [ [ AS ] $output_name$ ] [ , ... ] ] + [ FROM $from_item$ [ , ... ] ] + [ WHERE $condition$ ] + [ GROUP BY [ ALL | DISTINCT ] $grouping_element$ [ , ... ] ] + [ HAVING $condition$ ] + [ WINDOW $window_name$ AS ( $window_definition$ ) [ , ... ] ] + [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] $select$ ] + [ ORDER BY $expression$ [ ASC | DESC | USING $operator$ ] [ NULLS { FIRST | LAST } ] [ , ... ] ] + [ LIMIT { $count$ | ALL } ] + [ OFFSET $start$ [ ROW | ROWS ] ] + [ FETCH { FIRST | NEXT } [ $count$ ] { ROW | ROWS } { ONLY | WITH TIES } ] + [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF $table_name$ [ , ... ] ] [ NOWAIT | SKIP LOCKED ] [ ... ] ] + +TABLE [ ONLY ] $table_name$ [ * ] + +where $from_item$ is: + +[ ONLY ] $table_name$ [ * ] [ [ AS ] $alias$ [ ( $column_alias$ [ , ... ] ) ] ] + [ TABLESAMPLE $sampling_method$ ( $argument$ [ , ... ] ) [ REPEATABLE ( $seed$ ) ] ] | + [ LATERAL ] ( $select$ ) [ AS ] $alias$ [ ( $column_alias$ [ , ... ] ) ] | + $with_query_name$ [ [ AS ] $alias$ [ ( $column_alias$ [ , ... ] ) ] ] | + [ LATERAL ] $function_name$ ( [ $argument$ [ , ... ] ] ) + [ WITH ORDINALITY ] [ [ AS ] $alias$ [ ( $column_alias$ [ , ... ] ) ] ] | + [ LATERAL ] $function_name$ ( [ $argument$ [ , ... ] ] ) [ AS ] $alias$ ( $column_definition$ [ , ... ] ) | + [ LATERAL ] $function_name$ ( [ $argument$ [ , ... ] ] ) AS ( $column_definition$ [ , ... ] ) | + [ LATERAL ] ROWS FROM( $function_name$ ( [ $argument$ [ , ... ] ] ) [ AS ( $column_definition$ [ , ... ] ) ] [ , ... ] ) + [ WITH ORDINALITY ] [ [ AS ] $alias$ [ ( $column_alias$ [ , ... ] ) ] ] | + $from_item$ $join_type$ $from_item$ { ON $join_condition$ | USING ( $join_column$ [ , ... ] ) [ AS $join_using_alias$ ] } | + $from_item$ NATURAL $join_type$ $from_item$ | + $from_item$ CROSS JOIN $from_item$ + +where $grouping_element$ is: + +( ) | + $expression$ | + ( $expression$ [ , ... ] ) | + ROLLUP ( { $expression$ | ( $expression$ [ , ... ] ) } [ , ... ] ) | + CUBE ( { $expression$ | ( $expression$ [ , ... ] ) } [ , ... ] ) | + GROUPING SETS ( $grouping_element$ [ , ... ] ) + +where $with_query$ is: + +$with_query_name$ [ ( $column_name$ [ , ... ] ) ] AS [ [ NOT ] MATERIALIZED ] ( $select$ | $values$ | $insert$ | $update$ | $delete$ ) + [ SEARCH { BREADTH | DEPTH } FIRST BY $column_name$ [ , ... ] SET $search_seq_col_name$ ] + [ CYCLE $column_name$ [ , ... ] SET $cycle_mark_col_name$ [ TO $cycle_mark_value$ DEFAULT $cycle_mark_default$ ] USING $cycle_path_col_name$ ] diff --git a/testing/generation/command_docs/synopses/select_into.txt b/testing/generation/command_docs/synopses/select_into.txt new file mode 100644 index 0000000000..e6f63b110d --- /dev/null +++ b/testing/generation/command_docs/synopses/select_into.txt @@ -0,0 +1,14 @@ +[ WITH [ RECURSIVE ] $with_query$ [ , ... ] ] SELECT [ ALL | DISTINCT [ ON ( $expression$ [ , ... ] ) ] ] + * | $expression$ [ [ AS ] $output_name$ ] [ , ... ] + INTO [ TEMPORARY | TEMP | UNLOGGED ] [ TABLE ] $new_table$ + [ FROM $from_item$ [ , ... ] ] + [ WHERE $condition$ ] + [ GROUP BY $expression$ [ , ... ] ] + [ HAVING $condition$ ] + [ WINDOW $window_name$ AS ( $window_definition$ ) [ , ... ] ] + [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] $select$ ] + [ ORDER BY $expression$ [ ASC | DESC | USING $operator$ ] [ NULLS { FIRST | LAST } ] [ , ... ] ] + [ LIMIT { $count$ | ALL } ] + [ OFFSET $start$ [ ROW | ROWS ] ] + [ FETCH { FIRST | NEXT } [ $count$ ] { ROW | ROWS } ONLY ] + [ FOR { UPDATE | SHARE } [ OF $table_name$ [ , ... ] ] [ NOWAIT ] [ ... ] ] diff --git a/testing/generation/command_docs/synopses/set.txt b/testing/generation/command_docs/synopses/set.txt new file mode 100644 index 0000000000..288bbf938c --- /dev/null +++ b/testing/generation/command_docs/synopses/set.txt @@ -0,0 +1,3 @@ +SET [ SESSION | LOCAL ] $configuration_parameter$ { TO | = } { $value$ | '$value$' | DEFAULT } + +SET [ SESSION | LOCAL ] TIME ZONE { $value$ | '$value$' | LOCAL | DEFAULT } diff --git a/testing/generation/command_docs/synopses/set_constraints.txt b/testing/generation/command_docs/synopses/set_constraints.txt new file mode 100644 index 0000000000..5d5be0998e --- /dev/null +++ b/testing/generation/command_docs/synopses/set_constraints.txt @@ -0,0 +1 @@ +SET CONSTRAINTS { ALL | $name$ [ , ... ] } { DEFERRED | IMMEDIATE } diff --git a/testing/generation/command_docs/synopses/set_role.txt b/testing/generation/command_docs/synopses/set_role.txt new file mode 100644 index 0000000000..8aa1b7aaf5 --- /dev/null +++ b/testing/generation/command_docs/synopses/set_role.txt @@ -0,0 +1,5 @@ +SET [ SESSION | LOCAL ] ROLE $role_name$ + +SET [ SESSION | LOCAL ] ROLE NONE + +RESET ROLE diff --git a/testing/generation/command_docs/synopses/set_session_authorization.txt b/testing/generation/command_docs/synopses/set_session_authorization.txt new file mode 100644 index 0000000000..8e452ab036 --- /dev/null +++ b/testing/generation/command_docs/synopses/set_session_authorization.txt @@ -0,0 +1,5 @@ +SET [ SESSION | LOCAL ] SESSION AUTHORIZATION $user_name$ + +SET [ SESSION | LOCAL ] SESSION AUTHORIZATION DEFAULT + +RESET SESSION AUTHORIZATION diff --git a/testing/generation/command_docs/synopses/set_transaction.txt b/testing/generation/command_docs/synopses/set_transaction.txt new file mode 100644 index 0000000000..0e0d152d5b --- /dev/null +++ b/testing/generation/command_docs/synopses/set_transaction.txt @@ -0,0 +1,11 @@ +SET TRANSACTION $transaction_mode$ [ , ... ] + +SET TRANSACTION SNAPSHOT $snapshot_id$ + +SET SESSION CHARACTERISTICS AS TRANSACTION $transaction_mode$ [ , ... ] + +where $transaction_mode$ is: + +ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED } | + READ WRITE | READ ONLY | + [ NOT ] DEFERRABLE diff --git a/testing/generation/command_docs/synopses/show.txt b/testing/generation/command_docs/synopses/show.txt new file mode 100644 index 0000000000..46892ad2c9 --- /dev/null +++ b/testing/generation/command_docs/synopses/show.txt @@ -0,0 +1,12 @@ +SHOW $name$ + +SHOW ALL + +where $name$ is: + +SERVER_VERSION | + SERVER_ENCODING | + LC_COLLATE | + LC_CTYPE | + IS_SUPERUSER | + DateStyle diff --git a/testing/generation/command_docs/synopses/start_transaction.txt b/testing/generation/command_docs/synopses/start_transaction.txt new file mode 100644 index 0000000000..681dcd224a --- /dev/null +++ b/testing/generation/command_docs/synopses/start_transaction.txt @@ -0,0 +1,8 @@ +START TRANSACTION [ $transaction_mode$ [ , ... ] ] + +where $transaction_mode$ is: + +ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED } | + READ WRITE | + READ ONLY | + [ NOT ] DEFERRABLE diff --git a/testing/generation/command_docs/synopses/truncate.txt b/testing/generation/command_docs/synopses/truncate.txt new file mode 100644 index 0000000000..9873835187 --- /dev/null +++ b/testing/generation/command_docs/synopses/truncate.txt @@ -0,0 +1,2 @@ +TRUNCATE [ TABLE ] [ ONLY ] $name$ [ * ] [ , ... ] + [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ] diff --git a/testing/generation/command_docs/synopses/unlisten.txt b/testing/generation/command_docs/synopses/unlisten.txt new file mode 100644 index 0000000000..211ebf06a3 --- /dev/null +++ b/testing/generation/command_docs/synopses/unlisten.txt @@ -0,0 +1 @@ +UNLISTEN { $channel$ | * } diff --git a/testing/generation/command_docs/synopses/update.txt b/testing/generation/command_docs/synopses/update.txt new file mode 100644 index 0000000000..958d0ed01b --- /dev/null +++ b/testing/generation/command_docs/synopses/update.txt @@ -0,0 +1,8 @@ +[ WITH [ RECURSIVE ] $with_query$ [ , ... ] ] UPDATE [ ONLY ] $table_name$ [ * ] [ [ AS ] $alias$ ] + SET { $column_name$ = { $expression$ | DEFAULT } | + ( $column_name$ [ , ... ] ) = [ ROW ] ( { $expression$ | DEFAULT } [ , ... ] ) | + ( $column_name$ [ , ... ] ) = ( $sub-SELECT$ ) + } [ , ... ] + [ FROM $from_item$ [ , ... ] ] + [ WHERE $condition$ | WHERE CURRENT OF $cursor_name$ ] + [ RETURNING * | $output_expression$ [ [ AS ] $output_name$ ] [ , ... ] ] diff --git a/testing/generation/command_docs/synopses/vacuum.txt b/testing/generation/command_docs/synopses/vacuum.txt new file mode 100644 index 0000000000..9d8a8ebcea --- /dev/null +++ b/testing/generation/command_docs/synopses/vacuum.txt @@ -0,0 +1,20 @@ +VACUUM [ ( $option$ [ , ... ] ) ] [ $table_and_columns$ [ , ... ] ] + +VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ $table_and_columns$ [ , ... ] ] + +where $option$ is: + +FULL [ $boolean$ ] | + FREEZE [ $boolean$ ] | + VERBOSE [ $boolean$ ] | + ANALYZE [ $boolean$ ] | + DISABLE_PAGE_SKIPPING [ $boolean$ ] | + SKIP_LOCKED [ $boolean$ ] | + INDEX_CLEANUP { AUTO | ON | OFF } | + PROCESS_TOAST [ $boolean$ ] | + TRUNCATE [ $boolean$ ] | + PARALLEL $integer$ + +where $table_and_columns$ is: + +$table_name$ [ ( $column_name$ [ , ... ] ) ] diff --git a/testing/generation/command_docs/synopses/values.txt b/testing/generation/command_docs/synopses/values.txt new file mode 100644 index 0000000000..f62f730b7b --- /dev/null +++ b/testing/generation/command_docs/synopses/values.txt @@ -0,0 +1,5 @@ +VALUES ( $expression$ [ , ... ] ) [ , ... ] + [ ORDER BY $sort_expression$ [ ASC | DESC | USING $operator$ ] [ , ... ] ] + [ LIMIT { $count$ | ALL } ] + [ OFFSET $start$ [ ROW | ROWS ] ] + [ FETCH { FIRST | NEXT } [ $count$ ] { ROW | ROWS } ONLY ] diff --git a/testing/generation/command_docs/token.go b/testing/generation/command_docs/token.go new file mode 100644 index 0000000000..4bd94d6dbd --- /dev/null +++ b/testing/generation/command_docs/token.go @@ -0,0 +1,115 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// TokenType is the type of the token. +type TokenType uint8 + +const ( + TokenType_Text TokenType = iota + TokenType_Variable + TokenType_VariableDefinition + TokenType_Or + TokenType_Repeat + TokenType_CommaRepeat + TokenType_OptionalRepeat + TokenType_OptionalCommaRepeat + TokenType_ShortSpace + TokenType_MediumSpace + TokenType_LongSpace + TokenType_ParenOpen + TokenType_ParenClose + TokenType_OptionalOpen + TokenType_OptionalClose + TokenType_OneOfOpen + TokenType_OneOfClose + TokenType_EOF +) + +// Token represents a token in the synopsis. Unlike with traditional lexers, whitespace is tokenized, with multiple +// token types for differing lengths, as the whitespace has some significance to the definition. +type Token struct { + Type TokenType + Literal string +} + +// IsSpace returns whether the token represents one of the space types. +func (t Token) IsSpace() bool { + return t.Type == TokenType_ShortSpace || t.Type == TokenType_MediumSpace || t.Type == TokenType_LongSpace +} + +// IsStandardSpace returns whether the token represents a short or medium space, which will not end a statement. +func (t Token) IsStandardSpace() bool { + return t.Type == TokenType_ShortSpace || t.Type == TokenType_MediumSpace +} + +// IsNewStatement returns whether the token represents one a long space, which will end a statement +func (t Token) IsNewStatement() bool { + return t.Type == TokenType_LongSpace +} + +// CreatesNewScope returns whether the token creates a new scope. +func (t Token) CreatesNewScope() bool { + return t.Type == TokenType_ParenOpen || t.Type == TokenType_OptionalOpen || t.Type == TokenType_OneOfOpen +} + +// ExitsScope returns whether the token exits the current scope. +func (t Token) ExitsScope() bool { + return t.Type == TokenType_ParenClose || t.Type == TokenType_OptionalClose || t.Type == TokenType_OneOfClose +} + +// String returns a string representation of the token. +func (t Token) String() string { + switch t.Type { + case TokenType_Text: + return t.Literal + case TokenType_Variable: + return "$" + t.Literal + "$" + case TokenType_VariableDefinition: + return "where $" + t.Literal + "$ is:" + case TokenType_Or: + return "|" + case TokenType_Repeat: + return "..." + case TokenType_CommaRepeat: + return ", ..." + case TokenType_OptionalRepeat: + return "[ ... ]" + case TokenType_OptionalCommaRepeat: + return "[ , ... ]" + case TokenType_ShortSpace: + return " " + case TokenType_MediumSpace: + return "\n " + case TokenType_LongSpace: + return "\n\n" + case TokenType_ParenOpen: + return "(" + case TokenType_ParenClose: + return ")" + case TokenType_OptionalOpen: + return "[" + case TokenType_OptionalClose: + return "]" + case TokenType_OneOfOpen: + return "{" + case TokenType_OneOfClose: + return "}" + case TokenType_EOF: + return "" + default: + panic("unexpected token type") + } +} diff --git a/testing/generation/command_docs/token_reader.go b/testing/generation/command_docs/token_reader.go new file mode 100644 index 0000000000..33012f6096 --- /dev/null +++ b/testing/generation/command_docs/token_reader.go @@ -0,0 +1,80 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// TokenReader may be used to easily read through a collection of tokens generated from a synopsis. Of note, a +// TokenReader will skip all short and medium spaces, as clients of a reader will only care about statement boundaries. +type TokenReader struct { + tokens []Token + index int +} + +// NewTokenReader returns a new *TokenReader created from the given tokens. +func NewTokenReader(tokens []Token) *TokenReader { + sanitizedTokens := make([]Token, 0, len(tokens)) + for _, token := range tokens { + if token.IsStandardSpace() { + continue + } + sanitizedTokens = append(sanitizedTokens, token) + } + return &TokenReader{ + tokens: sanitizedTokens, + index: -1, + } +} + +// Next returns the next token while advancing the reader. Returns false if there are no more tokens. +func (reader *TokenReader) Next() (Token, bool) { + if reader.index+1 >= len(reader.tokens) { + return Token{}, false + } + reader.index++ + return reader.tokens[reader.index], true +} + +// Peek returns the next token. Does not advance the reader. Returns false if there are no more tokens. +func (reader *TokenReader) Peek() (Token, bool) { + if reader.index+1 >= len(reader.tokens) { + return Token{}, false + } + return reader.tokens[reader.index+1], true +} + +// PeekBy returns the next token that is n positions from the current token. Does not advance the reader. Returns false +// if we are peeking beyond the slice. +func (reader *TokenReader) PeekBy(n int) (Token, bool) { + if reader.index+n >= len(reader.tokens) || reader.index+n < 0 { + return Token{}, false + } + return reader.tokens[reader.index+n], true +} + +// Advance is equivalent to calling AdvanceBy(1). +func (reader *TokenReader) Advance() { + reader.AdvanceBy(1) +} + +// AdvanceBy advances the reader by the given amount. If the amount is greater than the number of remaining tokens, then +// it advances to the end. Cannot advance backwards. +func (reader *TokenReader) AdvanceBy(n int) { + if n < 0 { + n = 0 + } + if reader.index+n >= len(reader.tokens) { + n = len(reader.tokens) - reader.index - 1 + } + reader.index += n +}