Permalink
Switch branches/tags
v2.2.0-alpha.00000000 v2.1.0-beta.20181015 v2.1.0-beta.20181008 v2.1.0-beta.20181001 v2.1.0-beta.20180924 v2.1.0-beta.20180917 v2.1.0-beta.20180910 v2.1.0-beta.20180904 v2.1.0-beta.20180827 v2.1.0-alpha.20180730 v2.1.0-alpha.20180702 v2.1.0-alpha.20180604 v2.1.0-alpha.20180507 v2.1.0-alpha.20180416 v2.1.0-alpha.00000000 v2.0.6 v2.0.6-rc.1 v2.0.5 v2.0.4 v2.0.3 v2.0.2 v2.0.1 v2.0.0 v2.0-rc.1 v2.0-beta.20180326 v2.0-beta.20180319 v2.0-beta.20180312 v2.0-beta.20180305 v2.0-alpha.20180212 v2.0-alpha.20180129 v2.0-alpha.20180122 v2.0-alpha.20180116 v2.0-alpha.20171218 v2.0-alpha.20171218-plus-left-join-fix v1.2-alpha.20171211 v1.2-alpha.20171204 v1.2-alpha.20171113 v1.2-alpha.20171026 v1.2-alpha.20170901 v1.1.9 v1.1.9-rc.1 v1.1.8 v1.1.7 v1.1.6 v1.1.5 v1.1.4 v1.1.3 v1.1.2 v1.1.1 v1.1.0 v1.1.0-rc.1 v1.1-beta.20170928 v1.1-beta.20170921 v1.1-beta.20170907 v1.1-alpha.20170817 v1.1-alpha.20170810 v1.1-alpha.20170803 v1.1-alpha.20170720 v1.1-alpha.20170713 v1.1-alpha.20170629 v1.1-alpha.20170622 v1.1-alpha.20170608 v1.1-alpha.20170601 v1.0.7 v1.0.6 v1.0.5 v1.0.4 v1.0.3 v1.0.2 v1.0.1 v1.0 v1.0-rc.3 v1.0-rc.2 v1.0-rc.1 v0.1-alpha beta-20170420 beta-20170413 beta-20170406 beta-20170330 beta-20170323 beta-20170309 beta-20170223 beta-20170216 beta-20170209 beta-20170126 beta-20170112 beta-20170105 beta-20161215 beta-20161208 beta-20161201 beta-20161110 beta-20161103 beta-20161027 beta-20161013 beta-20161006 beta-20160929 beta-20160915 beta-20160908 beta-20160829 beta-20160728
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
8748 lines (8187 sloc) 241 KB
// Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
// Portions Copyright (c) 1994, Regents of the University of California
// Portions of this file are additionally subject to the following
// license and copyright.
//
// 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.
// Going to add a new statement?
// Consider taking a look at our codelab guide to learn what is needed to add a statement.
// https://github.com/cockroachdb/cockroach/blob/master/docs/codelabs/01-sql-statement.md
%{
package parser
import (
"fmt"
"strings"
"go/constant"
"github.com/cockroachdb/cockroach/pkg/sql/coltypes"
"github.com/cockroachdb/cockroach/pkg/sql/lex"
"github.com/cockroachdb/cockroach/pkg/sql/privilege"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
)
// MaxUint is the maximum value of an uint.
const MaxUint = ^uint(0)
// MaxInt is the maximum value of an int.
const MaxInt = int(MaxUint >> 1)
func unimplemented(sqllex sqlLexer, feature string) int {
sqllex.(*Scanner).Unimplemented(feature)
return 1
}
func unimplementedWithIssue(sqllex sqlLexer, issue int) int {
sqllex.(*Scanner).UnimplementedWithIssue(issue)
return 1
}
func unimplementedWithIssueDetail(sqllex sqlLexer, issue int, detail string) int {
sqllex.(*Scanner).UnimplementedWithIssueDetail(issue, detail)
return 1
}
%}
%{
// sqlSymUnion represents a union of types, providing accessor methods
// to retrieve the underlying type stored in the union's empty interface.
// The purpose of the sqlSymUnion struct is to reduce the memory footprint of
// the sqlSymType because only one value (of a variety of types) is ever needed
// to be stored in the union field at a time.
//
// By using an empty interface, we lose the type checking previously provided
// by yacc and the Go compiler when dealing with union values. Instead, runtime
// type assertions must be relied upon in the methods below, and as such, the
// parser should be thoroughly tested whenever new syntax is added.
//
// It is important to note that when assigning values to sqlSymUnion.val, all
// nil values should be typed so that they are stored as nil instances in the
// empty interface, instead of setting the empty interface to nil. This means
// that:
// $$ = []String(nil)
// should be used, instead of:
// $$ = nil
// to assign a nil string slice to the union.
type sqlSymUnion struct {
val interface{}
}
// The following accessor methods come in three forms, depending on the
// type of the value being accessed and whether a nil value is admissible
// for the corresponding grammar rule.
// - Values and pointers are directly type asserted from the empty
// interface, regardless of whether a nil value is admissible or
// not. A panic occurs if the type assertion is incorrect; no panic occurs
// if a nil is not expected but present. (TODO(knz): split this category of
// accessor in two; with one checking for unexpected nils.)
// Examples: bool(), tableWithIdx().
//
// - Interfaces where a nil is admissible are handled differently
// because a nil instance of an interface inserted into the empty interface
// becomes a nil instance of the empty interface and therefore will fail a
// direct type assertion. Instead, a guarded type assertion must be used,
// which returns nil if the type assertion fails.
// Examples: expr(), stmt().
//
// - Interfaces where a nil is not admissible are implemented as a direct
// type assertion, which causes a panic to occur if an unexpected nil
// is encountered.
// Examples: tblDef().
//
func (u *sqlSymUnion) numVal() *tree.NumVal {
return u.val.(*tree.NumVal)
}
func (u *sqlSymUnion) strVal() *tree.StrVal {
if stmt, ok := u.val.(*tree.StrVal); ok {
return stmt
}
return nil
}
func (u *sqlSymUnion) auditMode() tree.AuditMode {
return u.val.(tree.AuditMode)
}
func (u *sqlSymUnion) bool() bool {
return u.val.(bool)
}
func (u *sqlSymUnion) strPtr() *string {
return u.val.(*string)
}
func (u *sqlSymUnion) strs() []string {
return u.val.([]string)
}
func (u *sqlSymUnion) newTableWithIdx() *tree.TableNameWithIndex {
tn := u.val.(tree.TableNameWithIndex)
return &tn
}
func (u *sqlSymUnion) tableWithIdx() tree.TableNameWithIndex {
return u.val.(tree.TableNameWithIndex)
}
func (u *sqlSymUnion) newTableWithIdxList() tree.TableNameWithIndexList {
return u.val.(tree.TableNameWithIndexList)
}
func (u *sqlSymUnion) nameList() tree.NameList {
return u.val.(tree.NameList)
}
func (u *sqlSymUnion) unresolvedName() *tree.UnresolvedName {
return u.val.(*tree.UnresolvedName)
}
func (u *sqlSymUnion) functionReference() tree.FunctionReference {
return u.val.(tree.FunctionReference)
}
func (u *sqlSymUnion) tablePatterns() tree.TablePatterns {
return u.val.(tree.TablePatterns)
}
func (u *sqlSymUnion) normalizableTableNames() tree.NormalizableTableNames {
return u.val.(tree.NormalizableTableNames)
}
func (u *sqlSymUnion) indexFlags() *tree.IndexFlags {
return u.val.(*tree.IndexFlags)
}
func (u *sqlSymUnion) arraySubscript() *tree.ArraySubscript {
return u.val.(*tree.ArraySubscript)
}
func (u *sqlSymUnion) arraySubscripts() tree.ArraySubscripts {
if as, ok := u.val.(tree.ArraySubscripts); ok {
return as
}
return nil
}
func (u *sqlSymUnion) stmt() tree.Statement {
if stmt, ok := u.val.(tree.Statement); ok {
return stmt
}
return nil
}
func (u *sqlSymUnion) stmts() []tree.Statement {
return u.val.([]tree.Statement)
}
func (u *sqlSymUnion) cte() *tree.CTE {
if cte, ok := u.val.(*tree.CTE); ok {
return cte
}
return nil
}
func (u *sqlSymUnion) ctes() []*tree.CTE {
return u.val.([]*tree.CTE)
}
func (u *sqlSymUnion) with() *tree.With {
if with, ok := u.val.(*tree.With); ok {
return with
}
return nil
}
func (u *sqlSymUnion) slct() *tree.Select {
return u.val.(*tree.Select)
}
func (u *sqlSymUnion) selectStmt() tree.SelectStatement {
return u.val.(tree.SelectStatement)
}
func (u *sqlSymUnion) colDef() *tree.ColumnTableDef {
return u.val.(*tree.ColumnTableDef)
}
func (u *sqlSymUnion) constraintDef() tree.ConstraintTableDef {
return u.val.(tree.ConstraintTableDef)
}
func (u *sqlSymUnion) tblDef() tree.TableDef {
return u.val.(tree.TableDef)
}
func (u *sqlSymUnion) tblDefs() tree.TableDefs {
return u.val.(tree.TableDefs)
}
func (u *sqlSymUnion) colQual() tree.NamedColumnQualification {
return u.val.(tree.NamedColumnQualification)
}
func (u *sqlSymUnion) colQualElem() tree.ColumnQualification {
return u.val.(tree.ColumnQualification)
}
func (u *sqlSymUnion) colQuals() []tree.NamedColumnQualification {
return u.val.([]tree.NamedColumnQualification)
}
func (u *sqlSymUnion) colType() coltypes.T {
if colType, ok := u.val.(coltypes.T); ok {
return colType
}
return nil
}
func (u *sqlSymUnion) tableRefCols() []tree.ColumnID {
if refCols, ok := u.val.([]tree.ColumnID); ok {
return refCols
}
return nil
}
func (u *sqlSymUnion) castTargetType() coltypes.CastTargetType {
return u.val.(coltypes.CastTargetType)
}
func (u *sqlSymUnion) colTypes() []coltypes.T {
return u.val.([]coltypes.T)
}
func (u *sqlSymUnion) int64() int64 {
return u.val.(int64)
}
func (u *sqlSymUnion) seqOpt() tree.SequenceOption {
return u.val.(tree.SequenceOption)
}
func (u *sqlSymUnion) seqOpts() []tree.SequenceOption {
return u.val.([]tree.SequenceOption)
}
func (u *sqlSymUnion) expr() tree.Expr {
if expr, ok := u.val.(tree.Expr); ok {
return expr
}
return nil
}
func (u *sqlSymUnion) exprs() tree.Exprs {
return u.val.(tree.Exprs)
}
func (u *sqlSymUnion) selExpr() tree.SelectExpr {
return u.val.(tree.SelectExpr)
}
func (u *sqlSymUnion) selExprs() tree.SelectExprs {
return u.val.(tree.SelectExprs)
}
func (u *sqlSymUnion) retClause() tree.ReturningClause {
return u.val.(tree.ReturningClause)
}
func (u *sqlSymUnion) aliasClause() tree.AliasClause {
return u.val.(tree.AliasClause)
}
func (u *sqlSymUnion) asOfClause() tree.AsOfClause {
return u.val.(tree.AsOfClause)
}
func (u *sqlSymUnion) tblExpr() tree.TableExpr {
return u.val.(tree.TableExpr)
}
func (u *sqlSymUnion) tblExprs() tree.TableExprs {
return u.val.(tree.TableExprs)
}
func (u *sqlSymUnion) from() *tree.From {
return u.val.(*tree.From)
}
func (u *sqlSymUnion) int32s() []int32 {
return u.val.([]int32)
}
func (u *sqlSymUnion) joinCond() tree.JoinCond {
return u.val.(tree.JoinCond)
}
func (u *sqlSymUnion) when() *tree.When {
return u.val.(*tree.When)
}
func (u *sqlSymUnion) whens() []*tree.When {
return u.val.([]*tree.When)
}
func (u *sqlSymUnion) updateExpr() *tree.UpdateExpr {
return u.val.(*tree.UpdateExpr)
}
func (u *sqlSymUnion) updateExprs() tree.UpdateExprs {
return u.val.(tree.UpdateExprs)
}
func (u *sqlSymUnion) limit() *tree.Limit {
return u.val.(*tree.Limit)
}
func (u *sqlSymUnion) targetList() tree.TargetList {
return u.val.(tree.TargetList)
}
func (u *sqlSymUnion) targetListPtr() *tree.TargetList {
return u.val.(*tree.TargetList)
}
func (u *sqlSymUnion) privilegeType() privilege.Kind {
return u.val.(privilege.Kind)
}
func (u *sqlSymUnion) privilegeList() privilege.List {
return u.val.(privilege.List)
}
func (u *sqlSymUnion) onConflict() *tree.OnConflict {
return u.val.(*tree.OnConflict)
}
func (u *sqlSymUnion) orderBy() tree.OrderBy {
return u.val.(tree.OrderBy)
}
func (u *sqlSymUnion) order() *tree.Order {
return u.val.(*tree.Order)
}
func (u *sqlSymUnion) orders() []*tree.Order {
return u.val.([]*tree.Order)
}
func (u *sqlSymUnion) groupBy() tree.GroupBy {
return u.val.(tree.GroupBy)
}
func (u *sqlSymUnion) windowFrame() *tree.WindowFrame {
return u.val.(*tree.WindowFrame)
}
func (u *sqlSymUnion) windowFrameBounds() tree.WindowFrameBounds {
return u.val.(tree.WindowFrameBounds)
}
func (u *sqlSymUnion) windowFrameBound() *tree.WindowFrameBound {
return u.val.(*tree.WindowFrameBound)
}
func (u *sqlSymUnion) distinctOn() tree.DistinctOn {
return u.val.(tree.DistinctOn)
}
func (u *sqlSymUnion) dir() tree.Direction {
return u.val.(tree.Direction)
}
func (u *sqlSymUnion) alterTableCmd() tree.AlterTableCmd {
return u.val.(tree.AlterTableCmd)
}
func (u *sqlSymUnion) alterTableCmds() tree.AlterTableCmds {
return u.val.(tree.AlterTableCmds)
}
func (u *sqlSymUnion) alterIndexCmd() tree.AlterIndexCmd {
return u.val.(tree.AlterIndexCmd)
}
func (u *sqlSymUnion) alterIndexCmds() tree.AlterIndexCmds {
return u.val.(tree.AlterIndexCmds)
}
func (u *sqlSymUnion) isoLevel() tree.IsolationLevel {
return u.val.(tree.IsolationLevel)
}
func (u *sqlSymUnion) userPriority() tree.UserPriority {
return u.val.(tree.UserPriority)
}
func (u *sqlSymUnion) readWriteMode() tree.ReadWriteMode {
return u.val.(tree.ReadWriteMode)
}
func (u *sqlSymUnion) idxElem() tree.IndexElem {
return u.val.(tree.IndexElem)
}
func (u *sqlSymUnion) idxElems() tree.IndexElemList {
return u.val.(tree.IndexElemList)
}
func (u *sqlSymUnion) dropBehavior() tree.DropBehavior {
return u.val.(tree.DropBehavior)
}
func (u *sqlSymUnion) validationBehavior() tree.ValidationBehavior {
return u.val.(tree.ValidationBehavior)
}
func (u *sqlSymUnion) interleave() *tree.InterleaveDef {
return u.val.(*tree.InterleaveDef)
}
func (u *sqlSymUnion) partitionBy() *tree.PartitionBy {
return u.val.(*tree.PartitionBy)
}
func (u *sqlSymUnion) listPartition() tree.ListPartition {
return u.val.(tree.ListPartition)
}
func (u *sqlSymUnion) listPartitions() []tree.ListPartition {
return u.val.([]tree.ListPartition)
}
func (u *sqlSymUnion) rangePartition() tree.RangePartition {
return u.val.(tree.RangePartition)
}
func (u *sqlSymUnion) rangePartitions() []tree.RangePartition {
return u.val.([]tree.RangePartition)
}
func (u *sqlSymUnion) setZoneConfig() *tree.SetZoneConfig {
return u.val.(*tree.SetZoneConfig)
}
func (u *sqlSymUnion) tuples() []*tree.Tuple {
return u.val.([]*tree.Tuple)
}
func (u *sqlSymUnion) tuple() *tree.Tuple {
return u.val.(*tree.Tuple)
}
func (u *sqlSymUnion) windowDef() *tree.WindowDef {
return u.val.(*tree.WindowDef)
}
func (u *sqlSymUnion) window() tree.Window {
return u.val.(tree.Window)
}
func (u *sqlSymUnion) op() tree.Operator {
return u.val.(tree.Operator)
}
func (u *sqlSymUnion) cmpOp() tree.ComparisonOperator {
return u.val.(tree.ComparisonOperator)
}
func (u *sqlSymUnion) durationField() tree.DurationField {
return u.val.(tree.DurationField)
}
func (u *sqlSymUnion) kvOption() tree.KVOption {
return u.val.(tree.KVOption)
}
func (u *sqlSymUnion) kvOptions() []tree.KVOption {
if colType, ok := u.val.([]tree.KVOption); ok {
return colType
}
return nil
}
func (u *sqlSymUnion) transactionModes() tree.TransactionModes {
return u.val.(tree.TransactionModes)
}
func (u *sqlSymUnion) referenceAction() tree.ReferenceAction {
return u.val.(tree.ReferenceAction)
}
func (u *sqlSymUnion) referenceActions() tree.ReferenceActions {
return u.val.(tree.ReferenceActions)
}
func (u *sqlSymUnion) scrubOptions() tree.ScrubOptions {
return u.val.(tree.ScrubOptions)
}
func (u *sqlSymUnion) scrubOption() tree.ScrubOption {
return u.val.(tree.ScrubOption)
}
func (u *sqlSymUnion) normalizableTableNameFromUnresolvedName() tree.NormalizableTableName {
return tree.NormalizableTableName{TableNameReference: u.unresolvedName()}
}
func (u *sqlSymUnion) newNormalizableTableNameFromUnresolvedName() *tree.NormalizableTableName {
return &tree.NormalizableTableName{TableNameReference: u.unresolvedName()}
}
func (u *sqlSymUnion) resolvableFuncRefFromName() tree.ResolvableFunctionReference {
return tree.ResolvableFunctionReference{FunctionReference: u.unresolvedName()}
}
func (u *sqlSymUnion) rowsFromExpr() *tree.RowsFromExpr {
return u.val.(*tree.RowsFromExpr)
}
func newNameFromStr(s string) *tree.Name {
return (*tree.Name)(&s)
}
%}
// NB: the %token definitions must come before the %type definitions in this
// file to work around a bug in goyacc. See #16369 for more details.
// Non-keyword token types.
%token <str> IDENT SCONST BCONST BITCONST
%token <*tree.NumVal> ICONST FCONST
%token <str> PLACEHOLDER
%token <str> TYPECAST TYPEANNOTATE DOT_DOT
%token <str> LESS_EQUALS GREATER_EQUALS NOT_EQUALS
%token <str> NOT_REGMATCH REGIMATCH NOT_REGIMATCH
%token <str> ERROR
// If you want to make any keyword changes, add the new keyword here as well as
// to the appropriate one of the reserved-or-not-so-reserved keyword lists,
// below; search this file for "Keyword category lists".
// Ordinary key words in alphabetical order.
%token <str> ABORT ACTION ADD ADMIN AGGREGATE
%token <str> ALL ALTER ANALYSE ANALYZE AND ANY ANNOTATE_TYPE ARRAY AS ASC
%token <str> ASYMMETRIC AT
%token <str> BACKUP BEGIN BETWEEN BIGINT BIGSERIAL BIT
%token <str> BLOB BOOL BOOLEAN BOTH BY BYTEA BYTES
%token <str> CACHE CANCEL CASCADE CASE CAST CHANGEFEED CHAR
%token <str> CHARACTER CHARACTERISTICS CHECK
%token <str> CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMIT
%token <str> COMMITTED COMPACT CONCAT CONFIGURATION CONFIGURATIONS CONFIGURE
%token <str> CONFLICT CONSTRAINT CONSTRAINTS CONTAINS CONVERSION COPY COVERING CREATE
%token <str> CROSS CUBE CURRENT CURRENT_CATALOG CURRENT_DATE CURRENT_SCHEMA
%token <str> CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP
%token <str> CURRENT_USER CYCLE
%token <str> DATA DATABASE DATABASES DATE DAY DEC DECIMAL DEFAULT
%token <str> DEALLOCATE DEFERRABLE DELETE DESC
%token <str> DISCARD DISTINCT DO DOMAIN DOUBLE DROP
%token <str> ELSE ENCODING END ENUM ESCAPE EXCEPT
%token <str> EXISTS EXECUTE EXPERIMENTAL
%token <str> EXPERIMENTAL_FINGERPRINTS EXPERIMENTAL_REPLICA
%token <str> EXPERIMENTAL_AUDIT
%token <str> EXPLAIN EXPORT EXTENSION EXTRACT EXTRACT_DURATION
%token <str> FALSE FAMILY FETCH FETCHVAL FETCHTEXT FETCHVAL_PATH FETCHTEXT_PATH
%token <str> FILES FILTER
%token <str> FIRST FLOAT FLOAT4 FLOAT8 FLOORDIV FOLLOWING FOR FORCE_INDEX FOREIGN FROM FULL FUNCTION
%token <str> GLOBAL GRANT GRANTS GREATEST GROUP GROUPING GROUPS
%token <str> HAVING HIGH HISTOGRAM HOUR
%token <str> IMPORT INCREMENT INCREMENTAL IF IFERROR IFNULL ILIKE IN ISERROR
%token <str> INET INET_CONTAINED_BY_OR_EQUALS INET_CONTAINS_OR_CONTAINED_BY
%token <str> INET_CONTAINS_OR_EQUALS INDEX INDEXES INJECT INTERLEAVE INITIALLY
%token <str> INNER INSERT INT INT2VECTOR INT2 INT4 INT8 INT64 INTEGER
%token <str> INTERSECT INTERVAL INTO INVERTED IS ISNULL ISOLATION
%token <str> JOB JOBS JOIN JSON JSONB JSON_SOME_EXISTS JSON_ALL_EXISTS
%token <str> KEY KEYS KV
%token <str> LANGUAGE LATERAL LC_CTYPE LC_COLLATE
%token <str> LEADING LEASE LEAST LEFT LESS LEVEL LIKE LIMIT LIST LOCAL
%token <str> LOCALTIME LOCALTIMESTAMP LOW LSHIFT
%token <str> MATCH MATERIALIZED MINVALUE MAXVALUE MINUTE MONTH
%token <str> NAN NAME NAMES NATURAL NEXT NO NO_INDEX_JOIN NORMAL
%token <str> NOT NOTHING NOTNULL NULL NULLIF NUMERIC
%token <str> OF OFF OFFSET OID OIDVECTOR ON ONLY OPTION OPTIONS OR
%token <str> ORDER ORDINALITY OUT OUTER OVER OVERLAPS OVERLAY OWNED OPERATOR
%token <str> PARENT PARTIAL PARTITION PASSWORD PAUSE PHYSICAL PLACING
%token <str> PLANS POSITION PRECEDING PRECISION PREPARE PRIMARY PRIORITY
%token <str> PROCEDURAL PUBLICATION
%token <str> QUERIES QUERY
%token <str> RANGE RANGES READ REAL RECURSIVE REF REFERENCES
%token <str> REGCLASS REGPROC REGPROCEDURE REGNAMESPACE REGTYPE
%token <str> REMOVE_PATH RENAME REPEATABLE REPLACE
%token <str> RELEASE RESET RESTORE RESTRICT RESUME RETURNING REVOKE RIGHT
%token <str> ROLE ROLES ROLLBACK ROLLUP ROW ROWS RSHIFT RULE
%token <str> SAVEPOINT SCATTER SCHEMA SCHEMAS SCRUB SEARCH SECOND SELECT SEQUENCE SEQUENCES
%token <str> SERIAL SERIAL2 SERIAL4 SERIAL8
%token <str> SERIALIZABLE SERVER SESSION SESSIONS SESSION_USER SET SETTING SETTINGS
%token <str> SHOW SIMILAR SIMPLE SMALLINT SMALLSERIAL SNAPSHOT SOME SPLIT SQL
%token <str> START STATISTICS STATUS STDIN STRICT STRING STORE STORED STORING SUBSTRING
%token <str> SYMMETRIC SYNTAX SYSTEM SUBSCRIPTION
%token <str> TABLE TABLES TEMP TEMPLATE TEMPORARY TESTING_RANGES EXPERIMENTAL_RANGES TESTING_RELOCATE EXPERIMENTAL_RELOCATE TEXT THEN
%token <str> TIME TIMETZ TIMESTAMP TIMESTAMPTZ TO TRAILING TRACE TRANSACTION TREAT TRIGGER TRIM TRUE
%token <str> TRUNCATE TRUSTED TYPE
%token <str> TRACING
%token <str> UNBOUNDED UNCOMMITTED UNION UNIQUE UNKNOWN UNLOGGED
%token <str> UPDATE UPSERT USE USER USERS USING UUID
%token <str> VALID VALIDATE VALUE VALUES VARBIT VARCHAR VARIADIC VIEW VARYING VIRTUAL
%token <str> WHEN WHERE WINDOW WITH WITHIN WITHOUT WORK WRITE
%token <str> YEAR
%token <str> ZONE
// The grammar thinks these are keywords, but they are not in any category
// and so can never be entered directly. The filter in scan.go creates these
// tokens when required (based on looking one token ahead).
//
// NOT_LA exists so that productions such as NOT LIKE can be given the same
// precedence as LIKE; otherwise they'd effectively have the same precedence as
// NOT, at least with respect to their left-hand subexpression. WITH_LA is
// needed to make the grammar LALR(1).
%token NOT_LA WITH_LA AS_LA
%union {
id int
pos int
str string
union sqlSymUnion
}
%type <[]tree.Statement> stmt_block
%type <[]tree.Statement> stmt_list
%type <tree.Statement> stmt
%type <tree.Statement> alter_stmt
%type <tree.Statement> alter_ddl_stmt
%type <tree.Statement> alter_table_stmt
%type <tree.Statement> alter_index_stmt
%type <tree.Statement> alter_view_stmt
%type <tree.Statement> alter_sequence_stmt
%type <tree.Statement> alter_database_stmt
%type <tree.Statement> alter_user_stmt
%type <tree.Statement> alter_range_stmt
// ALTER RANGE
%type <tree.Statement> alter_zone_range_stmt
// ALTER TABLE
%type <tree.Statement> alter_onetable_stmt
%type <tree.Statement> alter_split_stmt
%type <tree.Statement> alter_rename_table_stmt
%type <tree.Statement> alter_scatter_stmt
%type <tree.Statement> alter_relocate_stmt
%type <tree.Statement> alter_relocate_lease_stmt
%type <tree.Statement> alter_zone_table_stmt
// ALTER DATABASE
%type <tree.Statement> alter_rename_database_stmt
%type <tree.Statement> alter_zone_database_stmt
// ALTER USER
%type <tree.Statement> alter_user_password_stmt
// ALTER INDEX
%type <tree.Statement> alter_oneindex_stmt
%type <tree.Statement> alter_scatter_index_stmt
%type <tree.Statement> alter_split_index_stmt
%type <tree.Statement> alter_rename_index_stmt
%type <tree.Statement> alter_relocate_index_stmt
%type <tree.Statement> alter_relocate_index_lease_stmt
%type <tree.Statement> alter_zone_index_stmt
// ALTER VIEW
%type <tree.Statement> alter_rename_view_stmt
// ALTER SEQUENCE
%type <tree.Statement> alter_rename_sequence_stmt
%type <tree.Statement> alter_sequence_options_stmt
%type <tree.Statement> backup_stmt
%type <tree.Statement> begin_stmt
%type <tree.Statement> cancel_stmt
%type <tree.Statement> cancel_jobs_stmt
%type <tree.Statement> cancel_queries_stmt
%type <tree.Statement> cancel_sessions_stmt
// SCRUB
%type <tree.Statement> scrub_stmt
%type <tree.Statement> scrub_database_stmt
%type <tree.Statement> scrub_table_stmt
%type <tree.ScrubOptions> opt_scrub_options_clause
%type <tree.ScrubOptions> scrub_option_list
%type <tree.ScrubOption> scrub_option
%type <tree.Statement> comment_stmt
%type <tree.Statement> commit_stmt
%type <tree.Statement> copy_from_stmt
%type <tree.Statement> create_stmt
%type <tree.Statement> create_changefeed_stmt
%type <tree.Statement> create_ddl_stmt
%type <tree.Statement> create_database_stmt
%type <tree.Statement> create_index_stmt
%type <tree.Statement> create_role_stmt
%type <tree.Statement> create_table_stmt
%type <tree.Statement> create_table_as_stmt
%type <tree.Statement> create_user_stmt
%type <tree.Statement> create_view_stmt
%type <tree.Statement> create_sequence_stmt
%type <tree.Statement> create_stats_stmt
%type <tree.Statement> create_type_stmt
%type <tree.Statement> delete_stmt
%type <tree.Statement> discard_stmt
%type <tree.Statement> drop_stmt
%type <tree.Statement> drop_ddl_stmt
%type <tree.Statement> drop_database_stmt
%type <tree.Statement> drop_index_stmt
%type <tree.Statement> drop_role_stmt
%type <tree.Statement> drop_table_stmt
%type <tree.Statement> drop_user_stmt
%type <tree.Statement> drop_view_stmt
%type <tree.Statement> drop_sequence_stmt
%type <tree.Statement> explain_stmt
%type <tree.Statement> prepare_stmt
%type <tree.Statement> preparable_stmt
%type <tree.Statement> export_stmt
%type <tree.Statement> execute_stmt
%type <tree.Statement> deallocate_stmt
%type <tree.Statement> grant_stmt
%type <tree.Statement> insert_stmt
%type <tree.Statement> import_stmt
%type <tree.Statement> pause_stmt
%type <tree.Statement> release_stmt
%type <tree.Statement> reset_stmt reset_session_stmt reset_csetting_stmt
%type <tree.Statement> resume_stmt
%type <tree.Statement> restore_stmt
%type <tree.Statement> revoke_stmt
%type <*tree.Select> select_stmt
%type <tree.Statement> abort_stmt
%type <tree.Statement> rollback_stmt
%type <tree.Statement> savepoint_stmt
%type <tree.Statement> preparable_set_stmt nonpreparable_set_stmt
%type <tree.Statement> set_session_stmt
%type <tree.Statement> set_csetting_stmt
%type <tree.Statement> set_transaction_stmt
%type <tree.Statement> set_exprs_internal
%type <tree.Statement> generic_set
%type <tree.Statement> set_rest_more
%type <tree.Statement> set_names
%type <tree.Statement> show_stmt
%type <tree.Statement> show_backup_stmt
%type <tree.Statement> show_columns_stmt
%type <tree.Statement> show_constraints_stmt
%type <tree.Statement> show_create_stmt
%type <tree.Statement> show_csettings_stmt
%type <tree.Statement> show_databases_stmt
%type <tree.Statement> show_fingerprints_stmt
%type <tree.Statement> show_grants_stmt
%type <tree.Statement> show_histogram_stmt
%type <tree.Statement> show_indexes_stmt
%type <tree.Statement> show_jobs_stmt
%type <tree.Statement> show_queries_stmt
%type <tree.Statement> show_ranges_stmt
%type <tree.Statement> show_roles_stmt
%type <tree.Statement> show_schemas_stmt
%type <tree.Statement> show_session_stmt
%type <tree.Statement> show_sessions_stmt
%type <tree.Statement> show_stats_stmt
%type <tree.Statement> show_syntax_stmt
%type <tree.Statement> show_tables_stmt
%type <tree.Statement> show_trace_stmt
%type <tree.Statement> show_transaction_stmt
%type <tree.Statement> show_users_stmt
%type <tree.Statement> show_zone_stmt
%type <str> session_var
%type <str> comment_text
%type <tree.Statement> transaction_stmt
%type <tree.Statement> truncate_stmt
%type <tree.Statement> update_stmt
%type <tree.Statement> upsert_stmt
%type <tree.Statement> use_stmt
%type <[]string> opt_incremental
%type <tree.KVOption> kv_option
%type <[]tree.KVOption> kv_option_list opt_with_options var_set_list
%type <str> import_format
%type <*tree.Select> select_no_parens
%type <tree.SelectStatement> select_clause select_with_parens simple_select values_clause table_clause simple_select_clause
%type <tree.SelectStatement> set_operation
%type <tree.Expr> alter_column_default
%type <tree.Direction> opt_asc_desc
%type <tree.AlterTableCmd> alter_table_cmd
%type <tree.AlterTableCmds> alter_table_cmds
%type <tree.AlterIndexCmd> alter_index_cmd
%type <tree.AlterIndexCmds> alter_index_cmds
%type <tree.DropBehavior> opt_drop_behavior
%type <tree.DropBehavior> opt_interleave_drop_behavior
%type <tree.ValidationBehavior> opt_validate_behavior
%type <str> opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause
%type <tree.Expr> opt_password
%type <tree.IsolationLevel> transaction_iso_level
%type <tree.UserPriority> transaction_user_priority
%type <tree.ReadWriteMode> transaction_read_mode
%type <str> name opt_name opt_name_parens opt_to_savepoint
%type <str> privilege savepoint_name
%type <tree.Operator> subquery_op
%type <*tree.UnresolvedName> func_name
%type <str> opt_collate
%type <str> database_name index_name opt_index_name column_name insert_column_item statistics_name window_name
%type <str> family_name opt_family_name table_alias_name constraint_name target_name zone_name partition_name collation_name
%type <*tree.UnresolvedName> table_name sequence_name type_name view_name db_object_name simple_db_object_name complex_db_object_name
%type <*tree.UnresolvedName> table_pattern complex_table_pattern
%type <*tree.UnresolvedName> column_path prefixed_column_path column_path_with_star
%type <tree.TableExpr> insert_target
%type <*tree.TableNameWithIndex> table_name_with_index
%type <tree.TableNameWithIndexList> table_name_with_index_list
%type <tree.Operator> math_op
%type <tree.IsolationLevel> iso_level
%type <tree.UserPriority> user_priority
%type <tree.TableDefs> opt_table_elem_list table_elem_list
%type <*tree.InterleaveDef> opt_interleave
%type <*tree.PartitionBy> opt_partition_by partition_by
%type <str> partition opt_partition
%type <tree.ListPartition> list_partition
%type <[]tree.ListPartition> list_partitions
%type <tree.RangePartition> range_partition
%type <[]tree.RangePartition> range_partitions
%type <empty> opt_all_clause
%type <bool> distinct_clause
%type <tree.DistinctOn> distinct_on_clause
%type <tree.NameList> opt_column_list insert_column_list
%type <tree.OrderBy> sort_clause opt_sort_clause
%type <[]*tree.Order> sortby_list
%type <tree.IndexElemList> index_params
%type <tree.NameList> name_list privilege_list
%type <[]int32> opt_array_bounds
%type <*tree.From> from_clause update_from_clause
%type <tree.TableExprs> from_list rowsfrom_list
%type <tree.TablePatterns> table_pattern_list single_table_pattern_list
%type <tree.NormalizableTableNames> table_name_list
%type <tree.Exprs> expr_list opt_expr_list tuple1_ambiguous_values tuple1_unambiguous_values
%type <*tree.Tuple> expr_tuple1_ambiguous expr_tuple_unambiguous
%type <tree.NameList> attrs
%type <tree.SelectExprs> target_list
%type <tree.UpdateExprs> set_clause_list
%type <*tree.UpdateExpr> set_clause multiple_set_clause
%type <tree.ArraySubscripts> array_subscripts
%type <tree.GroupBy> group_clause
%type <*tree.Limit> select_limit
%type <tree.NormalizableTableNames> relation_expr_list
%type <tree.ReturningClause> returning_clause
%type <[]tree.SequenceOption> sequence_option_list opt_sequence_option_list
%type <tree.SequenceOption> sequence_option_elem
%type <bool> all_or_distinct
%type <empty> join_outer
%type <tree.JoinCond> join_qual
%type <str> join_type
%type <tree.Exprs> extract_list
%type <tree.Exprs> overlay_list
%type <tree.Exprs> position_list
%type <tree.Exprs> substr_list
%type <tree.Exprs> trim_list
%type <tree.Exprs> execute_param_clause
%type <tree.DurationField> opt_interval interval_second interval_qualifier
%type <tree.Expr> overlay_placing
%type <bool> opt_unique
%type <bool> opt_using_gin_btree
%type <*tree.Limit> limit_clause offset_clause opt_limit_clause
%type <tree.Expr> select_limit_value
%type <tree.Expr> opt_select_fetch_first_value
%type <empty> row_or_rows
%type <empty> first_or_next
%type <tree.Statement> insert_rest
%type <tree.NameList> opt_conf_expr opt_col_def_list
%type <*tree.OnConflict> on_conflict
%type <tree.Statement> begin_transaction
%type <tree.TransactionModes> transaction_mode_list transaction_mode
%type <tree.NameList> opt_storing
%type <*tree.ColumnTableDef> column_def
%type <tree.TableDef> table_elem
%type <tree.Expr> where_clause
%type <*tree.ArraySubscript> array_subscript
%type <tree.Expr> opt_slice_bound
%type <*tree.IndexFlags> opt_index_flags
%type <*tree.IndexFlags> index_flags_param
%type <*tree.IndexFlags> index_flags_param_list
%type <tree.Expr> a_expr b_expr c_expr d_expr
%type <tree.Expr> substr_from substr_for
%type <tree.Expr> in_expr
%type <tree.Expr> having_clause
%type <tree.Expr> array_expr
%type <tree.Expr> interval
%type <[]coltypes.T> type_list prep_type_clause
%type <tree.Exprs> array_expr_list
%type <*tree.Tuple> row labeled_row
%type <tree.Expr> case_expr case_arg case_default
%type <*tree.When> when_clause
%type <[]*tree.When> when_clause_list
%type <tree.ComparisonOperator> sub_type
%type <tree.Expr> numeric_only
%type <tree.AliasClause> alias_clause opt_alias_clause
%type <bool> opt_ordinality opt_compact
%type <*tree.Order> sortby
%type <tree.IndexElem> index_elem
%type <tree.TableExpr> table_ref func_table
%type <tree.Exprs> rowsfrom_list
%type <tree.Expr> rowsfrom_item
%type <tree.TableExpr> joined_table
%type <*tree.UnresolvedName> relation_expr
%type <tree.TableExpr> table_name_expr_opt_alias_idx table_name_expr_with_index
%type <tree.SelectExpr> target_elem
%type <*tree.UpdateExpr> single_set_clause
%type <tree.AsOfClause> as_of_clause opt_as_of_clause
%type <tree.Expr> opt_changefeed_sink
%type <str> explain_option_name
%type <[]string> explain_option_list
%type <coltypes.T> typename simple_typename const_typename
%type <coltypes.T> numeric opt_numeric_modifiers
%type <coltypes.T> opt_float
%type <coltypes.T> character_with_length character_without_length
%type <coltypes.T> const_datetime const_interval
%type <coltypes.T> bit_with_length bit_without_length
%type <coltypes.T> character_base
%type <coltypes.CastTargetType> postgres_oid
%type <coltypes.CastTargetType> cast_target
%type <str> extract_arg
%type <bool> opt_varying
%type <*tree.NumVal> signed_iconst
%type <int64> signed_iconst64
%type <int64> iconst64
%type <tree.Expr> var_value
%type <tree.Exprs> var_list
%type <tree.NameList> var_name
%type <str> unrestricted_name type_function_name
%type <str> non_reserved_word
%type <str> non_reserved_word_or_sconst
%type <tree.Expr> zone_value
%type <tree.Expr> string_or_placeholder
%type <tree.Expr> string_or_placeholder_list
%type <str> unreserved_keyword type_func_name_keyword
%type <str> col_name_keyword reserved_keyword
%type <tree.ConstraintTableDef> table_constraint constraint_elem
%type <tree.TableDef> index_def
%type <tree.TableDef> family_def
%type <[]tree.NamedColumnQualification> col_qual_list
%type <tree.NamedColumnQualification> col_qualification
%type <tree.ColumnQualification> col_qualification_elem
%type <empty> key_match
%type <tree.ReferenceActions> reference_actions
%type <tree.ReferenceAction> reference_action reference_on_delete reference_on_update
%type <tree.Expr> func_application func_expr_common_subexpr special_function
%type <tree.Expr> func_expr func_expr_windowless
%type <empty> opt_with
%type <*tree.With> with_clause opt_with_clause
%type <[]*tree.CTE> cte_list
%type <*tree.CTE> common_table_expr
%type <empty> within_group_clause
%type <tree.Expr> filter_clause
%type <tree.Exprs> opt_partition_clause
%type <tree.Window> window_clause window_definition_list
%type <*tree.WindowDef> window_definition over_clause window_specification
%type <str> opt_existing_window_name
%type <*tree.WindowFrame> opt_frame_clause
%type <tree.WindowFrameBounds> frame_extent
%type <*tree.WindowFrameBound> frame_bound
%type <[]tree.ColumnID> opt_tableref_col_list tableref_col_list
%type <tree.TargetList> targets targets_roles changefeed_targets
%type <*tree.TargetList> opt_on_targets_roles
%type <tree.NameList> for_grantee_clause
%type <privilege.List> privileges
%type <tree.AuditMode> audit_mode
%type <str> relocate_kw ranges_kw
%type <*tree.SetZoneConfig> set_zone_config
%type <tree.Expr> opt_alter_column_using
// Precedence: lowest to highest
%nonassoc VALUES // see value_clause
%nonassoc SET // see table_name_expr_opt_alias_idx
%left UNION EXCEPT
%left INTERSECT
%left OR
%left AND
%right NOT
%nonassoc IS ISNULL NOTNULL // IS sets precedence for IS NULL, etc
%nonassoc '<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS CONTAINS CONTAINED_BY '?' JSON_SOME_EXISTS JSON_ALL_EXISTS
%nonassoc '~' BETWEEN IN LIKE ILIKE SIMILAR NOT_REGMATCH REGIMATCH NOT_REGIMATCH NOT_LA
%nonassoc ESCAPE // ESCAPE must be just above LIKE/ILIKE/SIMILAR
%nonassoc OVERLAPS
%left POSTFIXOP // dummy for postfix OP rules
// To support target_elem without AS, we must give IDENT an explicit priority
// between POSTFIXOP and OP. We can safely assign the same priority to various
// unreserved keywords as needed to resolve ambiguities (this can't have any
// bad effects since obviously the keywords will still behave the same as if
// they weren't keywords). We need to do this for PARTITION, RANGE, ROWS,
// GROUPS to support opt_existing_window_name; and for RANGE, ROWS, GROUPS so
// that they can follow a_expr without creating postfix-operator problems; and
// for NULL so that it can follow b_expr in col_qual_list without creating
// postfix-operator problems.
//
// To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
// an explicit priority lower than '(', so that a rule with CUBE '(' will shift
// rather than reducing a conflicting rule that takes CUBE as a function name.
// Using the same precedence as IDENT seems right for the reasons given above.
//
// The frame_bound productions UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING are
// even messier: since UNBOUNDED is an unreserved keyword (per spec!), there is
// no principled way to distinguish these from the productions a_expr
// PRECEDING/FOLLOWING. We hack this up by giving UNBOUNDED slightly lower
// precedence than PRECEDING and FOLLOWING. At present this doesn't appear to
// cause UNBOUNDED to be treated differently from other unreserved keywords
// anywhere else in the grammar, but it's definitely risky. We can blame any
// funny behavior of UNBOUNDED on the SQL standard, though.
%nonassoc UNBOUNDED // ideally should have same precedence as IDENT
%nonassoc IDENT NULL PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
%left CONCAT FETCHVAL FETCHTEXT FETCHVAL_PATH FETCHTEXT_PATH REMOVE_PATH // multi-character ops
%left '|'
%left '#'
%left '&'
%left LSHIFT RSHIFT INET_CONTAINS_OR_EQUALS INET_CONTAINED_BY_OR_EQUALS INET_CONTAINS_OR_CONTAINED_BY
%left '+' '-'
%left '*' '/' FLOORDIV '%'
%left '^'
// Unary Operators
%left AT // sets precedence for AT TIME ZONE
%left COLLATE
%right UMINUS
%left '[' ']'
%left '(' ')'
%left TYPEANNOTATE
%left TYPECAST
%left '.'
// These might seem to be low-precedence, but actually they are not part
// of the arithmetic hierarchy at all in their use as JOIN operators.
// We make them high-precedence to support their use as function names.
// They wouldn't be given a precedence at all, were it not that we need
// left-associativity among the JOIN rules themselves.
%left JOIN CROSS LEFT FULL RIGHT INNER NATURAL
%right HELPTOKEN
%%
stmt_block:
stmt_list
{
sqllex.(*Scanner).stmts = $1.stmts()
}
stmt_list:
stmt_list ';' stmt
{
l := $1.stmts()
s := $3.stmt()
if s != nil {
l = append(l, s)
}
$$.val = l
}
| stmt
{
$$.val = []tree.Statement(nil)
s := $1.stmt()
if s != nil {
$$.val = []tree.Statement{s}
}
}
stmt:
HELPTOKEN { return helpWith(sqllex, "") }
| preparable_stmt // help texts in sub-rule
| copy_from_stmt
| comment_stmt
| execute_stmt // EXTEND WITH HELP: EXECUTE
| deallocate_stmt // EXTEND WITH HELP: DEALLOCATE
| discard_stmt // EXTEND WITH HELP: DISCARD
| export_stmt // EXTEND WITH HELP: EXPORT
| grant_stmt // EXTEND WITH HELP: GRANT
| prepare_stmt // EXTEND WITH HELP: PREPARE
| revoke_stmt // EXTEND WITH HELP: REVOKE
| savepoint_stmt // EXTEND WITH HELP: SAVEPOINT
| release_stmt // EXTEND WITH HELP: RELEASE
| nonpreparable_set_stmt // help texts in sub-rule
| transaction_stmt // help texts in sub-rule
| /* EMPTY */
{
$$.val = tree.Statement(nil)
}
// %Help: ALTER
// %Category: Group
// %Text: ALTER TABLE, ALTER INDEX, ALTER VIEW, ALTER SEQUENCE, ALTER DATABASE, ALTER USER
alter_stmt:
alter_ddl_stmt // help texts in sub-rule
| alter_user_stmt // EXTEND WITH HELP: ALTER USER
| ALTER error // SHOW HELP: ALTER
alter_ddl_stmt:
alter_table_stmt // EXTEND WITH HELP: ALTER TABLE
| alter_index_stmt // EXTEND WITH HELP: ALTER INDEX
| alter_view_stmt // EXTEND WITH HELP: ALTER VIEW
| alter_sequence_stmt // EXTEND WITH HELP: ALTER SEQUENCE
| alter_database_stmt // EXTEND WITH HELP: ALTER DATABASE
| alter_range_stmt // EXTEND WITH HELP: ALTER RANGE
// %Help: ALTER TABLE - change the definition of a table
// %Category: DDL
// %Text:
// ALTER TABLE [IF EXISTS] <tablename> <command> [, ...]
//
// Commands:
// ALTER TABLE ... ADD [COLUMN] [IF NOT EXISTS] <colname> <type> [<qualifiers...>]
// ALTER TABLE ... ADD <constraint>
// ALTER TABLE ... DROP [COLUMN] [IF EXISTS] <colname> [RESTRICT | CASCADE]
// ALTER TABLE ... DROP CONSTRAINT [IF EXISTS] <constraintname> [RESTRICT | CASCADE]
// ALTER TABLE ... ALTER [COLUMN] <colname> {SET DEFAULT <expr> | DROP DEFAULT}
// ALTER TABLE ... ALTER [COLUMN] <colname> DROP NOT NULL
// ALTER TABLE ... ALTER [COLUMN] <colname> DROP STORED
// ALTER TABLE ... ALTER [COLUMN] <colname> [SET DATA] TYPE <type> [COLLATE <collation>]
// ALTER TABLE ... RENAME TO <newname>
// ALTER TABLE ... RENAME [COLUMN] <colname> TO <newname>
// ALTER TABLE ... VALIDATE CONSTRAINT <constraintname>
// ALTER TABLE ... SPLIT AT <selectclause>
// ALTER TABLE ... SCATTER [ FROM ( <exprs...> ) TO ( <exprs...> ) ]
// ALTER TABLE ... INJECT STATISTICS ... (experimental)
// ALTER TABLE ... PARTITION BY RANGE ( <name...> ) ( <rangespec> )
// ALTER TABLE ... PARTITION BY LIST ( <name...> ) ( <listspec> )
// ALTER TABLE ... PARTITION BY NOTHING
// ALTER TABLE ... CONFIGURE ZONE <zoneconfig>
// ALTER PARTITION ... OF TABLE ... CONFIGURE ZONE <zoneconfig>
//
// Column qualifiers:
// [CONSTRAINT <constraintname>] {NULL | NOT NULL | UNIQUE | PRIMARY KEY | CHECK (<expr>) | DEFAULT <expr>}
// FAMILY <familyname>, CREATE [IF NOT EXISTS] FAMILY [<familyname>]
// REFERENCES <tablename> [( <colnames...> )]
// COLLATE <collationname>
//
// Zone configurations:
// DISCARD
// USING <var> = <expr> [, ...]
// { TO | = } <expr>
//
// %SeeAlso: WEBDOCS/alter-table.html
alter_table_stmt:
alter_onetable_stmt
| alter_relocate_stmt
| alter_relocate_lease_stmt
| alter_split_stmt
| alter_scatter_stmt
| alter_zone_table_stmt
| alter_rename_table_stmt
// ALTER TABLE has its error help token here because the ALTER TABLE
// prefix is spread over multiple non-terminals.
| ALTER TABLE error // SHOW HELP: ALTER TABLE
| ALTER PARTITION error // SHOW HELP: ALTER TABLE
// %Help: ALTER VIEW - change the definition of a view
// %Category: DDL
// %Text:
// ALTER VIEW [IF EXISTS] <name> RENAME TO <newname>
// %SeeAlso: WEBDOCS/alter-view.html
alter_view_stmt:
alter_rename_view_stmt
// ALTER VIEW has its error help token here because the ALTER VIEW
// prefix is spread over multiple non-terminals.
| ALTER VIEW error // SHOW HELP: ALTER VIEW
// %Help: ALTER SEQUENCE - change the definition of a sequence
// %Category: DDL
// %Text:
// ALTER SEQUENCE [IF EXISTS] <name>
// [INCREMENT <increment>]
// [MINVALUE <minvalue> | NO MINVALUE]
// [MAXVALUE <maxvalue> | NO MAXVALUE]
// [START <start>]
// [[NO] CYCLE]
// ALTER SEQUENCE [IF EXISTS] <name> RENAME TO <newname>
alter_sequence_stmt:
alter_rename_sequence_stmt
| alter_sequence_options_stmt
| ALTER SEQUENCE error // SHOW HELP: ALTER SEQUENCE
alter_sequence_options_stmt:
ALTER SEQUENCE sequence_name sequence_option_list
{
$$.val = &tree.AlterSequence{Name: $3.normalizableTableNameFromUnresolvedName(), Options: $4.seqOpts(), IfExists: false}
}
| ALTER SEQUENCE IF EXISTS sequence_name sequence_option_list
{
$$.val = &tree.AlterSequence{Name: $5.normalizableTableNameFromUnresolvedName(), Options: $6.seqOpts(), IfExists: true}
}
// %Help: ALTER USER - change user properties
// %Category: Priv
// %Text:
// ALTER USER [IF EXISTS] <name> WITH PASSWORD <password>
// %SeeAlso: CREATE USER
alter_user_stmt:
alter_user_password_stmt
| ALTER USER error // SHOW HELP: ALTER USER
// %Help: ALTER DATABASE - change the definition of a database
// %Category: DDL
// %Text:
// ALTER DATABASE <name> RENAME TO <newname>
// %SeeAlso: WEBDOCS/alter-database.html
alter_database_stmt:
alter_rename_database_stmt
| alter_zone_database_stmt
// ALTER DATABASE has its error help token here because the ALTER DATABASE
// prefix is spread over multiple non-terminals.
| ALTER DATABASE error // SHOW HELP: ALTER DATABASE
// %Help: ALTER RANGE - change the parameters of a range
// %Category: DDL
// %Text:
// ALTER RANGE <zonename> <command>
//
// Commands:
// ALTER RANGE ... CONFIGURE ZONE <zoneconfig>
//
// Zone configurations:
// DISCARD
// USING <var> = <expr> [, ...]
// { TO | = } <expr>
//
// %SeeAlso: ALTER TABLE
alter_range_stmt:
alter_zone_range_stmt
| ALTER RANGE error // SHOW HELP: ALTER RANGE
// %Help: ALTER INDEX - change the definition of an index
// %Category: DDL
// %Text:
// ALTER INDEX [IF EXISTS] <idxname> <command>
//
// Commands:
// ALTER INDEX ... RENAME TO <newname>
// ALTER INDEX ... SPLIT AT <selectclause>
// ALTER INDEX ... SCATTER [ FROM ( <exprs...> ) TO ( <exprs...> ) ]
//
// %SeeAlso: WEBDOCS/alter-index.html
alter_index_stmt:
alter_oneindex_stmt
| alter_relocate_index_stmt
| alter_relocate_index_lease_stmt
| alter_split_index_stmt
| alter_scatter_index_stmt
| alter_rename_index_stmt
| alter_zone_index_stmt
// ALTER INDEX has its error help token here because the ALTER INDEX
// prefix is spread over multiple non-terminals.
| ALTER INDEX error // SHOW HELP: ALTER INDEX
alter_onetable_stmt:
ALTER TABLE relation_expr alter_table_cmds
{
$$.val = &tree.AlterTable{Table: $3.normalizableTableNameFromUnresolvedName(), IfExists: false, Cmds: $4.alterTableCmds()}
}
| ALTER TABLE IF EXISTS relation_expr alter_table_cmds
{
$$.val = &tree.AlterTable{Table: $5.normalizableTableNameFromUnresolvedName(), IfExists: true, Cmds: $6.alterTableCmds()}
}
alter_oneindex_stmt:
ALTER INDEX table_name_with_index alter_index_cmds
{
$$.val = &tree.AlterIndex{Index: $3.newTableWithIdx(), IfExists: false, Cmds: $4.alterIndexCmds()}
}
| ALTER INDEX IF EXISTS table_name_with_index alter_index_cmds
{
$$.val = &tree.AlterIndex{Index: $5.newTableWithIdx(), IfExists: true, Cmds: $6.alterIndexCmds()}
}
alter_split_stmt:
ALTER TABLE table_name SPLIT AT select_stmt
{
$$.val = &tree.Split{Table: $3.newNormalizableTableNameFromUnresolvedName(), Rows: $6.slct()}
}
alter_split_index_stmt:
ALTER INDEX table_name_with_index SPLIT AT select_stmt
{
$$.val = &tree.Split{Index: $3.newTableWithIdx(), Rows: $6.slct()}
}
relocate_kw:
TESTING_RELOCATE
| EXPERIMENTAL_RELOCATE
alter_relocate_stmt:
ALTER TABLE table_name relocate_kw select_stmt
{
/* SKIP DOC */
$$.val = &tree.Relocate{Table: $3.newNormalizableTableNameFromUnresolvedName(), Rows: $5.slct()}
}
alter_relocate_index_stmt:
ALTER INDEX table_name_with_index relocate_kw select_stmt
{
/* SKIP DOC */
$$.val = &tree.Relocate{Index: $3.newTableWithIdx(), Rows: $5.slct()}
}
alter_relocate_lease_stmt:
ALTER TABLE table_name relocate_kw LEASE select_stmt
{
/* SKIP DOC */
$$.val = &tree.Relocate{Table: $3.newNormalizableTableNameFromUnresolvedName(), Rows: $6.slct(), RelocateLease: true}
}
alter_relocate_index_lease_stmt:
ALTER INDEX table_name_with_index relocate_kw LEASE select_stmt
{
/* SKIP DOC */
$$.val = &tree.Relocate{Index: $3.newTableWithIdx(), Rows: $6.slct(), RelocateLease: true}
}
alter_zone_range_stmt:
ALTER RANGE zone_name set_zone_config
{
s := $4.setZoneConfig()
s.ZoneSpecifier = tree.ZoneSpecifier{NamedZone: tree.UnrestrictedName($3)}
$$.val = s
}
set_zone_config:
CONFIGURE ZONE to_or_eq a_expr
{
/* SKIP DOC */
$$.val = &tree.SetZoneConfig{YAMLConfig: $4.expr()}
}
| CONFIGURE ZONE USING var_set_list
{
$$.val = &tree.SetZoneConfig{Options: $4.kvOptions()}
}
| CONFIGURE ZONE USING DEFAULT
{
/* SKIP DOC */
$$.val = &tree.SetZoneConfig{SetDefault: true}
}
| CONFIGURE ZONE DISCARD
{
$$.val = &tree.SetZoneConfig{YAMLConfig: tree.DNull}
}
alter_zone_database_stmt:
ALTER DATABASE database_name set_zone_config
{
s := $4.setZoneConfig()
s.ZoneSpecifier = tree.ZoneSpecifier{Database: tree.Name($3)}
$$.val = s
}
alter_zone_table_stmt:
ALTER TABLE table_name set_zone_config
{
s := $4.setZoneConfig()
s.ZoneSpecifier = tree.ZoneSpecifier{
TableOrIndex: tree.TableNameWithIndex{Table: $3.normalizableTableNameFromUnresolvedName()},
}
$$.val = s
}
| ALTER PARTITION partition_name OF TABLE table_name set_zone_config
{
s := $7.setZoneConfig()
s.ZoneSpecifier = tree.ZoneSpecifier{
TableOrIndex: tree.TableNameWithIndex{Table: $6.normalizableTableNameFromUnresolvedName()},
Partition: tree.Name($3),
}
$$.val = s
}
alter_zone_index_stmt:
ALTER INDEX table_name_with_index set_zone_config
{
s := $4.setZoneConfig()
s.ZoneSpecifier = tree.ZoneSpecifier{
TableOrIndex: $3.tableWithIdx(),
}
$$.val = s
}
var_set_list:
var_name '=' var_value
{
$$.val = []tree.KVOption{tree.KVOption{Key: tree.Name(strings.Join($1.strs(), ".")), Value: $3.expr()}}
}
| var_set_list ',' var_name '=' var_value
{
$$.val = append($1.kvOptions(), tree.KVOption{Key: tree.Name(strings.Join($3.strs(), ".")), Value: $5.expr()})
}
alter_scatter_stmt:
ALTER TABLE table_name SCATTER
{
$$.val = &tree.Scatter{Table: $3.newNormalizableTableNameFromUnresolvedName()}
}
| ALTER TABLE table_name SCATTER FROM '(' expr_list ')' TO '(' expr_list ')'
{
$$.val = &tree.Scatter{Table: $3.newNormalizableTableNameFromUnresolvedName(), From: $7.exprs(), To: $11.exprs()}
}
alter_scatter_index_stmt:
ALTER INDEX table_name_with_index SCATTER
{
$$.val = &tree.Scatter{Index: $3.newTableWithIdx()}
}
| ALTER INDEX table_name_with_index SCATTER FROM '(' expr_list ')' TO '(' expr_list ')'
{
$$.val = &tree.Scatter{Index: $3.newTableWithIdx(), From: $7.exprs(), To: $11.exprs()}
}
alter_table_cmds:
alter_table_cmd
{
$$.val = tree.AlterTableCmds{$1.alterTableCmd()}
}
| alter_table_cmds ',' alter_table_cmd
{
$$.val = append($1.alterTableCmds(), $3.alterTableCmd())
}
alter_table_cmd:
// ALTER TABLE <name> ADD <coldef>
ADD column_def
{
$$.val = &tree.AlterTableAddColumn{IfNotExists: false, ColumnDef: $2.colDef()}
}
// ALTER TABLE <name> ADD IF NOT EXISTS <coldef>
| ADD IF NOT EXISTS column_def
{
$$.val = &tree.AlterTableAddColumn{IfNotExists: true, ColumnDef: $5.colDef()}
}
// ALTER TABLE <name> ADD COLUMN <coldef>
| ADD COLUMN column_def
{
$$.val = &tree.AlterTableAddColumn{IfNotExists: false, ColumnDef: $3.colDef()}
}
// ALTER TABLE <name> ADD COLUMN IF NOT EXISTS <coldef>
| ADD COLUMN IF NOT EXISTS column_def
{
$$.val = &tree.AlterTableAddColumn{IfNotExists: true, ColumnDef: $6.colDef()}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT}
| ALTER opt_column column_name alter_column_default
{
$$.val = &tree.AlterTableSetDefault{Column: tree.Name($3), Default: $4.expr()}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname> DROP NOT NULL
| ALTER opt_column column_name DROP NOT NULL
{
$$.val = &tree.AlterTableDropNotNull{Column: tree.Name($3)}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname> DROP STORED
| ALTER opt_column column_name DROP STORED
{
$$.val = &tree.AlterTableDropStored{Column: tree.Name($3)}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname> SET NOT NULL
| ALTER opt_column column_name SET NOT NULL { return unimplementedWithIssue(sqllex, 28751) }
// ALTER TABLE <name> DROP [COLUMN] IF EXISTS <colname> [RESTRICT|CASCADE]
| DROP opt_column IF EXISTS column_name opt_drop_behavior
{
$$.val = &tree.AlterTableDropColumn{
IfExists: true,
Column: tree.Name($5),
DropBehavior: $6.dropBehavior(),
}
}
// ALTER TABLE <name> DROP [COLUMN] <colname> [RESTRICT|CASCADE]
| DROP opt_column column_name opt_drop_behavior
{
$$.val = &tree.AlterTableDropColumn{
IfExists: false,
Column: tree.Name($3),
DropBehavior: $4.dropBehavior(),
}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname>
// [SET DATA] TYPE <typename>
// [ COLLATE collation ]
// [ USING <expression> ]
| ALTER opt_column column_name opt_set_data TYPE typename opt_collate opt_alter_column_using
{
$$.val = &tree.AlterTableAlterColumnType{
Column: tree.Name($3),
ToType: $6.colType(),
Collation: $7,
Using: $8.expr(),
}
}
// ALTER TABLE <name> ADD CONSTRAINT ...
| ADD table_constraint opt_validate_behavior
{
$$.val = &tree.AlterTableAddConstraint{
ConstraintDef: $2.constraintDef(),
ValidationBehavior: $3.validationBehavior(),
}
}
// ALTER TABLE <name> ALTER CONSTRAINT ...
| ALTER CONSTRAINT constraint_name error { return unimplemented(sqllex, "alter constraint") }
// ALTER TABLE <name> VALIDATE CONSTRAINT ...
| VALIDATE CONSTRAINT constraint_name
{
$$.val = &tree.AlterTableValidateConstraint{
Constraint: tree.Name($3),
}
}
// ALTER TABLE <name> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE]
| DROP CONSTRAINT IF EXISTS constraint_name opt_drop_behavior
{
$$.val = &tree.AlterTableDropConstraint{
IfExists: true,
Constraint: tree.Name($5),
DropBehavior: $6.dropBehavior(),
}
}
// ALTER TABLE <name> DROP CONSTRAINT <name> [RESTRICT|CASCADE]
| DROP CONSTRAINT constraint_name opt_drop_behavior
{
$$.val = &tree.AlterTableDropConstraint{
IfExists: false,
Constraint: tree.Name($3),
DropBehavior: $4.dropBehavior(),
}
}
// ALTER TABLE <name> EXPERIMENTAL_AUDIT SET <mode>
| EXPERIMENTAL_AUDIT SET audit_mode
{
$$.val = &tree.AlterTableSetAudit{Mode: $3.auditMode()}
}
// ALTER TABLE <name> PARTITION BY ...
| partition_by
{
$$.val = &tree.AlterTablePartitionBy{
PartitionBy: $1.partitionBy(),
}
}
// ALTER TABLE <name> INJECT STATISTICS <json>
| INJECT STATISTICS a_expr
{
/* SKIP DOC */
$$.val = &tree.AlterTableInjectStats{
Stats: $3.expr(),
}
}
audit_mode:
READ WRITE { $$.val = tree.AuditModeReadWrite }
| OFF { $$.val = tree.AuditModeDisable }
alter_index_cmds:
alter_index_cmd
{
$$.val = tree.AlterIndexCmds{$1.alterIndexCmd()}
}
| alter_index_cmds ',' alter_index_cmd
{
$$.val = append($1.alterIndexCmds(), $3.alterIndexCmd())
}
alter_index_cmd:
partition_by
{
$$.val = &tree.AlterIndexPartitionBy{
PartitionBy: $1.partitionBy(),
}
}
alter_column_default:
SET DEFAULT a_expr
{
$$.val = $3.expr()
}
| DROP DEFAULT
{
$$.val = nil
}
opt_alter_column_using:
USING a_expr
{
$$.val = $2.expr()
}
| /* EMPTY */
{
$$.val = nil
}
opt_drop_behavior:
CASCADE
{
$$.val = tree.DropCascade
}
| RESTRICT
{
$$.val = tree.DropRestrict
}
| /* EMPTY */
{
$$.val = tree.DropDefault
}
opt_validate_behavior:
NOT VALID
{
$$.val = tree.ValidationSkip
}
| /* EMPTY */
{
$$.val = tree.ValidationDefault
}
// %Help: BACKUP - back up data to external storage
// %Category: CCL
// %Text:
// BACKUP <targets...> TO <location...>
// [ AS OF SYSTEM TIME <expr> ]
// [ INCREMENTAL FROM <location...> ]
// [ WITH <option> [= <value>] [, ...] ]
//
// Targets:
// TABLE <pattern> [, ...]
// DATABASE <databasename> [, ...]
//
// Location:
// "[scheme]://[host]/[path to backup]?[parameters]"
//
// Options:
// INTO_DB
// SKIP_MISSING_FOREIGN_KEYS
//
// %SeeAlso: RESTORE, WEBDOCS/backup.html
backup_stmt:
BACKUP targets TO string_or_placeholder opt_as_of_clause opt_incremental opt_with_options
{
$$.val = &tree.Backup{Targets: $2.targetList(), To: $4.expr(), IncrementalFrom: $6.exprs(), AsOf: $5.asOfClause(), Options: $7.kvOptions()}
}
| BACKUP error // SHOW HELP: BACKUP
// %Help: RESTORE - restore data from external storage
// %Category: CCL
// %Text:
// RESTORE <targets...> FROM <location...>
// [ AS OF SYSTEM TIME <expr> ]
// [ WITH <option> [= <value>] [, ...] ]
//
// Targets:
// TABLE <pattern> [, ...]
// DATABASE <databasename> [, ...]
//
// Locations:
// "[scheme]://[host]/[path to backup]?[parameters]"
//
// Options:
// INTO_DB
// SKIP_MISSING_FOREIGN_KEYS
//
// %SeeAlso: BACKUP, WEBDOCS/restore.html
restore_stmt:
RESTORE targets FROM string_or_placeholder_list opt_with_options
{
$$.val = &tree.Restore{Targets: $2.targetList(), From: $4.exprs(), Options: $5.kvOptions()}
}
| RESTORE targets FROM string_or_placeholder_list as_of_clause opt_with_options
{
$$.val = &tree.Restore{Targets: $2.targetList(), From: $4.exprs(), AsOf: $5.asOfClause(), Options: $6.kvOptions()}
}
| RESTORE error // SHOW HELP: RESTORE
import_format:
name
{
$$ = strings.ToUpper($1)
}
// %Help: IMPORT - load data from file in a distributed manner
// %Category: CCL
// %Text:
// IMPORT [ TABLE <tablename> FROM ]
// <format> ( <datafile> )
// [ WITH <option> [= <value>] [, ...] ]
//
// IMPORT TABLE <tablename>
// { ( <elements> ) | CREATE USING <schemafile> }
// <format>
// DATA ( <datafile> [, ...] )
// [ WITH <option> [= <value>] [, ...] ]
//
// Formats:
// CSV
// MYSQLOUTFILE
// MYSQLDUMP (mysqldump's SQL output)
// PGCOPY
// PGDUMP
//
// Options:
// distributed = '...'
// sstsize = '...'
// temp = '...'
// delimiter = '...' [CSV, PGCOPY-specific]
// nullif = '...' [CSV, PGCOPY-specific]
// comment = '...' [CSV-specific]
//
// %SeeAlso: CREATE TABLE
import_stmt:
IMPORT import_format '(' string_or_placeholder ')' opt_with_options
{
$$.val = &tree.Import{Bundle: true, FileFormat: $2, Files: tree.Exprs{$4.expr()}, Options: $6.kvOptions()}
}
| IMPORT import_format string_or_placeholder opt_with_options
{
$$.val = &tree.Import{Bundle: true, FileFormat: $2, Files: tree.Exprs{$3.expr()}, Options: $4.kvOptions()}
}
| IMPORT TABLE table_name FROM import_format '(' string_or_placeholder ')' opt_with_options
{
$$.val = &tree.Import{Bundle: true, Table: $3.normalizableTableNameFromUnresolvedName(), FileFormat: $5, Files: tree.Exprs{$7.expr()}, Options: $9.kvOptions()}
}
| IMPORT TABLE table_name FROM import_format string_or_placeholder opt_with_options
{
$$.val = &tree.Import{Bundle: true, Table: $3.normalizableTableNameFromUnresolvedName(), FileFormat: $5, Files: tree.Exprs{$6.expr()}, Options: $7.kvOptions()}
}
| IMPORT TABLE table_name CREATE USING string_or_placeholder import_format DATA '(' string_or_placeholder_list ')' opt_with_options
{
$$.val = &tree.Import{Table: $3.normalizableTableNameFromUnresolvedName(), CreateFile: $6.expr(), FileFormat: $7, Files: $10.exprs(), Options: $12.kvOptions()}
}
| IMPORT TABLE table_name '(' table_elem_list ')' import_format DATA '(' string_or_placeholder_list ')' opt_with_options
{
$$.val = &tree.Import{Table: $3.normalizableTableNameFromUnresolvedName(), CreateDefs: $5.tblDefs(), FileFormat: $7, Files: $10.exprs(), Options: $12.kvOptions()}
}
| IMPORT error // SHOW HELP: IMPORT
// %Help: EXPORT - export data to file in a distributed manner
// %Category: CCL
// %Text:
// EXPORT INTO <format> (<datafile> [WITH <option> [= value] [,...]]) FROM <query>
//
// Formats:
// CSV
//
// Options:
// delimiter = '...' [CSV-specific]
//
// %SeeAlso: SELECT
export_stmt:
EXPORT INTO import_format string_or_placeholder opt_with_options FROM select_stmt
{
$$.val = &tree.Export{Query: $7.slct(), FileFormat: $3, File: $4.expr(), Options: $5.kvOptions()}
}
| EXPORT error // SHOW HELP: EXPORT
string_or_placeholder:
non_reserved_word_or_sconst
{
$$.val = tree.NewStrVal($1)
}
| PLACEHOLDER
{
$$.val = tree.NewPlaceholder($1)
}
string_or_placeholder_list:
string_or_placeholder
{
$$.val = tree.Exprs{$1.expr()}
}
| string_or_placeholder_list ',' string_or_placeholder
{
$$.val = append($1.exprs(), $3.expr())
}
opt_incremental:
INCREMENTAL FROM string_or_placeholder_list
{
$$.val = $3.exprs()
}
| /* EMPTY */
{
$$.val = tree.Exprs(nil)
}
kv_option:
name '=' string_or_placeholder
{
$$.val = tree.KVOption{Key: tree.Name($1), Value: $3.expr()}
}
| name
{
$$.val = tree.KVOption{Key: tree.Name($1)}
}
| SCONST '=' string_or_placeholder
{
$$.val = tree.KVOption{Key: tree.Name($1), Value: $3.expr()}
}
| SCONST
{
$$.val = tree.KVOption{Key: tree.Name($1)}
}
kv_option_list:
kv_option
{
$$.val = []tree.KVOption{$1.kvOption()}
}
| kv_option_list ',' kv_option
{
$$.val = append($1.kvOptions(), $3.kvOption())
}
opt_with_options:
WITH kv_option_list
{
$$.val = $2.kvOptions()
}
| WITH OPTIONS '(' kv_option_list ')'
{
$$.val = $4.kvOptions()
}
| /* EMPTY */
{
$$.val = nil
}
copy_from_stmt:
COPY table_name opt_column_list FROM STDIN
{
$$.val = &tree.CopyFrom{
Table: $2.normalizableTableNameFromUnresolvedName(),
Columns: $3.nameList(),
Stdin: true,
}
}
// %Help: CANCEL
// %Category: Group
// %Text: CANCEL JOBS, CANCEL QUERIES, CANCEL SESSIONS
cancel_stmt:
cancel_jobs_stmt // EXTEND WITH HELP: CANCEL JOBS
| cancel_queries_stmt // EXTEND WITH HELP: CANCEL QUERIES
| cancel_sessions_stmt // EXTEND WITH HELP: CANCEL SESSIONS
| CANCEL error // SHOW HELP: CANCEL
// %Help: CANCEL JOBS - cancel background jobs
// %Category: Misc
// %Text:
// CANCEL JOBS <selectclause>
// CANCEL JOB <jobid>
// %SeeAlso: SHOW JOBS, PAUSE JOBS, RESUME JOBS
cancel_jobs_stmt:
CANCEL JOB a_expr
{
$$.val = &tree.ControlJobs{
Jobs: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$3.expr()}}},
},
Command: tree.CancelJob,
}
}
| CANCEL JOB error // SHOW HELP: CANCEL JOBS
| CANCEL JOBS select_stmt
{
$$.val = &tree.ControlJobs{Jobs: $3.slct(), Command: tree.CancelJob}
}
| CANCEL JOBS error // SHOW HELP: CANCEL JOBS
// %Help: CANCEL QUERIES - cancel running queries
// %Category: Misc
// %Text:
// CANCEL QUERIES [IF EXISTS] <selectclause>
// CANCEL QUERY [IF EXISTS] <expr>
// %SeeAlso: SHOW QUERIES
cancel_queries_stmt:
CANCEL QUERY a_expr
{
$$.val = &tree.CancelQueries{
Queries: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$3.expr()}}},
},
IfExists: false,
}
}
| CANCEL QUERY IF EXISTS a_expr
{
$$.val = &tree.CancelQueries{
Queries: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$5.expr()}}},
},
IfExists: true,
}
}
| CANCEL QUERY error // SHOW HELP: CANCEL QUERIES
| CANCEL QUERIES select_stmt
{
$$.val = &tree.CancelQueries{Queries: $3.slct(), IfExists: false}
}
| CANCEL QUERIES IF EXISTS select_stmt
{
$$.val = &tree.CancelQueries{Queries: $5.slct(), IfExists: true}
}
| CANCEL QUERIES error // SHOW HELP: CANCEL QUERIES
// %Help: CANCEL SESSIONS - cancel open sessions
// %Category: Misc
// %Text:
// CANCEL SESSIONS [IF EXISTS] <selectclause>
// CANCEL SESSION [IF EXISTS] <sessionid>
// %SeeAlso: SHOW SESSIONS
cancel_sessions_stmt:
CANCEL SESSION a_expr
{
$$.val = &tree.CancelSessions{
Sessions: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$3.expr()}}},
},
IfExists: false,
}
}
| CANCEL SESSION IF EXISTS a_expr
{
$$.val = &tree.CancelSessions{
Sessions: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$5.expr()}}},
},
IfExists: true,
}
}
| CANCEL SESSION error // SHOW HELP: CANCEL SESSIONS
| CANCEL SESSIONS select_stmt
{
$$.val = &tree.CancelSessions{Sessions: $3.slct(), IfExists: false}
}
| CANCEL SESSIONS IF EXISTS select_stmt
{
$$.val = &tree.CancelSessions{Sessions: $5.slct(), IfExists: true}
}
| CANCEL SESSIONS error // SHOW HELP: CANCEL SESSIONS
comment_stmt:
COMMENT ON TABLE table_name IS comment_text
{
return unimplementedWithIssueDetail(sqllex, 19472, "table")
}
| COMMENT ON COLUMN column_path IS comment_text
{
return unimplementedWithIssueDetail(sqllex, 19472, "column")
}
| COMMENT ON error
{
return unimplementedWithIssue(sqllex, 19472)
}
comment_text:
SCONST { $$ = $1 }
| NULL { $$ = "" }
// %Help: CREATE
// %Category: Group
// %Text:
// CREATE DATABASE, CREATE TABLE, CREATE INDEX, CREATE TABLE AS,
// CREATE USER, CREATE VIEW, CREATE SEQUENCE, CREATE STATISTICS,
// CREATE ROLE
create_stmt:
create_user_stmt // EXTEND WITH HELP: CREATE USER
| create_role_stmt // EXTEND WITH HELP: CREATE ROLE
| create_ddl_stmt // help texts in sub-rule
| create_stats_stmt // EXTEND WITH HELP: CREATE STATISTICS
| create_unsupported {}
| CREATE error // SHOW HELP: CREATE
create_unsupported:
CREATE AGGREGATE error { return unimplemented(sqllex, "create aggregate") }
| CREATE CAST error { return unimplemented(sqllex, "create cast") }
| CREATE CONSTRAINT TRIGGER error { return unimplementedWithIssueDetail(sqllex, 28296, "create constraint") }
| CREATE CONVERSION error { return unimplemented(sqllex, "create conversion") }
| CREATE DEFAULT CONVERSION error { return unimplemented(sqllex, "create def conv") }
| CREATE EXTENSION IF NOT EXISTS name error { return unimplemented(sqllex, "create extension " + $6) }
| CREATE EXTENSION name error { return unimplemented(sqllex, "create extension " + $3) }
| CREATE FOREIGN TABLE error { return unimplemented(sqllex, "create foreign table") }
| CREATE FOREIGN DATA error { return unimplemented(sqllex, "create fdw") }
| CREATE FUNCTION error { return unimplementedWithIssueDetail(sqllex, 17511, "create function") }
| CREATE OR REPLACE FUNCTION error { return unimplementedWithIssueDetail(sqllex, 17511, "create function") }
| CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE name error { return unimplementedWithIssueDetail(sqllex, 17511, "create language " + $6) }
| CREATE MATERIALIZED VIEW error { return unimplementedWithIssue(sqllex, 24747) }
| CREATE OPERATOR error { return unimplemented(sqllex, "create operator") }
| CREATE PUBLICATION error { return unimplemented(sqllex, "create publication") }
| CREATE opt_or_replace RULE error { return unimplemented(sqllex, "create rule") }
| CREATE SERVER error { return unimplemented(sqllex, "create server") }
| CREATE SUBSCRIPTION error { return unimplemented(sqllex, "create subscription") }
| CREATE TEXT error { return unimplementedWithIssueDetail(sqllex, 7821, "create text") }
| CREATE TRIGGER error { return unimplementedWithIssueDetail(sqllex, 28296, "create") }
opt_or_replace:
OR REPLACE {}
| /* EMPTY */ {}
opt_trusted:
TRUSTED {}
| /* EMPTY */ {}
opt_procedural:
PROCEDURAL {}
| /* EMPTY */ {}
drop_unsupported:
DROP AGGREGATE error { return unimplemented(sqllex, "drop aggregate") }
| DROP CAST error { return unimplemented(sqllex, "drop cast") }
| DROP COLLATION error { return unimplemented(sqllex, "drop collation") }
| DROP CONVERSION error { return unimplemented(sqllex, "drop conversion") }
| DROP DOMAIN error { return unimplementedWithIssueDetail(sqllex, 27796, "drop") }
| DROP EXTENSION IF EXISTS name error { return unimplemented(sqllex, "drop extension " + $5) }
| DROP EXTENSION name error { return unimplemented(sqllex, "drop extension " + $3) }
| DROP FOREIGN TABLE error { return unimplemented(sqllex, "drop foreign table") }
| DROP FOREIGN DATA error { return unimplemented(sqllex, "drop fdw") }
| DROP FUNCTION error { return unimplementedWithIssueDetail(sqllex, 17511, "drop function") }
| DROP opt_procedural LANGUAGE name error { return unimplementedWithIssueDetail(sqllex, 17511, "drop language " + $4) }
| DROP OPERATOR error { return unimplemented(sqllex, "drop operator") }
| DROP PUBLICATION error { return unimplemented(sqllex, "drop publication") }
| DROP RULE error { return unimplemented(sqllex, "drop rule") }
| DROP SERVER error { return unimplemented(sqllex, "drop server") }
| DROP SUBSCRIPTION error { return unimplemented(sqllex, "drop subscription") }
| DROP TEXT error { return unimplementedWithIssueDetail(sqllex, 7821, "drop text") }
| DROP TYPE error { return unimplementedWithIssueDetail(sqllex, 27793, "drop type") }
| DROP TRIGGER error { return unimplementedWithIssueDetail(sqllex, 28296, "drop") }
create_ddl_stmt:
create_changefeed_stmt
| create_database_stmt // EXTEND WITH HELP: CREATE DATABASE
| create_index_stmt // EXTEND WITH HELP: CREATE INDEX
| create_table_stmt // EXTEND WITH HELP: CREATE TABLE
| create_table_as_stmt // EXTEND WITH HELP: CREATE TABLE
// Error case for both CREATE TABLE and CREATE TABLE ... AS in one
| CREATE opt_temp TABLE error // SHOW HELP: CREATE TABLE
| create_type_stmt { /* SKIP DOC */ }
| create_view_stmt // EXTEND WITH HELP: CREATE VIEW
| create_sequence_stmt // EXTEND WITH HELP: CREATE SEQUENCE
// %Help: CREATE STATISTICS - create a new table statistic (experimental)
// %Category: Experimental
// %Text:
// CREATE STATISTICS <statisticname>
// ON <colname> [, ...]
// FROM <tablename>
create_stats_stmt:
CREATE STATISTICS statistics_name ON name_list FROM table_name
{
/* SKIP DOC */
$$.val = &tree.CreateStats{
Name: tree.Name($3),
ColumnNames: $5.nameList(),
Table: $7.normalizableTableNameFromUnresolvedName(),
}
}
| CREATE STATISTICS error // SHOW HELP: CREATE STATISTICS
create_changefeed_stmt:
CREATE CHANGEFEED FOR changefeed_targets opt_changefeed_sink opt_with_options
{
$$.val = &tree.CreateChangefeed{
Targets: $4.targetList(),
SinkURI: $5.expr(),
Options: $6.kvOptions(),
}
}
changefeed_targets:
single_table_pattern_list
{
$$.val = tree.TargetList{Tables: $1.tablePatterns()}
}
| TABLE single_table_pattern_list
{
$$.val = tree.TargetList{Tables: $2.tablePatterns()}
}
single_table_pattern_list:
table_name
{
$$.val = tree.TablePatterns{$1.unresolvedName()}
}
| single_table_pattern_list ',' table_name
{
$$.val = append($1.tablePatterns(), $3.unresolvedName())
}
opt_changefeed_sink:
INTO string_or_placeholder
{
$$.val = $2.expr()
}
| /* EMPTY */
{
/* SKIP DOC */
$$.val = nil
}
// %Help: DELETE - delete rows from a table
// %Category: DML
// %Text: DELETE FROM <tablename> [WHERE <expr>]
// [ORDER BY <exprs...>]
// [LIMIT <expr>]
// [RETURNING <exprs...>]
// %SeeAlso: WEBDOCS/delete.html
delete_stmt:
opt_with_clause DELETE FROM table_name_expr_opt_alias_idx where_clause opt_sort_clause opt_limit_clause returning_clause
{
$$.val = &tree.Delete{
With: $1.with(),
Table: $4.tblExpr(),
Where: tree.NewWhere(tree.AstWhere, $5.expr()),
OrderBy: $6.orderBy(),
Limit: $7.limit(),
Returning: $8.retClause(),
}
}
| opt_with_clause DELETE error // SHOW HELP: DELETE
// %Help: DISCARD - reset the session to its initial state
// %Category: Cfg
// %Text: DISCARD ALL
discard_stmt:
DISCARD ALL
{
$$.val = &tree.Discard{Mode: tree.DiscardModeAll}
}
| DISCARD PLANS { return unimplemented(sqllex, "discard plans") }
| DISCARD SEQUENCES { return unimplemented(sqllex, "discard sequences") }
| DISCARD TEMP { return unimplemented(sqllex, "discard temp") }
| DISCARD TEMPORARY { return unimplemented(sqllex, "discard temp") }
| DISCARD error // SHOW HELP: DISCARD
// %Help: DROP
// %Category: Group
// %Text:
// DROP DATABASE, DROP INDEX, DROP TABLE, DROP VIEW, DROP SEQUENCE,
// DROP USER, DROP ROLE
drop_stmt:
drop_ddl_stmt // help texts in sub-rule
| drop_role_stmt // EXTEND WITH HELP: DROP ROLE
| drop_user_stmt // EXTEND WITH HELP: DROP USER
| drop_unsupported {}
| DROP error // SHOW HELP: DROP
drop_ddl_stmt:
drop_database_stmt // EXTEND WITH HELP: DROP DATABASE
| drop_index_stmt // EXTEND WITH HELP: DROP INDEX
| drop_table_stmt // EXTEND WITH HELP: DROP TABLE
| drop_view_stmt // EXTEND WITH HELP: DROP VIEW
| drop_sequence_stmt // EXTEND WITH HELP: DROP SEQUENCE
// %Help: DROP VIEW - remove a view
// %Category: DDL
// %Text: DROP VIEW [IF EXISTS] <tablename> [, ...] [CASCADE | RESTRICT]
// %SeeAlso: WEBDOCS/drop-index.html
drop_view_stmt:
DROP VIEW table_name_list opt_drop_behavior
{
$$.val = &tree.DropView{Names: $3.normalizableTableNames(), IfExists: false, DropBehavior: $4.dropBehavior()}
}
| DROP VIEW IF EXISTS table_name_list opt_drop_behavior
{
$$.val = &tree.DropView{Names: $5.normalizableTableNames(), IfExists: true, DropBehavior: $6.dropBehavior()}
}
| DROP VIEW error // SHOW HELP: DROP VIEW
// %Help: DROP SEQUENCE - remove a sequence
// %Category: DDL
// %Text: DROP SEQUENCE [IF EXISTS] <sequenceName> [, ...] [CASCADE | RESTRICT]
// %SeeAlso: DROP
drop_sequence_stmt:
DROP SEQUENCE table_name_list opt_drop_behavior
{
$$.val = &tree.DropSequence{Names: $3.normalizableTableNames(), IfExists: false, DropBehavior: $4.dropBehavior()}
}
| DROP SEQUENCE IF EXISTS table_name_list opt_drop_behavior
{
$$.val = &tree.DropSequence{Names: $5.normalizableTableNames(), IfExists: true, DropBehavior: $6.dropBehavior()}
}
| DROP SEQUENCE error // SHOW HELP: DROP VIEW
// %Help: DROP TABLE - remove a table
// %Category: DDL
// %Text: DROP TABLE [IF EXISTS] <tablename> [, ...] [CASCADE | RESTRICT]
// %SeeAlso: WEBDOCS/drop-table.html
drop_table_stmt:
DROP TABLE table_name_list opt_drop_behavior
{
$$.val = &tree.DropTable{Names: $3.normalizableTableNames(), IfExists: false, DropBehavior: $4.dropBehavior()}
}
| DROP TABLE IF EXISTS table_name_list opt_drop_behavior
{
$$.val = &tree.DropTable{Names: $5.normalizableTableNames(), IfExists: true, DropBehavior: $6.dropBehavior()}
}
| DROP TABLE error // SHOW HELP: DROP TABLE
// %Help: DROP INDEX - remove an index
// %Category: DDL
// %Text: DROP INDEX [IF EXISTS] <idxname> [, ...] [CASCADE | RESTRICT]
// %SeeAlso: WEBDOCS/drop-index.html
drop_index_stmt:
DROP INDEX table_name_with_index_list opt_drop_behavior
{
$$.val = &tree.DropIndex{
IndexList: $3.newTableWithIdxList(),
IfExists: false,
DropBehavior: $4.dropBehavior(),
}
}
| DROP INDEX IF EXISTS table_name_with_index_list opt_drop_behavior
{
$$.val = &tree.DropIndex{
IndexList: $5.newTableWithIdxList(),
IfExists: true,
DropBehavior: $6.dropBehavior(),
}
}
| DROP INDEX error // SHOW HELP: DROP INDEX
// %Help: DROP DATABASE - remove a database
// %Category: DDL
// %Text: DROP DATABASE [IF EXISTS] <databasename> [CASCADE | RESTRICT]
// %SeeAlso: WEBDOCS/drop-database.html
drop_database_stmt:
DROP DATABASE database_name opt_drop_behavior
{
$$.val = &tree.DropDatabase{
Name: tree.Name($3),
IfExists: false,
DropBehavior: $4.dropBehavior(),
}
}
| DROP DATABASE IF EXISTS database_name opt_drop_behavior
{
$$.val = &tree.DropDatabase{
Name: tree.Name($5),
IfExists: true,
DropBehavior: $6.dropBehavior(),
}
}
| DROP DATABASE error // SHOW HELP: DROP DATABASE
// %Help: DROP USER - remove a user
// %Category: Priv
// %Text: DROP USER [IF EXISTS] <user> [, ...]
// %SeeAlso: CREATE USER, SHOW USERS
drop_user_stmt:
DROP USER string_or_placeholder_list
{
$$.val = &tree.DropUser{Names: $3.exprs(), IfExists: false}
}
| DROP USER IF EXISTS string_or_placeholder_list
{
$$.val = &tree.DropUser{Names: $5.exprs(), IfExists: true}
}
| DROP USER error // SHOW HELP: DROP USER
// %Help: DROP ROLE - remove a role
// %Category: Priv
// %Text: DROP ROLE [IF EXISTS] <role> [, ...]
// %SeeAlso: CREATE ROLE, SHOW ROLES
drop_role_stmt:
DROP ROLE string_or_placeholder_list
{
$$.val = &tree.DropRole{Names: $3.exprs(), IfExists: false}
}
| DROP ROLE IF EXISTS string_or_placeholder_list
{
$$.val = &tree.DropRole{Names: $5.exprs(), IfExists: true}
}
| DROP ROLE error // SHOW HELP: DROP ROLE
table_name_list:
table_name
{
$$.val = tree.NormalizableTableNames{$1.normalizableTableNameFromUnresolvedName()}
}
| table_name_list ',' table_name
{
$$.val = append($1.normalizableTableNames(), $3.normalizableTableNameFromUnresolvedName())
}
// %Help: EXPLAIN - show the logical plan of a query
// %Category: Misc
// %Text:
// EXPLAIN <statement>
// EXPLAIN ([PLAN ,] <planoptions...> ) <statement>
// EXPLAIN [ANALYZE] (DISTSQL) <statement>
// EXPLAIN ANALYZE [(DISTSQL)] <statement>
//
// Explainable statements:
// SELECT, CREATE, DROP, ALTER, INSERT, UPSERT, UPDATE, DELETE,
// SHOW, EXPLAIN
//
// Plan options:
// TYPES, VERBOSE, OPT
//
// %SeeAlso: WEBDOCS/explain.html
explain_stmt:
EXPLAIN preparable_stmt
{
$$.val = &tree.Explain{Statement: $2.stmt()}
}
| EXPLAIN error // SHOW HELP: EXPLAIN
| EXPLAIN '(' explain_option_list ')' preparable_stmt
{
$$.val = &tree.Explain{Options: $3.strs(), Statement: $5.stmt()}
}
| EXPLAIN ANALYZE preparable_stmt
{
$$.val = &tree.Explain{Options: []string{"DISTSQL", $2}, Statement: $3.stmt()}
}
| EXPLAIN ANALYZE '(' explain_option_list ')' preparable_stmt
{
$$.val = &tree.Explain{Options: append($4.strs(), $2), Statement: $6.stmt()}
}
// This second error rule is necessary, because otherwise
// preparable_stmt also provides "selectclause := '(' error ..." and
// cause a help text for the select clause, which will be confusing in
// the context of EXPLAIN.
| EXPLAIN '(' error // SHOW HELP: EXPLAIN
preparable_stmt:
alter_stmt // help texts in sub-rule
| backup_stmt // EXTEND WITH HELP: BACKUP
| cancel_stmt // help texts in sub-rule
| create_stmt // help texts in sub-rule
| delete_stmt // EXTEND WITH HELP: DELETE
| drop_stmt // help texts in sub-rule
| explain_stmt { /* SKIP DOC */ }
| import_stmt // EXTEND WITH HELP: IMPORT
| insert_stmt // EXTEND WITH HELP: INSERT
| pause_stmt // EXTEND WITH HELP: PAUSE JOBS
| reset_stmt // help texts in sub-rule
| restore_stmt // EXTEND WITH HELP: RESTORE
| resume_stmt // EXTEND WITH HELP: RESUME JOBS
| scrub_stmt // help texts in sub-rule
| select_stmt // help texts in sub-rule
{
$$.val = $1.slct()
}
| preparable_set_stmt // help texts in sub-rule
| show_stmt // help texts in sub-rule
| truncate_stmt // EXTEND WITH HELP: TRUNCATE
| update_stmt // EXTEND WITH HELP: UPDATE
| upsert_stmt // EXTEND WITH HELP: UPSERT
explain_option_list:
explain_option_name
{
$$.val = []string{$1}
}
| explain_option_list ',' explain_option_name
{
$$.val = append($1.strs(), $3)
}
// %Help: PREPARE - prepare a statement for later execution
// %Category: Misc
// %Text: PREPARE <name> [ ( <types...> ) ] AS <query>
// %SeeAlso: EXECUTE, DEALLOCATE, DISCARD
prepare_stmt:
PREPARE table_alias_name prep_type_clause AS preparable_stmt
{
$$.val = &tree.Prepare{
Name: tree.Name($2),
Types: $3.colTypes(),
Statement: $5.stmt(),
}
}
| PREPARE error // SHOW HELP: PREPARE
prep_type_clause:
'(' type_list ')'
{
$$.val = $2.colTypes();
}
| /* EMPTY */
{
$$.val = []coltypes.T(nil)
}
// %Help: EXECUTE - execute a statement prepared previously
// %Category: Misc
// %Text: EXECUTE <name> [ ( <exprs...> ) ]
// %SeeAlso: PREPARE, DEALLOCATE, DISCARD
execute_stmt:
EXECUTE table_alias_name execute_param_clause
{
$$.val = &tree.Execute{
Name: tree.Name($2),
Params: $3.exprs(),
}
}
| EXECUTE error // SHOW HELP: EXECUTE
execute_param_clause:
'(' expr_list ')'
{
$$.val = $2.exprs()
}
| /* EMPTY */
{
$$.val = tree.Exprs(nil)
}
// %Help: DEALLOCATE - remove a prepared statement
// %Category: Misc
// %Text: DEALLOCATE [PREPARE] { <name> | ALL }
// %SeeAlso: PREPARE, EXECUTE, DISCARD
deallocate_stmt:
DEALLOCATE name
{
$$.val = &tree.Deallocate{Name: tree.Name($2)}
}
| DEALLOCATE PREPARE name
{
$$.val = &tree.Deallocate{Name: tree.Name($3)}
}
| DEALLOCATE ALL
{
$$.val = &tree.Deallocate{}
}
| DEALLOCATE PREPARE ALL
{
$$.val = &tree.Deallocate{}
}
| DEALLOCATE error // SHOW HELP: DEALLOCATE
// %Help: GRANT - define access privileges and role memberships
// %Category: Priv
// %Text:
// Grant privileges:
// GRANT {ALL | <privileges...> } ON <targets...> TO <grantees...>
// Grant role membership (CCL only):
// GRANT <roles...> TO <grantees...> [WITH ADMIN OPTION]
//
// Privileges:
// CREATE, DROP, GRANT, SELECT, INSERT, DELETE, UPDATE
//
// Targets:
// DATABASE <databasename> [, ...]
// [TABLE] [<databasename> .] { <tablename> | * } [, ...]
//
// %SeeAlso: REVOKE, WEBDOCS/grant.html
grant_stmt:
GRANT privileges ON targets TO name_list
{
$$.val = &tree.Grant{Privileges: $2.privilegeList(), Grantees: $6.nameList(), Targets: $4.targetList()}
}
| GRANT privilege_list TO name_list
{
$$.val = &tree.GrantRole{Roles: $2.nameList(), Members: $4.nameList(), AdminOption: false}
}
| GRANT privilege_list TO name_list WITH ADMIN OPTION
{
$$.val = &tree.GrantRole{Roles: $2.nameList(), Members: $4.nameList(), AdminOption: true}
}
| GRANT error // SHOW HELP: GRANT
// %Help: REVOKE - remove access privileges and role memberships
// %Category: Priv
// %Text:
// Revoke privileges:
// REVOKE {ALL | <privileges...> } ON <targets...> FROM <grantees...>
// Revoke role membership (CCL only):
// REVOKE [ADMIN OPTION FOR] <roles...> FROM <grantees...>
//
// Privileges:
// CREATE, DROP, GRANT, SELECT, INSERT, DELETE, UPDATE
//
// Targets:
// DATABASE <databasename> [, <databasename>]...
// [TABLE] [<databasename> .] { <tablename> | * } [, ...]
//
// %SeeAlso: GRANT, WEBDOCS/revoke.html
revoke_stmt:
REVOKE privileges ON targets FROM name_list
{
$$.val = &tree.Revoke{Privileges: $2.privilegeList(), Grantees: $6.nameList(), Targets: $4.targetList()}
}
| REVOKE privilege_list FROM name_list
{
$$.val = &tree.RevokeRole{Roles: $2.nameList(), Members: $4.nameList(), AdminOption: false }
}
| REVOKE ADMIN OPTION FOR privilege_list FROM name_list
{
$$.val = &tree.RevokeRole{Roles: $5.nameList(), Members: $7.nameList(), AdminOption: true }
}
| REVOKE error // SHOW HELP: REVOKE
// ALL is always by itself.
privileges:
ALL
{
$$.val = privilege.List{privilege.ALL}
}
| privilege_list
{
privList, err := privilege.ListFromStrings($1.nameList().ToStrings())
if err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = privList
}
privilege_list:
privilege
{
$$.val = tree.NameList{tree.Name($1)}
}
| privilege_list ',' privilege
{
$$.val = append($1.nameList(), tree.Name($3))
}
// Privileges are parsed at execution time to avoid having to make them reserved.
// Any privileges above `col_name_keyword` should be listed here.
// The full list is in sql/privilege/privilege.go.
privilege:
name
| CREATE
| GRANT
| SELECT
reset_stmt:
reset_session_stmt // EXTEND WITH HELP: RESET
| reset_csetting_stmt // EXTEND WITH HELP: RESET CLUSTER SETTING
// %Help: RESET - reset a session variable to its default value
// %Category: Cfg
// %Text: RESET [SESSION] <var>
// %SeeAlso: RESET CLUSTER SETTING, WEBDOCS/set-vars.html
reset_session_stmt:
RESET session_var
{
$$.val = &tree.SetVar{Name: $2, Values:tree.Exprs{tree.DefaultVal{}}}
}
| RESET SESSION session_var
{
$$.val = &tree.SetVar{Name: $3, Values:tree.Exprs{tree.DefaultVal{}}}
}
| RESET error // SHOW HELP: RESET
// %Help: RESET CLUSTER SETTING - reset a cluster setting to its default value
// %Category: Cfg
// %Text: RESET CLUSTER SETTING <var>
// %SeeAlso: SET CLUSTER SETTING, RESET
reset_csetting_stmt:
RESET CLUSTER SETTING var_name
{
$$.val = &tree.SetClusterSetting{Name: strings.Join($4.strs(), "."), Value:tree.DefaultVal{}}
}
| RESET CLUSTER error // SHOW HELP: RESET CLUSTER SETTING
// USE is the MSSQL/MySQL equivalent of SET DATABASE. Alias it for convenience.
// %Help: USE - set the current database
// %Category: Cfg
// %Text: USE <dbname>
//
// "USE <dbname>" is an alias for "SET [SESSION] database = <dbname>".
// %SeeAlso: SET SESSION, WEBDOCS/set-vars.html
use_stmt:
USE var_value
{
$$.val = &tree.SetVar{Name: "database", Values: tree.Exprs{$2.expr()}}
}
| USE error // SHOW HELP: USE
// SET remainder, e.g. SET TRANSACTION
nonpreparable_set_stmt:
set_transaction_stmt // EXTEND WITH HELP: SET TRANSACTION
| set_exprs_internal { /* SKIP DOC */ }
| SET CONSTRAINTS error { return unimplemented(sqllex, "set constraints") }
| SET LOCAL error { return unimplemented(sqllex, "set local") }
// SET SESSION / SET CLUSTER SETTING
preparable_set_stmt:
set_session_stmt // EXTEND WITH HELP: SET SESSION
| set_csetting_stmt // EXTEND WITH HELP: SET CLUSTER SETTING
| use_stmt // EXTEND WITH HELP: USE
// %Help: SCRUB - run checks against databases or tables
// %Category: Experimental
// %Text:
// EXPERIMENTAL SCRUB TABLE <table> ...
// EXPERIMENTAL SCRUB DATABASE <database>
//
// The various checks that ca be run with SCRUB includes:
// - Physical table data (encoding)
// - Secondary index integrity
// - Constraint integrity (NOT NULL, CHECK, FOREIGN KEY, UNIQUE)
// %SeeAlso: SCRUB TABLE, SCRUB DATABASE
scrub_stmt:
scrub_table_stmt
| scrub_database_stmt
| EXPERIMENTAL SCRUB error // SHOW HELP: SCRUB
// %Help: SCRUB DATABASE - run scrub checks on a database
// %Category: Experimental
// %Text:
// EXPERIMENTAL SCRUB DATABASE <database>
// [AS OF SYSTEM TIME <expr>]
//
// All scrub checks will be run on the database. This includes:
// - Physical table data (encoding)
// - Secondary index integrity
// - Constraint integrity (NOT NULL, CHECK, FOREIGN KEY, UNIQUE)
// %SeeAlso: SCRUB TABLE, SCRUB
scrub_database_stmt:
EXPERIMENTAL SCRUB DATABASE database_name opt_as_of_clause
{
$$.val = &tree.Scrub{Typ: tree.ScrubDatabase, Database: tree.Name($4), AsOf: $5.asOfClause()}
}
| EXPERIMENTAL SCRUB DATABASE error // SHOW HELP: SCRUB DATABASE
// %Help: SCRUB TABLE - run scrub checks on a table
// %Category: Experimental
// %Text:
// SCRUB TABLE <tablename>
// [AS OF SYSTEM TIME <expr>]
// [WITH OPTIONS <option> [, ...]]
//
// Options:
// EXPERIMENTAL SCRUB TABLE ... WITH OPTIONS INDEX ALL
// EXPERIMENTAL SCRUB TABLE ... WITH OPTIONS INDEX (<index>...)
// EXPERIMENTAL SCRUB TABLE ... WITH OPTIONS CONSTRAINT ALL
// EXPERIMENTAL SCRUB TABLE ... WITH OPTIONS CONSTRAINT (<constraint>...)
// EXPERIMENTAL SCRUB TABLE ... WITH OPTIONS PHYSICAL
// %SeeAlso: SCRUB DATABASE, SRUB
scrub_table_stmt:
EXPERIMENTAL SCRUB TABLE table_name opt_as_of_clause opt_scrub_options_clause
{
$$.val = &tree.Scrub{
Typ: tree.ScrubTable,
Table: $4.normalizableTableNameFromUnresolvedName(),
AsOf: $5.asOfClause(),
Options: $6.scrubOptions(),
}
}
| EXPERIMENTAL SCRUB TABLE error // SHOW HELP: SCRUB TABLE
opt_scrub_options_clause:
WITH OPTIONS scrub_option_list
{
$$.val = $3.scrubOptions()
}
| /* EMPTY */
{
$$.val = tree.ScrubOptions{}
}
scrub_option_list:
scrub_option
{
$$.val = tree.ScrubOptions{$1.scrubOption()}
}
| scrub_option_list ',' scrub_option
{
$$.val = append($1.scrubOptions(), $3.scrubOption())
}
scrub_option:
INDEX ALL
{
$$.val = &tree.ScrubOptionIndex{}
}
| INDEX '(' name_list ')'
{
$$.val = &tree.ScrubOptionIndex{IndexNames: $3.nameList()}
}
| CONSTRAINT ALL
{
$$.val = &tree.ScrubOptionConstraint{}
}
| CONSTRAINT '(' name_list ')'
{
$$.val = &tree.ScrubOptionConstraint{ConstraintNames: $3.nameList()}
}
| PHYSICAL
{
$$.val = &tree.ScrubOptionPhysical{}
}
// %Help: SET CLUSTER SETTING - change a cluster setting
// %Category: Cfg
// %Text: SET CLUSTER SETTING <var> { TO | = } <value>
// %SeeAlso: SHOW CLUSTER SETTING, RESET CLUSTER SETTING, SET SESSION,
// WEBDOCS/cluster-settings.html
set_csetting_stmt:
SET CLUSTER SETTING var_name to_or_eq var_value
{
$$.val = &tree.SetClusterSetting{Name: strings.Join($4.strs(), "."), Value: $6.expr()}
}
| SET CLUSTER error // SHOW HELP: SET CLUSTER SETTING
to_or_eq:
'='
| TO
set_exprs_internal:
/* SET ROW serves to accelerate parser.parseExprs().
It cannot be used by clients. */
SET ROW '(' expr_list ')'
{
$$.val = &tree.SetVar{Values: $4.exprs()}
}
// %Help: SET SESSION - change a session variable
// %Category: Cfg
// %Text:
// SET [SESSION] <var> { TO | = } <values...>
// SET [SESSION] TIME ZONE <tz>
// SET [SESSION] CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL { SNAPSHOT | SERIALIZABLE }
// SET [SESSION] TRACING { TO | = } { on | off | cluster | local | kv | results } [,...]
//
// %SeeAlso: SHOW SESSION, RESET, DISCARD, SHOW, SET CLUSTER SETTING, SET TRANSACTION,
// WEBDOCS/set-vars.html
set_session_stmt:
SET SESSION set_rest_more
{
$$.val = $3.stmt()
}
| SET set_rest_more
{
$$.val = $2.stmt()
}
// Special form for pg compatibility:
| SET SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list
{
$$.val = &tree.SetSessionCharacteristics{Modes: $6.transactionModes()}
}
// %Help: SET TRANSACTION - configure the transaction settings
// %Category: Txn
// %Text:
// SET [SESSION] TRANSACTION <txnparameters...>
//
// Transaction parameters:
// ISOLATION LEVEL { SNAPSHOT | SERIALIZABLE }
// PRIORITY { LOW | NORMAL | HIGH }
//
// %SeeAlso: SHOW TRANSACTION, SET SESSION,
// WEBDOCS/set-transaction.html
set_transaction_stmt:
SET TRANSACTION transaction_mode_list
{
$$.val = &tree.SetTransaction{Modes: $3.transactionModes()}
}
| SET TRANSACTION error // SHOW HELP: SET TRANSACTION
| SET SESSION TRANSACTION transaction_mode_list
{
$$.val = &tree.SetTransaction{Modes: $4.transactionModes()}
}
| SET SESSION TRANSACTION error // SHOW HELP: SET TRANSACTION
generic_set:
var_name to_or_eq var_list
{
// We need to recognize the "set tracing" specially here; couldn't make "set
// tracing" a different grammar rule because of ambiguity.
varName := $1.strs()
if len(varName) == 1 && varName[0] == "tracing" {
$$.val = &tree.SetTracing{Values: $3.exprs()}
} else {
$$.val = &tree.SetVar{Name: strings.Join($1.strs(), "."), Values: $3.exprs()}
}
}
set_rest_more:
// Generic SET syntaxes:
generic_set
// Special SET syntax forms in addition to the generic form.
// See: https://www.postgresql.org/docs/10/static/sql-set.html
//
// "SET TIME ZONE value is an alias for SET timezone TO value."
| TIME ZONE zone_value
{
/* SKIP DOC */
$$.val = &tree.SetVar{Name: "timezone", Values: tree.Exprs{$3.expr()}}
}
// "SET SCHEMA 'value' is an alias for SET search_path TO value. Only
// one schema can be specified using this syntax."
| SCHEMA var_value
{
/* SKIP DOC */
$$.val = &tree.SetVar{Name: "search_path", Values: tree.Exprs{$2.expr()}}
}
// See comment for the non-terminal for SET NAMES below.
| set_names
| var_name FROM CURRENT { return unimplemented(sqllex, "set from current") }
| error // SHOW HELP: SET SESSION
// SET NAMES is the SQL standard syntax for SET client_encoding.
// "SET NAMES value is an alias for SET client_encoding TO value."
// See https://www.postgresql.org/docs/10/static/sql-set.html
// Also see https://www.postgresql.org/docs/9.6/static/multibyte.html#AEN39236
set_names:
NAMES var_value
{
/* SKIP DOC */
$$.val = &tree.SetVar{Name: "client_encoding", Values: tree.Exprs{$2.expr()}}
}
| NAMES
{
/* SKIP DOC */
$$.val = &tree.SetVar{Name: "client_encoding", Values: tree.Exprs{tree.DefaultVal{}}}
}
var_name:
name
{
$$.val = []string{$1}
}
| name attrs
{
$$.val = append([]string{$1}, $2.strs()...)
}
attrs:
'.' unrestricted_name
{
$$.val = []string{$2}
}
| attrs '.' unrestricted_name
{
$$.val = append($1.strs(), $3)
}
var_value:
a_expr
| ON
{
$$.val = tree.Expr(&tree.UnresolvedName{NumParts: 1, Parts: tree.NameParts{$1}})
}
var_list:
var_value
{
$$.val = tree.Exprs{$1.expr()}
}
| var_list ',' var_value
{
$$.val = append($1.exprs(), $3.expr())
}
iso_level:
READ UNCOMMITTED
{
$$.val = tree.SerializableIsolation
}
| READ COMMITTED
{
$$.val = tree.SerializableIsolation
}
| SNAPSHOT
{
$$.val = tree.SerializableIsolation
}
| REPEATABLE READ
{
$$.val = tree.SerializableIsolation
}
| SERIALIZABLE
{
$$.val = tree.SerializableIsolation
}
user_priority:
LOW
{
$$.val = tree.Low
}
| NORMAL
{
$$.val = tree.Normal
}
| HIGH
{
$$.val = tree.High
}
// Timezone values can be:
// - a string such as 'pst8pdt'
// - an identifier such as "pst8pdt"
// - an integer or floating point number
// - a time interval per SQL99
zone_value:
SCONST
{
$$.val = tree.NewStrVal($1)
}
| IDENT
{
$$.val = tree.NewStrVal($1)
}
| interval
{
$$.val = $1.expr()
}
| numeric_only
| DEFAULT
{
$$.val = tree.DefaultVal{}
}
| LOCAL
{
$$.val = tree.NewStrVal($1)
}
// %Help: SHOW
// %Category: Group
// %Text:
// SHOW BACKUP, SHOW CLUSTER SETTING, SHOW COLUMNS, SHOW CONSTRAINTS,
// SHOW CREATE, SHOW DATABASES, SHOW HISTOGRAM, SHOW INDEXES, SHOW JOBS,
// SHOW QUERIES, SHOW ROLES, SHOW SESSION, SHOW SESSIONS, SHOW STATISTICS,
// SHOW SYNTAX, SHOW TABLES, SHOW TRACE SHOW TRANSACTION, SHOW USERS
show_stmt:
show_backup_stmt // EXTEND WITH HELP: SHOW BACKUP
| show_columns_stmt // EXTEND WITH HELP: SHOW COLUMNS
| show_constraints_stmt // EXTEND WITH HELP: SHOW CONSTRAINTS
| show_create_stmt // EXTEND WITH HELP: SHOW CREATE
| show_csettings_stmt // EXTEND WITH HELP: SHOW CLUSTER SETTING
| show_databases_stmt // EXTEND WITH HELP: SHOW DATABASES
| show_fingerprints_stmt
| show_grants_stmt // EXTEND WITH HELP: SHOW GRANTS
| show_histogram_stmt // EXTEND WITH HELP: SHOW HISTOGRAM
| show_indexes_stmt // EXTEND WITH HELP: SHOW INDEXES
| show_jobs_stmt // EXTEND WITH HELP: SHOW JOBS
| show_queries_stmt // EXTEND WITH HELP: SHOW QUERIES
| show_ranges_stmt // EXTEND WITH HELP: SHOW RANGES
| show_roles_stmt // EXTEND WITH HELP: SHOW ROLES
| show_schemas_stmt // EXTEND WITH HELP: SHOW SCHEMAS
| show_session_stmt // EXTEND WITH HELP: SHOW SESSION
| show_sessions_stmt // EXTEND WITH HELP: SHOW SESSIONS
| show_stats_stmt // EXTEND WITH HELP: SHOW STATISTICS
| show_syntax_stmt // EXTEND WITH HELP: SHOW SYNTAX
| show_tables_stmt // EXTEND WITH HELP: SHOW TABLES
| show_trace_stmt // EXTEND WITH HELP: SHOW TRACE
| show_transaction_stmt // EXTEND WITH HELP: SHOW TRANSACTION
| show_users_stmt // EXTEND WITH HELP: SHOW USERS
| show_zone_stmt
| SHOW error // SHOW HELP: SHOW
// %Help: SHOW SESSION - display session variables
// %Category: Cfg
// %Text: SHOW [SESSION] { <var> | ALL }
// %SeeAlso: WEBDOCS/show-vars.html
show_session_stmt:
SHOW session_var { $$.val = &tree.ShowVar{Name: $2} }
| SHOW SESSION session_var { $$.val = &tree.ShowVar{Name: $3} }
| SHOW SESSION error // SHOW HELP: SHOW SESSION
session_var:
IDENT
// Although ALL, SESSION_USER and DATABASE are identifiers for the
// purpose of SHOW, they lex as separate token types, so they need
// separate rules.
| ALL
| DATABASE
// SET NAMES is standard SQL for SET client_encoding.
// See https://www.postgresql.org/docs/9.6/static/multibyte.html#AEN39236
| NAMES { $$ = "client_encoding" }
| SESSION_USER
// TIME ZONE is special: it is two tokens, but is really the identifier "TIME ZONE".
| TIME ZONE { $$ = "timezone" }
| TIME error // SHOW HELP: SHOW SESSION
// %Help: SHOW STATISTICS - display table statistics (experimental)
// %Category: Experimental
// %Text: SHOW STATISTICS [USING JSON] FOR TABLE <table_name>
//
// Returns the available statistics for a table.
// The statistics can include a histogram ID, which can
// be used with SHOW HISTOGRAM.
// If USING JSON is specified, the statistics and histograms
// are encoded in JSON format.
// %SeeAlso: SHOW HISTOGRAM
show_stats_stmt:
SHOW STATISTICS FOR TABLE table_name
{
/* SKIP DOC */
$$.val = &tree.ShowTableStats{Table: $5.normalizableTableNameFromUnresolvedName() }
}
| SHOW STATISTICS USING JSON FOR TABLE table_name
{
/* SKIP DOC */
$$.val = &tree.ShowTableStats{Table: $7.normalizableTableNameFromUnresolvedName(), UsingJSON: true}
}
| SHOW STATISTICS error // SHOW HELP: SHOW STATISTICS
// %Help: SHOW HISTOGRAM - display histogram (experimental)
// %Category: Experimental
// %Text: SHOW HISTOGRAM <histogram_id>
//
// Returns the data in the histogram with the
// given ID (as returned by SHOW STATISTICS).
// %SeeAlso: SHOW STATISTICS
show_histogram_stmt:
SHOW HISTOGRAM ICONST
{
/* SKIP DOC */
id, err := $3.numVal().AsInt64()
if err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = &tree.ShowHistogram{HistogramID: id}
}
| SHOW HISTOGRAM error // SHOW HELP: SHOW HISTOGRAM
// %Help: SHOW BACKUP - list backup contents
// %Category: CCL
// %Text: SHOW BACKUP [FILES|RANGES] <location>
// %SeeAlso: WEBDOCS/show-backup.html
show_backup_stmt:
SHOW BACKUP string_or_placeholder
{
$$.val = &tree.ShowBackup{
Details: tree.BackupDefaultDetails,
Path: $3.expr(),
}
}
| SHOW BACKUP RANGES string_or_placeholder
{
/* SKIP DOC */
$$.val = &tree.ShowBackup{
Details: tree.BackupRangeDetails,
Path: $4.expr(),
}
}
| SHOW BACKUP FILES string_or_placeholder
{
/* SKIP DOC */
$$.val = &tree.ShowBackup{
Details: tree.BackupFileDetails,
Path: $4.expr(),
}
}
| SHOW BACKUP error // SHOW HELP: SHOW BACKUP
// %Help: SHOW CLUSTER SETTING - display cluster settings
// %Category: Cfg
// %Text:
// SHOW CLUSTER SETTING <var>
// SHOW ALL CLUSTER SETTINGS
// %SeeAlso: WEBDOCS/cluster-settings.html
show_csettings_stmt:
SHOW CLUSTER SETTING var_name
{
$$.val = &tree.ShowClusterSetting{Name: strings.Join($4.strs(), ".")}
}
| SHOW CLUSTER SETTING ALL
{
$$.val = &tree.ShowClusterSetting{Name: "all"}
}
| SHOW CLUSTER error // SHOW HELP: SHOW CLUSTER SETTING
| SHOW ALL CLUSTER SETTINGS
{
$$.val = &tree.ShowClusterSetting{Name: "all"}
}
| SHOW ALL CLUSTER error // SHOW HELP: SHOW CLUSTER SETTING
// %Help: SHOW COLUMNS - list columns in relation
// %Category: DDL
// %Text: SHOW COLUMNS FROM <tablename>
// %SeeAlso: WEBDOCS/show-columns.html
show_columns_stmt:
SHOW COLUMNS FROM table_name
{
$$.val = &tree.ShowColumns{Table: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW COLUMNS error // SHOW HELP: SHOW COLUMNS
// %Help: SHOW DATABASES - list databases
// %Category: DDL
// %Text: SHOW DATABASES
// %SeeAlso: WEBDOCS/show-databases.html
show_databases_stmt:
SHOW DATABASES
{
$$.val = &tree.ShowDatabases{}
}
| SHOW DATABASES error // SHOW HELP: SHOW DATABASES
// %Help: SHOW GRANTS - list grants
// %Category: Priv
// %Text:
// Show privilege grants:
// SHOW GRANTS [ON <targets...>] [FOR <users...>]
// Show role grants:
// SHOW GRANTS ON ROLE [<roles...>] [FOR <grantees...>]
//
// %SeeAlso: WEBDOCS/show-grants.html
show_grants_stmt:
SHOW GRANTS opt_on_targets_roles for_grantee_clause
{
lst := $3.targetListPtr()
if lst != nil && lst.ForRoles {
$$.val = &tree.ShowRoleGrants{Roles: lst.Roles, Grantees: $4.nameList()}
} else {
$$.val = &tree.ShowGrants{Targets: lst, Grantees: $4.nameList()}
}
}
| SHOW GRANTS error // SHOW HELP: SHOW GRANTS
// %Help: SHOW INDEXES - list indexes
// %Category: DDL
// %Text: SHOW INDEXES FROM <tablename>
// %SeeAlso: WEBDOCS/show-index.html
show_indexes_stmt:
SHOW INDEX FROM table_name
{
$$.val = &tree.ShowIndex{Table: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW INDEX error // SHOW HELP: SHOW INDEXES
| SHOW INDEXES FROM table_name
{
$$.val = &tree.ShowIndex{Table: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW INDEXES error // SHOW HELP: SHOW INDEXES
| SHOW KEYS FROM table_name
{
$$.val = &tree.ShowIndex{Table: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW KEYS error // SHOW HELP: SHOW INDEXES
// %Help: SHOW CONSTRAINTS - list constraints
// %Category: DDL
// %Text: SHOW CONSTRAINTS FROM <tablename>
// %SeeAlso: WEBDOCS/show-constraints.html
show_constraints_stmt:
SHOW CONSTRAINT FROM table_name
{
$$.val = &tree.ShowConstraints{Table: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW CONSTRAINT error // SHOW HELP: SHOW CONSTRAINTS
| SHOW CONSTRAINTS FROM table_name
{
$$.val = &tree.ShowConstraints{Table: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW CONSTRAINTS error // SHOW HELP: SHOW CONSTRAINTS
// %Help: SHOW QUERIES - list running queries
// %Category: Misc
// %Text: SHOW [CLUSTER | LOCAL] QUERIES
// %SeeAlso: CANCEL QUERIES
show_queries_stmt:
SHOW QUERIES
{
$$.val = &tree.ShowQueries{Cluster: true}
}
| SHOW QUERIES error // SHOW HELP: SHOW QUERIES
| SHOW CLUSTER QUERIES
{
$$.val = &tree.ShowQueries{Cluster: true}
}
| SHOW LOCAL QUERIES
{
$$.val = &tree.ShowQueries{Cluster: false}
}
// %Help: SHOW JOBS - list background jobs
// %Category: Misc
// %Text: SHOW JOBS
// %SeeAlso: CANCEL JOBS, PAUSE JOBS, RESUME JOBS
show_jobs_stmt:
SHOW JOBS
{
$$.val = &tree.ShowJobs{}
}
| SHOW JOBS error // SHOW HELP: SHOW JOBS
// %Help: SHOW TRACE - display an execution trace
// %Category: Misc
// %Text:
// SHOW [COMPACT] [KV] TRACE FOR SESSION
// %SeeAlso: EXPLAIN
show_trace_stmt:
SHOW opt_compact TRACE FOR SESSION
{
$$.val = &tree.ShowTraceForSession{TraceType: tree.ShowTraceRaw, Compact: $2.bool()}
}
| SHOW opt_compact TRACE error // SHOW HELP: SHOW TRACE
| SHOW opt_compact KV TRACE FOR SESSION
{
$$.val = &tree.ShowTraceForSession{TraceType: tree.ShowTraceKV, Compact: $2.bool()}
}
| SHOW opt_compact KV error // SHOW HELP: SHOW TRACE
| SHOW opt_compact EXPERIMENTAL_REPLICA TRACE FOR SESSION
{
/* SKIP DOC */
$$.val = &tree.ShowTraceForSession{TraceType: tree.ShowTraceReplica, Compact: $2.bool()}
}
| SHOW opt_compact EXPERIMENTAL_REPLICA error // SHOW HELP: SHOW TRACE
opt_compact:
COMPACT { $$.val = true }
| /* EMPTY */ { $$.val = false }
// %Help: SHOW SESSIONS - list open client sessions
// %Category: Misc
// %Text: SHOW [CLUSTER | LOCAL] SESSIONS
// %SeeAlso: CANCEL SESSIONS
show_sessions_stmt:
SHOW SESSIONS
{
$$.val = &tree.ShowSessions{Cluster: true}
}
| SHOW SESSIONS error // SHOW HELP: SHOW SESSIONS
| SHOW CLUSTER SESSIONS
{
$$.val = &tree.ShowSessions{Cluster: true}
}
| SHOW LOCAL SESSIONS
{
$$.val = &tree.ShowSessions{Cluster: false}
}
// %Help: SHOW TABLES - list tables
// %Category: DDL
// %Text: SHOW TABLES [FROM <databasename> [ . <schemaname> ] ]
// %SeeAlso: WEBDOCS/show-tables.html
show_tables_stmt:
SHOW TABLES FROM name '.' name
{
$$.val = &tree.ShowTables{TableNamePrefix:tree.TableNamePrefix{
CatalogName: tree.Name($4),
ExplicitCatalog: true,
SchemaName: tree.Name($6),
ExplicitSchema: true,
}}
}
| SHOW TABLES FROM name
{
$$.val = &tree.ShowTables{TableNamePrefix:tree.TableNamePrefix{
// Note: the schema name may be interpreted as database name,
// see name_resolution.go.
SchemaName: tree.Name($4),
ExplicitSchema: true,
}}
}
| SHOW TABLES
{
$$.val = &tree.ShowTables{}
}
| SHOW TABLES error // SHOW HELP: SHOW TABLES
// %Help: SHOW SCHEMAS - list schemas
// %Category: DDL
// %Text: SHOW SCHEMAS [FROM <databasename> ]
show_schemas_stmt:
SHOW SCHEMAS FROM name
{
$$.val = &tree.ShowSchemas{Database: tree.Name($4)}
}
| SHOW SCHEMAS
{
$$.val = &tree.ShowSchemas{}
}
| SHOW SCHEMAS error // SHOW HELP: SHOW SCHEMAS
// %Help: SHOW SYNTAX - analyze SQL syntax
// %Category: Misc
// %Text: SHOW SYNTAX <string>
show_syntax_stmt:
SHOW SYNTAX SCONST
{
/* SKIP DOC */
$$.val = &tree.ShowSyntax{Statement: $3}
}
| SHOW SYNTAX error // SHOW HELP: SHOW SYNTAX
// %Help: SHOW TRANSACTION - display current transaction properties
// %Category: Cfg
// %Text: SHOW TRANSACTION {ISOLATION LEVEL | PRIORITY | STATUS}
// %SeeAlso: WEBDOCS/show-transaction.html
show_transaction_stmt:
SHOW TRANSACTION ISOLATION LEVEL
{
/* SKIP DOC */
$$.val = &tree.ShowVar{Name: "transaction_isolation"}
}
| SHOW TRANSACTION PRIORITY
{
/* SKIP DOC */
$$.val = &tree.ShowVar{Name: "transaction_priority"}
}
| SHOW TRANSACTION STATUS
{
/* SKIP DOC */
$$.val = &tree.ShowTransactionStatus{}
}
| SHOW TRANSACTION error // SHOW HELP: SHOW TRANSACTION
// %Help: SHOW CREATE - display the CREATE statement for a table, sequence or view
// %Category: DDL
// %Text: SHOW CREATE [ TABLE | SEQUENCE | VIEW ] <tablename>
// %SeeAlso: WEBDOCS/show-create-table.html
show_create_stmt:
SHOW CREATE table_name
{
$$.val = &tree.ShowCreate{Name: $3.normalizableTableNameFromUnresolvedName()}
}
| SHOW CREATE create_kw table_name
{
/* SKIP DOC */
$$.val = &tree.ShowCreate{Name: $4.normalizableTableNameFromUnresolvedName()}
}
| SHOW CREATE error // SHOW HELP: SHOW CREATE
create_kw:
TABLE
| VIEW
| SEQUENCE
// %Help: SHOW USERS - list defined users
// %Category: Priv
// %Text: SHOW USERS
// %SeeAlso: CREATE USER, DROP USER, WEBDOCS/show-users.html
show_users_stmt:
SHOW USERS
{
$$.val = &tree.ShowUsers{}
}
| SHOW USERS error // SHOW HELP: SHOW USERS
// %Help: SHOW ROLES - list defined roles
// %Category: Priv
// %Text: SHOW ROLES
// %SeeAlso: CREATE ROLE, DROP ROLE
show_roles_stmt:
SHOW ROLES
{
$$.val = &tree.ShowRoles{}
}
| SHOW ROLES error // SHOW HELP: SHOW ROLES
show_zone_stmt:
SHOW ZONE CONFIGURATION FOR RANGE zone_name
{
$$.val = &tree.ShowZoneConfig{ZoneSpecifier: tree.ZoneSpecifier{NamedZone: tree.UnrestrictedName($6)}}
}
| SHOW ZONE CONFIGURATION FOR DATABASE database_name
{
$$.val = &tree.ShowZoneConfig{ZoneSpecifier: tree.ZoneSpecifier{Database: tree.Name($6)}}
}
| SHOW ZONE CONFIGURATION FOR TABLE table_name opt_partition
{
$$.val = &tree.ShowZoneConfig{ZoneSpecifier: tree.ZoneSpecifier{
TableOrIndex: tree.TableNameWithIndex{Table: $6.normalizableTableNameFromUnresolvedName()},
}}
}
| SHOW ZONE CONFIGURATION FOR PARTITION partition_name OF TABLE table_name
{
$$.val = &tree.ShowZoneConfig{ZoneSpecifier: tree.ZoneSpecifier{
TableOrIndex: tree.TableNameWithIndex{Table: $9.normalizableTableNameFromUnresolvedName()},
Partition: tree.Name($6),
}}
}
| SHOW ZONE CONFIGURATION FOR INDEX table_name_with_index
{
$$.val = &tree.ShowZoneConfig{ZoneSpecifier: tree.ZoneSpecifier{
TableOrIndex: $6.tableWithIdx(),
}}
}
| SHOW ZONE CONFIGURATIONS
{
$$.val = &tree.ShowZoneConfig{}
}
| SHOW ALL ZONE CONFIGURATIONS
{
$$.val = &tree.ShowZoneConfig{}
}
// %Help: SHOW RANGES - list ranges
// %Category: Misc
// %Text:
// SHOW EXPERIMENTAL_RANGES FROM TABLE <tablename>
// SHOW EXPERIMENTAL_RANGES FROM INDEX [ <tablename> @ ] <indexname>
show_ranges_stmt:
SHOW ranges_kw FROM TABLE table_name
{
$$.val = &tree.ShowRanges{Table: $5.newNormalizableTableNameFromUnresolvedName()}
}
| SHOW ranges_kw FROM INDEX table_name_with_index
{
$$.val = &tree.ShowRanges{Index: $5.newTableWithIdx()}
}
| SHOW ranges_kw error // SHOW HELP: SHOW RANGES
ranges_kw:
TESTING_RANGES
| EXPERIMENTAL_RANGES
show_fingerprints_stmt:
SHOW EXPERIMENTAL_FINGERPRINTS FROM TABLE table_name
{
/* SKIP DOC */
$$.val = &tree.ShowFingerprints{Table: $5.newNormalizableTableNameFromUnresolvedName()}
}
opt_on_targets_roles:
ON targets_roles
{
tmp := $2.targetList()
$$.val = &tmp
}
| /* EMPTY */
{
$$.val = (*tree.TargetList)(nil)
}
// targets is a non-terminal for a list of privilege targets, either a
// list of databases or a list of tables.
//
// This rule is complex and cannot be decomposed as a tree of
// non-terminals because it must resolve syntax ambiguities in the
// SHOW GRANTS ON ROLE statement. It was constructed as follows.
//
// 1. Start with the desired definition of targets:
//
// targets ::=
// table_pattern_list
// TABLE table_pattern_list
// DATABASE name_list
//
// 2. Now we must disambiguate the first rule "table_pattern_list"
// between one that recognizes ROLE and one that recognizes
// <some table pattern list>". So first, inline the definition of
// table_pattern_list.
//
// targets ::=
// table_pattern # <- here
// table_pattern_list ',' table_pattern # <- here
// TABLE table_pattern_list
// DATABASE name_list
//
// 3. We now must disambiguate the "ROLE" inside the prefix "table_pattern".
// However having "table_pattern_list" as prefix is cumbersome, so swap it.
//
// targets ::=
// table_pattern
// table_pattern ',' table_pattern_list # <- here
// TABLE table_pattern_list
// DATABASE name_list
//
// 4. The rule that has table_pattern followed by a comma is now
// non-problematic, because it will never match "ROLE" followed
// by an optional name list (neither "ROLE;" nor "ROLE <ident>"
// would match). We just need to focus on the first one "table_pattern".
// This needs to tweak "table_pattern".
//
// Here we could inline table_pattern but now we don't have to any
// more, we just need to create a variant of it which is
// unambiguous with a single ROLE keyword. That is, we need a
// table_pattern which cannot contain a single name. We do
// this as follows.
//
// targets ::=
// complex_table_pattern # <- here
// table_pattern ',' table_pattern_list
// TABLE table_pattern_list
// DATABASE name_list
// complex_table_pattern ::=
// name '.' unrestricted_name
// name '.' unrestricted_name '.' unrestricted_name
// name '.' unrestricted_name '.' '*'
// name '.' '*'
// '*'
//
// 5. At this point the rule cannot start with a simple identifier any
// more, keyword or not. But more importantly, any token sequence
// that starts with ROLE cannot be matched by any of these remaining
// rules. This means that the prefix is now free to use, without
// ambiguity. We do this as follows, to gain a syntax rule for "ROLE
// <namelist>". (We'll handle a ROLE with no name list below.)
//
// targets ::=
// ROLE name_list # <- here
// complex_table_pattern
// table_pattern ',' table_pattern_list
// TABLE table_pattern_list
// DATABASE name_list
//
// 6. Now on to the finishing touches. First we'd like to regain the
// ability to use "<tablename>" when the table name is a simple
// identifier. This is done as follows:
//
// targets ::=
// ROLE name_list
// name # <- here
// complex_table_pattern
// table_pattern ',' table_pattern_list
// TABLE table_pattern_list
// DATABASE name_list
//
// 7. Then, we want to recognize "ROLE" without any subsequent name
// list. This requires some care: we can't add "ROLE" to the set of
// rules above, because "name" would then overlap. To disambiguate,
// we must first inline "name" as follows:
//
// targets ::=
// ROLE name_list
// IDENT # <- here, always <table>
// col_name_keyword # <- here, always <table>
// unreserved_keyword # <- here, either ROLE or <table>
// complex_table_pattern
// table_pattern ',' table_pattern_list
// TABLE table_pattern_list
// DATABASE name_list
//
// 8. And now the rule is sufficiently simple that we can disambiguate
// in the action, like this:
//
// targets ::=
// ...
// unreserved_keyword {
// if $1 == "role" { /* handle ROLE */ }
// else { /* handle ON <tablename> */ }
// }
// ...
//
// (but see the comment on the action of this sub-rule below for
// more nuance.)
//
// Tada!
targets:
IDENT
{
$$.val = tree.TargetList{Tables: tree.TablePatterns{&tree.UnresolvedName{NumParts:1, Parts: tree.NameParts{$1}}}}
}
| col_name_keyword
{
$$.val = tree.TargetList{Tables: tree.TablePatterns{&tree.UnresolvedName{NumParts:1, Parts: tree.NameParts{$1}}}}
}
| unreserved_keyword
{
// This sub-rule is meant to support both ROLE and other keywords
// used as table name without the TABLE prefix. The keyword ROLE
// here can have two meanings:
//
// - for all statements except SHOW GRANTS, it must be interpreted
// as a plain table name.
// - for SHOW GRANTS specifically, it must be handled as an ON ROLE
// specifier without a name list (the rule with a name list is separate,
// see above).
//
// Yet we want to use a single "targets" non-terminal for all
// statements that use targets, to share the code. This action
// achieves this as follows:
//
// - for all statements (including SHOW GRANTS), it populates the
// Tables list in TargetList{} with the given name. This will
// include the given keyword as table pattern in all cases,
// including when the keyword was ROLE.
//
// - if ROLE was specified, it remembers this fact in the ForRoles
// field. This distinguishes `ON ROLE` (where "role" is
// specified as keyword), which triggers the special case in
// SHOW GRANTS, from `ON "role"` (where "role" is specified as
// identifier), which is always handled as a table name.
//
// Both `ON ROLE` and `ON "role"` populate the Tables list in the same way,
// so that other statements than SHOW GRANTS don't observe any difference.
//
// Arguably this code is a bit too clever. Future work should aim
// to remove the special casing of SHOW GRANTS altogether instead
// of increasing (or attempting to modify) the grey magic occurring
// here.
$$.val = tree.TargetList{
Tables: tree.TablePatterns{&tree.UnresolvedName{NumParts:1, Parts: tree.NameParts{$1}}},
ForRoles: $1 == "role", // backdoor for "SHOW GRANTS ON ROLE" (no name list)
}
}
| complex_table_pattern
{
$$.val = tree.TargetList{Tables: tree.TablePatterns{$1.unresolvedName()}}
}
| table_pattern ',' table_pattern_list
{
remainderPats := $3.tablePatterns()
$$.val = tree.TargetList{Tables: append(tree.TablePatterns{$1.unresolvedName()}, remainderPats...)}
}
| TABLE table_pattern_list
{
$$.val = tree.TargetList{Tables: $2.tablePatterns()}
}
| DATABASE name_list
{
$$.val = tree.TargetList{Databases: $2.nameList()}
}
// target_roles is the variant of targets which recognizes ON ROLES
// with a name list. This cannot be included in targets directly
// because some statements must not recognize this syntax.
targets_roles:
ROLE name_list
{
$$.val = tree.TargetList{ForRoles: true, Roles: $2.nameList()}
}
| targets
for_grantee_clause:
FOR name_list
{
$$.val = $2.nameList()
}
| /* EMPTY */
{
$$.val = tree.NameList(nil)
}
// %Help: PAUSE JOBS - pause background jobs
// %Category: Misc
// %Text:
// PAUSE JOBS <selectclause>
// PAUSE JOB <jobid>
// %SeeAlso: SHOW JOBS, CANCEL JOBS, RESUME JOBS
pause_stmt:
PAUSE JOB a_expr
{
$$.val = &tree.ControlJobs{
Jobs: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$3.expr()}}},
},
Command: tree.PauseJob,
}
}
| PAUSE JOBS select_stmt
{
$$.val = &tree.ControlJobs{Jobs: $3.slct(), Command: tree.PauseJob}
}
| PAUSE error // SHOW HELP: PAUSE JOBS
// %Help: CREATE TABLE - create a new table
// %Category: DDL
// %Text:
// CREATE TABLE [IF NOT EXISTS] <tablename> ( <elements...> ) [<interleave>]
// CREATE TABLE [IF NOT EXISTS] <tablename> [( <colnames...> )] AS <source>
//
// Table elements:
// <name> <type> [<qualifiers...>]
// [UNIQUE | INVERTED] INDEX [<name>] ( <colname> [ASC | DESC] [, ...] )
// [STORING ( <colnames...> )] [<interleave>]
// FAMILY [<name>] ( <colnames...> )
// [CONSTRAINT <name>] <constraint>
//
// Table constraints:
// PRIMARY KEY ( <colnames...> )
// FOREIGN KEY ( <colnames...> ) REFERENCES <tablename> [( <colnames...> )] [ON DELETE {NO ACTION | RESTRICT}] [ON UPDATE {NO ACTION | RESTRICT}]
// UNIQUE ( <colnames... ) [STORING ( <colnames...> )] [<interleave>]
// CHECK ( <expr> )
//
// Column qualifiers:
// [CONSTRAINT <constraintname>] {NULL | NOT NULL | UNIQUE | PRIMARY KEY | CHECK (<expr>) | DEFAULT <expr>}
// FAMILY <familyname>, CREATE [IF NOT EXISTS] FAMILY [<familyname>]
// REFERENCES <tablename> [( <colnames...> )] [ON DELETE {NO ACTION | RESTRICT}] [ON UPDATE {NO ACTION | RESTRICT}]
// COLLATE <collationname>
// AS ( <expr> ) STORED
//
// Interleave clause:
// INTERLEAVE IN PARENT <tablename> ( <colnames...> ) [CASCADE | RESTRICT]
//
// %SeeAlso: SHOW TABLES, CREATE VIEW, SHOW CREATE,
// WEBDOCS/create-table.html
// WEBDOCS/create-table-as.html
create_table_stmt:
CREATE opt_temp TABLE table_name '(' opt_table_elem_list ')' opt_interleave opt_partition_by
{
$$.val = &tree.CreateTable{
Table: $4.normalizableTableNameFromUnresolvedName(),
IfNotExists: false,
Interleave: $8.interleave(),
Defs: $6.tblDefs(),
AsSource: nil,
AsColumnNames: nil,
PartitionBy: $9.partitionBy(),
}
}
| CREATE opt_temp TABLE IF NOT EXISTS table_name '(' opt_table_elem_list ')' opt_interleave opt_partition_by
{
$$.val = &tree.CreateTable{
Table: $7.normalizableTableNameFromUnresolvedName(),
IfNotExists: true,
Interleave: $11.interleave(),
Defs: $9.tblDefs(),
AsSource: nil,
AsColumnNames: nil,
PartitionBy: $12.partitionBy(),
}
}
create_table_as_stmt:
CREATE opt_temp TABLE table_name opt_column_list AS select_stmt
{
$$.val = &tree.CreateTable{
Table: $4.normalizableTableNameFromUnresolvedName(),
IfNotExists: false,
Interleave: nil,
Defs: nil,
AsSource: $7.slct(),
AsColumnNames: $5.nameList(),
}
}
| CREATE opt_temp TABLE IF NOT EXISTS table_name opt_column_list AS select_stmt
{
$$.val = &tree.CreateTable{
Table: $7.normalizableTableNameFromUnresolvedName(),
IfNotExists: true,
Interleave: nil,
Defs: nil,
AsSource: $10.slct(),
AsColumnNames: $8.nameList(),
}
}
/*
* Redundancy here is needed to avoid shift/reduce conflicts,
* since TEMP is not a reserved word. See also OptTempTableName.
*
* NOTE: we accept both GLOBAL and LOCAL options. They currently do nothing,
* but future versions might consider GLOBAL to request SQL-spec-compliant
* temp table behavior, so warn about that. Since we have no modules the
* LOCAL keyword is really meaningless; furthermore, some other products
* implement LOCAL as meaning the same as our default temp table behavior,
* so we'll probably continue to treat LOCAL as a noise word.
*/
opt_temp:
TEMPORARY { return unimplementedWithIssue(sqllex, 5807) }
| TEMP { return unimplementedWithIssue(sqllex, 5807) }
| LOCAL TEMPORARY { return unimplementedWithIssue(sqllex, 5807) }
| LOCAL TEMP { return unimplementedWithIssue(sqllex, 5807) }
| GLOBAL TEMPORARY { return unimplementedWithIssue(sqllex, 5807) }
| GLOBAL TEMP { return unimplementedWithIssue(sqllex, 5807) }
| UNLOGGED { return unimplemented(sqllex, "create unlogged") }
| /*EMPTY*/ { /* no error */ }
opt_table_elem_list:
table_elem_list
| /* EMPTY */
{
$$.val = tree.TableDefs(nil)
}
table_elem_list:
table_elem
{
$$.val = tree.TableDefs{$1.tblDef()}
}
| table_elem_list ',' table_elem
{
$$.val = append($1.tblDefs(), $3.tblDef())
}
table_elem:
column_def
{
$$.val = $1.colDef()
}
| index_def
| family_def
| table_constraint
{
$$.val = $1.constraintDef()
}
opt_interleave:
INTERLEAVE IN PARENT table_name '(' name_list ')' opt_interleave_drop_behavior
{
$$.val = &tree.InterleaveDef{
Parent: $4.newNormalizableTableNameFromUnresolvedName(),
Fields: $6.nameList(),
DropBehavior: $8.dropBehavior(),
}
}
| /* EMPTY */
{
$$.val = (*tree.InterleaveDef)(nil)
}
// TODO(dan): This can be removed in favor of opt_drop_behavior when #7854 is fixed.
opt_interleave_drop_behavior:
CASCADE
{
/* SKIP DOC */
$$.val = tree.DropCascade
}
| RESTRICT
{
/* SKIP DOC */
$$.val = tree.DropRestrict
}
| /* EMPTY */
{
$$.val = tree.DropDefault
}
partition:
PARTITION partition_name
{
$$ = $2
}
opt_partition:
partition
| /* EMPTY */
{
$$ = ""
}
opt_partition_by:
partition_by
| /* EMPTY */
{
$$.val = (*tree.PartitionBy)(nil)
}
partition_by:
PARTITION BY LIST '(' name_list ')' '(' list_partitions ')'
{
$$.val = &tree.PartitionBy{
Fields: $5.nameList(),
List: $8.listPartitions(),
}
}
| PARTITION BY RANGE '(' name_list ')' '(' range_partitions ')'
{
$$.val = &tree.PartitionBy{
Fields: $5.nameList(),
Range: $8.rangePartitions(),
}
}
| PARTITION BY NOTHING
{
$$.val = (*tree.PartitionBy)(nil)
}
list_partitions:
list_partition
{
$$.val = []tree.ListPartition{$1.listPartition()}
}
| list_partitions ',' list_partition
{
$$.val = append($1.listPartitions(), $3.listPartition())
}
list_partition:
partition VALUES IN '(' expr_list ')' opt_partition_by
{
$$.val = tree.ListPartition{
Name: tree.UnrestrictedName($1),
Exprs: $5.exprs(),
Subpartition: $7.partitionBy(),
}
}
range_partitions:
range_partition
{
$$.val = []tree.RangePartition{$1.rangePartition()}
}
| range_partitions ',' range_partition
{
$$.val = append($1.rangePartitions(), $3.rangePartition())
}
range_partition:
partition VALUES FROM '(' expr_list ')' TO '(' expr_list ')' opt_partition_by
{
$$.val = tree.RangePartition{
Name: tree.UnrestrictedName($1),
From: $5.exprs(),
To: $9.exprs(),
Subpartition: $11.partitionBy(),
}
}
column_def:
column_name typename col_qual_list
{
tableDef, err := tree.NewColumnTableDef(tree.Name($1), $2.colType(), $3.colQuals())
if err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = tableDef
}
col_qual_list:
col_qual_list col_qualification
{
$$.val = append($1.colQuals(), $2.colQual())
}
| /* EMPTY */
{
$$.val = []tree.NamedColumnQualification(nil)
}
col_qualification:
CONSTRAINT constraint_name col_qualification_elem
{
$$.val = tree.NamedColumnQualification{Name: tree.Name($2), Qualification: $3.colQualElem()}
}
| col_qualification_elem
{
$$.val = tree.NamedColumnQualification{Qualification: $1.colQualElem()}
}
| COLLATE collation_name
{
$$.val = tree.NamedColumnQualification{Qualification: tree.ColumnCollation($2)}
}
| FAMILY family_name
{
$$.val = tree.NamedColumnQualification{Qualification: &tree.ColumnFamilyConstraint{Family: tree.Name($2)}}
}
| CREATE FAMILY family_name
{
$$.val = tree.NamedColumnQualification{Qualification: &tree.ColumnFamilyConstraint{Family: tree.Name($3), Create: true}}
}
| CREATE FAMILY
{
$$.val = tree.NamedColumnQualification{Qualification: &tree.ColumnFamilyConstraint{Create: true}}
}
| CREATE IF NOT EXISTS FAMILY family_name
{
$$.val = tree.NamedColumnQualification{Qualification: &tree.ColumnFamilyConstraint{Family: tree.Name($6), Create: true, IfNotExists: true}}
}
// DEFAULT NULL is already the default for Postgres. But define it here and
// carry it forward into the system to make it explicit.
// - thomas 1998-09-13
//
// WITH NULL and NULL are not SQL-standard syntax elements, so leave them
// out. Use DEFAULT NULL to explicitly indicate that a column may have that
// value. WITH NULL leads to shift/reduce conflicts with WITH TIME ZONE anyway.
// - thomas 1999-01-08
//
// DEFAULT expression must be b_expr not a_expr to prevent shift/reduce
// conflict on NOT (since NOT might start a subsequent NOT NULL constraint, or
// be part of a_expr NOT LIKE or similar constructs).
col_qualification_elem:
NOT NULL
{
$$.val = tree.NotNullConstraint{}
}
| NULL
{
$$.val = tree.NullConstraint{}
}
| UNIQUE
{
$$.val = tree.UniqueConstraint{}
}
| PRIMARY KEY
{
$$.val = tree.PrimaryKeyConstraint{}
}
| CHECK '(' a_expr ')'
{
$$.val = &tree.ColumnCheckConstraint{Expr: $3.expr()}
}
| DEFAULT b_expr
{
$$.val = &tree.ColumnDefault{Expr: $2.expr()}
}
| REFERENCES table_name opt_name_parens key_match reference_actions
{
$$.val = &tree.ColumnFKConstraint{
Table: $2.normalizableTableNameFromUnresolvedName(),
Col: tree.Name($3),
Actions: $5.referenceActions(),
}
}
| AS '(' a_expr ')' STORED
{
$$.val = &tree.ColumnComputedDef{Expr: $3.expr()}
}
| AS '(' a_expr ')' VIRTUAL
{
return unimplemented(sqllex, "virtual computed columns")
}
| AS error
{
sqllex.Error("syntax error: use AS ( <expr> ) STORED")
return 1
}
index_def:
INDEX opt_index_name '(' index_params ')' opt_storing opt_interleave opt_partition_by
{
$$.val = &tree.IndexTableDef{
Name: tree.Name($2),
Columns: $4.idxElems(),
Storing: $6.nameList(),
Interleave: $7.interleave(),
PartitionBy: $8.partitionBy(),
}
}
| UNIQUE INDEX opt_index_name '(' index_params ')' opt_storing opt_interleave opt_partition_by
{
$$.val = &tree.UniqueConstraintTableDef{
IndexTableDef: tree.IndexTableDef {
Name: tree.Name($3),
Columns: $5.idxElems(),
Storing: $7.nameList(),
Interleave: $8.interleave(),
PartitionBy: $9.partitionBy(),
},
}
}
| INVERTED INDEX opt_name '(' index_params ')'
{
$$.val = &tree.IndexTableDef{
Name: tree.Name($3),
Columns: $5.idxElems(),
Inverted: true,
}
}
family_def:
FAMILY opt_family_name '(' name_list ')'
{
$$.val = &tree.FamilyTableDef{
Name: tree.Name($2),
Columns: $4.nameList(),
}
}
// constraint_elem specifies constraint syntax which is not embedded into a
// column definition. col_qualification_elem specifies the embedded form.
// - thomas 1997-12-03
table_constraint:
CONSTRAINT constraint_name constraint_elem
{
$$.val = $3.constraintDef()
$$.val.(tree.ConstraintTableDef).SetName(tree.Name($2))
}
| constraint_elem
{
$$.val = $1.constraintDef()
}
constraint_elem:
CHECK '(' a_expr ')'
{
$$.val = &tree.CheckConstraintTableDef{
Expr: $3.expr(),
}
}
| UNIQUE '(' index_params ')' opt_storing opt_interleave opt_partition_by
{
$$.val = &tree.UniqueConstraintTableDef{
IndexTableDef: tree.IndexTableDef{
Columns: $3.idxElems(),
Storing: $5.nameList(),
Interleave: $6.interleave(),
PartitionBy: $7.partitionBy(),
},
}
}
| PRIMARY KEY '(' index_params ')'
{
$$.val = &tree.UniqueConstraintTableDef{
IndexTableDef: tree.IndexTableDef{
Columns: $4.idxElems(),
},
PrimaryKey: true,
}
}
| FOREIGN KEY '(' name_list ')' REFERENCES table_name
opt_column_list key_match reference_actions
{
$$.val = &tree.ForeignKeyConstraintTableDef{
Table: $7.normalizableTableNameFromUnresolvedName(),
FromCols: $4.nameList(),
ToCols: $8.nameList(),
Actions: $10.referenceActions(),
}
}
storing:
COVERING
| STORING
// TODO(pmattis): It would be nice to support a syntax like STORING
// ALL or STORING (*). The syntax addition is straightforward, but we
// need to be careful with the rest of the implementation. In
// particular, columns stored at indexes are currently encoded in such
// a way that adding a new column would require rewriting the existing
// index values. We will need to change the storage format so that it
// is a list of <columnID, value> pairs which will allow both adding
// and dropping columns without rewriting indexes that are storing the
// adjusted column.
opt_storing:
storing '(' name_list ')'
{
$$.val = $3.nameList()
}
| /* EMPTY */
{
$$.val = tree.NameList(nil)
}
opt_column_list:
'(' name_list ')'
{
$$.val = $2.nameList()
}
| /* EMPTY */
{
$$.val = tree.NameList(nil)
}
key_match:
MATCH FULL { return unimplemented(sqllex, "references match full") }
| MATCH PARTIAL { return unimplemented(sqllex, "references match partial") }
| MATCH SIMPLE { return unimplemented(sqllex, "references match simple") }
| /* EMPTY */ {}
// We combine the update and delete actions into one value temporarily for
// simplicity of parsing, and then break them down again in the calling
// production.
reference_actions:
reference_on_update
{
$$.val = tree.ReferenceActions{Update: $1.referenceAction()}
}
| reference_on_delete
{
$$.val = tree.ReferenceActions{Delete: $1.referenceAction()}
}
| reference_on_update reference_on_delete
{
$$.val = tree.ReferenceActions{Update: $1.referenceAction(), Delete: $2.referenceAction()}
}
| reference_on_delete reference_on_update
{
$$.val = tree.ReferenceActions{Delete: $1.referenceAction(), Update: $2.referenceAction()}
}
| /* EMPTY */
{
$$.val = tree.ReferenceActions{}
}
reference_on_update:
ON UPDATE reference_action
{
$$.val = $3.referenceAction()
}
reference_on_delete:
ON DELETE reference_action
{
$$.val = $3.referenceAction()
}
reference_action:
// NO ACTION is currently the default behavior. It is functionally the same as
// RESTRICT.
NO ACTION
{
$$.val = tree.NoAction
}
| RESTRICT
{
$$.val = tree.Restrict
}
| CASCADE
{
$$.val = tree.Cascade
}
| SET NULL
{
$$.val = tree.SetNull
}
| SET DEFAULT
{
$$.val = tree.SetDefault
}
numeric_only:
FCONST
{
$$.val = $1.numVal()
}
| '-' FCONST
{
n := $2.numVal()
n.Negative = true
$$.val = n
}
| signed_iconst
{
$$.val = $1.numVal()
}
// %Help: CREATE SEQUENCE - create a new sequence
// %Category: DDL
// %Text:
// CREATE SEQUENCE <seqname>
// [INCREMENT <increment>]
// [MINVALUE <minvalue> | NO MINVALUE]
// [MAXVALUE <maxvalue> | NO MAXVALUE]
// [START [WITH] <start>]
// [CACHE <cache>]
// [NO CYCLE]
// [VIRTUAL]
//
// %SeeAlso: CREATE TABLE
create_sequence_stmt:
CREATE opt_temp SEQUENCE sequence_name opt_sequence_option_list
{
node := &tree.CreateSequence{
Name: $4.normalizableTableNameFromUnresolvedName(),
Options: $5.seqOpts(),
}
$$.val = node
}
| CREATE opt_temp SEQUENCE IF NOT EXISTS sequence_name opt_sequence_option_list
{
node := &tree.CreateSequence{
Name: $7.normalizableTableNameFromUnresolvedName(),
Options: $8.seqOpts(),
IfNotExists: true,
}
$$.val = node
}
| CREATE opt_temp SEQUENCE error // SHOW HELP: CREATE SEQUENCE
opt_sequence_option_list:
sequence_option_list
| /* EMPTY */ { $$.val = []tree.SequenceOption(nil) }
sequence_option_list:
sequence_option_elem { $$.val = []tree.SequenceOption{$1.seqOpt()} }
| sequence_option_list sequence_option_elem { $$.val = append($1.seqOpts(), $2.seqOpt()) }
sequence_option_elem:
AS typename { return unimplementedWithIssueDetail(sqllex, 25110, $2.colType().String()) }
| CYCLE { /* SKIP DOC */
$$.val = tree.SequenceOption{Name: tree.SeqOptCycle} }
| NO CYCLE { $$.val = tree.SequenceOption{Name: tree.SeqOptNoCycle} }
| OWNED BY column_path { return unimplementedWithIssue(sqllex, 26382) }
| CACHE signed_iconst64 { /* SKIP DOC */
x := $2.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptCache, IntVal: &x} }
| INCREMENT signed_iconst64 { x := $2.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptIncrement, IntVal: &x} }
| INCREMENT BY signed_iconst64 { x := $3.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptIncrement, IntVal: &x, OptionalWord: true} }
| MINVALUE signed_iconst64 { x := $2.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptMinValue, IntVal: &x} }
| NO MINVALUE { $$.val = tree.SequenceOption{Name: tree.SeqOptMinValue} }
| MAXVALUE signed_iconst64 { x := $2.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptMaxValue, IntVal: &x} }
| NO MAXVALUE { $$.val = tree.SequenceOption{Name: tree.SeqOptMaxValue} }
| START signed_iconst64 { x := $2.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptStart, IntVal: &x} }
| START WITH signed_iconst64 { x := $3.int64()
$$.val = tree.SequenceOption{Name: tree.SeqOptStart, IntVal: &x, OptionalWord: true} }
| VIRTUAL { $$.val = tree.SequenceOption{Name: tree.SeqOptVirtual} }
// %Help: TRUNCATE - empty one or more tables
// %Category: DML
// %Text: TRUNCATE [TABLE] <tablename> [, ...] [CASCADE | RESTRICT]
// %SeeAlso: WEBDOCS/truncate.html
truncate_stmt:
TRUNCATE opt_table relation_expr_list opt_drop_behavior
{
$$.val = &tree.Truncate{Tables: $3.normalizableTableNames(), DropBehavior: $4.dropBehavior()}
}
| TRUNCATE error // SHOW HELP: TRUNCATE
// %Help: CREATE USER - define a new user
// %Category: Priv
// %Text: CREATE USER [IF NOT EXISTS] <name> [ [WITH] PASSWORD <passwd> ]
// %SeeAlso: DROP USER, SHOW USERS, WEBDOCS/create-user.html
create_user_stmt:
CREATE USER string_or_placeholder opt_password
{
$$.val = &tree.CreateUser{Name: $3.expr(), Password: $4.expr()}
}
| CREATE USER IF NOT EXISTS string_or_placeholder opt_password
{
$$.val = &tree.CreateUser{Name: $6.expr(), Password: $7.expr(), IfNotExists: true}
}
| CREATE USER error // SHOW HELP: CREATE USER
opt_password:
opt_with PASSWORD string_or_placeholder
{
$$.val = $3.expr()
}
| /* EMPTY */
{
$$.val = nil
}
// %Help: CREATE ROLE - define a new role
// %Category: Priv
// %Text: CREATE ROLE [IF NOT EXISTS] <name>
// %SeeAlso: DROP ROLE, SHOW ROLES
create_role_stmt:
CREATE role_or_group string_or_placeholder
{
$$.val = &tree.CreateRole{Name: $3.expr()}
}
| CREATE role_or_group IF NOT EXISTS string_or_placeholder
{
$$.val = &tree.CreateRole{Name: $6.expr(), IfNotExists: true}
}
| CREATE role_or_group error // SHOW HELP: CREATE ROLE
// "CREATE GROUP is now an alias for CREATE ROLE"
// https://www.postgresql.org/docs/10/static/sql-creategroup.html
role_or_group:
ROLE { }
| GROUP { /* SKIP DOC */ }
// %Help: CREATE VIEW - create a new view
// %Category: DDL
// %Text: CREATE VIEW <viewname> [( <colnames...> )] AS <source>
// %SeeAlso: CREATE TABLE, SHOW CREATE, WEBDOCS/create-view.html
create_view_stmt:
CREATE opt_temp opt_view_recursive VIEW view_name opt_column_list AS select_stmt
{
$$.val = &tree.CreateView{
Name: $5.normalizableTableNameFromUnresolvedName(),
ColumnNames: $6.nameList(),
AsSource: $8.slct(),
}
}
| CREATE OR REPLACE opt_temp opt_view_recursive VIEW error { return unimplementedWithIssue(sqllex, 24897) }
| CREATE opt_temp opt_view_recursive VIEW error // SHOW HELP: CREATE VIEW
opt_view_recursive:
/* EMPTY */ { /* no error */ }
| RECURSIVE { return unimplemented(sqllex, "create recursive view") }
// CREATE TYPE/DOMAIN is not yet supported by CockroachDB but we
// want to report it with the right issue number.
create_type_stmt:
// Record/Composite types.
CREATE TYPE type_name AS '(' error { return unimplementedWithIssue(sqllex, 27792) }
// Enum types.
| CREATE TYPE type_name AS ENUM '(' error { return unimplementedWithIssue(sqllex, 24873) }
// Range types.
| CREATE TYPE type_name AS RANGE error { return unimplementedWithIssue(sqllex, 27791) }
// Base (primitive) types.
| CREATE TYPE type_name '(' error { return unimplementedWithIssueDetail(sqllex, 27793, "base") }
// Shell types, gateway to define base types using the previous syntax.
| CREATE TYPE type_name { return unimplementedWithIssueDetail(sqllex, 27793, "shell") }
// Domain types.
| CREATE DOMAIN type_name error { return unimplementedWithIssueDetail(sqllex, 27796, "create") }
// %Help: CREATE INDEX - create a new index
// %Category: DDL
// %Text:
// CREATE [UNIQUE | INVERTED] INDEX [IF NOT EXISTS] [<idxname>]
// ON <tablename> ( <colname> [ASC | DESC] [, ...] )
// [STORING ( <colnames...> )] [<interleave>]
//
// Interleave clause:
// INTERLEAVE IN PARENT <tablename> ( <colnames...> ) [CASCADE | RESTRICT]
//
// %SeeAlso: CREATE TABLE, SHOW INDEXES, SHOW CREATE,
// WEBDOCS/create-index.html
create_index_stmt:
CREATE opt_unique INDEX opt_index_name ON table_name opt_using_gin_btree '(' index_params ')' opt_storing opt_interleave opt_partition_by opt_idx_where
{
$$.val = &tree.CreateIndex{
Name: tree.Name($4),
Table: $6.normalizableTableNameFromUnresolvedName(),
Unique: $2.bool(),
Columns: $9.idxElems(),
Storing: $11.nameList(),
Interleave: $12.interleave(),
PartitionBy: $13.partitionBy(),
Inverted: $7.bool(),
}
}
| CREATE opt_unique INDEX IF NOT EXISTS index_name ON table_name opt_using_gin_btree '(' index_params ')' opt_storing opt_interleave opt_partition_by opt_idx_where
{
$$.val = &tree.CreateIndex{
Name: tree.Name($7),
Table: $9.normalizableTableNameFromUnresolvedName(),
Unique: $2.bool(),
IfNotExists: true,
Columns: $12.idxElems(),
Storing: $14.nameList(),
Interleave: $15.interleave(),
PartitionBy: $16.partitionBy(),
Inverted: $10.bool(),
}
}
| CREATE opt_unique INVERTED INDEX opt_index_name ON table_name '(' index_params ')' opt_storing opt_interleave opt_partition_by opt_idx_where
{
$$.val = &tree.CreateIndex{
Name: tree.Name($5),
Table: $7.normalizableTableNameFromUnresolvedName(),
Unique: $2.bool(),
Inverted: true,
Columns: $9.idxElems(),
Storing: $11.nameList(),
Interleave: $12.interleave(),
PartitionBy: $13.partitionBy(),
}
}
| CREATE opt_unique INVERTED INDEX IF NOT EXISTS index_name ON table_name '(' index_params ')' opt_storing opt_interleave opt_partition_by opt_idx_where
{
$$.val = &tree.CreateIndex{
Name: tree.Name($8),
Table: $10.normalizableTableNameFromUnresolvedName(),
Unique: $2.bool(),
Inverted: true,
IfNotExists: true,
Columns: $12.idxElems(),
Storing: $14.nameList(),
Interleave: $15.interleave(),
PartitionBy: $16.partitionBy(),
}
}
| CREATE opt_unique INDEX error // SHOW HELP: CREATE INDEX
opt_idx_where:
/* EMPTY */ { /* no error */ }
| WHERE error { return unimplementedWithIssue(sqllex, 9683) }
opt_using_gin_btree:
USING name
{
/* FORCE DOC */
switch $2 {
case "gin":
$$.val = true
case "btree":
$$.val = false
case "hash", "gist", "spgist", "brin":
return unimplemented(sqllex, "index using " + $2)
default:
sqllex.Error("unrecognized access method: " + $2)
return 1
}
}
| /* EMPTY */
{
$$.val = false
}
opt_unique:
UNIQUE
{
$$.val = true
}
| /* EMPTY */
{
$$.val = false
}
index_params:
index_elem
{
$$.val = tree.IndexElemList{$1.idxElem()}
}
| index_params ',' index_elem
{
$$.val = append($1.idxElems(), $3.idxElem())
}
// Index attributes can be either simple column references, or arbitrary
// expressions in parens. For backwards-compatibility reasons, we allow an
// expression that's just a function call to be written without parens.
index_elem:
a_expr opt_asc_desc
{
/* FORCE DOC */
e := $1.expr()
if colName, ok := e.(*tree.UnresolvedName); ok && colName.NumParts == 1 {
$$.val = tree.IndexElem{Column: tree.Name(colName.Parts[0]), Direction: $2.dir()}
} else {
return unimplementedWithIssueDetail(sqllex, 9682, fmt.Sprintf("%T", e))
}
}
opt_collate:
COLLATE collation_name { $$ = $2 }
| /* EMPTY */ { $$ = "" }
opt_asc_desc:
ASC
{
$$.val = tree.Ascending
}
| DESC
{
$$.val = tree.Descending
}
| /* EMPTY */
{
$$.val = tree.DefaultDirection
}
alter_rename_database_stmt:
ALTER DATABASE database_name RENAME TO database_name
{
$$.val = &tree.RenameDatabase{Name: tree.Name($3), NewName: tree.Name($6)}
}
// https://www.postgresql.org/docs/10/static/sql-alteruser.html
alter_user_password_stmt:
ALTER USER string_or_placeholder WITH PASSWORD string_or_placeholder
{
$$.val = &tree.AlterUserSetPassword{Name: $3.expr(), Password: $6.expr()}
}
| ALTER USER IF EXISTS string_or_placeholder WITH PASSWORD string_or_placeholder
{
$$.val = &tree.AlterUserSetPassword{Name: $5.expr(), Password: $8.expr(), IfExists: true}
}
alter_rename_table_stmt:
ALTER TABLE relation_expr RENAME TO table_name
{
$$.val = &tree.RenameTable{Name: $3.normalizableTableNameFromUnresolvedName(), NewName: $6.normalizableTableNameFromUnresolvedName(), IfExists: false, IsView: false}
}
| ALTER TABLE IF EXISTS relation_expr RENAME TO table_name
{
$$.val = &tree.RenameTable{Name: $5.normalizableTableNameFromUnresolvedName(), NewName: $8.normalizableTableNameFromUnresolvedName(), IfExists: true, IsView: false}
}
| ALTER TABLE relation_expr RENAME opt_column column_name TO column_name
{
$$.val = &tree.RenameColumn{Table: $3.normalizableTableNameFromUnresolvedName(), Name: tree.Name($6), NewName: tree.Name($8), IfExists: false}
}
| ALTER TABLE IF EXISTS relation_expr RENAME opt_column column_name TO column_name
{
$$.val = &tree.RenameColumn{Table: $5.normalizableTableNameFromUnresolvedName(), Name: tree.Name($8), NewName: tree.Name($10), IfExists: true}
}
| ALTER TABLE relation_expr RENAME CONSTRAINT constraint_name TO constraint_name
{ return unimplemented(sqllex, "alter table rename constraint") }
| ALTER TABLE IF EXISTS relation_expr RENAME CONSTRAINT constraint_name TO constraint_name
{ return unimplemented(sqllex, "alter table rename constraint") }
alter_rename_view_stmt:
ALTER VIEW relation_expr RENAME TO view_name
{
$$.val = &tree.RenameTable{Name: $3.normalizableTableNameFromUnresolvedName(), NewName: $6.normalizableTableNameFromUnresolvedName(), IfExists: false, IsView: true}
}
| ALTER VIEW IF EXISTS relation_expr RENAME TO view_name
{
$$.val = &tree.RenameTable{Name: $5.normalizableTableNameFromUnresolvedName(), NewName: $8.normalizableTableNameFromUnresolvedName(), IfExists: true, IsView: true}
}
alter_rename_sequence_stmt:
ALTER SEQUENCE relation_expr RENAME TO sequence_name
{
$$.val = &tree.RenameTable{Name: $3.normalizableTableNameFromUnresolvedName(), NewName: $6.normalizableTableNameFromUnresolvedName(), IfExists: false, IsSequence: true}
}
| ALTER SEQUENCE IF EXISTS relation_expr RENAME TO sequence_name
{
$$.val = &tree.RenameTable{Name: $5.normalizableTableNameFromUnresolvedName(), NewName: $8.normalizableTableNameFromUnresolvedName(), IfExists: true, IsSequence: true}
}
alter_rename_index_stmt:
ALTER INDEX table_name_with_index RENAME TO index_name
{
$$.val = &tree.RenameIndex{Index: $3.newTableWithIdx(), NewName: tree.UnrestrictedName($6), IfExists: false}
}
| ALTER INDEX IF EXISTS table_name_with_index RENAME TO index_name
{
$$.val = &tree.RenameIndex{Index: $5.newTableWithIdx(), NewName: tree.UnrestrictedName($8), IfExists: true}
}
opt_column:
COLUMN {}
| /* EMPTY */ {}
opt_set_data:
SET DATA {}
| /* EMPTY */ {}
// %Help: RELEASE - complete a retryable block
// %Category: Txn
// %Text: RELEASE [SAVEPOINT] cockroach_restart
// %SeeAlso: SAVEPOINT, WEBDOCS/savepoint.html
release_stmt:
RELEASE savepoint_name
{
$$.val = &tree.ReleaseSavepoint{Savepoint: $2}
}
| RELEASE error // SHOW HELP: RELEASE
// %Help: RESUME JOBS - resume background jobs
// %Category: Misc
// %Text:
// RESUME JOBS <selectclause>
// RESUME JOB <jobid>
// %SeeAlso: SHOW JOBS, CANCEL JOBS, PAUSE JOBS
resume_stmt:
RESUME JOB a_expr
{
$$.val = &tree.ControlJobs{
Jobs: &tree.Select{
Select: &tree.ValuesClause{Rows: []tree.Exprs{tree.Exprs{$3.expr()}}},
},
Command: tree.ResumeJob,
}
}
| RESUME JOBS select_stmt
{
$$.val = &tree.ControlJobs{Jobs: $3.slct(), Command: tree.ResumeJob}
}
| RESUME error // SHOW HELP: RESUME JOBS
// %Help: SAVEPOINT - start a retryable block
// %Category: Txn
// %Text: SAVEPOINT cockroach_restart
// %SeeAlso: RELEASE, WEBDOCS/savepoint.html
savepoint_stmt:
SAVEPOINT name
{
$$.val = &tree.Savepoint{Name: $2}
}
| SAVEPOINT error // SHOW HELP: SAVEPOINT
// BEGIN / START / COMMIT / END / ROLLBACK / ...
transaction_stmt:
begin_stmt // EXTEND WITH HELP: BEGIN
| commit_stmt // EXTEND WITH HELP: COMMIT
| rollback_stmt // EXTEND WITH HELP: ROLLBACK
| abort_stmt /* SKIP DOC */
// %Help: BEGIN - start a transaction
// %Category: Txn
// %Text:
// BEGIN [TRANSACTION] [ <txnparameter> [[,] ...] ]
// START TRANSACTION [ <txnparameter> [[,] ...] ]
//
// Transaction parameters:
// ISOLATION LEVEL { SNAPSHOT | SERIALIZABLE }
// PRIORITY { LOW | NORMAL | HIGH }
//
// %SeeAlso: COMMIT, ROLLBACK, WEBDOCS/begin-transaction.html
begin_stmt:
BEGIN opt_transaction begin_transaction
{
$$.val = $3.stmt()
}
| BEGIN error // SHOW HELP: BEGIN
| START TRANSACTION begin_transaction
{
$$.val = $3.stmt()
}
| START error // SHOW HELP: BEGIN
// %Help: COMMIT - commit the current transaction
// %Category: Txn
// %Text:
// COMMIT [TRANSACTION]
// END [TRANSACTION]
// %SeeAlso: BEGIN, ROLLBACK, WEBDOCS/commit-transaction.html
commit_stmt:
COMMIT opt_transaction
{
$$.val = &tree.CommitTransaction{}
}
| COMMIT error // SHOW HELP: COMMIT
| END opt_transaction
{
$$.val = &tree.CommitTransaction{}
}
| END error // SHOW HELP: COMMIT
abort_stmt:
ABORT opt_abort_mod
{
$$.val = &tree.RollbackTransaction{}
}
opt_abort_mod:
TRANSACTION {}
| WORK {}
| /* EMPTY */ {}
// %Help: ROLLBACK - abort the current transaction
// %Category: Txn
// %Text: ROLLBACK [TRANSACTION] [TO [SAVEPOINT] cockroach_restart]
// %SeeAlso: BEGIN, COMMIT, SAVEPOINT, WEBDOCS/rollback-transaction.html
rollback_stmt:
ROLLBACK opt_to_savepoint
{
if $2 != "" {
$$.val = &tree.RollbackToSavepoint{Savepoint: $2}
} else {
$$.val = &tree.RollbackTransaction{}
}
}
| ROLLBACK error // SHOW HELP: ROLLBACK
opt_transaction:
TRANSACTION {}
| /* EMPTY */ {}
opt_to_savepoint:
TRANSACTION
{
$$ = ""
}
| TRANSACTION TO savepoint_name
{
$$ = $3
}
| TO savepoint_name
{
$$ = $2
}
| /* EMPTY */
{
$$ = ""
}
savepoint_name:
SAVEPOINT name
{
$$ = $2
}
| name
{
$$ = $1
}
begin_transaction:
transaction_mode_list
{
$$.val = &tree.BeginTransaction{Modes: $1.transactionModes()}
}
| /* EMPTY */
{
$$.val = &tree.BeginTransaction{}
}
transaction_mode_list:
transaction_mode
{
$$.val = $1.transactionModes()
}
| transaction_mode_list opt_comma transaction_mode
{
a := $1.transactionModes()
b := $3.transactionModes()
err := a.Merge(b)
if err != nil { sqllex.Error(err.Error()); return 1 }
$$.val = a
}
// The transaction mode list after BEGIN should use comma-separated
// modes as per the SQL standard, but PostgreSQL historically allowed
// them to be listed without commas too.
opt_comma:
','
{ }
| /* EMPTY */
{ }
transaction_mode:
transaction_iso_level
{
$$.val = tree.TransactionModes{Isolation: $1.isoLevel()}
}
| transaction_user_priority
{
$$.val = tree.TransactionModes{UserPriority: $1.userPriority()}
}
| transaction_read_mode
{
$$.val = tree.TransactionModes{ReadWriteMode: $1.readWriteMode()}
}
transaction_user_priority:
PRIORITY user_priority
{
$$.val = $2.userPriority()
}
transaction_iso_level:
ISOLATION LEVEL iso_level
{
$$.val = $3.isoLevel()
}
transaction_read_mode:
READ ONLY
{
$$.val = tree.ReadOnly
}
| READ WRITE
{
$$.val = tree.ReadWrite
}
// %Help: CREATE DATABASE - create a new database
// %Category: DDL
// %Text: CREATE DATABASE [IF NOT EXISTS] <name>
// %SeeAlso: WEBDOCS/create-database.html
create_database_stmt:
CREATE DATABASE database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause
{
$$.val = &tree.CreateDatabase{
Name: tree.Name($3),
Template: $5,
Encoding: $6,
Collate: $7,
CType: $8,
}
}
| CREATE DATABASE IF NOT EXISTS database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause
{
$$.val = &tree.CreateDatabase{
IfNotExists: true,
Name: tree.Name($6),
Template: $8,
Encoding: $9,
Collate: $10,
CType: $11,
}
}
| CREATE DATABASE error // SHOW HELP: CREATE DATABASE
opt_template_clause:
TEMPLATE opt_equal non_reserved_word_or_sconst
{
$$ = $3
}
| /* EMPTY */
{
$$ = ""
}
opt_encoding_clause:
ENCODING opt_equal non_reserved_word_or_sconst
{
$$ = $3
}
| /* EMPTY */
{
$$ = ""
}
opt_lc_collate_clause:
LC_COLLATE opt_equal non_reserved_word_or_sconst
{
$$ = $3
}
| /* EMPTY */
{
$$ = ""
}
opt_lc_ctype_clause:
LC_CTYPE opt_equal non_reserved_word_or_sconst
{
$$ = $3
}
| /* EMPTY */
{
$$ = ""
}
opt_equal:
'=' {}
| /* EMPTY */ {}
// %Help: INSERT - create new rows in a table
// %Category: DML
// %Text:
// INSERT INTO <tablename> [[AS] <name>] [( <colnames...> )]
// <selectclause>
// [ON CONFLICT [( <colnames...> )] {DO UPDATE SET ... [WHERE <expr>] | DO NOTHING}]
// [RETURNING <exprs...>]
// %SeeAlso: UPSERT, UPDATE, DELETE, WEBDOCS/insert.html
insert_stmt:
opt_with_clause INSERT INTO insert_target insert_rest returning_clause
{
$$.val = $5.stmt()
$$.val.(*tree.Insert).With = $1.with()
$$.val.(*tree.Insert).Table = $4.tblExpr()
$$.val.(*tree.Insert).Returning = $6.retClause()
}
| opt_with_clause INSERT INTO insert_target insert_rest on_conflict returning_clause
{
$$.val = $5.stmt()
$$.val.(*tree.Insert).With = $1.with()
$$.val.(*tree.Insert).Table = $4.tblExpr()
$$.val.(*tree.Insert).OnConflict = $6.onConflict()
$$.val.(*tree.Insert).Returning = $7.retClause()
}
| opt_with_clause INSERT error // SHOW HELP: INSERT
// %Help: UPSERT - create or replace rows in a table
// %Category: DML
// %Text:
// UPSERT INTO <tablename> [AS <name>] [( <colnames...> )]
// <selectclause>
// [RETURNING <exprs...>]
// %SeeAlso: INSERT, UPDATE, DELETE, WEBDOCS/upsert.html
upsert_stmt:
opt_with_clause UPSERT INTO insert_target insert_rest returning_clause
{
$$.val = $5.stmt()
$$.val.(*tree.Insert).With = $1.with()
$$.val.(*tree.Insert).Table = $4.tblExpr()
$$.val.(*tree.Insert).OnConflict = &tree.OnConflict{}
$$.val.(*tree.Insert).Returning = $6.retClause()
}
| opt_with_clause UPSERT error // SHOW HELP: UPSERT
insert_target:
table_name
{
$$.val = $1.newNormalizableTableNameFromUnresolvedName()
}
// Can't easily make AS optional here, because VALUES in insert_rest would have
// a shift/reduce conflict with VALUES as an optional alias. We could easily
// allow unreserved_keywords as optional aliases, but that'd be an odd
// divergence from other places. So just require AS for now.
| table_name AS table_alias_name
{
$$.val = &tree.AliasedTableExpr{Expr: $1.newNormalizableTableNameFromUnresolvedName(), As: tree.AliasClause{Alias: tree.Name($3)}}
}
insert_rest:
select_stmt
{
$$.val = &tree.Insert{Rows: $1.slct()}
}
| '(' insert_column_list ')' select_stmt
{
$$.val = &tree.Insert{Columns: $2.nameList(), Rows: $4.slct()}
}
| DEFAULT VALUES
{
$$.val = &tree.Insert{Rows: &tree.Select{}}
}
insert_column_list:
insert_column_item
{
$$.val = tree.NameList{tree.Name($1)}
}
| insert_column_list ',' insert_column_item
{
$$.val = append($1.nameList(), tree.Name($3))
}
// insert_column_item represents the target of an INSERT/UPSERT or one
// of the LHS operands in an UPDATE SET statement.
//
// INSERT INTO foo (x, y) VALUES ...
// ^^^^ here
//
// UPDATE foo SET x = 1+2, (y, z) = (4, 5)
// ^^ here ^^^^ here
//
// Currently CockroachDB only supports simple column names in this
// position. The rule below can be extended to support a sequence of
// field subscript or array indexing operators to designate a part of
// a field, when partial updates are to be supported. This likely will
// be needed together with support for compound types (#8318).
insert_column_item:
column_name
| column_name '.' error { return unimplementedWithIssue(sqllex, 8318) }
on_conflict:
ON CONFLICT opt_conf_expr DO UPDATE SET set_clause_list where_clause
{
$$.val = &tree.OnConflict{Columns: $3.nameList(), Exprs: $7.updateExprs(), Where: tree.NewWhere(tree.AstWhere, $8.expr())}
}
| ON CONFLICT opt_conf_expr DO NOTHING
{
$$.val = &tree.OnConflict{Columns: $3.nameList(), DoNothing: true}
}
opt_conf_expr:
'(' name_list ')' where_clause
{
// TODO(dan): Support the where_clause.
$$.val = $2.nameList()
}
| ON CONSTRAINT constraint_name { return unimplemented(sqllex, "on conflict on constraint") }
| /* EMPTY */
{
$$.val = tree.NameList(nil)
}
returning_clause:
RETURNING target_list
{
ret := tree.ReturningExprs($2.selExprs())
$$.val = &ret
}
| RETURNING NOTHING
{
$$.val = tree.ReturningNothingClause
}
| /* EMPTY */
{
$$.val = tree.AbsentReturningClause
}
// %Help: UPDATE - update rows of a table
// %Category: DML
// %Text:
// UPDATE <tablename> [[AS] <name>]
// SET ...
// [WHERE <expr>]
// [ORDER BY <exprs...>]
// [LIMIT <expr>]
// [RETURNING <exprs...>]
// %SeeAlso: INSERT, UPSERT, DELETE, WEBDOCS/update.html
update_stmt:
opt_with_clause UPDATE table_name_expr_opt_alias_idx
SET set_clause_list update_from_clause where_clause opt_sort_clause opt_limit_clause returning_clause
{
$$.val = &tree.Update{
With: $1.with(),
Table: $3.tblExpr(),
Exprs: $5.updateExprs(),
Where: tree.NewWhere(tree.AstWhere, $7.expr()),
OrderBy: $8.orderBy(),
Limit: $9.limit(),
Returning: $10.retClause(),
}
}
| opt_with_clause UPDATE error // SHOW HELP: UPDATE
// Mark this as unimplemented until the normal from_clause is supported here.
update_from_clause:
FROM from_list { return unimplementedWithIssue(sqllex, 7841) }
| /* EMPTY */ {}
set_clause_list:
set_clause
{
$$.val = tree.UpdateExprs{$1.updateExpr()}
}
| set_clause_list ',' set_clause
{
$$.val = append($1.updateExprs(), $3.updateExpr())
}
// TODO(knz): The LHS in these can be extended to support
// a path to a field member when compound types are supported.
// Keep it simple for now.
set_clause:
single_set_clause
| multiple_set_clause
single_set_clause:
column_name '=' a_expr
{
$$.val = &tree.UpdateExpr{Names: tree.NameList{tree.Name($1)}, Expr: $3.expr()}
}
| column_name '.' error { return unimplementedWithIssue(sqllex, 8318) }
multiple_set_clause:
'(' insert_column_list ')' '=' in_expr
{
$$.val = &tree.UpdateExpr{Tuple: true, Names: $2.nameList(), Expr: $5.expr()}
}
// A complete SELECT statement looks like this.
//
// The rule returns either a single select_stmt node or a tree of them,
// representing a set-operation tree.
//
// There is an ambiguity when a sub-SELECT is within an a_expr and there are
// excess parentheses: do the parentheses belong to the sub-SELECT or to the
// surrounding a_expr? We don't really care, but bison wants to know. To
// resolve the ambiguity, we are careful to define the grammar so that the
// decision is staved off as long as possible: as long as we can keep absorbing
// parentheses into the sub-SELECT, we will do so, and only when it's no longer
// possible to do that will we decide that parens belong to the expression. For
// example, in "SELECT (((SELECT 2)) + 3)" the extra parentheses are treated as
// part of the sub-select. The necessity of doing it that way is shown by
// "SELECT (((SELECT 2)) UNION SELECT 2)". Had we parsed "((SELECT 2))" as an
// a_expr, it'd be too late to go back to the SELECT viewpoint when we see the
// UNION.
//
// This approach is implemented by defining a nonterminal select_with_parens,
// which represents a SELECT with at least one outer layer of parentheses, and
// being careful to use select_with_parens, never '(' select_stmt ')', in the
// expression grammar. We will then have shift-reduce conflicts which we can
// resolve in favor of always treating '(' <select> ')' as a
// select_with_parens. To resolve the conflicts, the productions that conflict
// with the select_with_parens productions are manually given precedences lower
// than the precedence of ')', thereby ensuring that we shift ')' (and then
// reduce to select_with_parens) rather than trying to reduce the inner
// <select> nonterminal to something else. We use UMINUS precedence for this,
// which is a fairly arbitrary choice.
//
// To be able to define select_with_parens itself without ambiguity, we need a
// nonterminal select_no_parens that represents a SELECT structure with no
// outermost parentheses. This is a little bit tedious, but it works.
//
// In non-expression contexts, we use select_stmt which can represent a SELECT
// with or without outer parentheses.
select_stmt:
select_no_parens %prec UMINUS
| select_with_parens %prec UMINUS
{
$$.val = &tree.Select{Select: $1.selectStmt()}
}
select_with_parens:
'(' select_no_parens ')'
{
$$.val = &tree.ParenSelect{Select: $2.slct()}
}
| '(' select_with_parens ')'
{
$$.val = &tree.ParenSelect{Select: &tree.Select{Select: $2.selectStmt()}}
}
// This rule parses the equivalent of the standard's <query expression>. The
// duplicative productions are annoying, but hard to get rid of without
// creating shift/reduce conflicts.
//
// The locking clause (FOR UPDATE etc) may be before or after
// LIMIT/OFFSET. In <=7.2.X, LIMIT/OFFSET had to be after FOR UPDATE We
// now support both orderings, but prefer LIMIT/OFFSET before the locking
// clause.
// - 2002-08-28 bjm
select_no_parens:
simple_select opt_for
{
$$.val = &tree.Select{Select: $1.selectStmt()}
}
| select_clause sort_clause opt_for
{
$$.val = &tree.Select{Select: $1.selectStmt(), OrderBy: $2.orderBy()}
}
| select_clause opt_sort_clause select_limit opt_for
{
$$.val = &tree.Select{Select: $1.selectStmt(), OrderBy: $2.orderBy(), Limit: $3.limit()}
}
| with_clause select_clause opt_for
{
$$.val = &tree.Select{With: $1.with(), Select: $2.selectStmt()}
}
| with_clause select_clause sort_clause opt_for
{
$$.val = &tree.Select{With: $1.with(), Select: $2.selectStmt(), OrderBy: $3.orderBy()}
}
| with_clause select_clause opt_sort_clause select_limit opt_for
{
$$.val = &tree.Select{With: $1.with(), Select: $2.selectStmt(), OrderBy: $3.orderBy(), Limit: $4.limit()}
}
opt_for:
/* EMPTY */ { /* no error */ }
| FOR error { return unimplementedWithIssue(sqllex, 6583) }
select_clause:
// We only provide help if an open parenthesis is provided, because
// otherwise the rule is ambiguous with the top-level statement list.
'(' error // SHOW HELP: <SELECTCLAUSE>
| simple_select
| select_with_parens
// This rule parses SELECT statements that can appear within set operations,
// including UNION, INTERSECT and EXCEPT. '(' and ')' can be used to specify
// the ordering of the set operations. Without '(' and ')' we want the
// operations to be ordered per the precedence specs at the head of this file.
//
// As with select_no_parens, simple_select cannot have outer parentheses, but
// can have parenthesized subclauses.
//
// Note that sort clauses cannot be included at this level --- SQL requires
// SELECT foo UNION SELECT bar ORDER BY baz
// to be parsed as
// (SELECT foo UNION SELECT bar) ORDER BY baz
// not
// SELECT foo UNION (SELECT bar ORDER BY baz)
//
// Likewise for WITH, FOR UPDATE and LIMIT. Therefore, those clauses are
// described as part of the select_no_parens production, not simple_select.
// This does not limit functionality, because you can reintroduce these clauses
// inside parentheses.
//
// NOTE: only the leftmost component select_stmt should have INTO. However,
// this is not checked by the grammar; parse analysis must check it.
//
// %Help: <SELECTCLAUSE> - access tabular data
// %Category: DML
// %Text:
// Select clause:
// TABLE <tablename>
// VALUES ( <exprs...> ) [ , ... ]
// SELECT ... [ { INTERSECT | UNION | EXCEPT } [ ALL | DISTINCT ] <selectclause> ]
simple_select:
simple_select_clause // EXTEND WITH HELP: SELECT
| values_clause // EXTEND WITH HELP: VALUES
| table_clause // EXTEND WITH HELP: TABLE
| set_operation
// %Help: SELECT - retrieve rows from a data source and compute a result
// %Category: DML
// %Text:
// SELECT [DISTINCT [ ON ( <expr> [ , ... ] ) ] ]
// { <expr> [[AS] <name>] | [ [<dbname>.] <tablename>. ] * } [, ...]
// [ FROM <source> ]
// [ WHERE <expr> ]
// [ GROUP BY <expr> [ , ... ] ]
// [ HAVING <expr> ]
// [ WINDOW <name> AS ( <definition> ) ]
// [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] <selectclause> ]
// [ ORDER BY <expr> [ ASC | DESC ] [, ...] ]
// [ LIMIT { <expr> | ALL } ]
// [ OFFSET <expr> [ ROW | ROWS ] ]
// %SeeAlso: WEBDOCS/select-clause.html
simple_select_clause:
SELECT opt_all_clause target_list
from_clause where_clause
group_clause having_clause window_clause
{
$$.val = &tree.SelectClause{
Exprs: $3.selExprs(),
From: $4.from(),
Where: tree.NewWhere(tree.AstWhere, $5.expr()),
GroupBy: $6.groupBy(),
Having: tree.NewWhere(tree.AstHaving, $7.expr()),
Window: $8.window(),
}
}
| SELECT distinct_clause target_list
from_clause where_clause
group_clause having_clause window_clause
{
$$.val = &tree.SelectClause{
Distinct: $2.bool(),
Exprs: $3.selExprs(),
From: $4.from(),
Where: tree.NewWhere(tree.AstWhere, $5.expr()),
GroupBy: $6.groupBy(),
Having: tree.NewWhere(tree.AstHaving, $7.expr()),
Window: $8.window(),
}
}
| SELECT distinct_on_clause target_list
from_clause where_clause
group_clause having_clause window_clause
{
$$.val = &tree.SelectClause{
Distinct: true,
DistinctOn: $2.distinctOn(),
Exprs: $3.selExprs(),
From: $4.from(),
Where: tree.NewWhere(tree.AstWhere, $5.expr()),
GroupBy: $6.groupBy(),
Having: tree.NewWhere(tree.AstHaving, $7.expr()),
Window: $8.window(),
}
}
| SELECT error // SHOW HELP: SELECT
set_operation:
select_clause UNION all_or_distinct select_clause
{
$$.val = &tree.UnionClause{
Type: tree.UnionOp,
Left: &tree.Select{Select: $1.selectStmt()},
Right: &tree.Select{Select: $4.selectStmt()},
All: $3.bool(),
}
}
| select_clause INTERSECT all_or_distinct select_clause
{
$$.val = &tree.UnionClause{
Type: tree.IntersectOp,
Left: &tree.Select{Select: $1.selectStmt()},
Right: &tree.Select{Select: $4.selectStmt()},
All: $3.bool(),
}
}
| select_clause EXCEPT all_or_distinct select_clause
{
$$.val = &tree.UnionClause{
Type: tree.ExceptOp,
Left: &tree.Select{Select: $1.selectStmt()},
Right: &tree.Select{Select: $4.selectStmt()},
All: $3.bool(),
}
}
// %Help: TABLE - select an entire table
// %Category: DML
// %Text: TABLE <tablename>
// %SeeAlso: SELECT, VALUES, WEBDOCS/table-expressions.html
table_clause:
TABLE table_ref
{
$$.val = &tree.SelectClause{
Exprs: tree.SelectExprs{tree.StarSelectExpr()},
From: &tree.From{Tables: tree.TableExprs{$2.tblExpr()}},
TableSelect: true,
}
}
| TABLE error // SHOW HELP: TABLE
// SQL standard WITH clause looks like:
//
// WITH [ RECURSIVE ] <query name> [ (<column> [, ...]) ]
// AS (query) [ SEARCH or CYCLE clause ]
//
// We don't currently support the SEARCH or CYCLE clause.
//
// Recognizing WITH_LA here allows a CTE to be named TIME or ORDINALITY.
with_clause:
WITH cte_list
{
$$.val = &tree.With{CTEList: $2.ctes()}
}
| WITH_LA cte_list
{
/* SKIP DOC */
$$.val = &tree.With{CTEList: $2.ctes()}
}
| WITH RECURSIVE cte_list { return unimplementedWithIssue(sqllex, 21085) }
cte_list:
common_table_expr
{
$$.val = []*tree.CTE{$1.cte()}
}
| cte_list ',' common_table_expr
{
$$.val = append($1.ctes(), $3.cte())
}
common_table_expr:
table_alias_name opt_column_list AS '(' preparable_stmt ')'
{
$$.val = &tree.CTE{
Name: tree.AliasClause{Alias: tree.Name($1), Cols: $2.nameList() },
Stmt: $5.stmt(),
}
}
opt_with:
WITH {}
| /* EMPTY */ {}
opt_with_clause:
with_clause
{
$$.val = $1.with()
}
| /* EMPTY */
{
$$.val = nil
}
opt_table:
TABLE {}
| /* EMPTY */ {}
all_or_distinct:
ALL
{
$$.val = true
}
| DISTINCT
{
$$.val = false
}
| /* EMPTY */
{
$$.val = false
}
distinct_clause:
DISTINCT
{
$$.val = true
}
distinct_on_clause:
DISTINCT ON '(' expr_list ')'
{
$$.val = tree.DistinctOn($4.exprs())
}
opt_all_clause:
ALL {}
| /* EMPTY */ {}
opt_sort_clause_err:
sort_clause { return unimplementedWithIssue(sqllex, 23620) }
| /* EMPTY */ {}
opt_sort_clause:
sort_clause
{
$$.val = $1.orderBy()
}
| /* EMPTY */
{
$$.val = tree.OrderBy(nil)
}
sort_clause:
ORDER BY sortby_list
{
$$.val = tree.OrderBy($3.orders())
}
sortby_list:
sortby
{
$$.val = []*tree.Order{$1.order()}
}
| sortby_list ',' sortby
{
$$.val = append($1.orders(), $3.order())
}
sortby:
a_expr opt_asc_desc
{
$$.val = &tree.Order{OrderType: tree.OrderByColumn, Expr: $1.expr(), Direction: $2.dir()}
}
| PRIMARY KEY table_name opt_asc_desc
{
$$.val = &tree.Order{OrderType: tree.OrderByIndex, Direction: $4.dir(), Table: $3.normalizableTableNameFromUnresolvedName()}
}
| INDEX table_name '@' index_name opt_asc_desc
{
$$.val = &tree.Order{OrderType: tree.OrderByIndex, Direction: $5.dir(), Table: $2.normalizableTableNameFromUnresolvedName(), Index: tree.UnrestrictedName($4) }
}
// TODO(pmattis): Support ordering using arbitrary math ops?
// | a_expr USING math_op {}
select_limit:
limit_clause offset_clause
{
if $1.limit() == nil {
$$.val = $2.limit()
} else {
$$.val = $1.limit()
$$.val.(*tree.Limit).Offset = $2.limit().Offset
}
}
| offset_clause limit_clause
{
$$.val = $1.limit()
if $2.limit() != nil {
$$.val.(*tree.Limit).Count = $2.limit().Count
}
}
| limit_clause
| offset_clause
opt_limit_clause:
limit_clause
| /* EMPTY */ { $$.val = (*tree.Limit)(nil) }
limit_clause:
LIMIT select_limit_value
{
if $2.expr() == nil {
$$.val = (*tree.Limit)(nil)
} else {
$$.val = &tree.Limit{Count: $2.expr()}
}
}
// SQL:2008 syntax
| FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY
{
$$.val = &tree.Limit{Count: $3.expr()}
}
offset_clause:
OFFSET a_expr
{
$$.val = &tree.Limit{Offset: $2.expr()}
}
// SQL:2008 syntax
// The trailing ROW/ROWS in this case prevent the full expression
// syntax. c_expr is the best we can do.
| OFFSET c_expr row_or_rows
{
$$.val = &tree.Limit{Offset: $2.expr()}
}
select_limit_value:
a_expr
| ALL
{
$$.val = tree.Expr(nil)
}
// Allowing full expressions without parentheses causes various parsing
// problems with the trailing ROW/ROWS key words. SQL only calls for constants,
// so we allow the rest only with parentheses. If omitted, default to 1.
opt_select_fetch_first_value:
signed_iconst
{
$$.val = $1.expr()
}
| '(' a_expr ')'
{
$$.val = $2.expr()
}
| /* EMPTY */
{
$$.val = &tree.NumVal{Value: constant.MakeInt64(1)}
}
// noise words
row_or_rows:
ROW {}
| ROWS {}
first_or_next:
FIRST {}
| NEXT {}
// This syntax for group_clause tries to follow the spec quite closely.
// However, the spec allows only column references, not expressions,
// which introduces an ambiguity between implicit row constructors
// (a,b) and lists of column references.
//
// We handle this by using the a_expr production for what the spec calls
// <ordinary grouping set>, which in the spec represents either one column
// reference or a parenthesized list of column references. Then, we check the
// top node of the a_expr to see if it's an RowExpr, and if so, just grab and
// use the list, discarding the node. (this is done in parse analysis, not here)
//
// Each item in the group_clause list is either an expression tree or a
// GroupingSet node of some type.
group_clause:
GROUP BY expr_list
{
$$.val = tree.GroupBy($3.exprs())
}
| /* EMPTY */
{
$$.val = tree.GroupBy(nil)
}
having_clause:
HAVING a_expr
{
$$.val = $2.expr()
}
| /* EMPTY */
{
$$.val = tree.Expr(nil)
}
// Given "VALUES (a, b)" in a table expression context, we have to
// decide without looking any further ahead whether VALUES is the
// values clause or a set-generating function. Since VALUES is allowed
// as a function name both interpretations are feasible. We resolve
// the shift/reduce conflict by giving the first values_clause
// production a higher precedence than the VALUES token has, causing
// the parser to prefer to reduce, in effect assuming that the VALUES
// is not a function name.
//
// %Help: VALUES - select a given set of values
// %Category: DML
// %Text: VALUES ( <exprs...> ) [, ...]
// %SeeAlso: SELECT, TABLE, WEBDOCS/table-expressions.html
values_clause:
VALUES '(' expr_list ')' %prec UMINUS
{
$$.val = &tree.ValuesClause{Rows: []tree.Exprs{$3.exprs()}}
}
| VALUES error // SHOW HELP: VALUES
| values_clause ',' '(' expr_list ')'
{
valNode := $1.selectStmt().(*tree.ValuesClause)
valNode.Rows = append(valNode.Rows, $4.exprs())
$$.val = valNode
}
// clauses common to all optimizable statements:
// from_clause - allow list of both JOIN expressions and table names
// where_clause - qualifications for joins or restrictions
from_clause:
FROM from_list opt_as_of_clause
{
$$.val = &tree.From{Tables: $2.tblExprs(), AsOf: $3.asOfClause()}
}
| FROM error // SHOW HELP: <SOURCE>
| /* EMPTY */
{
$$.val = &tree.From{}
}
from_list:
table_ref
{
$$.val = tree.TableExprs{$1.tblExpr()}
}
| from_list ',' table_ref
{
$$.val = append($1.tblExprs(), $3.tblExpr())
}
index_flags_param:
FORCE_INDEX '=' index_name
{
$$.val = &tree.IndexFlags{Index: tree.UnrestrictedName($3)}
}
| FORCE_INDEX '=' '[' iconst64 ']'
{
/* SKIP DOC */
$$.val = &tree.IndexFlags{IndexID: tree.IndexID($4.int64())}
}
|
NO_INDEX_JOIN
{
$$.val = &tree.IndexFlags{NoIndexJoin: true}
}
index_flags_param_list:
index_flags_param
{
$$.val = $1.indexFlags()
}
|
index_flags_param_list ',' index_flags_param
{
a := $1.indexFlags()
b := $3.indexFlags()
if err := a.CombineWith(b); err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = a
}
opt_index_flags:
'@' index_name
{
$$.val = &tree.IndexFlags{Index: tree.UnrestrictedName($2)}
}
| '@' '[' iconst64 ']'
{
$$.val = &tree.IndexFlags{IndexID: tree.IndexID($3.int64())}
}
| '@' '{' index_flags_param_list '}'
{
$$.val = $3.indexFlags()
}
| /* EMPTY */
{
$$.val = (*tree.IndexFlags)(nil)
}
// %Help: <SOURCE> - define a data source for SELECT
// %Category: DML
// %Text:
// Data sources:
// <tablename> [ @ { <idxname> | <indexhint> } ]
// <tablefunc> ( <exprs...> )
// ( { <selectclause> | <source> } )
// <source> [AS] <alias> [( <colnames...> )]
// <source> { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN <source> ON <expr>
// <source> { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN <source> USING ( <colnames...> )
// <source> NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN <source>
// <source> CROSS JOIN <source>
// <source> WITH ORDINALITY
// '[' EXPLAIN ... ']'
// '[' SHOW ... ']'
//
// Index flags:
// '{' FORCE_INDEX = <idxname> [, ...] '}'
// '{' NO_INDEX_JOIN [, ...] '}'
//
// %SeeAlso: WEBDOCS/table-expressions.html
table_ref:
'[' iconst64 opt_tableref_col_list alias_clause ']' opt_index_flags opt_ordinality opt_alias_clause
{
/* SKIP DOC */
$$.val = &tree.AliasedTableExpr{
Expr: &tree.TableRef{
TableID: $2.int64(),
Columns: $3.tableRefCols(),
As: $4.aliasClause(),
},
IndexFlags: $6.indexFlags(),
Ordinality: $7.bool(),
As: $8.aliasClause(),
}
}
| relation_expr opt_index_flags opt_ordinality opt_alias_clause
{
$$.val = &tree.AliasedTableExpr{
Expr: $1.newNormalizableTableNameFromUnresolvedName(),
IndexFlags: $2.indexFlags(),
Ordinality: $3.bool(),
As: $4.aliasClause(),
}
}
| select_with_parens opt_ordinality opt_alias_clause
{
$$.val = &tree.AliasedTableExpr{
Expr: &tree.Subquery{Select: $1.selectStmt()},
Ordinality: $2.bool(),
As: $3.aliasClause(),
}
}
| LATERAL select_with_parens opt_ordinality opt_alias_clause { return unimplementedWithIssueDetail(sqllex, 24560, "select") }
| joined_table
{
$$.val = $1.tblExpr()
}
| '(' joined_table ')' opt_ordinality alias_clause
{
$$.val = &tree.AliasedTableExpr{Expr: &tree.ParenTableExpr{Expr: $2.tblExpr()}, Ordinality: $4.bool(), As: $5.aliasClause()}
}
| func_table opt_ordinality opt_alias_clause
{
f := $1.tblExpr()
$$.val = &tree.AliasedTableExpr{Expr: f, Ordinality: $2.bool(), As: $3.aliasClause()}
}
| LATERAL func_table opt_ordinality opt_alias_clause { return unimplementedWithIssueDetail(sqllex, 24560, "srf") }
// The following syntax is a CockroachDB extension:
// SELECT ... FROM [ EXPLAIN .... ] WHERE ...
// SELECT ... FROM [ SHOW .... ] WHERE ...
// SELECT ... FROM [ INSERT ... RETURNING ... ] WHERE ...
// A statement within square brackets can be used as a table expression (data source).
// We use square brackets for two reasons:
// - the grammar would be terribly ambiguous if we used simple
// parentheses or no parentheses at all.
// - it carries visual semantic information, by marking the table
// expression as radically different from the other things.
// If a user does not know this and encounters this syntax, they
// will know from the unusual choice that something rather different
// is going on and may be pushed by the unusual syntax to
// investigate further in the docs.
| '[' preparable_stmt ']' opt_ordinality opt_alias_clause
{
$$.val = &tree.AliasedTableExpr{Expr: &tree.StatementSource{ Statement: $2.stmt() }, Ordinality: $4.bool(), As: $5.aliasClause() }
}
func_table:
func_expr_windowless
{
$$.val = &tree.RowsFromExpr{Items: tree.Exprs{$1.expr()}}
}
| ROWS FROM '(' rowsfrom_list ')'
{
$$.val = &tree.RowsFromExpr{Items: $4.exprs()}
}
rowsfrom_list:
rowsfrom_item
{ $$.val = tree.Exprs{$1.expr()} }
| rowsfrom_list ',' rowsfrom_item
{ $$.val = append($1.exprs(), $3.expr()) }
rowsfrom_item:
func_expr_windowless opt_col_def_list
{
$$.val = $1.expr()
}
opt_col_def_list:
/* EMPTY */
{ }
| AS '(' error
{ return unimplemented(sqllex, "ROWS FROM with col_def_list") }
opt_tableref_col_list:
/* EMPTY */ { $$.val = nil }
| '(' ')' { $$.val = []tree.ColumnID{} }
| '(' tableref_col_list ')' { $$.val = $2.tableRefCols() }
tableref_col_list:
iconst64
{
$$.val = []tree.ColumnID{tree.ColumnID($1.int64())}
}
| tableref_col_list ',' iconst64
{
$$.val = append($1.tableRefCols(), tree.ColumnID($3.int64()))
}
opt_ordinality:
WITH_LA ORDINALITY
{
$$.val = true
}
| /* EMPTY */
{
$$.val = false
}
// It may seem silly to separate joined_table from table_ref, but there is
// method in SQL's madness: if you don't do it this way you get reduce- reduce
// conflicts, because it's not clear to the parser generator whether to expect
// alias_clause after ')' or not. For the same reason we must treat 'JOIN' and
// 'join_type JOIN' separately, rather than allowing join_type to expand to
// empty; if we try it, the parser generator can't figure out when to reduce an
// empty join_type right after table_ref.
//
// Note that a CROSS JOIN is the same as an unqualified INNER JOIN, and an
// INNER JOIN/ON has the same shape but a qualification expression to limit
// membership. A NATURAL JOIN implicitly matches column names between tables
// and the shape is determined by which columns are in common. We'll collect
// columns during the later transformations.
joined_table:
'(' joined_table ')'
{
$$.val = &tree.ParenTableExpr{Expr: $2.tblExpr()}
}
| table_ref CROSS JOIN table_ref
{
$$.val = &tree.JoinTableExpr{Join: tree.AstCrossJoin, Left: $1.tblExpr(), Right: $4.tblExpr()}
}
| table_ref join_type JOIN table_ref join_qual
{
$$.val = &tree.JoinTableExpr{Join: $2, Left: $1.tblExpr(), Right: $4.tblExpr(), Cond: $5.joinCond()}
}
| table_ref JOIN table_ref join_qual
{
$$.val = &tree.JoinTableExpr{Join: tree.AstJoin, Left: $1.tblExpr(), Right: $3.tblExpr(), Cond: $4.joinCond()}
}
| table_ref NATURAL join_type JOIN table_ref
{
$$.val = &tree.JoinTableExpr{Join: $3, Left: $1.tblExpr(), Right: $5.tblExpr(), Cond: tree.NaturalJoinCond{}}
}
| table_ref NATURAL JOIN table_ref
{
$$.val = &tree.JoinTableExpr{Join: tree.AstJoin, Left: $1.tblExpr(), Right: $4.tblExpr(), Cond: tree.NaturalJoinCond{}}
}
alias_clause:
AS table_alias_name opt_column_list
{
$$.val = tree.AliasClause{Alias: tree.Name($2), Cols: $3.nameList()}
}
| table_alias_name opt_column_list
{
$$.val = tree.AliasClause{Alias: tree.Name($1), Cols: $2.nameList()}
}
opt_alias_clause:
alias_clause
| /* EMPTY */
{
$$.val = tree.AliasClause{}
}
as_of_clause:
AS_LA OF SYSTEM TIME a_expr
{
$$.val = tree.AsOfClause{Expr: $5.expr()}
}
opt_as_of_clause:
as_of_clause
| /* EMPTY */
{
$$.val = tree.AsOfClause{}
}
join_type:
FULL join_outer
{
$$ = tree.AstFullJoin
}
| LEFT join_outer
{
$$ = tree.AstLeftJoin
}
| RIGHT join_outer
{
$$ = tree.AstRightJoin
}
| INNER
{
$$ = tree.AstInnerJoin
}
// OUTER is just noise...
join_outer:
OUTER {}
| /* EMPTY */ {}
// JOIN qualification clauses
// Possibilities are:
// USING ( column list ) allows only unqualified column names,
// which must match between tables.
// ON expr allows more general qualifications.
//
// We return USING as a List node, while an ON-expr will not be a List.
join_qual:
USING '(' name_list ')'
{
$$.val = &tree.UsingJoinCond{Cols: $3.nameList()}
}
| ON a_expr
{
$$.val = &tree.OnJoinCond{Expr: $2.expr()}
}
relation_expr:
table_name { $$.val = $1.unresolvedName() }
| table_name '*' { $$.val = $1.unresolvedName() }
| ONLY table_name { $$.val = $2.unresolvedName() }
| ONLY '(' table_name ')' { $$.val = $3.unresolvedName() }
relation_expr_list:
relation_expr
{
$$.val = tree.NormalizableTableNames{$1.normalizableTableNameFromUnresolvedName()}
}
| relation_expr_list ',' relation_expr
{
$$.val = append($1.normalizableTableNames(), $3.normalizableTableNameFromUnresolvedName())
}
// Given "UPDATE foo set set ...", we have to decide without looking any
// further ahead whether the first "set" is an alias or the UPDATE's SET
// keyword. Since "set" is allowed as a column name both interpretations are
// feasible. We resolve the shift/reduce conflict by giving the first
// table_name_expr_opt_alias_idx production a higher precedence than the SET token
// has, causing the parser to prefer to reduce, in effect assuming that the SET
// is not an alias.
table_name_expr_opt_alias_idx:
table_name_expr_with_index %prec UMINUS
{
$$.val = $1.tblExpr()
}
| table_name_expr_with_index table_alias_name
{
alias := $1.tblExpr().(*tree.AliasedTableExpr)
alias.As = tree.AliasClause{Alias: tree.Name($2)}
$$.val = alias
}
| table_name_expr_with_index AS table_alias_name
{
alias := $1.tblExpr().(*tree.AliasedTableExpr)
alias.As = tree.AliasClause{Alias: tree.Name($3)}
$$.val = alias
}
table_name_expr_with_index:
table_name opt_index_flags
{
$$.val = &tree.AliasedTableExpr{
Expr: $1.newNormalizableTableNameFromUnresolvedName(),
IndexFlags: $2.indexFlags(),
}
}
where_clause:
WHERE a_expr
{
$$.val = $2.expr()
}
| /* EMPTY */
{
$$.val = tree.Expr(nil)
}
// Type syntax
// SQL introduces a large amount of type-specific syntax.
// Define individual clauses to handle these cases, and use
// the generic case to handle regular type-extensible Postgres syntax.
// - thomas 1997-10-10
typename:
simple_typename opt_array_bounds
{
if bounds := $2.int32s(); bounds != nil {
var err error
$$.val, err = coltypes.ArrayOf($1.colType(), bounds)
if err != nil {
sqllex.Error(err.Error())
return 1
}
} else {
$$.val = $1.colType()
}
}
// SQL standard syntax, currently only one-dimensional
// Undocumented but support for potential Postgres compat
| simple_typename ARRAY '[' ICONST ']' {
/* SKIP DOC */
var err error
$$.val, err = coltypes.ArrayOf($1.colType(), []int32{-1})
if err != nil {
sqllex.Error(err.Error())
return 1
}
}
| simple_typename ARRAY {
var err error
$$.val, err = coltypes.ArrayOf($1.colType(), []int32{-1})
if err != nil {
sqllex.Error(err.Error())
return 1
}
}
| postgres_oid
{
$$.val = $1.castTargetType()
}
cast_target:
typename
{
$$.val = $1.colType()
}
opt_array_bounds:
// TODO(justin): reintroduce multiple array bounds
// opt_array_bounds '[' ']' { $$.val = append($1.int32s(), -1) }
'[' ']' { $$.val = []int32{-1} }
| '[' ICONST ']'
{
/* SKIP DOC */
bound, err := $2.numVal().AsInt32()
if err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = []int32{bound}
}
| /* EMPTY */ { $$.val = []int32(nil) }
const_json:
JSON
| JSONB
simple_typename:
const_typename
| bit_with_length
| character_with_length
| const_interval
| const_interval interval_qualifier { return unimplemented(sqllex, "interval with unit qualifier") }
| const_interval '(' ICONST ')' { return unimplemented(sqllex, "interval with precision") }
// We have a separate const_typename to allow defaulting fixed-length types
// such as CHAR() and BIT() to an unspecified length. SQL9x requires that these
// default to a length of one, but this makes no sense for constructs like CHAR
// 'hi' and BIT '0101', where there is an obvious better choice to make. Note
// that const_interval is not included here since it must be pushed up higher
// in the rules to accommodate the postfix options (e.g. INTERVAL '1'
// YEAR). Likewise, we have to handle the generic-type-name case in
// a_expr_const to avoid premature reduce/reduce conflicts against function
// names.
const_typename:
numeric
| bit_without_length
| character_without_length
| const_datetime
| const_json
{
$$.val = coltypes.JSON
}
| BLOB
{
$$.val = coltypes.Bytes
}
| BYTES
{
$$.val = coltypes.Bytes
}
| BYTEA
{
$$.val = coltypes.Bytes
}
| TEXT
{
$$.val = coltypes.String
}
| NAME
{
$$.val = coltypes.Name
}
| SERIAL
{
$$.val = coltypes.Serial
}
| SERIAL2
{
$$.val = coltypes.Serial2
}
| SMALLSERIAL
{
$$.val = coltypes.Serial2
}
| SERIAL4
{
$$.val = coltypes.Serial4
}
| SERIAL8
{
$$.val = coltypes.Serial8
}
| BIGSERIAL
{
$$.val = coltypes.Serial8
}
| UUID
{
$$.val = coltypes.UUID
}
| INET
{
$$.val = coltypes.INet
}
| OID
{
$$.val = coltypes.Oid
}
| OIDVECTOR
{
$$.val = coltypes.OidVector
}
| INT2VECTOR
{
$$.val = coltypes.Int2vector
}
| IDENT
{
/* FORCE DOC */
// See https://www.postgresql.org/docs/9.1/static/datatype-character.html
// Postgres supports a special character type named "char" (with the quotes)
// that is a single-character column type. It's used by system tables.
// Eventually this clause will be used to parse user-defined types as well,
// since their names can be quoted.
if $1 == "char" {
$$.val = coltypes.QChar
} else {
var ok bool
var unimp int
$$.val, ok, unimp = coltypes.TypeForNonKeywordTypeName($1)
if !ok {
switch unimp {
case 0:
// Note: we can only report an unimplemented error for specific
// known type names. Anything else may return PII.
sqllex.Error("type does not exist")
return 1
case -1:
return unimplemented(sqllex, "type name " + $1)
default:
return unimplementedWithIssueDetail(sqllex, unimp, $1)
}
}
}
}
opt_numeric_modifiers:
'(' iconst64 ')'
{
$$.val = &coltypes.TDecimal{Prec: int($2.int64())}
}
| '(' iconst64 ',' iconst64 ')'
{
$$.val = &coltypes.TDecimal{Prec: int($2.int64()), Scale: int($4.int64())}
}
| /* EMPTY */
{
$$.val = nil
}
// SQL numeric data types
numeric:
INT
{
$$.val = coltypes.Int
}
| INTEGER
{
$$.val = coltypes.Int
}
| INT2
{
$$.val = coltypes.Int2
}
| SMALLINT
{
$$.val = coltypes.Int2
}
| INT4
{
$$.val = coltypes.Int4
}
| INT8
{
$$.val = coltypes.Int8
}
| INT64
{
$$.val = coltypes.Int8
}
| BIGINT
{
$$.val = coltypes.Int8
}
| REAL
{
$$.val = coltypes.Float4
}
| FLOAT4
{
$$.val = coltypes.Float4
}
| FLOAT8
{
$$.val = coltypes.Float8
}
| FLOAT opt_float
{
$$.val = $2.colType()
}
| DOUBLE PRECISION
{
$$.val = coltypes.Float8
}
| DECIMAL opt_numeric_modifiers
{
$$.val = $2.colType()
if $$.val == nil {
$$.val = coltypes.Decimal
}
}
| DEC opt_numeric_modifiers
{
$$.val = $2.colType()
if $$.val == nil {
$$.val = coltypes.Decimal
}
}
| NUMERIC opt_numeric_modifiers
{
$$.val = $2.colType()
if $$.val == nil {
$$.val = coltypes.Decimal
}
}
| BOOLEAN
{
$$.val = coltypes.Bool
}
| BOOL
{
$$.val = coltypes.Bool
}
// Postgres OID pseudo-types. See https://www.postgresql.org/docs/9.4/static/datatype-oid.html.
postgres_oid:
REGPROC
{
$$.val = coltypes.RegProc
}
| REGPROCEDURE
{
$$.val = coltypes.RegProcedure
}
| REGCLASS
{
$$.val = coltypes.RegClass
}
| REGTYPE
{
$$.val = coltypes.RegType
}
| REGNAMESPACE
{
$$.val = coltypes.RegNamespace
}
opt_float:
'(' ICONST ')'
{
nv := $2.numVal()
prec, err := nv.AsInt64()
if err != nil {
sqllex.Error(err.Error())
return 1
}
typ, err := coltypes.NewFloat(prec)
if err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = typ
}
| /* EMPTY */
{
$$.val = coltypes.Float8
}
bit_with_length:
BIT opt_varying '(' iconst64 ')'
{
bit, err := coltypes.NewBitArrayType(int($4.int64()), $2.bool())
if err != nil { sqllex.Error(err.Error()); return 1 }
$$.val = bit
}
| VARBIT '(' iconst64 ')'
{
bit, err := coltypes.NewBitArrayType(int($3.int64()), true)
if err != nil { sqllex.Error(err.Error()); return 1 }
$$.val = bit
}
bit_without_length:
BIT
{
$$.val = coltypes.Bit
}
| BIT VARYING
{
$$.val = coltypes.VarBit
}
| VARBIT
{
$$.val = coltypes.VarBit
}
character_with_length:
character_base '(' iconst64 ')'
{
colTyp := *($1.colType().(*coltypes.TString))
n := $3.int64()
if n == 0 {
sqllex.Error(fmt.Sprintf("length for type %s must be at least 1", &colTyp))
return 1
}
colTyp.N = uint(n)
$$.val = &colTyp
}
character_without_length:
character_base
{
$$.val = $1.colType()
}
character_base:
char_aliases
{
$$.val = coltypes.Char
}
| char_aliases VARYING
{
$$.val = coltypes.VarChar
}
| VARCHAR
{
$$.val = coltypes.VarChar
}
| STRING
{
$$.val = coltypes.String
}
char_aliases:
CHAR
| CHARACTER
opt_varying:
VARYING { $$.val = true }
| /* EMPTY */ { $$.val = false }
// SQL date/time types
const_datetime:
DATE
{
$$.val = coltypes.Date
}
| TIME
{
$$.val = coltypes.Time
}
| TIME WITHOUT TIME ZONE
{
$$.val = coltypes.Time
}
| TIMETZ
{
return unimplementedWithIssueDetail(sqllex, 26097, "type")
}
| TIME WITH_LA TIME ZONE
{
return unimplementedWithIssueDetail(sqllex, 26097, "type")
}
| TIMESTAMP
{
$$.val = coltypes.Timestamp
}
| TIMESTAMP WITHOUT TIME ZONE
{
$$.val = coltypes.Timestamp
}
| TIMESTAMPTZ
{
$$.val = coltypes.TimestampWithTZ
}
| TIMESTAMP WITH_LA TIME ZONE
{
$$.val = coltypes.TimestampWithTZ
}
const_interval:
INTERVAL {
$$.val = coltypes.Interval
}
interval_qualifier:
YEAR
{
$$.val = tree.Year
}
| MONTH
{
$$.val = tree.Month
}
| DAY
{
$$.val = tree.Day
}
| HOUR
{
$$.val = tree.Hour
}
| MINUTE
{
$$.val = tree.Minute
}
| interval_second
{
$$.val = $1.durationField()
}
// Like Postgres, we ignore the left duration field. See explanation:
// https://www.postgresql.org/message-id/20110510040219.GD5617%40tornado.gateway.2wire.net
| YEAR TO MONTH
{
$$.val = tree.Month
}
| DAY TO HOUR
{
$$.val = tree.Hour
}
| DAY TO MINUTE
{
$$.val = tree.Minute
}
| DAY TO interval_second
{
$$.val = $3.durationField()
}
| HOUR TO MINUTE
{
$$.val = tree.Minute
}
| HOUR TO interval_second
{
$$.val = $3.durationField()
}
| MINUTE TO interval_second
{
$$.val = $3.durationField()
}
opt_interval:
interval_qualifier
| /* EMPTY */
{
$$.val = nil
}
interval_second:
SECOND
{
$$.val = tree.Second
}
| SECOND '(' ICONST ')' { return unimplemented(sqllex, "interval second with precision") }
// General expressions. This is the heart of the expression syntax.
//
// We have two expression types: a_expr is the unrestricted kind, and b_expr is
// a subset that must be used in some places to avoid shift/reduce conflicts.
// For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr" because that
// use of AND conflicts with AND as a boolean operator. So, b_expr is used in
// BETWEEN and we remove boolean keywords from b_expr.
//
// Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can
// always be used by surrounding it with parens.
//
// c_expr is all the productions that are common to a_expr and b_expr; it's
// factored out just to eliminate redundant coding.
//
// Be careful of productions involving more than one terminal token. By
// default, bison will assign such productions the precedence of their last
// terminal, but in nearly all cases you want it to be the precedence of the
// first terminal instead; otherwise you will not get the behavior you expect!
// So we use %prec annotations freely to set precedences.
a_expr:
c_expr
| a_expr TYPECAST cast_target
{
$$.val = &tree.CastExpr{Expr: $1.expr(), Type: $3.castTargetType(), SyntaxMode: tree.CastShort}
}
| a_expr TYPEANNOTATE typename
{
$$.val = &tree.AnnotateTypeExpr{Expr: $1.expr(), Type: $3.colType(), SyntaxMode: tree.AnnotateShort}
}
| a_expr COLLATE collation_name
{
$$.val = &tree.CollateExpr{Expr: $1.expr(), Locale: $3}
}
| a_expr AT TIME ZONE a_expr %prec AT { return unimplemented(sqllex, "at tz") }
// These operators must be called out explicitly in order to make use of
// bison's automatic operator-precedence handling. All other operator names
// are handled by the generic productions using "OP", below; and all those
// operators will have the same precedence.
//
// If you add more explicitly-known operators, be sure to add them also to
// b_expr and to the math_op list below.
| '+' a_expr %prec UMINUS
{
// Unary plus is a no-op. Desugar immediately.
$$.val = $2.expr()
}
| '-' a_expr %prec UMINUS
{
$$.val = unaryNegation($2.expr())
}
| '~' a_expr %prec UMINUS
{
$$.val = &tree.UnaryExpr{Operator: tree.UnaryComplement, Expr: $2.expr()}
}
| a_expr '+' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Plus, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '-' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Minus, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '*' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Mult, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '/' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Div, Left: $1.expr(), Right: $3.expr()}
}
| a_expr FLOORDIV a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.FloorDiv, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '%' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Mod, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '^' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Pow, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '#' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Bitxor, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '&' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Bitand, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '|' a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Bitor, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '<' a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.LT, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '>' a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.GT, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '?' a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.JSONExists, Left: $1.expr(), Right: $3.expr()}
}
| a_expr JSON_SOME_EXISTS a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.JSONSomeExists, Left: $1.expr(), Right: $3.expr()}
}
| a_expr JSON_ALL_EXISTS a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.JSONAllExists, Left: $1.expr(), Right: $3.expr()}
}
| a_expr CONTAINS a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.Contains, Left: $1.expr(), Right: $3.expr()}
}
| a_expr CONTAINED_BY a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.ContainedBy, Left: $1.expr(), Right: $3.expr()}
}
| a_expr '=' a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.EQ, Left: $1.expr(), Right: $3.expr()}
}
| a_expr CONCAT a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Concat, Left: $1.expr(), Right: $3.expr()}
}
| a_expr LSHIFT a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.LShift, Left: $1.expr(), Right: $3.expr()}
}
| a_expr RSHIFT a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.RShift, Left: $1.expr(), Right: $3.expr()}
}
| a_expr FETCHVAL a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.JSONFetchVal, Left: $1.expr(), Right: $3.expr()}
}
| a_expr FETCHTEXT a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.JSONFetchText, Left: $1.expr(), Right: $3.expr()}
}
| a_expr FETCHVAL_PATH a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.JSONFetchValPath, Left: $1.expr(), Right: $3.expr()}
}
| a_expr FETCHTEXT_PATH a_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.JSONFetchTextPath, Left: $1.expr(), Right: $3.expr()}
}
| a_expr REMOVE_PATH a_expr
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("json_remove_path"), Exprs: tree.Exprs{$1.expr(), $3.expr()}}
}
| a_expr INET_CONTAINED_BY_OR_EQUALS a_expr
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("inet_contained_by_or_equals"), Exprs: tree.Exprs{$1.expr(), $3.expr()}}
}
| a_expr INET_CONTAINS_OR_CONTAINED_BY a_expr
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("inet_contains_or_contained_by"), Exprs: tree.Exprs{$1.expr(), $3.expr()}}
}
| a_expr INET_CONTAINS_OR_EQUALS a_expr
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("inet_contains_or_equals"), Exprs: tree.Exprs{$1.expr(), $3.expr()}}
}
| a_expr LESS_EQUALS a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.LE, Left: $1.expr(), Right: $3.expr()}
}
| a_expr GREATER_EQUALS a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.GE, Left: $1.expr(), Right: $3.expr()}
}
| a_expr NOT_EQUALS a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.NE, Left: $1.expr(), Right: $3.expr()}
}
| a_expr AND a_expr
{
$$.val = &tree.AndExpr{Left: $1.expr(), Right: $3.expr()}
}
| a_expr OR a_expr
{
$$.val = &tree.OrExpr{Left: $1.expr(), Right: $3.expr()}
}
| NOT a_expr
{
$$.val = &tree.NotExpr{Expr: $2.expr()}
}
| NOT_LA a_expr %prec NOT
{
$$.val = &tree.NotExpr{Expr: $2.expr()}
}
| a_expr LIKE a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.Like, Left: $1.expr(), Right: $3.expr()}
}
| a_expr LIKE a_expr ESCAPE a_expr %prec ESCAPE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("like_escape"), Exprs: tree.Exprs{$1.expr(), $3.expr(), $5.expr()}}
}
| a_expr NOT_LA LIKE a_expr %prec NOT_LA
{
$$.val = &tree.ComparisonExpr{Operator: tree.NotLike, Left: $1.expr(), Right: $4.expr()}
}
| a_expr NOT_LA LIKE a_expr ESCAPE a_expr %prec ESCAPE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("not_like_escape"), Exprs: tree.Exprs{$1.expr(), $4.expr(), $6.expr()}}
}
| a_expr ILIKE a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.ILike, Left: $1.expr(), Right: $3.expr()}
}
| a_expr ILIKE a_expr ESCAPE a_expr %prec ESCAPE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("ilike_escape"), Exprs: tree.Exprs{$1.expr(), $3.expr(), $5.expr()}}
}
| a_expr NOT_LA ILIKE a_expr %prec NOT_LA
{
$$.val = &tree.ComparisonExpr{Operator: tree.NotILike, Left: $1.expr(), Right: $4.expr()}
}
| a_expr NOT_LA ILIKE a_expr ESCAPE a_expr %prec ESCAPE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("not_ilike_escape"), Exprs: tree.Exprs{$1.expr(), $4.expr(), $6.expr()}}
}
| a_expr SIMILAR TO a_expr %prec SIMILAR
{
$$.val = &tree.ComparisonExpr{Operator: tree.SimilarTo, Left: $1.expr(), Right: $4.expr()}
}
| a_expr SIMILAR TO a_expr ESCAPE a_expr %prec ESCAPE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("similar_to_escape"), Exprs: tree.Exprs{$1.expr(), $4.expr(), $6.expr()}}
}
| a_expr NOT_LA SIMILAR TO a_expr %prec NOT_LA
{
$$.val = &tree.ComparisonExpr{Operator: tree.NotSimilarTo, Left: $1.expr(), Right: $5.expr()}
}
| a_expr NOT_LA SIMILAR TO a_expr ESCAPE a_expr %prec ESCAPE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("not_similar_to_escape"), Exprs: tree.Exprs{$1.expr(), $5.expr(), $7.expr()}}
}
| a_expr '~' a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.RegMatch, Left: $1.expr(), Right: $3.expr()}
}
| a_expr NOT_REGMATCH a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.NotRegMatch, Left: $1.expr(), Right: $3.expr()}
}
| a_expr REGIMATCH a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.RegIMatch, Left: $1.expr(), Right: $3.expr()}
}
| a_expr NOT_REGIMATCH a_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.NotRegIMatch, Left: $1.expr(), Right: $3.expr()}
}
| a_expr IS NAN %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.EQ, Left: $1.expr(), Right: tree.NewStrVal("NaN")}
}
| a_expr IS NOT NAN %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.NE, Left: $1.expr(), Right: tree.NewStrVal("NaN")}
}
| a_expr IS NULL %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: tree.DNull}
}
| a_expr ISNULL %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: tree.DNull}
}
| a_expr IS NOT NULL %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: tree.DNull}
}
| a_expr NOTNULL %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: tree.DNull}
}
| row OVERLAPS row { return unimplemented(sqllex, "overlaps") }
| a_expr IS TRUE %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: tree.MakeDBool(true)}
}
| a_expr IS NOT TRUE %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: tree.MakeDBool(true)}
}
| a_expr IS FALSE %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: tree.MakeDBool(false)}
}
| a_expr IS NOT FALSE %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: tree.MakeDBool(false)}
}
| a_expr IS UNKNOWN %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: tree.DNull}
}
| a_expr IS NOT UNKNOWN %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: tree.DNull}
}
| a_expr IS DISTINCT FROM a_expr %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: $5.expr()}
}
| a_expr IS NOT DISTINCT FROM a_expr %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: $6.expr()}
}
| a_expr IS OF '(' type_list ')' %prec IS
{
$$.val = &tree.IsOfTypeExpr{Expr: $1.expr(), Types: $5.colTypes()}
}
| a_expr IS NOT OF '(' type_list ')' %prec IS
{
$$.val = &tree.IsOfTypeExpr{Not: true, Expr: $1.expr(), Types: $6.colTypes()}
}
| a_expr BETWEEN opt_asymmetric b_expr AND a_expr %prec BETWEEN
{
$$.val = &tree.RangeCond{Left: $1.expr(), From: $4.expr(), To: $6.expr()}
}
| a_expr NOT_LA BETWEEN opt_asymmetric b_expr AND a_expr %prec NOT_LA
{
$$.val = &tree.RangeCond{Not: true, Left: $1.expr(), From: $5.expr(), To: $7.expr()}
}
| a_expr BETWEEN SYMMETRIC b_expr AND a_expr %prec BETWEEN
{
$$.val = &tree.RangeCond{Symmetric: true, Left: $1.expr(), From: $4.expr(), To: $6.expr()}
}
| a_expr NOT_LA BETWEEN SYMMETRIC b_expr AND a_expr %prec NOT_LA
{
$$.val = &tree.RangeCond{Not: true, Symmetric: true, Left: $1.expr(), From: $5.expr(), To: $7.expr()}
}
| a_expr IN in_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.In, Left: $1.expr(), Right: $3.expr()}
}
| a_expr NOT_LA IN in_expr %prec NOT_LA
{
$$.val = &tree.ComparisonExpr{Operator: tree.NotIn, Left: $1.expr(), Right: $4.expr()}
}
| a_expr subquery_op sub_type a_expr %prec CONCAT
{
op := $3.cmpOp()
subOp := $2.op()
subOpCmp, ok := subOp.(tree.ComparisonOperator)
if !ok {
sqllex.Error(fmt.Sprintf("%s %s <array> is invalid because %q is not a boolean operator",
subOp, op, subOp))
return 1
}
$$.val = &tree.ComparisonExpr{
Operator: op,
SubOperator: subOpCmp,
Left: $1.expr(),
Right: $4.expr(),
}
}
| DEFAULT
{
$$.val = tree.DefaultVal{}
}
| MAXVALUE
{
$$.val = tree.MaxVal{}
}
| MINVALUE
{
$$.val = tree.MinVal{}
}
// The UNIQUE predicate is a standard SQL feature but not yet implemented
// in PostgreSQL (as of 10.5).
| UNIQUE '(' error { return unimplemented(sqllex, "UNIQUE predicate") }
// Restricted expressions
//
// b_expr is a subset of the complete expression syntax defined by a_expr.
//
// Presently, AND, NOT, IS, and IN are the a_expr keywords that would cause
// trouble in the places where b_expr is used. For simplicity, we just
// eliminate all the boolean-keyword-operator productions from b_expr.
b_expr:
c_expr
| b_expr TYPECAST cast_target
{
$$.val = &tree.CastExpr{Expr: $1.expr(), Type: $3.castTargetType(), SyntaxMode: tree.CastShort}
}
| b_expr TYPEANNOTATE typename
{
$$.val = &tree.AnnotateTypeExpr{Expr: $1.expr(), Type: $3.colType(), SyntaxMode: tree.AnnotateShort}
}
| '+' b_expr %prec UMINUS
{
$$.val = $2.expr()
}
| '-' b_expr %prec UMINUS
{
$$.val = unaryNegation($2.expr())
}
| '~' b_expr %prec UMINUS
{
$$.val = &tree.UnaryExpr{Operator: tree.UnaryComplement, Expr: $2.expr()}
}
| b_expr '+' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Plus, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '-' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Minus, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '*' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Mult, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '/' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Div, Left: $1.expr(), Right: $3.expr()}
}
| b_expr FLOORDIV b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.FloorDiv, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '%' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Mod, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '^' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Pow, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '#' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Bitxor, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '&' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Bitand, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '|' b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Bitor, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '<' b_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.LT, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '>' b_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.GT, Left: $1.expr(), Right: $3.expr()}
}
| b_expr '=' b_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.EQ, Left: $1.expr(), Right: $3.expr()}
}
| b_expr CONCAT b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.Concat, Left: $1.expr(), Right: $3.expr()}
}
| b_expr LSHIFT b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.LShift, Left: $1.expr(), Right: $3.expr()}
}
| b_expr RSHIFT b_expr
{
$$.val = &tree.BinaryExpr{Operator: tree.RShift, Left: $1.expr(), Right: $3.expr()}
}
| b_expr LESS_EQUALS b_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.LE, Left: $1.expr(), Right: $3.expr()}
}
| b_expr GREATER_EQUALS b_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.GE, Left: $1.expr(), Right: $3.expr()}
}
| b_expr NOT_EQUALS b_expr
{
$$.val = &tree.ComparisonExpr{Operator: tree.NE, Left: $1.expr(), Right: $3.expr()}
}
| b_expr IS DISTINCT FROM b_expr %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsDistinctFrom, Left: $1.expr(), Right: $5.expr()}
}
| b_expr IS NOT DISTINCT FROM b_expr %prec IS
{
$$.val = &tree.ComparisonExpr{Operator: tree.IsNotDistinctFrom, Left: $1.expr(), Right: $6.expr()}
}
| b_expr IS OF '(' type_list ')' %prec IS
{
$$.val = &tree.IsOfTypeExpr{Expr: $1.expr(), Types: $5.colTypes()}
}
| b_expr IS NOT OF '(' type_list ')' %prec IS
{
$$.val = &tree.IsOfTypeExpr{Not: true, Expr: $1.expr(), Types: $6.colTypes()}
}
// Productions that can be used in both a_expr and b_expr.
//
// Note: productions that refer recursively to a_expr or b_expr mostly cannot
// appear here. However, it's OK to refer to a_exprs that occur inside
// parentheses, such as function arguments; that cannot introduce ambiguity to
// the b_expr syntax.
//
c_expr:
d_expr
| d_expr array_subscripts
{
$$.val = &tree.IndirectionExpr{
Expr: $1.expr(),
Indirection: $2.arraySubscripts(),
}
}
| case_expr
| EXISTS select_with_parens
{
$$.val = &tree.Subquery{Select: $2.selectStmt(), Exists: true}
}
// Productions that can be followed by a postfix operator.
//
// Currently we support array indexing (see c_expr above).
//
// TODO(knz/jordan): this is the rule that can be extended to support
// compound types (#8318) with e.g.:
//
// | '(' a_expr ')' field_access_ops
//
// [...]
//
// // field_access_ops supports the notations:
// // - .a
// // - .a[123]
// // - .a.b[123][5456].c.d
// // NOT [123] directly, this is handled in c_expr above.
//
// field_access_ops:
// field_access_op
// | field_access_op other_subscripts
//
// field_access_op:
// '.' name
// other_subscripts:
// other_subscript
// | other_subscripts other_subscript
// other_subscript:
// field_access_op
// | array_subscripts
d_expr:
ICONST
{
$$.val = $1.numVal()
}
| FCONST
{
$$.val = $1.numVal()
}
| SCONST
{
$$.val = tree.NewStrVal($1)
}
| BCONST
{
$$.val = tree.NewBytesStrVal($1)
}
| BITCONST
{
d, err := tree.ParseDBitArray($1)
if err != nil { sqllex.Error(err.Error()); return 1 }
$$.val = d
}
| func_name '(' expr_list opt_sort_clause_err ')' SCONST { return unimplemented(sqllex, "func const") }
| const_typename SCONST
{
$$.val = &tree.CastExpr{Expr: tree.NewStrVal($2), Type: $1.colType(), SyntaxMode: tree.CastPrepend}
}
| interval
{
$$.val = $1.expr()
}
| const_interval '(' ICONST ')' SCONST { return unimplemented(sqllex, "expr_const const_interval") }
| TRUE
{
$$.val = tree.MakeDBool(true)
}
| FALSE
{
$$.val = tree.MakeDBool(false)
}
| NULL
{
$$.val = tree.DNull
}
| column_path_with_star
{
$$.val = tree.Expr($1.unresolvedName())
}
| '@' iconst64
{
colNum := $2.int64()
if colNum < 1 || colNum > int64(MaxInt) {
sqllex.Error(fmt.Sprintf("invalid column ordinal: @%d", colNum))
return 1
}
$$.val = tree.NewOrdinalReference(int(colNum-1))
}
| PLACEHOLDER
{
$$.val = tree.NewPlaceholder($1)
}
// TODO(knz/jordan): extend this for compound types. See explanation above.
| '(' a_expr ')' '.' '*'
{
$$.val = &tree.TupleStar{Expr: $2.expr()}
}
| '(' a_expr ')' '.' unrestricted_name
{
$$.val = &tree.ColumnAccessExpr{Expr: $2.expr(), ColName: $5 }
}
| '(' a_expr ')'
{
$$.val = &tree.ParenExpr{Expr: $2.expr()}
}
| func_expr
| select_with_parens %prec UMINUS
{
$$.val = &tree.Subquery{Select: $1.selectStmt()}
}
| labeled_row
{
$$.val = $1.tuple()
}
| ARRAY select_with_parens %prec UMINUS
{
$$.val = &tree.ArrayFlatten{Subquery: &tree.Subquery{Select: $2.selectStmt()}}
}
| ARRAY row
{
$$.val = &tree.Array{Exprs: $2.tuple().Exprs}
}
| ARRAY array_expr
{
$$.val = $2.expr()
}
| GROUPING '(' expr_list ')' { return unimplemented(sqllex, "d_expr grouping") }
func_application:
func_name '(' ')'
{
$$.val = &tree.FuncExpr{Func: $1.resolvableFuncRefFromName()}
}
| func_name '(' expr_list opt_sort_clause_err ')'
{
$$.val = &tree.FuncExpr{Func: $1.resolvableFuncRefFromName(), Exprs: $3.exprs()}
}
| func_name '(' VARIADIC a_expr opt_sort_clause_err ')' { return unimplemented(sqllex, "variadic") }
| func_name '(' expr_list ',' VARIADIC a_expr opt_sort_clause_err ')' { return unimplemented(sqllex, "variadic") }
| func_name '(' ALL expr_list opt_sort_clause_err ')'
{
$$.val = &tree.FuncExpr{Func: $1.resolvableFuncRefFromName(), Type: tree.AllFuncType, Exprs: $4.exprs()}
}
| func_name '(' DISTINCT expr_list opt_sort_clause_err ')'
{
$$.val = &tree.FuncExpr{Func: $1.resolvableFuncRefFromName(), Type: tree.DistinctFuncType, Exprs: $4.exprs()}
}
| func_name '(' '*' ')'
{
$$.val = &tree.FuncExpr{Func: $1.resolvableFuncRefFromName(), Exprs: tree.Exprs{tree.StarExpr()}}
}
| func_name '(' error { return helpWithFunction(sqllex, $1.resolvableFuncRefFromName()) }
// func_expr and its cousin func_expr_windowless are split out from c_expr just
// so that we have classifications for "everything that is a function call or
// looks like one". This isn't very important, but it saves us having to
// document which variants are legal in places like "FROM function()" or the
// backwards-compatible functional-index syntax for CREATE INDEX. (Note that
// many of the special SQL functions wouldn't actually make any sense as
// functional index entries, but we ignore that consideration here.)
func_expr:
func_application within_group_clause filter_clause over_clause
{
f := $1.expr().(*tree.FuncExpr)
f.Filter = $3.expr()
f.WindowDef = $4.windowDef()
$$.val = f
}
| func_expr_common_subexpr
{
$$.val = $1.expr()
}
// As func_expr but does not accept WINDOW functions directly (but they can
// still be contained in arguments for functions etc). Use this when window
// expressions are not allowed, where needed to disambiguate the grammar
// (e.g. in CREATE INDEX).
func_expr_windowless:
func_application { $$.val = $1.expr() }
| func_expr_common_subexpr { $$.val = $1.expr() }
// Special expressions that are considered to be functions.
func_expr_common_subexpr:
COLLATION FOR '(' a_expr ')' { return unimplemented(sqllex, "func_expr_common_subexpr collation for") }
| CURRENT_DATE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_SCHEMA
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
// Special identifier current_catalog is equivalent to current_database().
// https://www.postgresql.org/docs/10/static/functions-info.html
| CURRENT_CATALOG
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("current_database")}
}
| CURRENT_TIMESTAMP
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_TIME
{
return unimplementedWithIssueDetail(sqllex, 26097, "current_time")
}
| CURRENT_USER
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
// Special identifier current_role is equivalent to current_user.
// https://www.postgresql.org/docs/10/static/functions-info.html
| CURRENT_ROLE
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("current_user")}
}
| SESSION_USER
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("current_user")}
}
| USER
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("current_user")}
}
| CAST '(' a_expr AS cast_target ')'
{
$$.val = &tree.CastExpr{Expr: $3.expr(), Type: $5.castTargetType(), SyntaxMode: tree.CastExplicit}
}
| ANNOTATE_TYPE '(' a_expr ',' typename ')'
{
$$.val = &tree.AnnotateTypeExpr{Expr: $3.expr(), Type: $5.colType(), SyntaxMode: tree.AnnotateExplicit}
}
| IF '(' a_expr ',' a_expr ',' a_expr ')'
{
$$.val = &tree.IfExpr{Cond: $3.expr(), True: $5.expr(), Else: $7.expr()}
}
| IFERROR '(' a_expr ',' a_expr ',' a_expr ')'
{
$$.val = &tree.IfErrExpr{Cond: $3.expr(), Else: $5.expr(), ErrCode: $7.expr()}
}
| IFERROR '(' a_expr ',' a_expr ')'
{
$$.val = &tree.IfErrExpr{Cond: $3.expr(), Else: $5.expr()}
}
| ISERROR '(' a_expr ')'
{
$$.val = &tree.IfErrExpr{Cond: $3.expr()}
}
| ISERROR '(' a_expr ',' a_expr ')'
{
$$.val = &tree.IfErrExpr{Cond: $3.expr(), ErrCode: $5.expr()}
}
| NULLIF '(' a_expr ',' a_expr ')'
{
$$.val = &tree.NullIfExpr{Expr1: $3.expr(), Expr2: $5.expr()}
}
| IFNULL '(' a_expr ',' a_expr ')'
{
$$.val = &tree.CoalesceExpr{Name: "IFNULL", Exprs: tree.Exprs{$3.expr(), $5.expr()}}
}
| COALESCE '(' expr_list ')'
{
$$.val = &tree.CoalesceExpr{Name: "COALESCE", Exprs: $3.exprs()}
}
| special_function
special_function:
CURRENT_DATE '(' ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_DATE '(' error { return helpWithFunctionByName(sqllex, $1) }
| CURRENT_SCHEMA '(' ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_SCHEMA '(' error { return helpWithFunctionByName(sqllex, $1) }
| CURRENT_TIMESTAMP '(' ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_TIMESTAMP '(' error { return helpWithFunctionByName(sqllex, $1) }
| CURRENT_TIME '(' ')'
{
return unimplementedWithIssueDetail(sqllex, 26097, "current_time")
}
| CURRENT_TIME '(' error { return helpWithFunctionByName(sqllex, $1) }
| CURRENT_USER '(' ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1)}
}
| CURRENT_USER '(' error { return helpWithFunctionByName(sqllex, $1) }
| EXTRACT '(' extract_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: $3.exprs()}
}
| EXTRACT '(' error { return helpWithFunctionByName(sqllex, $1) }
| EXTRACT_DURATION '(' extract_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: $3.exprs()}
}
| EXTRACT_DURATION '(' error { return helpWithFunctionByName(sqllex, $1) }
| OVERLAY '(' overlay_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: $3.exprs()}
}
| OVERLAY '(' error { return helpWithFunctionByName(sqllex, $1) }
| POSITION '(' position_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("strpos"), Exprs: $3.exprs()}
}
| SUBSTRING '(' substr_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: $3.exprs()}
}
| SUBSTRING '(' error { return helpWithFunctionByName(sqllex, $1) }
| TREAT '(' a_expr AS typename ')' { return unimplemented(sqllex, "treat") }
| TRIM '(' BOTH trim_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("btrim"), Exprs: $4.exprs()}
}
| TRIM '(' LEADING trim_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("ltrim"), Exprs: $4.exprs()}
}
| TRIM '(' TRAILING trim_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("rtrim"), Exprs: $4.exprs()}
}
| TRIM '(' trim_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction("btrim"), Exprs: $3.exprs()}
}
| GREATEST '(' expr_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: $3.exprs()}
}
| GREATEST '(' error { return helpWithFunctionByName(sqllex, $1) }
| LEAST '(' expr_list ')'
{
$$.val = &tree.FuncExpr{Func: tree.WrapFunction($1), Exprs: $3.exprs()}
}
| LEAST '(' error { return helpWithFunctionByName(sqllex, $1) }
// Aggregate decoration clauses
within_group_clause:
WITHIN GROUP '(' sort_clause ')' { return unimplemented(sqllex, "within group") }
| /* EMPTY */ {}
filter_clause:
FILTER '(' WHERE a_expr ')'
{
$$.val = $4.expr()
}
| /* EMPTY */
{
$$.val = tree.Expr(nil)
}
// Window Definitions
window_clause:
WINDOW window_definition_list
{
$$.val = $2.window()
}
| /* EMPTY */
{
$$.val = tree.Window(nil)
}
window_definition_list:
window_definition
{
$$.val = tree.Window{$1.windowDef()}
}
| window_definition_list ',' window_definition
{
$$.val = append($1.window(), $3.windowDef())
}
window_definition:
window_name AS window_specification
{
n := $3.windowDef()
n.Name = tree.Name($1)
$$.val = n
}
over_clause:
OVER window_specification
{
$$.val = $2.windowDef()
}
| OVER window_name
{
$$.val = &tree.WindowDef{Name: tree.Name($2)}
}
| /* EMPTY */
{
$$.val = (*tree.WindowDef)(nil)
}
window_specification:
'(' opt_existing_window_name opt_partition_clause
opt_sort_clause opt_frame_clause ')'
{
$$.val = &tree.WindowDef{
RefName: tree.Name($2),
Partitions: $3.exprs(),
OrderBy: $4.orderBy(),
Frame: $5.windowFrame(),
}
}
// If we see PARTITION, RANGE, ROWS, or GROUPS as the first token after the '('
// of a window_specification, we want the assumption to be that there is no
// existing_window_name; but those keywords are unreserved and so could be
// names. We fix this by making them have the same precedence as IDENT and
// giving the empty production here a slightly higher precedence, so that the
// shift/reduce conflict is resolved in favor of reducing the rule. These
// keywords are thus precluded from being an existing_window_name but are not
// reserved for any other purpose.
opt_existing_window_name:
name
| /* EMPTY */ %prec CONCAT
{
$$ = ""
}
opt_partition_clause:
PARTITION BY expr_list
{
$$.val = $3.exprs()
}
| /* EMPTY */
{
$$.val = tree.Exprs(nil)
}
// For frame clauses, we return a tree.WindowDef, but only some fields are used:
// frameOptions, startOffset, and endOffset.
//
// This is only a subset of the full SQL:2008 frame_clause grammar. We don't
// support <window frame exclusion> yet.
opt_frame_clause:
RANGE frame_extent
{
$$.val = &tree.WindowFrame{
Mode: tree.RANGE,
Bounds: $2.windowFrameBounds(),
}
}
| ROWS frame_extent
{
$$.val = &tree.WindowFrame{
Mode: tree.ROWS,
Bounds: $2.windowFrameBounds(),
}
}
| GROUPS frame_extent
{
$$.val = &tree.WindowFrame{
Mode: tree.GROUPS,
Bounds: $2.windowFrameBounds(),
}
}
| /* EMPTY */
{
$$.val = (*tree.WindowFrame)(nil)
}
frame_extent:
frame_bound
{
startBound := $1.windowFrameBound()
switch {
case startBound.BoundType == tree.UnboundedFollowing:
sqllex.Error("frame start cannot be UNBOUNDED FOLLOWING")
return 1
case startBound.BoundType == tree.OffsetFollowing:
sqllex.Error("frame starting from following row cannot end with current row")
return 1
}
$$.val = tree.WindowFrameBounds{StartBound: startBound}
}
| BETWEEN frame_bound AND frame_bound
{
startBound := $2.windowFrameBound()
endBound := $4.windowFrameBound()
switch {
case startBound.BoundType == tree.UnboundedFollowing:
sqllex.Error("frame start cannot be UNBOUNDED FOLLOWING")
return 1
case endBound.BoundType == tree.UnboundedPreceding:
sqllex.Error("frame end cannot be UNBOUNDED PRECEDING")
return 1
case startBound.BoundType == tree.CurrentRow && endBound.BoundType == tree.OffsetPreceding:
sqllex.Error("frame starting from current row cannot have preceding rows")
return 1
case startBound.BoundType == tree.OffsetFollowing && endBound.BoundType == tree.OffsetPreceding:
sqllex.Error("frame starting from following row cannot have preceding rows")
return 1
case startBound.BoundType == tree.OffsetFollowing && endBound.BoundType == tree.CurrentRow:
sqllex.Error("frame starting from following row cannot have preceding rows")
return 1
}
$$.val = tree.WindowFrameBounds{StartBound: startBound, EndBound: endBound}
}
// This is used for both frame start and frame end, with output set up on the
// assumption it's frame start; the frame_extent productions must reject
// invalid cases.
frame_bound:
UNBOUNDED PRECEDING
{
$$.val = &tree.WindowFrameBound{BoundType: tree.UnboundedPreceding}
}
| UNBOUNDED FOLLOWING
{
$$.val = &tree.WindowFrameBound{BoundType: tree.UnboundedFollowing}
}
| CURRENT ROW
{
$$.val = &tree.WindowFrameBound{BoundType: tree.CurrentRow}
}
| a_expr PRECEDING
{
$$.val = &tree.WindowFrameBound{
OffsetExpr: $1.expr(),
BoundType: tree.OffsetPreceding,
}
}
| a_expr FOLLOWING
{
$$.val = &tree.WindowFrameBound{
OffsetExpr: $1.expr(),
BoundType: tree.OffsetFollowing,
}
}
// Supporting nonterminals for expressions.
// Explicit row production.
//
// SQL99 allows an optional ROW keyword, so we can now do single-element rows
// without conflicting with the parenthesized a_expr production. Without the
// ROW keyword, there must be more than one a_expr inside the parens.
row:
ROW '(' opt_expr_list ')'
{
$$.val = &tree.Tuple{Exprs: $3.exprs(), Row: true}
}
| expr_tuple_unambiguous
{
$$.val = $1.tuple()
}
labeled_row:
row
| '(' row AS name_list ')'
{
t := $2.tuple()
labels := $4.nameList()
t.Labels = make([]string, len(labels))
for i, l := range labels {
t.Labels[i] = string(l)
}
$$.val = t
}
sub_type:
ANY
{
$$.val = tree.Any
}
| SOME
{
$$.val = tree.Some
}
| ALL
{
$$.val = tree.All
}
math_op:
'+' { $$.val = tree.Plus }
| '-' { $$.val = tree.Minus }
| '*' { $$.val = tree.Mult }
| '/' { $$.val = tree.Div }
| FLOORDIV { $$.val = tree.FloorDiv }
| '%' { $$.val = tree.Mod }
| '&' { $$.val = tree.Bitand }
| '|' { $$.val = tree.Bitor }
| '^' { $$.val = tree.Pow }
| '#' { $$.val = tree.Bitxor }
| '<' { $$.val = tree.LT }
| '>' { $$.val = tree.GT }
| '=' { $$.val = tree.EQ }
| LESS_EQUALS { $$.val = tree.LE }
| GREATER_EQUALS { $$.val = tree.GE }
| NOT_EQUALS { $$.val = tree.NE }
subquery_op:
math_op
| LIKE { $$.val = tree.Like }
| NOT_LA LIKE { $$.val = tree.NotLike }
| ILIKE { $$.val = tree.ILike }
| NOT_LA ILIKE { $$.val = tree.NotILike }
// cannot put SIMILAR TO here, because SIMILAR TO is a hack.
// the regular expression is preprocessed by a function (similar_escape),
// and the ~ operator for posix regular expressions is used.
// x SIMILAR TO y -> x ~ similar_escape(y)
// this transformation is made on the fly by the parser upwards.
// however the SubLink structure which handles any/some/all stuff
// is not ready for such a thing.
// expr_tuple1_ambiguous is a tuple expression with at least one expression.
// The allowable syntax is:
// ( ) -- empty tuple.
// ( E ) -- just one value, this is potentially ambiguous with
// -- grouping parentheses. The ambiguity is resolved
// -- by only allowing expr_tuple1_ambiguous on the RHS
// -- of a IN expression.
// ( E, E, E ) -- comma-separated values, no trailing comma allowed.
// ( E, ) -- just one value with a comma, makes the syntax unambiguous
// -- with grouping parentheses. This is not usually produced
// -- by SQL clients, but can be produced by pretty-printing
// -- internally in CockroachDB.
expr_tuple1_ambiguous:
'(' ')'
{
$$.val = &tree.Tuple{}
}
| '(' tuple1_ambiguous_values ')'
{
$$.val = &tree.Tuple{Exprs: $2.exprs()}
}
tuple1_ambiguous_values:
a_expr
{
$$.val = tree.Exprs{$1.expr()}
}
| a_expr ','
{
$$.val = tree.Exprs{$1.expr()}
}
| a_expr ',' expr_list
{
$$.val = append(tree.Exprs{$1.expr()}, $3.exprs()...)
}
// expr_tuple_unambiguous is a tuple expression with zero or more
// expressions. The allowable syntax is:
// ( ) -- zero values
// ( E, ) -- just one value. This is unambiguous with the (E) grouping syntax.
// ( E, E, E ) -- comma-separated values, more than 1.
expr_tuple_unambiguous:
'(' ')'
{
$$.val = &tree.Tuple{}
}
| '(' tuple1_unambiguous_values ')'
{
$$.val = &tree.Tuple{Exprs: $2.exprs()}
}
tuple1_unambiguous_values:
a_expr ','
{
$$.val = tree.Exprs{$1.expr()}
}
| a_expr ',' expr_list
{
$$.val = append(tree.Exprs{$1.expr()}, $3.exprs()...)
}
opt_expr_list:
expr_list
| /* EMPTY */
{
$$.val = tree.Exprs(nil)
}
expr_list:
a_expr
{
$$.val = tree.Exprs{$1.expr()}
}
| expr_list ',' a_expr
{
$$.val = append($1.exprs(), $3.expr())
}
type_list:
typename
{
$$.val = []coltypes.T{$1.colType()}
}
| type_list ',' typename
{
$$.val = append($1.colTypes(), $3.colType())
}
array_expr:
'[' opt_expr_list ']'
{
$$.val = &tree.Array{Exprs: $2.exprs()}
}
| '[' array_expr_list ']'
{
$$.val = &tree.Array{Exprs: $2.exprs()}
}
array_expr_list:
array_expr
{
$$.val = tree.Exprs{$1.expr()}
}
| array_expr_list ',' array_expr
{
$$.val = append($1.exprs(), $3.expr())
}
extract_list:
extract_arg FROM a_expr
{
$$.val = tree.Exprs{tree.NewStrVal($1), $3.expr()}
}
| expr_list
{
$$.val = $1.exprs()
}
// TODO(vivek): Narrow down to just IDENT once the other
// terms are not keywords.
extract_arg:
IDENT
| YEAR
| MONTH
| DAY
| HOUR
| MINUTE
| SECOND
// OVERLAY() arguments
// SQL99 defines the OVERLAY() function:
// - overlay(text placing text from int for int)
// - overlay(text placing text from int)
// and similarly for binary strings
overlay_list:
a_expr overlay_placing substr_from substr_for
{
$$.val = tree.Exprs{$1.expr(), $2.expr(), $3.expr(), $4.expr()}
}
| a_expr overlay_placing substr_from
{
$$.val = tree.Exprs{$1.expr(), $2.expr(), $3.expr()}
}
| expr_list
{
$$.val = $1.exprs()
}
overlay_placing:
PLACING a_expr
{
$$.val = $2.expr()
}
// position_list uses b_expr not a_expr to avoid conflict with general IN
position_list:
b_expr IN b_expr
{
$$.val = tree.Exprs{$3.expr(), $1.expr()}
}
| /* EMPTY */
{
$$.val = tree.Exprs(nil)
}
// SUBSTRING() arguments
// SQL9x defines a specific syntax for arguments to SUBSTRING():
// - substring(text from int for int)
// - substring(text from int) get entire string from starting point "int"
// - substring(text for int) get first "int" characters of string
// - substring(text from pattern) get entire string matching pattern
// - substring(text from pattern for escape) same with specified escape char
// We also want to support generic substring functions which accept
// the usual generic list of arguments. So we will accept both styles
// here, and convert the SQL9x style to the generic list for further
// processing. - thomas 2000-11-28
substr_list:
a_expr substr_from substr_for
{
$$.val = tree.Exprs{$1.expr(), $2.expr(), $3.expr()}
}
| a_expr substr_for substr_from
{
$$.val = tree.Exprs{$1.expr(), $3.expr(), $2.expr()}
}
| a_expr substr_from
{
$$.val = tree.Exprs{$1.expr(), $2.expr()}
}
| a_expr substr_for
{
$$.val = tree.Exprs{$1.expr(), tree.NewDInt(1), $2.expr()}
}
| opt_expr_list
{
$$.val = $1.exprs()
}
substr_from:
FROM a_expr
{
$$.val = $2.expr()
}
substr_for:
FOR a_expr
{
$$.val = $2.expr()
}
trim_list:
a_expr FROM expr_list
{
$$.val = append($3.exprs(), $1.expr())
}
| FROM expr_list
{
$$.val = $2.exprs()
}
| expr_list
{
$$.val = $1.exprs()
}
in_expr:
select_with_parens
{
$$.val = &tree.Subquery{Select: $1.selectStmt()}
}
| expr_tuple1_ambiguous
// Define SQL-style CASE clause.
// - Full specification
// CASE WHEN a = b THEN c ... ELSE d END
// - Implicit argument
// CASE a WHEN b THEN c ... ELSE d END
case_expr:
CASE case_arg when_clause_list case_default END
{
$$.val = &tree.CaseExpr{Expr: $2.expr(), Whens: $3.whens(), Else: $4.expr()}
}
when_clause_list:
// There must be at least one
when_clause
{
$$.val = []*tree.When{$1.when()}
}
| when_clause_list when_clause
{
$$.val = append($1.whens(), $2.when())
}
when_clause:
WHEN a_expr THEN a_expr
{
$$.val = &tree.When{Cond: $2.expr(), Val: $4.expr()}
}
case_default:
ELSE a_expr
{
$$.val = $2.expr()
}
| /* EMPTY */
{
$$.val = tree.Expr(nil)
}
case_arg:
a_expr
| /* EMPTY */
{
$$.val = tree.Expr(nil)
}
array_subscript:
'[' a_expr ']'
{
$$.val = &tree.ArraySubscript{Begin: $2.expr()}
}
| '[' opt_slice_bound ':' opt_slice_bound ']'
{
$$.val = &tree.ArraySubscript{Begin: $2.expr(), End: $4.expr(), Slice: true}
}
opt_slice_bound:
a_expr
| /*EMPTY*/
{
$$.val = tree.Expr(nil)
}
array_subscripts:
array_subscript
{
$$.val = tree.ArraySubscripts{$1.arraySubscript()}
}
| array_subscripts array_subscript
{
$$.val = append($1.arraySubscripts(), $2.arraySubscript())
}
opt_asymmetric:
ASYMMETRIC {}
| /* EMPTY */ {}
target_list:
target_elem
{
$$.val = tree.SelectExprs{$1.selExpr()}
}
| target_list ',' target_elem
{
$$.val = append($1.selExprs(), $3.selExpr())
}
target_elem:
a_expr AS target_name
{
$$.val = tree.SelectExpr{Expr: $1.expr(), As: tree.UnrestrictedName($3)}
}
// We support omitting AS only for column labels that aren't any known
// keyword. There is an ambiguity against postfix operators: is "a ! b" an
// infix expression, or a postfix expression and a column label? We prefer
// to resolve this as an infix expression, which we accomplish by assigning
// IDENT a precedence higher than POSTFIXOP.
| a_expr IDENT
{
$$.val = tree.SelectExpr{Expr: $1.expr(), As: tree.UnrestrictedName($2)}
}
| a_expr
{
$$.val = tree.SelectExpr{Expr: $1.expr()}
}
| '*'
{
$$.val = tree.StarSelectExpr()
}
// Names and constants.
table_name_with_index_list:
table_name_with_index
{
$$.val = tree.TableNameWithIndexList{$1.newTableWithIdx()}
}
| table_name_with_index_list ',' table_name_with_index
{
$$.val = append($1.newTableWithIdxList(), $3.newTableWithIdx())
}
table_pattern_list:
table_pattern
{
$$.val = tree.TablePatterns{$1.unresolvedName()}
}
| table_pattern_list ',' table_pattern
{
$$.val = append($1.tablePatterns(), $3.unresolvedName())
}
table_name_with_index:
table_name '@' index_name
{
$$.val = tree.TableNameWithIndex{
Table: $1.normalizableTableNameFromUnresolvedName(),
Index: tree.UnrestrictedName($3),
}
}
| table_name
{
// This case allows specifying just an index name (potentially schema-qualified).
// We temporarily store the index name in Table (see tree.TableNameWithIndex).
$$.val = tree.TableNameWithIndex{
Table: $1.normalizableTableNameFromUnresolvedName(),
SearchTable: true,
}
}
// table_pattern selects zero or more tables using a wildcard.
// Accepted patterns:
// - Patterns accepted by db_object_name
// <table>
// <schema>.<table>
// <catalog/db>.<schema>.<table>
// - Wildcards:
// <db/catalog>.<schema>.*
// <schema>.*
// *
table_pattern:
simple_db_object_name
| complex_table_pattern
// complex_table_pattern is the part of table_pattern which recognizes
// every pattern not composed of a single identifier.
complex_table_pattern:
complex_db_object_name
| name '.' unrestricted_name '.' '*'
{
$$.val = &tree.UnresolvedName{Star: true, NumParts: 3, Parts: tree.NameParts{"", $3, $1}}
}
| name '.' '*'
{
$$.val = &tree.UnresolvedName{Star: true, NumParts: 2, Parts: tree.NameParts{"", $1}}
}
| '*'
{
$$.val = &tree.UnresolvedName{Star: true, NumParts: 1}
}
name_list:
name
{
$$.val = tree.NameList{tree.Name($1)}
}
| name_list ',' name
{
$$.val = append($1.nameList(), tree.Name($3))
}
// Constants
signed_iconst:
ICONST
| '+' ICONST
{
$$.val = $2.numVal()
}
| '-' ICONST
{
n := $2.numVal()
n.Negative = true
$$.val = n
}
// signed_iconst64 is a variant of signed_iconst which only accepts (signed) integer literals that fit in an int64.
// If you use signed_iconst, you have to call AsInt64(), which returns an error if the value is too big.
// This rule just doesn't match in that case.
signed_iconst64:
signed_iconst
{
val, err := $1.numVal().AsInt64()
if err != nil {
sqllex.Error(err.Error()); return 1
}
$$.val = val
}
// iconst64 accepts only unsigned integer literals that fit in an int64.
iconst64:
ICONST
{
val, err := $1.numVal().AsInt64()
if err != nil {
sqllex.Error(err.Error()); return 1
}
$$.val = val
}
interval:
const_interval SCONST opt_interval
{
// We don't carry opt_interval information into the column type, so we need
// to parse the interval directly.
var err error
var d tree.Datum
if $3.val == nil {
d, err = tree.ParseDInterval($2)
} else {
d, err = tree.ParseDIntervalWithField($2, $3.durationField())
}
if err != nil {
sqllex.Error(err.Error())
return 1
}
$$.val = d
}
// Name classification hierarchy.
//
// IDENT is the lexeme returned by the lexer for identifiers that match no
// known keyword. In most cases, we can accept certain keywords as names, not
// only IDENTs. We prefer to accept as many such keywords as possible to
// minimize the impact of "reserved words" on programmers. So, we divide names
// into several possible classes. The classification is chosen in part to make
// keywords acceptable as names wherever possible.
// Names specific to syntactic positions.
//
// The non-terminals "name", "unrestricted_name", "non_reserved_word",
// "unreserved_keyword", "non_reserved_word_or_sconst" etc. defined
// below are low-level, structural constructs.
//
// They are separate only because having them all as one rule would
// make the rest of the grammar ambiguous. However, because they are
// separate the question is then raised throughout the rest of the
// grammar: which of the name non-terminals should one use when
// defining a grammar rule? Is an index a "name" or
// "unrestricted_name"? A partition? What about an index option?
//
// To make the decision easier, this section of the grammar creates
// meaningful, purpose-specific aliases to the non-terminals. These
// both make it easier to decide "which one should I use in this
// context" and also improves the readability of
// automatically-generated syntax diagrams.
// Note: newlines between non-terminals matter to the doc generator.
collation_name: unrestricted_name
partition_name: unrestricted_name
index_name: unrestricted_name
opt_index_name: opt_name
zone_name: unrestricted_name
target_name: unrestricted_name
constraint_name: name
database_name: name
column_name: name
family_name: name
opt_family_name: opt_name
table_alias_name: name
statistics_name: name
window_name: name
view_name: table_name
type_name: db_object_name
sequence_name: db_object_name
table_name: db_object_name
explain_option_name: non_reserved_word
// Names for column references.
// Accepted patterns:
// <colname>
// <table>.<colname>
// <schema>.<table>.<colname>
// <catalog/db>.<schema>.<table>.<colname>
//
// Note: the rule for accessing compound types, if those are ever
// supported, is not to be handled here. The syntax `a.b.c.d....y.z`
// in `select a.b.c.d from t` *always* designates a column `z` in a
// table `y`, regardless of the meaning of what's before.
column_path:
name
{
$$.val = &tree.UnresolvedName{NumParts:1, Parts: tree.NameParts{$1}}
}
| prefixed_column_path
prefixed_column_path:
name '.' unrestricted_name
{
$$.val = &tree.UnresolvedName{NumParts:2, Parts: tree.NameParts{$3,$1}}
}
| name '.' unrestricted_name '.' unrestricted_name
{
$$.val = &tree.UnresolvedName{NumParts:3, Parts: tree.NameParts{$5,$3,$1}}
}
| name '.' unrestricted_name '.' unrestricted_name '.' unrestricted_name
{
$$.val = &tree.UnresolvedName{NumParts:4, Parts: tree.NameParts{$7,$5,$3,$1}}
}
// Names for column references and wildcards.
// Accepted patterns:
// - those from column_path
// - <table>.*
// - <schema>.<table>.*
// - <catalog/db>.<schema>.<table>.*
// The single unqualified star is handled separately by target_elem.
column_path_with_star:
column_path
| name '.' unrestricted_name '.' unrestricted_name '.' '*'
{
$$.val = &tree.UnresolvedName{Star:true, NumParts:4, Parts: tree.NameParts{"",$5,$3,$1}}
}
| name '.' unrestricted_name '.' '*'
{
$$.val = &tree.UnresolvedName{Star:true, NumParts:3, Parts: tree.NameParts{"",$3,$1}}
}
| name '.' '*'
{
$$.val = &tree.UnresolvedName{Star:true, NumParts:2, Parts: tree.NameParts{"",$1}}
}
// Names for functions.
// The production for a qualified func_name has to exactly match the production
// for a column_path, because we cannot tell which we are parsing until
// we see what comes after it ('(' or SCONST for a func_name, anything else for
// a name).
// However we cannot use column_path directly, because for a single function name
// we allow more possible tokens than a simple column name.
func_name:
type_function_name
{
$$.val = &tree.UnresolvedName{NumParts:1, Parts: tree.NameParts{$1}}
}
| prefixed_column_path
// Names for database objects (tables, sequences, views, stored functions).
// Accepted patterns:
// <table>
// <schema>.<table>
// <catalog/db>.<schema>.<table>
db_object_name:
simple_db_object_name
| complex_db_object_name
// simple_db_object_name is the part of db_object_name that recognizes
// simple identifiers.
simple_db_object_name:
name
{
$$.val = &tree.UnresolvedName{NumParts:1, Parts: tree.NameParts{$1}}
}
// complex_db_object_name is the part of db_object_name that recognizes
// composite names (not simple identifiers).
// It is split away from db_object_name in order to enable the definition
// of table_pattern.
complex_db_object_name:
name '.' unrestricted_name
{
$$.val = &tree.UnresolvedName{NumParts:2, Parts: tree.NameParts{$3,$1}}
}
| name '.' unrestricted_name '.' unrestricted_name
{
$$.val = &tree.UnresolvedName{NumParts:3, Parts: tree.NameParts{$5,$3,$1}}
}
// General name --- names that can be column, table, etc names.
name:
IDENT
| unreserved_keyword
| col_name_keyword
opt_name:
name
| /* EMPTY */
{
$$ = ""
}
opt_name_parens:
'(' name ')'
{
$$ = $2
}
| /* EMPTY */
{
$$ = ""
}
// Structural, low-level names
// Non-reserved word and also string literal constants.
non_reserved_word_or_sconst:
non_reserved_word
| SCONST
// Type/function identifier --- names that can be type or function names.
type_function_name:
IDENT
| unreserved_keyword
| type_func_name_keyword
// Any not-fully-reserved word --- these names can be, eg, variable names.
non_reserved_word:
IDENT
| unreserved_keyword
| col_name_keyword
| type_func_name_keyword
// Unrestricted name --- allowable names when there is no ambiguity with even
// reserved keywords, like in "AS" clauses. This presently includes *all*
// Postgres keywords.
unrestricted_name:
IDENT
| unreserved_keyword
| col_name_keyword
| type_func_name_keyword
| reserved_keyword
// Keyword category lists. Generally, every keyword present in the Postgres
// grammar should appear in exactly one of these lists.
//
// Put a new keyword into the first list that it can go into without causing
// shift or reduce conflicts. The earlier lists define "less reserved"
// categories of keywords.
//
// "Unreserved" keywords --- available for use as any kind of name.
unreserved_keyword:
ABORT
| ACTION
| ADD
| ADMIN
| AGGREGATE
| ALTER
| AT
| BACKUP
| BEGIN
| BIGSERIAL
| BLOB
| BOOL
| BY
| BYTEA
| BYTES
| CACHE
| CANCEL
| CASCADE
| CHANGEFEED
| CLUSTER
| COLUMNS
| COMMENT
| COMMIT
| COMMITTED
| COMPACT
| CONFLICT
| CONFIGURATION
| CONFIGURATIONS
| CONFIGURE
| CONSTRAINTS
| CONVERSION
| COPY
| COVERING
| CUBE
| CURRENT
| CYCLE
| DATA
| DATABASE
| DATABASES
| DATE
| DAY
| DEALLOCATE
| DELETE
| DISCARD
| DOMAIN
| DOUBLE
| DROP
| ENCODING
| ENUM
| ESCAPE
| EXECUTE
| EXPERIMENTAL
| EXPERIMENTAL_AUDIT
| EXPERIMENTAL_FINGERPRINTS
| EXPERIMENTAL_RANGES
| EXPERIMENTAL_RELOCATE
| EXPERIMENTAL_REPLICA
| EXPLAIN
| EXPORT
| EXTENSION
| FILES
| FILTER
| FIRST
| FLOAT4
| FLOAT8
| FOLLOWING
| FORCE_INDEX
| FUNCTION
| GLOBAL
| GRANTS
| GROUPS
| HIGH
| HISTOGRAM
| HOUR
| IMPORT
| INCREMENT
| INCREMENTAL
| INDEXES
| INET
| INJECT
| INSERT
| INT2
| INT2VECTOR
| INT4
| INT8
| INT64
| INTERLEAVE
| INVERTED
| ISOLATION
| JOB
| JOBS
| JSON
| JSONB
| KEY
| KEYS
| KV
| LANGUAGE
| LC_COLLATE
| LC_CTYPE
| LEASE
| LESS
| LEVEL
| LIST
| LOCAL
| LOW
| MATCH
| MATERIALIZED
| MINUTE
| MONTH
| NAMES
| NAN
| NAME
| NEXT
| NO
| NORMAL
| NO_INDEX_JOIN
| OF
| OFF
| OID
| OIDVECTOR
| OPERATOR
| OPTION
| OPTIONS
| ORDINALITY
| OVER
| OWNED
| PARENT
| PARTIAL
| PARTITION
| PASSWORD
| PAUSE
| PHYSICAL
| PLANS
| PRECEDING
| PREPARE
| PRIORITY
| PUBLICATION
| QUERIES
| QUERY
| RANGE
| RANGES
| READ
| RECURSIVE
| REF
| REGCLASS
| REGPROC
| REGPROCEDURE
| REGNAMESPACE
| REGTYPE
| RELEASE
| RENAME
| REPEATABLE
| REPLACE
| RESET
| RESTORE
| RESTRICT
| RESUME
| REVOKE
| ROLE
| ROLES
| ROLLBACK
| ROLLUP
| ROWS
| RULE
| SETTING
| SETTINGS
| STATUS
| SAVEPOINT
| SCATTER
| SCHEMA
| SCHEMAS
| SCRUB
| SEARCH
| SECOND
| SERIAL
| SERIALIZABLE
| SERIAL2
| SERIAL4
| SERIAL8
| SERVER
| SEQUENCE
| SEQUENCES
| SESSION
| SESSIONS
| SET
| SHOW
| SIMPLE
| SMALLSERIAL
| SNAPSHOT
| SQL
| START
| STATISTICS
| STDIN
| STORE
| STORED
| STORING
| STRICT
| STRING
| SPLIT
| SUBSCRIPTION
| SYNTAX
| SYSTEM
| TABLES
| TEMP
| TEMPLATE
| TEMPORARY
| TESTING_RANGES
| TESTING_RELOCATE
| TEXT
| TIMESTAMPTZ
| TRACE
| TRANSACTION
| TRIGGER
| TRUNCATE
| TRUSTED
| TYPE
| UNBOUNDED
| UNCOMMITTED
| UNKNOWN
| UNLOGGED
| UPDATE
| UPSERT
| UUID
| USE
| USERS
| VALID
| VALIDATE
| VALUE
| VARYING
| VIEW
| WITHIN
| WITHOUT
| WRITE
| YEAR
| ZONE
// Column identifier --- keywords that can be column, table, etc names.
//
// Many of these keywords will in fact be recognized as type or function names
// too; but they have special productions for the purpose, and so can't be
// treated as "generic" type or function names.
//
// The type names appearing here are not usable as function names because they
// can be followed by '(' in typename productions, which looks too much like a
// function call for an LR(1) parser.
col_name_keyword:
ANNOTATE_TYPE
| BETWEEN
| BIGINT
| BIT
| BOOLEAN
| CHAR
| CHARACTER
| CHARACTERISTICS
| COALESCE
| DEC
| DECIMAL
| EXISTS
| EXTRACT
| EXTRACT_DURATION
| FLOAT
| GREATEST
| GROUPING
| IF
| IFERROR
| IFNULL
| INT
| INTEGER
| INTERVAL
| ISERROR
| LEAST
| NULLIF
| NUMERIC
| OUT
| OVERLAY
| POSITION
| PRECISION
| REAL
| ROW
| SMALLINT
| SUBSTRING
| TIME
| TIMETZ
| TIMESTAMP
| TREAT
| TRIM
| VALUES
| VARBIT
| VARCHAR
| VIRTUAL
| WORK
// Type/function identifier --- keywords that can be type or function names.
//
// Most of these are keywords that are used as operators in expressions; in
// general such keywords can't be column names because they would be ambiguous
// with variables, but they are unambiguous as function identifiers.
//
// Do not include POSITION, SUBSTRING, etc here since they have explicit
// productions in a_expr to support the goofy SQL9x argument syntax.
// - thomas 2000-11-28
//
// TODO(dan): see if we can move MAXVALUE and MINVALUE to a less restricted list
type_func_name_keyword:
COLLATION
| CROSS
| FAMILY
| FULL
| INNER
| ILIKE
| IS
| ISNULL
| JOIN
| LEFT
| LIKE
| MAXVALUE
| MINVALUE
| NATURAL
| NOTNULL
| OUTER
| OVERLAPS
| RIGHT
| SIMILAR
// Reserved keyword --- these keywords are usable only as a unrestricted_name.
//
// Keywords appear here if they could not be distinguished from variable, type,
// or function names in some contexts. Don't put things here unless forced to.
reserved_keyword:
ALL
| ANALYSE
| ANALYZE
| AND
| ANY
| ARRAY
| AS
| ASC
| ASYMMETRIC
| BOTH
| CASE
| CAST
| CHECK
| COLLATE
| COLUMN
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_SCHEMA
| CURRENT_TIME
| CURRENT_TIMESTAMP
| CURRENT_USER
| DEFAULT
| DEFERRABLE
| DESC
| DISTINCT
| DO
| ELSE
| END
| EXCEPT
| FALSE
| FETCH
| FOR
| FOREIGN
| FROM
| GRANT
| GROUP
| HAVING
| IN
| INDEX
| INITIALLY
| INTERSECT
| INTO
| LATERAL
| LEADING
| LIMIT
| LOCALTIME
| LOCALTIMESTAMP
| NOT
| NOTHING
| NULL
| OFFSET
| ON
| ONLY
| OR
| ORDER
| PLACING
| PRIMARY
| REFERENCES
| RETURNING
| SELECT
| SESSION_USER
| SOME
| SYMMETRIC
| TABLE
| THEN
| TO
| TRAILING
| TRUE
| UNION
| UNIQUE
| USER
| USING
| VARIADIC
| WHEN
| WHERE
| WINDOW
| WITH
%%