mirror of
https://github.com/prometheus/alertmanager
synced 2025-02-27 16:20:24 +00:00
1338 lines
23 KiB
Plaintext
1338 lines
23 KiB
Plaintext
%{
|
|
// Copyright (c) 2014 The ql Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Inital yacc source generated by ebnf2y[1]
|
|
// at 2013-10-04 23:10:47.861401015 +0200 CEST
|
|
//
|
|
// $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _
|
|
//
|
|
// [1]: http://github.com/cznic/ebnf2y
|
|
|
|
package ql
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/cznic/mathutil"
|
|
)
|
|
|
|
%}
|
|
|
|
%union {
|
|
line int
|
|
col int
|
|
item interface{}
|
|
list []interface{}
|
|
}
|
|
|
|
%token <item>
|
|
|
|
/*yy:token "1.%d" */ floatLit "floating-point literal"
|
|
/*yy:token "%c" */ identifier "identifier"
|
|
/*yy:token "%di" */ imaginaryLit "imaginary literal"
|
|
/*yy:token "%d" */ intLit "integer literal"
|
|
/*yy:token "$%d" */ qlParam "QL parameter"
|
|
/*yy:token "\"%c\"" */ stringLit "string literal"
|
|
|
|
add "ADD"
|
|
alter "ALTER"
|
|
and "AND"
|
|
andand "&&"
|
|
andnot "&^"
|
|
as "AS"
|
|
asc "ASC"
|
|
begin "BEGIN"
|
|
between "BETWEEN"
|
|
bigIntType "bigint"
|
|
bigRatType "bigrat"
|
|
blobType "blob"
|
|
boolType "bool"
|
|
by "BY"
|
|
byteType "byte"
|
|
column "COLUMN"
|
|
commit "COMMIT"
|
|
complex128Type "complex128"
|
|
complex64Type "complex64"
|
|
create "CREATE"
|
|
defaultKwd "DEFAULT"
|
|
deleteKwd "DELETE"
|
|
desc "DESC"
|
|
distinct "DISTINCT"
|
|
drop "DROP"
|
|
durationType "duration"
|
|
eq "=="
|
|
exists "EXISTS"
|
|
explain "EXPLAIN"
|
|
falseKwd "false"
|
|
floatType "float"
|
|
float32Type "float32"
|
|
float64Type "float64"
|
|
from "FROM"
|
|
full "FULL"
|
|
ge ">="
|
|
group "GROUP"
|
|
ifKwd "IF"
|
|
in "IN"
|
|
index "INDEX"
|
|
insert "INSERT"
|
|
intType "int"
|
|
int16Type "int16"
|
|
int32Type "int32"
|
|
int64Type "int64"
|
|
int8Type "int8"
|
|
into "INTO"
|
|
is "IS"
|
|
join "JOIN"
|
|
le "<="
|
|
left "LEFT"
|
|
like "LIKE"
|
|
limit "LIMIT"
|
|
lsh "<<"
|
|
neq "!="
|
|
not "NOT"
|
|
null "NULL"
|
|
offset "OFFSET"
|
|
on "ON"
|
|
or "OR"
|
|
order "ORDER"
|
|
oror "||"
|
|
outer "OUTER"
|
|
right "RIGHT"
|
|
rollback "ROLLBACK"
|
|
rsh ">>"
|
|
runeType "rune"
|
|
selectKwd "SELECT"
|
|
set "SET"
|
|
stringType "string"
|
|
tableKwd "TABLE"
|
|
timeType "time"
|
|
transaction "TRANSACTION"
|
|
trueKwd "true"
|
|
truncate "TRUNCATE"
|
|
uintType "uint"
|
|
uint16Type "uint16"
|
|
uint32Type "uint32"
|
|
uint64Type "uint64"
|
|
uint8Type "uint8",
|
|
unique "UNIQUE"
|
|
update "UPDATE"
|
|
values "VALUES"
|
|
where "WHERE"
|
|
|
|
parseExpression "parse expression prefix"
|
|
|
|
%type <item>
|
|
AlterTableStmt "ALTER TABLE statement"
|
|
Assignment "assignment"
|
|
AssignmentList "assignment list"
|
|
AssignmentList1 "assignment list optional trailing comma"
|
|
BeginTransactionStmt "BEGIN TRANSACTION statement"
|
|
Call "function call"
|
|
Call1 "function call optional argument list"
|
|
ColumnDef "table column definition"
|
|
ColumnName "column name"
|
|
ColumnNameList "column name list"
|
|
ColumnNameList1 "column name list with optional trailing comma"
|
|
CommaOpt "optional comma"
|
|
CommitStmt "COMMIT statement"
|
|
Constraint "column value constraint"
|
|
ConstraintOpt "optional column value constraint"
|
|
Conversion "conversion"
|
|
CreateIndexStmt "CREATE INDEX statement"
|
|
CreateIndexIfNotExists "CREATE INDEX statement optional IF NOT EXISTS cluse"
|
|
CreateIndexStmtUnique "CREATE INDEX optional UNIQUE clause"
|
|
CreateTableStmt "CREATE TABLE statement"
|
|
CreateTableStmt1 "CREATE TABLE statement colum definition list"
|
|
Default "DEFAULT clause"
|
|
DefaultOpt "optional DEFAULT clause"
|
|
DeleteFromStmt "DELETE FROM statement"
|
|
DropIndexStmt "DROP INDEX statement"
|
|
DropIndexIfExists "DROP INDEX statement optional IF EXISTS clause"
|
|
DropTableStmt "DROP TABLE statement"
|
|
EmptyStmt "empty statement"
|
|
ExplainStmt "EXPLAIN statement"
|
|
Expression "expression"
|
|
ExpressionList "expression list"
|
|
ExpressionList1 "expression list expression"
|
|
Factor "expression factor"
|
|
Factor1 "binary expression factor"
|
|
Field "field expression"
|
|
Field1 "field expression optional AS clause"
|
|
FieldList "field expression list"
|
|
GroupByClause "GROUP BY clause"
|
|
Index "string index"
|
|
InsertIntoStmt "INSERT INTO statement"
|
|
InsertIntoStmt1 "INSERT INTO statement optional column list clause"
|
|
InsertIntoStmt2 "INSERT INTO statement optional values list"
|
|
JoinClause "SELECT statement JOIN clause"
|
|
JoinClauseOpt "SELECT statement optional JOIN clause"
|
|
JoinType "join type"
|
|
Literal "literal value"
|
|
logAnd "logical and operator"
|
|
logOr "logical or operator"
|
|
Operand "operand"
|
|
OrderBy "ORDER BY clause"
|
|
OrderBy1 "ORDER BY clause optional collation specification"
|
|
OuterOpt "optional OUTER clause"
|
|
QualifiedIdent "qualified identifier"
|
|
PrimaryExpression "primary expression"
|
|
PrimaryFactor "primary expression factor"
|
|
PrimaryTerm "primary expression term"
|
|
RecordSet "record set"
|
|
RecordSet1 "record set name or parenthesized SELECTECT statement"
|
|
RecordSet2 "record set optional AS clause"
|
|
RollbackStmt "ROLLBACK statement"
|
|
SelectStmt "SELECT statement"
|
|
SelectStmtDistinct "SELECT statement optional DISTINCT clause"
|
|
SelectStmtFieldList "SELECT statement field list"
|
|
SelectStmtLimit "SELECT statement optional LIMIT clause"
|
|
SelectStmtWhere "SELECT statement optional WHERE clause"
|
|
SelectStmtGroup "SELECT statement optional GROUP BY clause"
|
|
SelectStmtOffset "SELECT statement optional OFFSET clause"
|
|
SelectStmtOrder "SELECT statement optional ORDER BY clause"
|
|
Slice "string slice"
|
|
Statement "statement"
|
|
StatementList "statement list"
|
|
TableName "table name"
|
|
Term "expression term"
|
|
TruncateTableStmt "TRANSACTION TABLE statement"
|
|
Type "type"
|
|
UnaryExpr "unary expression"
|
|
UpdateStmt "UPDATE statement"
|
|
UpdateStmt1 "UPDATE statement optional WHERE clause"
|
|
WhereClause "WHERE clause"
|
|
|
|
%type <list> RecordSetList
|
|
|
|
%start Start
|
|
|
|
%%
|
|
|
|
Start:
|
|
StatementList
|
|
| parseExpression Expression
|
|
{
|
|
yylex.(*lexer).expr = expr($2)
|
|
}
|
|
|
|
AlterTableStmt:
|
|
"ALTER" "TABLE" TableName "ADD" ColumnDef
|
|
{
|
|
$$ = &alterTableAddStmt{tableName: $3.(string), c: $5.(*col)}
|
|
}
|
|
| "ALTER" "TABLE" TableName "DROP" "COLUMN" ColumnName
|
|
{
|
|
$$ = &alterTableDropColumnStmt{tableName: $3.(string), colName: $6.(string)}
|
|
}
|
|
|
|
Assignment:
|
|
ColumnName '=' Expression
|
|
{
|
|
$$ = assignment{colName: $1.(string), expr: expr($3)}
|
|
}
|
|
|
|
AssignmentList:
|
|
Assignment AssignmentList1 CommaOpt
|
|
{
|
|
$$ = append([]assignment{$1.(assignment)}, $2.([]assignment)...)
|
|
}
|
|
|
|
AssignmentList1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []assignment{}
|
|
}
|
|
| AssignmentList1 ',' Assignment
|
|
{
|
|
$$ = append($1.([]assignment), $3.(assignment))
|
|
}
|
|
|
|
BeginTransactionStmt:
|
|
"BEGIN" "TRANSACTION"
|
|
{
|
|
$$ = beginTransactionStmt{}
|
|
}
|
|
|
|
Call:
|
|
'(' Call1 ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
| '(' '*' ')'
|
|
{
|
|
$<item>$ = '*'
|
|
}
|
|
|
|
Call1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []expression{}
|
|
}
|
|
| ExpressionList
|
|
|
|
ColumnDef:
|
|
ColumnName Type ConstraintOpt DefaultOpt
|
|
{
|
|
x := &col{name: $1.(string), typ: $2.(int), constraint: $3.(*constraint)}
|
|
if $4 != nil {
|
|
x.dflt = expr($4)
|
|
}
|
|
$$ = x
|
|
}
|
|
|
|
ColumnName:
|
|
identifier
|
|
|
|
ColumnNameList:
|
|
ColumnName ColumnNameList1 CommaOpt
|
|
{
|
|
$$ = append([]string{$1.(string)}, $2.([]string)...)
|
|
}
|
|
|
|
ColumnNameList1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []string{}
|
|
}
|
|
| ColumnNameList1 ',' ColumnName
|
|
{
|
|
$$ = append($1.([]string), $3.(string))
|
|
}
|
|
|
|
CommitStmt:
|
|
"COMMIT"
|
|
{
|
|
$$ = commitStmt{}
|
|
}
|
|
|
|
Constraint:
|
|
"NOT" "NULL"
|
|
{
|
|
$$ = &constraint{}
|
|
}
|
|
| Expression
|
|
{
|
|
$$ = &constraint{expr($1)}
|
|
}
|
|
|
|
ConstraintOpt:
|
|
{
|
|
$$ = (*constraint)(nil)
|
|
}
|
|
| Constraint
|
|
|
|
Conversion:
|
|
Type '(' Expression ')'
|
|
{
|
|
$$ = &conversion{typ: $1.(int), val: expr($3)}
|
|
}
|
|
|
|
CreateIndexStmt:
|
|
"CREATE" CreateIndexStmtUnique "INDEX" CreateIndexIfNotExists identifier "ON" identifier '(' ExpressionList ')'
|
|
{
|
|
indexName, tableName, exprList := $5.(string), $7.(string), $9.([]expression)
|
|
simpleIndex := len(exprList) == 1
|
|
var columnName string
|
|
if simpleIndex {
|
|
expr := exprList[0]
|
|
switch x := expr.(type) {
|
|
case *ident:
|
|
columnName = x.s
|
|
case *call:
|
|
if x.f == "id" && len(x.arg) == 0 {
|
|
columnName = "id()"
|
|
break
|
|
}
|
|
|
|
simpleIndex = false
|
|
default:
|
|
simpleIndex = false
|
|
}
|
|
}
|
|
|
|
if !simpleIndex {
|
|
columnName = ""
|
|
}
|
|
$$ = &createIndexStmt{unique: $2.(bool), ifNotExists: $4.(bool), indexName: indexName, tableName: tableName, colName: columnName, exprList: exprList}
|
|
|
|
if indexName == tableName || indexName == columnName {
|
|
yylex.(*lexer).err("index name collision: %s", indexName)
|
|
return 1
|
|
}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[indexName] || isSystemName[tableName] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", indexName)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
CreateIndexIfNotExists:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IF" "NOT" "EXISTS"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
CreateIndexStmtUnique:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "UNIQUE"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
CreateTableStmt:
|
|
"CREATE" "TABLE" TableName '(' ColumnDef CreateTableStmt1 CommaOpt ')'
|
|
{
|
|
nm := $3.(string)
|
|
$$ = &createTableStmt{tableName: nm, cols: append([]*col{$5.(*col)}, $6.([]*col)...)}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[nm] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", nm)
|
|
return 1
|
|
}
|
|
}
|
|
| "CREATE" "TABLE" "IF" "NOT" "EXISTS" TableName '(' ColumnDef CreateTableStmt1 CommaOpt ')'
|
|
{
|
|
nm := $6.(string)
|
|
$$ = &createTableStmt{ifNotExists: true, tableName: nm, cols: append([]*col{$8.(*col)}, $9.([]*col)...)}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[nm] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", nm)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
CreateTableStmt1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []*col{}
|
|
}
|
|
| CreateTableStmt1 ',' ColumnDef
|
|
{
|
|
$$ = append($1.([]*col), $3.(*col))
|
|
}
|
|
|
|
Default:
|
|
"DEFAULT" Expression
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
DefaultOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| Default
|
|
|
|
DeleteFromStmt:
|
|
"DELETE" "FROM" TableName
|
|
{
|
|
$$ = &truncateTableStmt{$3.(string)}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[$3.(string)] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", $3.(string))
|
|
return 1
|
|
}
|
|
}
|
|
| "DELETE" "FROM" TableName WhereClause
|
|
{
|
|
$$ = &deleteStmt{tableName: $3.(string), where: $4.(*whereRset).expr}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[$3.(string)] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", $3.(string))
|
|
return 1
|
|
}
|
|
}
|
|
|
|
DropIndexStmt:
|
|
"DROP" "INDEX" DropIndexIfExists identifier
|
|
{
|
|
$$ = &dropIndexStmt{ifExists: $3.(bool), indexName: $4.(string)}
|
|
}
|
|
|
|
DropIndexIfExists:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IF" "EXISTS"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
DropTableStmt:
|
|
"DROP" "TABLE" TableName
|
|
{
|
|
nm := $3.(string)
|
|
$$ = &dropTableStmt{tableName: nm}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[nm] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", nm)
|
|
return 1
|
|
}
|
|
}
|
|
| "DROP" "TABLE" "IF" "EXISTS" TableName
|
|
{
|
|
nm := $5.(string)
|
|
$$ = &dropTableStmt{ifExists: true, tableName: nm}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[nm] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", nm)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
EmptyStmt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
|
|
ExplainStmt:
|
|
"EXPLAIN" Statement
|
|
{
|
|
$$ = &explainStmt{$2.(stmt)}
|
|
}
|
|
|
|
Expression:
|
|
Term
|
|
| Expression logOr Term
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation(oror, $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
logOr:
|
|
"||"
|
|
{
|
|
}
|
|
| "OR"
|
|
{
|
|
}
|
|
|
|
ExpressionList:
|
|
Expression ExpressionList1 CommaOpt
|
|
{
|
|
$$ = append([]expression{expr($1)}, $2.([]expression)...)
|
|
}
|
|
|
|
ExpressionList1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []expression(nil)
|
|
}
|
|
| ExpressionList1 ',' Expression
|
|
{
|
|
$$ = append($1.([]expression), expr($3))
|
|
}
|
|
|
|
Factor:
|
|
Factor1
|
|
| Factor1 "IN" '(' ExpressionList ')'
|
|
{
|
|
$$ = &pIn{expr: $1.(expression), list: $4.([]expression)}
|
|
}
|
|
| Factor1 "NOT" "IN" '(' ExpressionList ')'
|
|
{
|
|
$$ = &pIn{expr: $1.(expression), not: true, list: $5.([]expression)}
|
|
}
|
|
| Factor1 "IN" '(' SelectStmt semiOpt ')'
|
|
{
|
|
$$ = &pIn{expr: $1.(expression), sel: $4.(*selectStmt)}
|
|
}
|
|
| Factor1 "NOT" "IN" '(' SelectStmt semiOpt ')'
|
|
{
|
|
$$ = &pIn{expr: $1.(expression), not: true, sel: $5.(*selectStmt)}
|
|
}
|
|
| Factor1 "BETWEEN" PrimaryFactor "AND" PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBetween($1, $3, $5, false); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 "NOT" "BETWEEN" PrimaryFactor "AND" PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBetween($1, $4, $6, true); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 "IS" "NULL"
|
|
{
|
|
$$ = &isNull{expr: $1.(expression)}
|
|
}
|
|
| Factor1 "IS" "NOT" "NULL"
|
|
{
|
|
$$ = &isNull{expr: $1.(expression), not: true}
|
|
}
|
|
|
|
Factor1:
|
|
PrimaryFactor
|
|
| Factor1 ">=" PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation(ge, $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 '>' PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation('>', $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 "<=" PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation(le, $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 '<' PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation('<', $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 "!=" PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation(neq, $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 "==" PrimaryFactor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation(eq, $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| Factor1 "LIKE" PrimaryFactor
|
|
{
|
|
$$ = &pLike{expr: $1.(expression), pattern: $3.(expression)}
|
|
}
|
|
|
|
Field:
|
|
Expression Field1
|
|
{
|
|
expr, name := expr($1), $2.(string)
|
|
if name == "" {
|
|
s, ok := expr.(*ident)
|
|
if ok {
|
|
name = s.s
|
|
}
|
|
}
|
|
$$ = &fld{expr: expr, name: name}
|
|
}
|
|
|
|
Field1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "AS" identifier
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
FieldList:
|
|
Field
|
|
{
|
|
$$ = []*fld{$1.(*fld)}
|
|
}
|
|
| FieldList ',' Field
|
|
{
|
|
l, f := $1.([]*fld), $3.(*fld)
|
|
if f.name != "" {
|
|
if f := findFld(l, f.name); f != nil {
|
|
yylex.(*lexer).err("duplicate field name %q", f.name)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
$$ = append($1.([]*fld), $3.(*fld))
|
|
}
|
|
|
|
GroupByClause:
|
|
"GROUP" "BY" ColumnNameList
|
|
{
|
|
$$ = &groupByRset{colNames: $3.([]string)}
|
|
}
|
|
|
|
Index:
|
|
'[' Expression ']'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
InsertIntoStmt:
|
|
"INSERT" "INTO" TableName InsertIntoStmt1 "VALUES" '(' ExpressionList ')' InsertIntoStmt2 CommaOpt
|
|
{
|
|
$$ = &insertIntoStmt{tableName: $3.(string), colNames: $4.([]string), lists: append([][]expression{$7.([]expression)}, $9.([][]expression)...)}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[$3.(string)] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", $3.(string))
|
|
return 1
|
|
}
|
|
}
|
|
| "INSERT" "INTO" TableName InsertIntoStmt1 SelectStmt
|
|
{
|
|
$$ = &insertIntoStmt{tableName: $3.(string), colNames: $4.([]string), sel: $5.(*selectStmt)}
|
|
}
|
|
|
|
InsertIntoStmt1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []string{}
|
|
}
|
|
| '(' ColumnNameList ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
InsertIntoStmt2:
|
|
/* EMPTY */
|
|
{
|
|
$$ = [][]expression{}
|
|
}
|
|
| InsertIntoStmt2 ',' '(' ExpressionList ')'
|
|
{
|
|
$$ = append($1.([][]expression), $4.([]expression))
|
|
}
|
|
|
|
Literal:
|
|
"false"
|
|
| "NULL"
|
|
| "true"
|
|
| floatLit
|
|
| imaginaryLit
|
|
| intLit
|
|
| stringLit
|
|
|
|
Operand:
|
|
Literal
|
|
{
|
|
$$ = value{$1}
|
|
}
|
|
| qlParam
|
|
{
|
|
n := $1.(int)
|
|
$$ = parameter{n}
|
|
l := yylex.(*lexer)
|
|
l.params = mathutil.Max(l.params, n)
|
|
if n == 0 {
|
|
l.err("parameter number must be non zero")
|
|
return 1
|
|
}
|
|
}
|
|
| QualifiedIdent
|
|
{
|
|
$$ = &ident{$1.(string)}
|
|
}
|
|
| '(' Expression ')'
|
|
{
|
|
$$ = &pexpr{expr: expr($2)}
|
|
}
|
|
|
|
OrderBy:
|
|
"ORDER" "BY" ExpressionList OrderBy1
|
|
{
|
|
$$ = &orderByRset{by: $3.([]expression), asc: $4.(bool)}
|
|
}
|
|
|
|
OrderBy1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = true // ASC by default
|
|
}
|
|
| "ASC"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "DESC"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
PrimaryExpression:
|
|
Operand
|
|
| Conversion
|
|
| PrimaryExpression Index
|
|
{
|
|
var err error
|
|
if $$, err = newIndex($1.(expression), expr($2)); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryExpression Slice
|
|
{
|
|
var err error
|
|
s := $2.([2]*expression)
|
|
if $$, err = newSlice($1.(expression), s[0], s[1]); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryExpression Call
|
|
{
|
|
x := yylex.(*lexer)
|
|
f, ok := $1.(*ident)
|
|
if !ok {
|
|
x.err("expected identifier or qualified identifier")
|
|
return 1
|
|
}
|
|
|
|
if r, ok := $2.(rune); ok {
|
|
if f.isQualified() || f.s != "count" || r != '*' {
|
|
x.err(fmt.Sprintf("invalid expression %s(%c)", f, r))
|
|
return 1
|
|
}
|
|
|
|
$2 = []expression(nil)
|
|
}
|
|
|
|
var err error
|
|
var agg bool
|
|
if $$, agg, err = newCall(f.s, $2.([]expression)); err != nil {
|
|
x.err("%v", err)
|
|
return 1
|
|
}
|
|
if n := len(x.agg); n > 0 {
|
|
x.agg[n-1] = x.agg[n-1] || agg
|
|
}
|
|
}
|
|
|
|
PrimaryFactor:
|
|
PrimaryTerm
|
|
| PrimaryFactor '^' PrimaryTerm
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation('^', $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryFactor '|' PrimaryTerm
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation('|', $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryFactor '-' PrimaryTerm
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation('-', $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryFactor '+' PrimaryTerm
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation('+', $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
PrimaryTerm:
|
|
UnaryExpr
|
|
| PrimaryTerm "&^" UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation(andnot, $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryTerm '&' UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation('&', $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryTerm "<<" UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation(lsh, $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryTerm ">>" UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation(rsh, $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryTerm '%' UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation('%', $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryTerm '/' UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation('/', $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| PrimaryTerm '*' UnaryExpr
|
|
{
|
|
var err error
|
|
$$, err = newBinaryOperation('*', $1, $3)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
QualifiedIdent:
|
|
identifier
|
|
| identifier '.' identifier
|
|
{
|
|
$$ = fmt.Sprintf("%s.%s", $1.(string), $3.(string))
|
|
}
|
|
|
|
RecordSet:
|
|
RecordSet1 RecordSet2
|
|
{
|
|
$$ = []interface{}{$1, $2}
|
|
}
|
|
|
|
RecordSet1:
|
|
identifier
|
|
| '(' SelectStmt semiOpt ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
semiOpt:
|
|
/* EMPTY */
|
|
| ';'
|
|
|
|
RecordSet2:
|
|
/* EMPTY */
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "AS" identifier
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
RecordSetList:
|
|
RecordSet
|
|
{
|
|
$$ = []interface{}{$1}
|
|
}
|
|
| RecordSetList ',' RecordSet
|
|
{
|
|
$$ = append($1, $3)
|
|
}
|
|
|
|
RollbackStmt:
|
|
"ROLLBACK"
|
|
{
|
|
$$ = rollbackStmt{}
|
|
}
|
|
|
|
JoinType:
|
|
"LEFT"
|
|
{
|
|
$$ = leftJoin
|
|
}
|
|
| "RIGHT"
|
|
{
|
|
$$ = rightJoin
|
|
}
|
|
| "FULL"
|
|
{
|
|
$$ = fullJoin
|
|
}
|
|
|
|
OuterOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "OUTER"
|
|
|
|
JoinClause:
|
|
JoinType OuterOpt "JOIN" RecordSet "ON" Expression
|
|
{
|
|
$$ = []interface{}{$1, $4, $6}
|
|
}
|
|
|
|
JoinClauseOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| JoinClause
|
|
|
|
SelectStmt:
|
|
"SELECT" SelectStmtDistinct SelectStmtFieldList "FROM" RecordSetList
|
|
CommaOpt JoinClauseOpt SelectStmtWhere SelectStmtGroup SelectStmtOrder
|
|
SelectStmtLimit SelectStmtOffset
|
|
{
|
|
x := yylex.(*lexer)
|
|
n := len(x.agg)
|
|
join := &joinRset{sources: $5}
|
|
if o := $7; o != nil {
|
|
o := o.([]interface{})
|
|
join.typ = o[0].(int)
|
|
join.sources = append(join.sources, o[1].([]interface{}))
|
|
join.on = o[2].(expression)
|
|
}
|
|
$$ = &selectStmt{
|
|
distinct: $2.(bool),
|
|
flds: $3.([]*fld),
|
|
from: join,
|
|
hasAggregates: x.agg[n-1],
|
|
where: $8.(*whereRset),
|
|
group: $9.(*groupByRset),
|
|
order: $10.(*orderByRset),
|
|
limit: $11.(*limitRset),
|
|
offset: $12.(*offsetRset),
|
|
}
|
|
x.agg = x.agg[:n-1]
|
|
}
|
|
|
|
SelectStmtLimit:
|
|
{
|
|
$$ = (*limitRset)(nil)
|
|
}
|
|
| "LIMIT" Expression
|
|
{
|
|
$$ = &limitRset{expr: expr($2)}
|
|
}
|
|
|
|
SelectStmtOffset:
|
|
{
|
|
$$ = (*offsetRset)(nil)
|
|
}
|
|
| "OFFSET" Expression
|
|
{
|
|
$$ = &offsetRset{expr: expr($2)}
|
|
}
|
|
|
|
SelectStmtDistinct:
|
|
/* EMPTY */
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DISTINCT"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
SelectStmtFieldList:
|
|
'*'
|
|
{
|
|
$$ = []*fld{}
|
|
}
|
|
| FieldList
|
|
{
|
|
$$ = $1
|
|
}
|
|
| FieldList ','
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
SelectStmtWhere:
|
|
/* EMPTY */
|
|
{
|
|
$$ = (*whereRset)(nil)
|
|
}
|
|
| WhereClause
|
|
|
|
SelectStmtGroup:
|
|
/* EMPTY */
|
|
{
|
|
$$ = (*groupByRset)(nil)
|
|
}
|
|
| GroupByClause
|
|
|
|
SelectStmtOrder:
|
|
/* EMPTY */
|
|
{
|
|
$$ = (*orderByRset)(nil)
|
|
}
|
|
| OrderBy
|
|
|
|
Slice:
|
|
'[' ':' ']'
|
|
{
|
|
$$ = [2]*expression{nil, nil}
|
|
}
|
|
| '[' ':' Expression ']'
|
|
{
|
|
hi := expr($3)
|
|
$$ = [2]*expression{nil, &hi}
|
|
}
|
|
| '[' Expression ':' ']'
|
|
{
|
|
lo := expr($2)
|
|
$$ = [2]*expression{&lo, nil}
|
|
}
|
|
| '[' Expression ':' Expression ']'
|
|
{
|
|
lo := expr($2)
|
|
hi := expr($4)
|
|
$$ = [2]*expression{&lo, &hi}
|
|
}
|
|
|
|
Statement:
|
|
EmptyStmt
|
|
| AlterTableStmt
|
|
| BeginTransactionStmt
|
|
| CommitStmt
|
|
| CreateIndexStmt
|
|
| CreateTableStmt
|
|
| DeleteFromStmt
|
|
| DropIndexStmt
|
|
| DropTableStmt
|
|
| ExplainStmt
|
|
| InsertIntoStmt
|
|
| RollbackStmt
|
|
| SelectStmt
|
|
| TruncateTableStmt
|
|
| UpdateStmt
|
|
|
|
StatementList:
|
|
Statement
|
|
{
|
|
if $1 != nil {
|
|
yylex.(*lexer).list = []stmt{$1.(stmt)}
|
|
}
|
|
}
|
|
| StatementList ';' Statement
|
|
{
|
|
if $3 != nil {
|
|
yylex.(*lexer).list = append(yylex.(*lexer).list, $3.(stmt))
|
|
}
|
|
}
|
|
|
|
TableName:
|
|
identifier
|
|
|
|
Term:
|
|
Factor
|
|
| Term logAnd Factor
|
|
{
|
|
var err error
|
|
if $$, err = newBinaryOperation(andand, $1, $3); err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
logAnd:
|
|
"&&"
|
|
{
|
|
}
|
|
| "AND"
|
|
{
|
|
}
|
|
|
|
TruncateTableStmt:
|
|
"TRUNCATE" "TABLE" TableName
|
|
{
|
|
$$ = &truncateTableStmt{tableName: $3.(string)}
|
|
}
|
|
|
|
Type:
|
|
"bigint"
|
|
| "bigrat"
|
|
| "blob"
|
|
| "bool"
|
|
| "byte"
|
|
| "complex128"
|
|
| "complex64"
|
|
| "duration"
|
|
| "float"
|
|
| "float32"
|
|
| "float64"
|
|
| "int"
|
|
| "int16"
|
|
| "int32"
|
|
| "int64"
|
|
| "int8"
|
|
| "rune"
|
|
| "string"
|
|
| "time"
|
|
| "uint"
|
|
| "uint16"
|
|
| "uint32"
|
|
| "uint64"
|
|
| "uint8"
|
|
|
|
UpdateStmt:
|
|
"UPDATE" TableName SetOpt AssignmentList UpdateStmt1
|
|
{
|
|
var expr expression
|
|
if w := $5; w != nil {
|
|
expr = w.(*whereRset).expr
|
|
}
|
|
$$ = &updateStmt{tableName: $2.(string), list: $4.([]assignment), where: expr}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
|
|
if isSystemName[$2.(string)] {
|
|
yylex.(*lexer).err("name is used for system tables: %s", $2.(string))
|
|
return 1
|
|
}
|
|
}
|
|
|
|
UpdateStmt1:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
| WhereClause
|
|
|
|
UnaryExpr:
|
|
PrimaryExpression
|
|
| '^' PrimaryExpression
|
|
{
|
|
var err error
|
|
$$, err = newUnaryOperation('^', $2)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| '!' PrimaryExpression
|
|
{
|
|
var err error
|
|
$$, err = newUnaryOperation('!', $2)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| '-' PrimaryExpression
|
|
{
|
|
var err error
|
|
$$, err = newUnaryOperation('-', $2)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
| '+' PrimaryExpression
|
|
{
|
|
var err error
|
|
$$, err = newUnaryOperation('+', $2)
|
|
if err != nil {
|
|
yylex.(*lexer).err("%v", err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
WhereClause:
|
|
"WHERE" Expression
|
|
{
|
|
$$ = &whereRset{expr: expr($2)}
|
|
}
|
|
|
|
|
|
SetOpt:
|
|
{
|
|
}
|
|
| "SET"
|
|
{
|
|
}
|
|
|
|
CommaOpt:
|
|
{
|
|
}
|
|
| ','
|
|
{
|
|
}
|
|
|
|
%%
|
|
|
|
func expr(v interface{}) expression {
|
|
e := v.(expression)
|
|
for {
|
|
x, ok := e.(*pexpr)
|
|
if !ok {
|
|
return e
|
|
}
|
|
e = x.expr
|
|
}
|
|
}
|